整理自尚硅谷周阳老师docker笔记
文章目录
一、Docker简介
1. 是什么?
docker是容器虚拟化技术
Docker是基于Go语言实现的云开源项目。
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”
。
Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。将应用运行在 Docker 容器上面,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。
解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
Docker版本
docker-io 是以前早期的版本,版本号是 1.*,最新版是 1.13,而 docker-ce 是新的版本,分为社区版 docker-ce 和企业版 docker-ee,版本号是 17.*
2. 能干嘛?
一次构建、随处运行
Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统
,而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
比较 Docker 和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。
- 而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,
而且也没有进行硬件虚拟。
因此容器要比传统虚拟机更为轻便。 - 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
3. 去哪下?
docker官网:http://www.docker.com docker
中文网站:https://www.docker-cn.com/
Docker Hub官网(仓库,一般用阿里网易镜像加速):https://hub.docker.com/
二、Docker安装
1. 前提说明
CentOS Docker 安装
Docker支持以下的CentOS版本:
- CentOS 7 (64-bit)
- CentOS 6.5 (64-bit) 或更高的版本
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。
- Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
- Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、
系统内核版本为 2.6.32-431 或者更高版本。
查看自己的内核
uname 命令用于打印当前系统相关信息(内核版本号、硬件架构、主机名称和操作系统类型等)。
[root@localhost ~]$ uname -r
2.6.32-642.el6.x86_64
查看已安装的CentOS版本信息(CentOS6.8有,CentOS7无该命令)
[root@localhost ~]$ cat /etc/redhat-release
CentOS release 6.8(Final)
升级系统内核
Centos6更新yum源仓库,升级内核
[root@localhost ~]$ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
[root@localhost ~]$ yum clean all
[root@localhost ~]$ yum -y update
[root@localhost ~]$ yum makecache
如果报错If above article doesn't help to resolve this issue please open a ticket wit
http://mirrors.cloud.aliyuncs.com/centos/6/os/x86_64/repodata/repomd.xml: [Errno 14] PYCURL ERROR 6 - "Couldn't resolve host 'mirrors.cloud.aliyuncs.com'"
解决办法:
CentOS 6已经经历了2020年11月的结束进入了EOL(生命终结),不过有一些老设备依然需要支持,CentOS官方也给这些还不想把CentOS 6扔进垃圾堆的用户保留了最后一个版本的充分,只是这个有意义不会再有更新了
官方便在12月2日正式将CentOS 6相关的软件源移出了官方资源,随之而来逐级甚至也会陆续将其删除。
一键修复(复制到SSH执行即可):
[root@localhost ~]$ sed -i "s|enabled=1|enabled=0|g" /etc/yum/pluginconf.d/fastestmirror.conf
[root@localhost ~]$ mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
[root@localhost ~]$ curl -o /etc/yum.repos.d/CentOS-Base.repo https://www.xmpan.com/Centos-6-Vault-Aliyun.repo
[root@localhost ~]$ yum clean all
[root@localhost ~]$ yum makecache
ELRepo 仓库是基于社区的用于企业级 Linux 仓库,提供对 RedHat Enterprise (RHEL) 和 其他基于 RHEL的 Linux 发行版(CentOS、Scientific、Fedora 等)的支持。
ELRepo 聚焦于和硬件相关的软件包,包括文件系统驱动、显卡驱动、网络驱动、声卡驱动和摄像头驱动等。#导入ELRepo仓库的公共密钥
[root@localhost ~]$ rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
安装ELRepo仓库的yum源
[root@localhost ~]$ rpm -Uvh http://www.elrepo.org/elrepo-release-6-8.el6.elrepo.noarch.rpm
安装 kernel-lt(lt=long-term)lt长期稳定版
[root@localhost ~]$ yum --enablerepo=elrepo-kernel install kernel-lt -y
编辑grub.conf文件,修改Grub引导顺序
[root@localhost ~]$ vim /etc/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE: You have a /boot partition. This means that
# all kernel and initrd paths are relative to /boot/, eg.
# root (hd0,0)
# kernel /vmlinuz-version ro root=/dev/mapper/vg_centos6-lv_root
# initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=1 #0,修改成4.4的内核,改成0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (4.4.239-1.el6.elrepo.x86_64)
root (hd0,0)
kernel /vmlinuz-4.4.239-1.el6.elrepo.x86_64 ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS rd_NO_MD rd_LVM_LV=vg_centos6/lv_swap crashkernel=auto LANG=zh_CN.UTF-8 rd_LVM_LV=vg_centos6/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-4.4.239-1.el6.elrepo.x86_64.img
title CentOS 6 (2.6.32-642.el6.x86_64)
root (hd0,0)
kernel /vmlinuz-2.6.32-642.el6.x86_64 ro root=/dev/mapper/vg_centos6-lv_root rd_NO_LUKS rd_NO_MD rd_LVM_LV=vg_centos6/lv_swap crashkernel=auto LANG=zh_CN.UTF-8 rd_LVM_LV=vg_centos6/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-642.el6.x86_64.img
[root@localhost ~]$ reboot #重启系统
Centos7更新yum源仓库,升级内核
[root@localhost ~]$ wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
或者
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@localhost ~]$ yum clean all
[root@localhost ~]$ yum -y update
[root@localhost ~]$ yum makecache
ELRepo 仓库是基于社区的用于企业级 Linux 仓库,提供对 RedHat Enterprise (RHEL) 和 其他基于 RHEL的 Linux 发行版(CentOS、Scientific、Fedora 等)的支持。
ELRepo 聚焦于和硬件相关的软件包,包括文件系统驱动、显卡驱动、网络驱动、声卡驱动和摄像头驱动等。#导入ELRepo仓库的公共密钥
[root@localhost ~]$ rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
安装ELRepo仓库的yum源
[root@localhost ~]$ rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
查看可用的系统内核包
[root@localhost ~]$ yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
安装最新版本内核
–enablerepo 选项开启 CentOS 系统上的指定仓库。默认开启的是 elrepo,这里用 elrepo-kernel 替换。
[root@localhost ~]$ yum --enablerepo=elrepo-kernel install kernel-ml
查看系统上的所有可用内核
[root@localhost ~]$ awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
0 : CentOS Linux (4.18.7-1.el7.elrepo.x86_64) 7 (Core)
1 : CentOS Linux (3.10.0-862.11.6.el7.x86_64) 7 (Core)
2 : CentOS Linux (3.10.0-514.el7.x86_64) 7 (Core)
3 : CentOS Linux (0-rescue-063ec330caa04d4baae54c6902c62e54) 7 (Core)
设置 GRUB 默认的内核版本
编辑 /etc/default/grub
文件设置 GRUB_DEFAULT=0
,通过上面查询显示的编号为 0 的内核作为默认内核:
[root@localhost ~]$ vim /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=0
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=cl/root rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
运行下面的命令来重新创建内核配置。
[root@localhost ~]$ grub2-mkconfig -o /boot/grub2/grub.cfg
验证
[root@localhost ~]$ uname -r
删除旧内核
[root@localhost ~]$ rpm -qa | grep kernel
[root@localhost ~]$ yum remove kernel-3.10.0-514.el7.x86_64
升级系统内核为 4.44
CentOS 7.x 系统自带的 3.10.x 内核存在一些 Bugs,导致运行的 Docker不稳定
[root@localhost ~]$ rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
# 安装完成后检查 /boot/grub2/grub.cfg 中对应内核 menuentry 中是否包含 initrd16 配置,如果没有,再安装一次!
[root@localhost ~]$ yum --enablerepo=elrepo-kernel install -y kernel-lt
# 设置开机从新内核启动
[root@localhost ~]$ grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)' && reboot
2. Docker的基本组成
镜像(image)
镜像,简单的来说,就是面向对象中的类,相当于一个模板。
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。
相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。
容器(container)
1. 从面向对象角度
Docker 利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例
。
它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
2. 从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境
(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的
仓库(repository)
仓库(Repository)是集中存放镜像
文件的场所。
仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为**公开仓库(Public)和私有仓库(Private)**两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云 等
3. 安装步骤
Centos 6.8 安装Docker
Docker使用EPEL发布,RHEL系的OS首先要确保已经持有EPEL仓库,否则先检查OS的版本,然后安装相应的EPEL包。
[root@localhost ~]$ yum install -y epel-release
[root@localhost ~]$ yum install -y docker-io
安装后的配置文件:
[root@localhost ~]$ cat /etc/sysconfig/docker
# etc/sysconfig/docker
#
# other arguments to pass to the docker daemon process
# These wiil be parsed by the sysv initscript and appended
# to the arguments list passed to docker -d
other_args=
DOCKER_CERT_PATH=ietc/docker
# Resolves:rhbz#1176302( docker issue #407)
DOCKER_NOWARN_KERNEL_VERSION=1
# Location used for temporary files,such as those created by
# # docker load and build operations. Default is /var/lib/docker/tmp
# # Can be overriden by setting the following environment variable.
# # DOCKER_TMPDIR=/var/tmp
启动Docker后台服务:
[root@localhost ~]$ service docker start
验证是否安装成功:
[root@localhost ~]$ docker version
卸载Docker
查询安装过的包:
[root@localhost ~]$ yum list installed | grep docker
docker-io.x86_64 1.7.1-2.el6 @epel
删除安装的软件包:
[root@localhost ~]$ yum -y remove docker-io.x86_64
Centos 7 安装Docker
安装gcc相关:
[root@localhost ~]$ yum -y install gcc gcc-c++
卸载旧版本:
[root@localhost ~]$ yum -y remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
安装需要的软件包:
[root@localhost ~]$ yum install -y yum-utils device-mapper-persistent-data lvm2
设置stable镜像仓库:
[root@localhost ~]$ yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum软件包索引:
[root@localhost ~]$ yum makecache fast
安装Docker ce:
[root@localhost ~]$ yum -y install docker-ce docker-ce-cli containerd.io
启动docker:
[root@localhost ~]$ systemctl start docker
测试:
[root@localhost ~]$ docker version
配置镜像加速:
[root@localhost ~]$ mkdir -p /etc/docker
#直接粘贴
[root@localhost ~]$ tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"]
}
EOF
# 重启docker
[root@localhost ~]$ systemctl daemon-reload
[root@localhost ~]$ systemctl restart docker
卸载:
[root@localhost ~]$ systemctl stop docker
[root@localhost ~]$ yum remove docker-ce docker-ce-cli containerd.io
[root@localhost ~]$ rm -rf /var/lib/docker
[root@localhost ~]$ rm -rf /var/lib/containerd
4. 永远的HelloWorld
启动Docker后台容器:
[root@localhost ~]$ docker run hello-world
输出 Hello from Docker! 这段提示以后,hello world就会停止运行,容器自动终止。
run干了什么?
5. 底层原理
Docker是怎么工作的?
详细了解Docker怎么工作的
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是鲸鱼背上的集装箱。
Docker运行的基本流程为:
- 用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
- Docker Daemon作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client的请求。
- Docker Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
- Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
- 当需要为Docker创建网络环境时,通过网络管理驱动Network driver创建并配置Docker容器网络环境。
- 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过Exec driver来完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
为什么Docker比较比VM快?
-
docker有着比虚拟机更少的抽象层。
由亍docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。 -
docker利用的是宿主机的内核,而不需要Guest OS。
因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。仍而避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。
三、Docker常用命令
3.1 帮助命令
[root@localhost ~]$ docker version
[root@localhost ~]$ docker info
[root@localhost ~]$ docker --help
含义 | 命令 |
---|---|
启动docker | systemctl start docker |
停止docker | systemctl stop docker |
重启docker | systemctl restart docker |
查看docker状态 | systemctl status docker |
开机启动 | systemctl enable docker |
查看docker概要信息 | dockerinfo |
查看docker总体帮助文档 | docker–help |
查看docker命令帮助文档 | docker具体命令–help |
3.2 镜像命令
#列出本地主机上的镜像:
[root@localhost ~]$ docker images [参数]
参数:
-a: 列出本地所有的镜像(含中间映像层)
-q: 只显示镜像ID
--digests: 显示镜像的摘要信息
--no-trunc: 显示完整的镜像信息
输出详情介绍:
REPOSITORY: 表示镜像的仓库源
TAG: 镜像的标签版本号
IMAGE ID: 镜像ID
CREATED: 镜像创建时间
SIZE: 镜像大小
含义 | 命令 |
---|---|
搜索镜像 | docker search 镜像名字 |
下载镜像 | docker pull 镜像名字 : [tag(版本)] |
查看镜像/容器/数据卷所占的空间 | docker system df |
删除单个镜像 | docker rmi -f 镜像名字ID |
删除多个镜像 | docker rmi -f 镜像名1:TAG 镜像名2:TAG |
删除全部 | docker rmi -f ${docker images -qa} |
3.3 容器命令
有镜像才能创建容器,这是根本前提(下载一个CentOS镜像演示)
[root@localhost ~]$ docker pull ubuntu
新建并启动容器:
[root@localhost ~]$ docker run [OPTIONS] 镜像名 [COMMAND] [ARG...]
选项:
--name="容器新名字": 为容器指定一个名称;
--link=[]: 添加链接到另一个容器;
-h "mars": 指定容器的hostname;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i: 以交互模式运行容器,通常与 -t 同时使用; (常用)
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;(常用)
-v: 绑定一个卷
-P: 随机端口映射;
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort(常用)
containerPort
启动交互式容器:
[root@localhost ~]$ docker run -it ubuntu /bin/bash
#使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
#/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
#要退出终端,直接输入 exit:
Docker中run和start的区别:
docker run 后面指定的是一个镜像
docker start 指定的是一个容器
docker run是利用镜像生成容器,并启动容器,而docker start是启动一个之前生成过的容器
-
docker run只有在第一次运行时使用,将镜像放到容器中,以后再次启动这个容器的时候,只需要使用命令docker start就可以。
docker run相当于执行了两步操作:将镜像(Image)放到容器(Container)中,这一步过程叫做docker create,然后将容器启动,使之变成运行时容器(docker start)。 -
docker start的作用是:重新启动已经存在的容器。也就是说,如果使用这个命令,我们必须先要知道这个容器的ID、或者这个容器的名字,我们可以使用docker ps命令找到这个容器的信息。
列出当前所有正在运行的容器:
[root@localhost ~]$ docker ps [参数]
参数:
-a : 列出当前所有正在运行的容器+历史上运行过的
-l : 显示最近创建的容器。
-n : 显示最近n个创建的容器。
-q : 静默模式,只显示容器编号。
--no-trunc : 不截断输出。
输出详情介绍:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
状态有7种:
created(已创建)
restarting(重启中)
running(运行中)
removing(迁移中)
paused(暂停)
exited(停止)
dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
列出最近创建的5个容器信息:
[root@localhost ~]$ docker ps -n 5
退出容器:
容器停止退出:
run进去容器,exit退出,容器停止
[root@localhost ~]$ exit
容器不停止退出:
ctrl+q+p
启动容器:
[root@localhost ~]$ docker start 容器ID或者容器名
重启容器:
[root@localhost ~]$ docker restart 容器ID或者容器名
停止容器:
[root@localhost ~]$ docker stop 容器ID或者容器名
强制停止容器:
[root@localhost ~]$ docker kill 容器ID或者容器名
删除已停止的容器:
[root@localhost ~]$ docker rm 容器ID
[root@localhost ~]$ docker rm -f $(docker ps -a -q) #删除多个容器
[root@localhost ~]$ docker ps -a -q | xargs docker rm #删除多个容器,同样效果
重要
启动守护式容器:
[root@localhost ~]$ docker run -d 容器名
[root@localhost ~]$ docker run -d ubuntu
然后docker ps -a 进行查看, 会发现容器已经退出
很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.
容器运行的命令如果不是那些一直挂起的命令
(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可
举例:redis 前后台启动演示
前台交互式启动
docker run -it redis:6.0.8
后台守护式启动
docker run -d redis:6.0.8
查看容器日志:
[root@localhost ~]$ docker logs [参数] 容器ID
参数:
-f : 跟随最新的日志打印
--since : 显示某个开始时间的所有日志
-t : 显示时间戳
--tail 数字: 仅列出最新N条容器日志
[root@localhost ~]$ docker logs -tf --tail 10 44ca95550bfe
查看容器内运行的进程:
[root@localhost ~]$ docker top 容器ID
查看容器内部细节:
[root@localhost ~]$ docker inspect 容器ID
进入正在运行的容器并以命令行交互:
[root@localhost ~]$ docker exec -it 容器ID /bin/bash
[root@localhost ~]$ docker attach 容器ID
exec和attach的区别:
-
exec 是在容器中打开新的终端,并且可以启动新的进程,可以在容器外面直接运行命令,也可以进入容器里面运行命令
-
attach 直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。
推荐使用 docker exec
一般用 -d 后台启动的程序,再用 exec 进入对应容器实例
查看容器内的目录:
[root@localhost ~]$ docker exec -it 容器ID ls
从容器内拷贝文件到主机上:
[root@localhost ~]$ docker cp 容器ID:容器内路径 目的主机路径
将主机/root目录拷贝到容器6ac9221c9a54的/tmp目录下:
[root@localhost ~]$ docker cp /root 6ac9221c9a54:/tmp
将容器6ac9221c9a54的/tmp目录拷贝到主机的/root目录中:
[root@localhost ~]$ docker cp 6ac9221c9a54:/tmp /root
导入和导出容器
- export 导出容器的内容留作为一个tar归档文件[对应import命令]
- import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
举例:
[root@localhost ~]$ docker export 容器ID > 文件名.tar
[root@localhost ~]$ cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
四、Docker镜像
4.1 是什么?
是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加
,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。
这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
Docker镜像特点
Docker镜像都是只读的,容器层是可写的,当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
为什么镜像要采用分层的架构?
最大的一个好处就是 - 共享资源
比如:有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
4.2 Docker镜像commit操作
docker commit提交容器副本使之成为一个新的镜像
语法格式:
[root@localhost ~]$ docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
案例1:运行tomcat
从Hub上下载tomcat镜像到本地并成功运行
[root@localhost ~]$ docker run -it -p 8080:8080 tomcat
故意删除上一步镜像生产tomcat容器的文档
[root@localhost ~]$ docker ps
[root@localhost ~]$ docker exec -it d5345dfs345(容器id) /bin/bash
[root@d5345dfs345 ]$ ls -l
[root@d5345dfs345 ]$ cd /usr/local/tomcat/webapps
[root@d5345dfs345 ]$ rm -rf docs
也即当前的tomcat运行实例是一个没有文档内容的容器,以它为模板commit一个没有doc的tomcat新镜像atguigu/tomcat02
[root@localhost ~]$ docker commit -a="root" -m="delete tocat docs" d5345dfs345 demo/tomcat02:1.2
启动我们的新镜像并和原来的对比
[root@localhost ~]$ docker run -it -p 7777:8080 demo/tomcat02:1.2
[root@localhost ~]$ docker run -it -p 8888:8080 tomcat
案例2:ubuntu安装vim
从Hub上下载ubuntu镜像到本地并成功运行
[root@localhost ~]$ docker pull ubuntu
外网连通的情况下,安装vim
[root@localhost ~]$ docker run -it ubuntu
# 更新包管理工具
root@0ab002f320ca:/# apt-get update
# 安装需要的vim
root@0ab002f320ca:/# apt-get -y install vim
安装完成后,commit我们自己的新镜像
[root@localhost ~]$ docker commit -m="add vim cmd" -a="root" 0ab002f320ca myubuntu:1.1
sha256:a8916b173c93783cbadb8c28cb555ea60681cb9599c2a19ced3dbdc7461cd8b7
启动我们的新镜像并和原来的对比
[root@localhost ~]$ docker images
[root@localhost ~]$ docker run -it a8916b173c93
小总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层
4.3 Docker镜像发布
本地镜像发布到私有库
本地镜像发布到私有库流程
将本地镜像推送到私有库
1 下载镜像Docker Registry
[root@localhost ~]$ docker pull registry
2 运行私有库Registry,相当于本地有个私有Docker hub
[root@localhost ~]$ mkdir -p /volume/registry
[root@localhost ~]$ docker run -d -p 5000:5000 -v /volume/registry/:/tmp/registry --privileged=true registry
# 默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
3 案例演示创建一个新镜像,ubuntu安装ifconfig命令
[root@localhost ~]$ docker run -it ubuntu /bin/bash
#docker容器内执行上述两条命令:
root@d9c58e70d1ae:/# apt-get update
root@d9c58e70d1ae:/# apt-get install net-tools
# commit自己的镜像
#公式:
#docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
[root@localhost ~]$ docker commit -m="ifconfig cmd add" -a="root" d9c58e70d1ae ubuntu/ifconfig:1.2
4 curl验证私服库上有什么镜像
[root@localhost ~]$ curl -XGET http://192.168.88.13:5000/v2/_catalog
{"repositories":[]}
#可以看到,目前私服库没有任何镜像上传过
5 将新镜像ubuntu/ifconfig:1.2修改符合私服规范的Tag
#按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
#使用命令 docker tag 将ubuntu/ifconfig:1.2 这个镜像修改为192.168.88.13:5000/ubuntu/ifconfig:1.2
[root@localhost ~]$ docker tag ubuntu/ifconfig:1.2 192.168.88.13:5000/ubuntu/ifconfig:1.2
6 修改配置文件使之支持http
#docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。
[root@localhost ~]$ cat > /etc/docker/daemon.json << EOF
{
"registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.88.13:5000"]
}
EOF
#重启
[root@localhost ~]$ systemctl restart docker
[root@localhost ~]$ docker run -d -p 5000:5000 -v /volume/registry/:/tmp/registry --privileged=true registry
7 push推送到私服库
[root@localhost ~]$ docker push 192.168.88.13:5000/ubuntu/ifconfig:1.2
8 curl验证私服库上有什么镜像2
[root@localhost ~]$ curl -XGET http://192.168.88.13:5000/v2/_catalog
{"repositories":["ubuntu/ifconfig"]}
9 pull到本地并运行
# 删除本地镜像
[root@localhost ~]$ docker rmi -f 3a627c8b283a
[root@localhost ~]$ docker pull 192.168.88.13:5000/ubuntu/ifconfig:1.2
五、Docker容器数据卷
5.1 是什么
将docker容器内的数据保存进宿主机的磁盘中
先来看看Docker的理念:
- 将运用与运行的环境打包形成容器运行 ,运行可以伴随着容器,但是我们对数据的要求希望是持久化的
- 容器之间希望有可能共享数据
Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。
为了能保存数据在docker中我们使用卷。
有点类似我们Redis里面的rdb和aof文件
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化
,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
5.2 能干嘛
容器的持久化
容器间的继承+共享数据
卷就是目录或文件
,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
5.3 数据卷
容器内目录和宿主机目录进行挂载
5.3.1 直接命令添加
命令:
[root@localhost ~]$ docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用–privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
案例:
在容器中创建 mydataVolume 目录,与宿主机的 /dataVolumeContainer绑定,实现数据共享
[root@localhost ~]$ docker run -it -v /tmp/host_data:/tmp/docker_date --privileged=true --name=u1 ubuntu
root@5f08ea4bc963:/# cd /tmp/docker_date #容器内操作
root@5f08ea4bc963:/tmp/docker_date# touch dockerin.txt
[root@localhost ~]$ cd /tmp/host_data/ #宿主机操作
[root@localhost host_data]# ls
dockerin.txt
# 会发现已经有dockerin.txt
查看数据卷是否挂载成功:
[root@localhost ~]$ docker inspect 容器ID
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/host_data",
"Destination": "/tmp/docker_date",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
#可以看到挂在上了,权限是RW: true,表示可读写
容器和宿主机之间数据共享:
root@5f08ea4bc963:/tmp/docker_date# echo "i 'm in container" > dockerin.txt #容器内操作
[root@localhost ~]$ ls -l
[root@localhost ~]$ echo "i 'm in container" > hostin.txt #宿主机内操作
容器停止退出后,主机修改后数据是否同步:
[root@localhost ~]$ docker attach 容器id
1. 容器先停止退出
2. 主机修改hostin.txt
3. 容器重启进入
4. 查看主机修改过的hostin.txt内容同步
经测试发现,即时容器退出,修改宿主机后,会实现同步
读写规则映射添加说明
-
读写(默认)
rw = read + writedocker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
-
只读
ro = read only
容器实例内部被限制,只能读取不能写,此时如果宿主机写入内容,可以同步给容器内,容器可以读取到。docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名 [root@localhost ~]$ docker run -it -privileged=true -v/mydocker/u:/tmp/u:ro --name u2 ubuntu
卷的继承和共享
容器1完成和宿主机的映射
[root@localhost ~]$ docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
容器2继承容器1的卷规则
[root@localhost ~]$ docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
5.3.2 DockerFile添加
在宿主机上新建一个目录
[root@localhost ~]$ mkdir mydockerfile
进入目录,新建Dockfile文件,并编辑它
[root@localhost ~]$ cd mydockerfile
[root@localhost ~]$ vim dockerfile
FROM centos
VOLUME ["/test_dockfile_container"]
CMD echo "lonely --success"
CMD "/bin/bash"
可在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷
VOLUME[“/dataVolumeContainer”,“/dataVolumeContainer2”,“/dataVolumeContainer3”]
说明:
出于可移植和分享的考虑,用-v 主机目录:容器目录这种方法不能够直接在Dockerfile中实现。
由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。
使用命令docker build 打包构建新镜像
[root@localhost ~]$ docker build -f dockerfile文件目录 -t 镜像名以及版本号
-f :表示Dockfile文件目录
-t:表示镜像名以及版本号.
最后的 . :表示使用当前目录的Dockfile文件进行构建
最后面有一个 . 表示在当前目录下,用法列如:
[root@localhost ~]$ docker build -f /mydockerfile/Dockerfile -t lonely/mydockerfile .
run 容器:
[root@localhost ~]$ docker run -it 容器id /bin/bash
进入容器后,查看是否存在Dockerfile文件中的 VOLUME对应的文件夹
那么对应宿主机目录上那个呢?
- 进入宿主机中,使用命令 docker inspect 查看绑定的 宿主机目录
- 去查看生成的宿主机挂载目录中 添加一个文件来测试是否挂载成功
Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true
参数即可
六、Docker常用安装
6.1 总体步骤
- 搜索镜像
- 拉取镜像
- 查看镜像
- 启动镜像(创建容器,服务端口映射)
- 停止容器
- 移除容器
6.2 安装tomcat
docker hub上面查找tomcat镜像
[root@localhost ~]$ docker search tomcat
从docker hub上拉取tomcat镜像到本地
[root@localhost ~]$ docker pull tomcat
docker images查看是否有拉取到的tomcat
[root@localhost ~]$ docker images
使用tomcat镜像创建容器(也叫运行镜像)
[root@localhost ~]$ docker run -d -p 8080:8080 tomcat
[root@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a14063c0a7ba tomcat "catalina.sh run" 2 minutes ago Up 2 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp determined_moser
宿主机ip:8080访问
访问提示404
# 进入容器
[root@localhost ~]$ docker exec -it a14063c0a7ba /bin/bash
# webapps目录是空的,需要删除
root@a14063c0a7ba:/usr/local/tomcat# rm -rf webapps
# 修改名字就可以了
root@a14063c0a7ba:/usr/local/tomcat# mv webapps.dist webapps
免修改版
[root@localhost ~]$ docker pull billygoo/tomcat8-jdk8
[root@localhost ~]$ docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
6.3 安装mysql
docker hub上面查找mysql镜像
[root@localhost ~]$ docker search mysql
从docker hub上(阿里云加速器)拉取mysql镜像到本地标签为5.7
[root@localhost ~]$ docker pull mysql:5.7
简单
# 使用mysql镜像
[root@localhost ~]$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
# 查看运行的容器
[root@localhost ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e2d3a6431e37 mysql:5.7 "docker-entrypoint.s…" 27 seconds ago Up 26 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp tender_taussig
# 进入容器
[root@localhost ~]$ docker exec -it e2d3a6431e37 /bin/bash
root@e2d3a6431e37:/# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
# 建库建表插入数据
mysql> create database db01;
Query OK, 1 row affected (0.00 sec)
mysql> use db01;
Database changed
mysql> create table aa(id int,name varchar(20));
Query OK, 0 rows affected (0.30 sec)
mysql> insert into aa values(1,'z3');
Query OK, 1 row affected (0.01 sec)
外部Win10也来连接运行在dokcer上的mysql容器实例服务
实战
使用mysql5.7镜像创建容器(也叫运行镜像)
# 没有目录会直接创建
[root@localhost ~]$ docker run -d -p 3306:3306 --privileged=true -v /volume/mysql/log:/var/log/mysql -v /volume/mysql/data:/var/lib/mysql -v /volume/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
命令说明:
-p 12345:3306:将主机的12345端口映射到docker容器的3306端口。
--name mysql:运行服务名字
-v /volume/mysql/conf:/etc/mysql/conf.d :将主机/volume/mysql录下的conf/my.cnf 挂载到容器的 /etc/mysql/conf.d
-v /volume/mysql/logs:/logs:将主机/volume/mysql目录下的 logs 目录挂载到容器的 /logs。
-v /volume/mysql/data:/var/lib/mysql :将主机/volume/mysql目录下的data目录挂载到容器的 /var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456:初始化 root 用户的密码。
-d mysql:5.6 : 后台程序运行mysql5.6
新建my.cnf
通过容器卷同步给mysql容器实例
# 直接复制粘贴
[root@localhost ~]$ cat > /volume/mysql/conf/my.cnf <<EOF
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
EOF
重新启动mysql容器实例再重新进入并查看字符编码
[root@localhost ~]$ docker restart mysql
[root@localhost ~]$ docker exec -it mysql /bin/bash
root@340896e86a16:/# mysql -uroot -p
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)
再新建库新建表再插入中文测试
数据备份:
[root@localhost ~]$ docker exec myql服务容器ID sh -c 'exec mysqldump --all-databases -uroot -p"123456" ' > /volume/all-databases.sql
6.4 安装redis
从docker hub上(阿里云加速器)拉取redis镜像到本地标签为6.0.8
[root@localhost ~]$ docker pull redis:6.0.8
在CentOS宿主机下新建目录/app/redis
[root@localhost ~]$ mkdir -p /app/redis
将一个redis.conf文件模板拷贝进/app/redis目录下
redis配置文件
https://wwz.lanzoul.com/iYKqk0a7vkji
密码:awyr
[root@localhost ~]$ mkdir -p /app/redis
[root@localhost ~]$ cp -a /myredis/redis.conf /app/redis/
/app/redis目录下修改redis.conf文件
[root@localhost ~]$ vim /app/redis/redis.conf
requirepass 123 #可选
bind 127.0.0.1 #允许redis外地连接
# 将daemonize yes注释起来或者 daemonize no设置,因为该配置和docker run中-d参数冲突,会导致容器一直启动失败
daemonize no
使用redis6.0.8镜像创建容器(也叫运行镜像)
[root@localhost ~]$ docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
测试redis-cli连接上来
[root@localhost ~]$ docker exec-it myr3 /bin/bash
root@d673b7fe3bc8: redis-cli
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
七、DockerFile解析
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,’#’ 为 Dockerfile 中的注释
。
构建三步骤
编写DockerFile文件 -------->docker build ------>docker run
DockerFile格式:
## Dockerfile文件格式
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
# 1、第一行必须指定 基础镜像信息
FROM ubuntu
# 2、维护者信息
MAINTAINER docker_user docker_user@email.com
# 3、镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 4、容器启动执行指令
CMD /usr/sbin/nginx
7.1 DockerFile构建过程解析
7.1.1 Dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
7.1.2 Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器则可以认为是软件的运行态。
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
-
Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
-
Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
-
Docker容器,容器是直接提供服务的。
7.2 DockerFile体系结构(保留字指令介绍)
指令 | 含义 |
---|---|
FROM | 基础镜像,当前新镜像是基于哪个镜像的 |
MAINTAINER | 镜像维护者的姓名和邮箱地址 |
RUN | 容器构建时需要运行的命令 |
EXPOSE | 当前容器对外暴露出的端口 |
WORKDIR | 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点 |
ENV | 用来在构建镜像过程中设置环境变量 |
ADD | 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包 |
COPY | 类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 |
VOLUME | 容器数据卷,用于数据保存和持久化工作 |
CMD | 指定一个容器启动时要运行的命令,Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换 |
ENTRYPOINT | 指定一个容器启动时要运行的命令,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数 |
ONBUILD | 当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发 |
FROM 命令 :添加基础镜像
FROM <image name>
,例如 FROM ubuntu
所有的 Dockerfile 都用该以 FROM
开头,FROM
命令指明 Dockerfile 所创建的镜像文件以什么镜像为基础,FROM 以后的所有指令都会在 FROM 的基础上进行创建镜像;可以在同一个 Dockerfile 中多次使用 FROM 命令用于创建多个镜像。
MAINTAINER 命令 :记录维护者
MAINTAINER <author name>
用于指定镜像创建者和联系方式。
例如
MAINTAINER Victor Coisne victor.coisne@dotcloud.com
RUN 命令 :生成镜像要执行的命令
RUN <command>
用于容器内部执行命令。
每个 RUN
命令相当于在原有的镜像基础上添加了一个改动层,原有的镜像不会有变化。RUN是在 docker build时运行。
run的两种格式
-
shell格式
RUN <命令行命令> #<命令行命令>等同于,在终端操作的shel1命令。 RUN yum -y install vim
-
exec格式
RUN["可执行文件","参数1","参数2"] #例如: #RUN ["./test.php","dev","offline"] 等价于 RUN ./test.php dev offline
RUN是在 docker build时运行
ADD 命令:向容器内添加文件或者目录 (推荐)
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
ADD <src> <dst>
用于将 文件复制到 文件: 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件 url, 是容器中的绝对路径。
COPY 命令:拷贝文件和目录到镜像中
类似ADD,将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
格式
- COPY src dest
- COPY [“src”, “dest”]
- <src源路径>:源文件或者源目录
- <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
CMD 命令 : 指定容器启动后的要干的事情
指定容器启动后的要干的事情
CMD
命令有三种格式:
- shell 形式
CMD command param1 param2:
- exec 格式
CMD ["executable","param1","param2"]:
推荐使用的 。 - 参数列表格式
CMD ["param1","param2"]:在指定了ENTRYPOINT指令后,用CMD指定具体的参数。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
CMD 命令用于启动容器时默认执行的命令,CMD 命令可以包含可执行文件,也可以不包含可执行文件:不包含可执行文件的情况下就要用 ENTRYPOINT 指定一个,然后 CMD 命令的参数就会作为ENTRYPOINT的参数。
一个 Dockerfile 中只能有一个CMD,如果有多个,则最后一个生效。 CMD 的 shell 形式默认调用 /bin/sh -c 执行命令。
CMD命令会被 Docker 命令行传入的参数覆盖:docker run busybox /bin/echo Hello Docker 会把CMD 里的命令覆盖。
命令行传入的算是最后一个cmd 命令,最后一个有效。
如果传入的参数里,没有可执行文件,则这些参数就作为entrypoint的参数,
如果传入的参数里,包含可执行文件,则entrypoint 不执行。
docker run busybox 不加启动命令的时候,会执行镜像busybox 默认的启动命令(busybox也是通过dockerFile 创建的,也可以指定启动执行的命令),这个时候,如果 如果默认命令不包含可执行文件,需要找到entrypoint作为可执行文件,默认命令作为 参数。
和RUN命令的区别
- CMD是在docker run 时运行。
- RUN是在 docker build时运行。
ENTRYPOINT 命令
ENTRYPOINT
命令的字面意思是进入点,而功能也恰如其意:他可以让你的容器表现得像一个可执行程序一样。
ENTRYPOINT 命令也有两种格式:
ENTRYPOINT ["executable", "param1", "param2"] :
推荐使用的 exec 形式ENTRYPOINT command param1 param2 :shell
形式
ENTRYPOINT可以和CMD一起用,一般是变参
才会使用CMD,这里的CMD等于是在给ENTRYPOINT传参。
当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成“”
一个 Dockerfile 中只能有一个 ENTRYPOINT,如果有多个,则最后一个生效。
关于 CMD
和 ENTRYPOINT
的联系请看下面的例子
仅仅使用 ENTRYPOINT
:
FROM ubuntu
ENTRYPOINT ls -l
执行 docker run 306cd7e8408b /etc/fstab
和 docker run 306cd7e8408b
结果并不会有什么差别:
[root@localhost ~]$ docker run 306cd7e8408b /etc/fstab
total 64
drwxr-xr-x 2 root root 4096 Mar 20 05:22 bin
drwxr-xr-x 2 root root 4096 Apr 10 2014 boot
drwxr-xr-x 5 root root 360 Apr 24 02:52 dev
drwxr-xr-x 64 root root 4096 Apr 24 02:52 etc
drwxr-xr-x 2 root root 4096 Apr 10 2014 home
……
但是我们通 常使用 ENTRYPOINT
作为容器的入口,使用 CMD
给 ENTRYPOINT
增加默认选项:
FROM ubuntu
ENTRYPOINT ["ls"]
CMD ["-l"]
然后执行这个容器:
不加参数便会默认有 -l
参数:
[root@localhost ~]$ docker run 89dc7e6d0ac1
total 64
drwxr-xr-x 2 root root 4096 Mar 20 05:22 bin
drwxr-xr-x 2 root root 4096 Apr 10 2014 boot
drwxr-xr-x 5 root root 360 Apr 24 02:47 dev
drwxr-xr-x 64 root root 4096 Apr 24 02:47 etc
drwxr-xr-x 2 root root 4096 Apr 10 2014 home
drwxr-xr-x 12 root root 4096 Mar 20 05:21 lib
drwxr-xr-x 2 root root 4096 Mar 20 05:20 lib64
drwxr-xr-x 2 root root 4096 Mar 20 05:19 media
drwxr-xr-x 2 root root 4096 Apr 10 2014 mnt
drwxr-xr-x 2 root root 4096 Mar 20 05:19 opt
dr-xr-xr-x 386 root root 0 Apr 24 02:47 proc
drwx------ 2 root root 4096 Mar 20 05:22 root
drwxr-xr-x 7 root root 4096 Mar 20 05:21 run
drwxr-xr-x 2 root root 4096 Apr 21 22:18 sbin
drwxr-xr-x 2 root root 4096 Mar 20 05:19 srv
dr-xr-xr-x 13 root root 0 Apr 24 02:47 sys
drwxrwxrwt 2 root root 4096 Mar 20 05:22 tmp
drwxr-xr-x 11 root root 4096 Apr 21 22:18 usr
drwxr-xr-x 12 root root 4096 Apr 21 22:18 var
加了 /etc/fstab
参数便会覆盖原有的 -l
参数:
[root@localhost ~]$ docker run 89dc7e6d0ac1 /etc/fstab
/etc/fstab
EXPOSE 命令
EXPOSE <port> [<port>...]
命令用来指定对外开放的端口。
例如 EXPOSE 80 3306
,开放 80
和 3306
端口。
WORKDIR命令 : 设置执行 Run,cmd entrypoint 命令的工作路径。
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点。
WORKDIR /path/to/work/dir
配合 RUN
,CMD
,ENTRYPOINT
命令设置当前工作路径。
可以设置多次,如果是相对路径,则相对前一个 WORKDIR
命令。默认路径为/。
例如:
FROM ubuntu
WORKDIR /etc
WORKDIR ..
WORKDIR usr
WORKDIR lib
ENTRYPOINT pwd
docker run ID
得到的结果为:/usr/lib
USER命令 : 指定执行命令的用户
USER <UID/Username>
为容器内指定 CMD
RUN
ENTRYPOINT
命令运行时的用户名或UID
。
VLOUME 命令 : 暴露某个目录给其他容器访问
VOLUME ['/data']
允许容器访问容器的目录、允许容器之间互相访问目录。
VOLUME
仅仅是允许将某一个目录暴露在外面,更多的操作还需要依赖 Docker 命令实现。
更多的内容可以参考 深入理解 Docker Volume(一)
ENV 命令 : 设置环境变量
参考 export
的用法咧:
ENV 环境变量的名字 环境变量的值
ENV LC_ALL en_US.UTF-8
#设置编码格式
ENV MY_PATH /usr/mytest
#这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
#也可以在其它指令中直接使用这些环境变量,
#比如:WORKDIR $MY_PATH
7.3 案例
案例:自定义镜像mycentosjava8
要求
Centos7镜像具备vim+ifconfig+jdk8
JDK的下载镜像地址 https://mirrors.yangxingzhen.com/jdk/
准备编写Dockerfile文件
# 拉取centos:7可不执行
# [root@localhost ~]$ docker pull centos:7
[root@localhost ~]$ mkdir /myfile && cd /myfile
[root@localhost ~]$ cat > Dockerfile << EOF
FROM centos:7 #没有基础镜像会自己拉取
MAINTAINER lurenjia<lurenjia@126.com>
ENV MYPATH /usr/local
WORKDIR \$MYPATH #落脚点
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库,glibc.i686是gcc加强安装包
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME \$JAVA_HOME/jre
ENV CLASSPATH \$JAVA_HOME/lib/dt.jar:\$JAVA_HOME/lib/tools.jar:\$JRE_HOME/lib:\$CLASSPATH
ENV PATH \$JAVA_HOME/bin:\$PATH
EXPOSE 80
CMD echo \$MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
EOF
构建
# 公式:docker build -t 新镜像名字:TAG 文件所在的目录
[root@localhost ~]$ docker build -t centosjava8:1.5 /myfile
运行
# 公式:docker run -it 新镜像名字:TAG
[root@localhost ~]$ docker run -it centosjava8:1.5 /bin/bash
案例:自定义镜像Tomcat9
1、创建目录
[root@localhost ~]$ mkdir -p /mydockerfile/tomcat9
2、在上述目录下touch c.txt
[root@localhost tomcat9]$ touch c.txt
3、将jdk和tomcat安装的压缩包拷贝进上一步目录
[root@localhost tomcat9]$ ls -l
4、在/mydockerfile/tomcat9目录下新建Dockerfile文件
[root@localhost tomcat9]$ vim Dockerfile
FROM centos
MAINTAINER zzyy<zzyybs@126.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u171-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.8.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.8
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.8
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.8/bin/startup.sh" ]#
CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.8/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out
[root@localhost tomcat9]#
5、构建tomcat9镜像
[root@localhost tomcat9]$ docker build -t wwtomcat9 .
查看镜像
[root@localhost tomcat9]$ docker images
6、运行tomcat9镜像
[root@localhost tomcat9]$ docker run -d -p 9080:8080 --name myt9 -v /mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.8/webapps/test -v /mydockerfile/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.8/logs --privileged=true zzyytomcat9
038cad9053022a7734e31cc589b1ecd1215cf96142ded6158ec8e2b146214
[root@localhost tomcat9]$ docker ps
Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
8、在自定义的tomcat9上发布演示实例
[root@localhost test]$ pwd
/mydockerfile/tomcat9/test
[root@localhost test]$ mkdir WEB-INF
[root@localhost test]$ cd WEB-INF/
[root@localhost WEB-INF] vim web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>test</display-name>
</web-app>
[root@localhost WEB-INF]# cd ..
[root@localhost test]# vim a.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
-----------welcome------------
<%="i am in docker tomcat self "%>
<br>
<br>
<% System.out.println("=============docker tomcat self");%>
</body>
</html>
[root@localhost test]#pwd
/mydockerfile/tomcat9/test
[root@localhost test]# ll
[root@localhost test]$ docker exec 038cad905302 ls -l /usr/local/apache-tomcat-9.0.8/webapps/test
因为第6步运行镜像的时候添加了容器卷,所以 在宿主机绝对路径目录/mydockerfile/tomcat9/test
下添加文件,会同步到容器内目录 /usr/local/apache-tomcat-9.0.8/webapps/test
虚悬镜像
仓库名、标签都是的镜像,俗称dangling image
Dockerfile写一个
[root@localhost ~]$ vim Dockerfile
from ubuntu
CMD echo 'action is success'
[root@localhost ~]$ docker build .
查看
[root@localhost ~]$ docker image ls -f dangling=true
删除
# 虚悬镜像已经失去存在价值,可以删除
[root@localhost ~]$ docker image prune