Docker的学习记录
# Docker 诞生的背景
主机时代比拼的是单个服务器物理性能(如CPU主频和内存)的强弱,那么在云时代,最为看重的则是凭借虚拟化技术所构建的集群处理能力。 虚拟化的概念早已经广泛应用到各种关键场景中。从20世纪60年代IBM推出的大型主机虚拟化,到后来以Xen、KVM为代表的虚拟机虚拟化,再到现在以Docker为代表的容器技术,虚拟化技术自身也在不断进行创新和突破。 虚拟化既可以通过硬件模拟来实现,也可以通过操作系统软件来实现。而容器技术则更为优雅,它充分利用了操作系统本身已有的机制和特性,可以实现远超传统虚拟机的轻量级虚拟化。因此,有人甚至把它称为“新一代的虚拟化”技术,并将基于容器打造的云平台亲切地称为“容器云”,Docker正是众多容器技术中的佼佼者
# 初始Docker容器
Docker是基于Go语言实现的开源容器项目。它诞生于2013年年初,最初发起者是dotCloud公司(现在已经改为Docker )。Docker项目已加入Linux基金会,并遵循Apache 2.0协议。
# Linux容器技术
与大部分新兴技术的诞生一样,Docker也并非“从石头缝里蹦出来的”,而是站在前人的肩膀上,就是Linux容器(Linux Containers, LXC)技术。IBM 开发者网站关于容器技术的描述十分准确:“容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与虚拟化相比,这样既不需要指令级模拟,也不需要即时编译。容器可以在核心CPU本地运行指令,而不需要任何专门的解释机制。此外,也避免了准虚拟化(para-virtualization)和系统调用替换中的复杂性。LXC也经历了长期的演化,最早可以追溯到1982年Unix系列操作系统上的chroot工具。
# 从Linux容器到Docker
在LXC的基础上,Docker进一步优化了容器的使用体验,首先,Docker提供了各种容器管理工具(如分发、版本、移植等),让用户无须关注底层的操作,更加简单明了地管理和使用容器;其次,Docker通过引入分层文件系统构建和高效的镜像机制,降低了迁移难度,极大地改善了用户体验。用户操作Docker容器就像操作应用自身一样简单。 早期的Docker代码实现是直接基于LXC的。自0.9版本开始,Docker开发了libcon-tainer项目作为更广泛的容器驱动实现,从而替换掉了LXC的实现。目前,Docker还积极推动成立了runC标准项目,并贡献给开放容器联盟,试图让容器的支持不再局限于Linux操作系统,而是更安全、更开放、更具扩展性。简单地讲。 Docker容器理解为一种轻量级的沙盒(sandbox)。每个容器内运行着一个或多个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信。容器的创建和停止十分快速,几乎跟创建和终止原生应用一致;另外,容器自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。
# Docker的目标
Docker的构想是要实现“Build, Ship and Run Any App, Anywhere”,即通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)全生命周期进行管理,达到应用组件级别的“一次封装,到处运行”。这里的应用组件,既可以是一个Web应用、一个编译环境,也可以是一套数据库平台服务,甚至是一个操作系统或集群。
# Docker引擎的认识
Docker 引擎由如下主要的组件构成: Docker 客户端(Docker Client) Docker 守护进程(Docker daemon) containerd 以及 runc。它们共同负责容器的创建和运行 最新的架构示意图:
# 核心概念与安装配置
介绍Docker的三大核心概念:❑ 镜像(Image)❑ 容器(Container)❑ 仓库(Repository)只有理解了这三个核心概念,才能顺利地理解Docker容器的整个生命周期。
# 镜像
Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了Apache应用程序(或用户需要的其他软件)。可以把它称为一个Apache镜像。镜像是创建Docker容器的基础。通过版本管理和增量的文件系统,Docker提供了一套十分简单的机制来创建和更新现有的镜像,用户甚至可以从网上下载一个已经做好的应用镜像,并直接使用。镜像可以理解成源代码。
# 容器
Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建的应用运行实例。它可以启动、开始、停止、删除,而这些容器都是彼此相互隔离、互不可见的。可以把容器看作一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。容器可以理解成从镜像编译运行的应用程序。
# 仓库
镜像仓库,则是指存放镜像文件的地方,可以理解成源代码仓库,列如GitHub,或者GitLab。 每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签(tag)来进行区分。例如存放Ubuntu操作系统镜像的仓库,被称为Ubuntu仓库,其中可能包括16.04、18.04等不同版本的镜像。 目前,最大的公开仓库是官方提供的Docker Hub,其中存放着数量庞大的镜像供用户下载。国内不少云服务提供商阿里云仓库也提供了仓库的本地源,可以提供稳定的国内访问。
# Docker的安装
Docker引擎目前分为两个版本:**社区版本(Community Edition, CE)和企业版本(Enterprise Edition, EE)。**对于windows和 Mac 版本的Docker 都是社区提供的,在生产环境中不建议使用。所以重点学习在其Linux系统的上面的使用,以centos8为例安装学习:
#!/bin/bash
echo -e '卸载旧版本的docker'
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
echo -e '安装常用软件包'
yum install yum-utils device-mapper-persistent-data lvm2 -y
echo -e '添加 阿里Docker源'
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
echo '更新并安装Docker-CE'
sudo yum makecache fast
echo -e '安装docker-ce'
yum install -y docker-ce docker-ce-cli containerd.io
echo -e '设置Docker开机自启动'
systemctl enable docker
echo -e '启动docker'
systemctl start docker
echo -e '查看docker版本'
docker --version
echo -e '给docker换阿里源'
cat <<EOF > /etc/docker/daemon.json
{
"registry-mirrors": ["https://fl791z1h.mirror.aliyuncs.com"]
}
EOF
echo -e '重启docker服务'
systemctl restart docker
echo -e '查看docker信息'
docker info
exit
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
安装过程出现的可能出现的问题排查: 由于最新的docker 依赖的container 的版本变化引起的安装问题
[root@localhost ~]# yum -y install docker-ce
上次元数据过期检查:0:00:32 前,执行于 2021年01月07日 星期四 08时07分56秒。
错误:
问题: package docker-ce-3:20.10.2-3.el7.x86_64 requires containerd.io >= 1.4.1, but none of the providers can be installed
- cannot install the best candidate for the job
- package containerd.io-1.4.3-3.1.el7.x86_64 is filtered out by modular filtering
# 出现上面的错误信息的时候 ,打开下面的链接 找到对应的 centos 版本,然后点进去找到继续找 下图所
https://mirrors.aliyun.com/docker-ce/linux/centos/
wget https://mirrors.aliyun.com/docker-ce/linux/centos/8/x86_64/stable/Packages/containerd.io-1.4.3-3.1.el8.x86_64.rpm
yum install containerd.io-1.4.3-3.1.el8.x86_64.rpm
# 在继续
yum -y install docker-ce
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 镜像 image
# docker image pull
或者 docker pull
镜像是运行容器的前提,可以使用docker [image] pull
命令直接从Docker Hub镜像源来下载镜像。该命令的格式为 docker [image] pull NAME[:TAG]
NAME是镜像仓库名称(用来区分镜像), TAG是镜像的标签(往往用来表示版本信息)。通常情况下,描述一个镜像需要包括“名称+标签”信息
[root@localhost ~]# docker pull centos 获取一个镜像,不加 tag 标签的时候 默认拉去的 tag是latest
Using default tag: latest
latest: Pulling from library/centos
7a0437f04f83: Pull complete
Digest: sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
2
3
4
5
6
7
下载过程中可以看出,镜像文件一般由若干层(layer)组成,7a0437f04f83这样的串是层的唯一id(实际上完整的id包括256比特,64个十六进制字符组成)。使用docker pull命令下载中会获取并输出镜像的各层信息。当不同的镜像包括相同的层时,本地仅存储了层的一份内容,减小了存储空间
# docker images
命令可以列出本地主机上已有镜像的基本信息
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest ae2feff98a0c 3 weeks ago 133MB
centos latest 300e315adb2f 4 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 5 months ago 79.1MB
2
3
4
5
可以看到几个字段信息: ❑ 来自于哪个仓库,比如centos表示centos系列的基础镜像; ❑ 镜像的标签信息,比如latest表示不同的版本信息。标签只是标记,并不能标识镜像内容; ❑ 镜像的ID(唯一标识镜像),如果两个镜像的ID相同,说明它们实际上指向了同一个镜像,只是具有不同标签名称而已; ❑ 创建时间,说明镜像最后的更新时间; ❑ 镜像大小,优秀的镜像往往体积都较小
# docker[image]inspect 镜像名称/镜像ID
命令可以获取该镜像的详细信息,包括制作者、适应架构、各层的数字摘要等
# docker history 镜像名称/镜像ID
命令查看镜像历史
# docker search 镜像名称
命令可以搜索Docker Hub官方仓库中的镜像
# docker rmi 镜像名称/镜像ID
或docker image rm 镜像名称/镜像ID
命令删除镜像
# docker image prune
命令来进行清理镜像
使用Docker一段时间后,系统中可能会遗留一些临时的镜像文件,以及一些没有被使用的镜像可以使用上述的命令清理掉 支持选项包括: ❑ -a, -all:删除所有无用镜像,不光是临时镜像 ❑ -filter filter:只清理符合给定过滤器的镜像 ❑ -f, -force:强制删除镜像,而不进行提示确认
# docker [container] commit
命令基于已有容器创建镜像
命令格式为 docker [container] commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] 主要选项包括:OPTIONS ❑ -a, --author="":作者信息 ❑ -c, --change=[]:提交的时候执行Dockerfile指令,包括CMD|ENTRYPOINT|ENV|EXPOSE|LABEL|ONBUILD|USER|VOLUME|WORKDIR等 ❑ -m, --message="":提交消息 ❑ -p, --pause=true:提交时暂停容器运行
# docker [container] import
从模板文件导入一个镜像
命令格式为 docker [image] import [OPTIONS]file|URL|-[REPOSITORY [:TAG]]
# 基于Dockerfile创建镜像
# docker [image] save
导出镜像到本地文件
该命令支持-o、-output string参数,导出镜像到指定的文件中,就可以通过复制到处的文件给别人使用
// 保存当前的centos 镜像为centos_letest.tar 文件
docker save -o centon_letest.tar centos:latest
2
3
# docker [image] load
将导出的tar文件再导入到本地镜像库
支持-i、-input string选项,从指定文件中读入镜像内容
docker load -i centon_letest.tar
# docker [image] push
命令上传镜像到仓库
默认上传到Docker Hub官方仓库,类似 git push
# 容器 container
容器是Docker的另一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层,同时,容器中的应用进程处于运行状态。
# 创建容器
# docker [container] create
命令新建一个容器
使用docker [container] create命令新建的容器处于停止状态,可以使用 docker[container] start
命令来启动它。
[root@localhost ~]# docker create -it centos:latest
27a89a80a2cb4e5c5fe0e24ef86cb2dac451219beeee3f11ac916fe2143f369a
2
# docker [container] start
启动容器
[root@localhost ~]# docker start 27a89a80a2c
27a89a80a2c
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
27a89a80a2cb centos:latest "/bin/bash" 6 minutes ago Up 4 seconds objective_lederberg
2
3
4
5
# docker [container] run
新建并启动容器
等价于先执行docker [container]create
命令,再执行docker [container] start
命令
当利用docker [container] run来创建并启动容器时,Docker在后台运行的标准操作包括:
❑ 检查本地是否存在指定的镜像,不存在就从公有仓库下载
❑ 利用镜像创建一个容器,并启动该容器
❑ 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层
❑ 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
❑ 从网桥的地址池配置一个IP地址给容器
❑ 执行用户指定的应用程序
❑ 执行完毕后容器被自动终止
[root@localhost ~]# docker run -it --name centos-test centos:latest /bin/bash
[root@d078291e042a /]#
2
常用选项
- **-t **选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,
- **-i **则让容器的标准输入保持打开
- --name 给这个启动的容器起一个名称
- -d 需要让Docker容器在后台以守护态(Daemonized)形式运行
- 更多的命令选项可以通过 docker run --help命令来查看
# docker [container] logs
查看容器输出日志
# 停止容器
# docker [container] pause
命令来暂停一个运行中的容器
处于paused状态的容器,可以使用docker [container] unpause
CONTAINER[CONTAINER...]命令来恢复到运行状态
# docker [container] unpause命令来恢复到运行状态
# docker [container] stop
来终止一个运行中的容器
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后(默认为10秒),再发送SIGKILL信号来终止容器,处于终止状态的容器,可以通过docker [container] start
命令来重新启动
# docker [container] kill
直接发送SIGKILL信号来强行终止容器
# docker [container] restart
命令会将一个运行态的容器先终止,然后再重新启动
# 进入容器
# docker [container] attach
连接到正在运行中的容器
# docker [container] exec
更加方便的工具exec命令,可以在运行中容器内直接执行任意命令
docker exec -it 容器名称/容器ID /bin/bash
# 删除容器
# docker [container] rm
命令来删除处于终止或退出状态的容器
主要支持的选项包括: ❑ -f, --force=false:是否强行终止并删除一个运行中的容器 ❑ -l, --link=false:删除容器的连接,但保留容器 ❑ -v, --volumes=false:删除容器挂载的数据卷
# 导入和导出容器
# docker [container] export
导出容器是指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态
docker export -o export_centos.tar 容器ID/容器名称
// -o 导出的文件名
2
# docker [container] import
命令导入变成镜像
# docker container inspect
查看容器详情
# docker [container] top
查看容器内进程
# docker [container] stats
查看统计信息
# docker [container] cp
命令支持在容器和主机之间复制文件
本地的路径data复制到test容器的/tmp路径下 docker cp data test:/tmp
# docker [container] diff
查看容器内文件系统的变更
# docker [container] port
命令可以查看容器的端口映射情况
# docker [container] update
命令可以更新容器的一些运行时配置,主要是一些资源限制份额
支持的选项包括: ❑ -blkio-weight uint16:更新块IO限制,10~1000,默认值为0,代表着无限制 ❑ -cpu-period int:限制CPU调度器CFS(Completely Fair Scheduler)使用时间,单位为微秒,最小1000 ❑ -cpu-quota int:限制CPU调度器CFS配额,单位为微秒,最小1000 ❑ -cpu-rt-period int:限制CPU调度器的实时周期,单位为微秒 ❑ -cpu-rt-runtime int:限制CPU调度器的实时运行时,单位为微秒 ❑ -c, -cpu-shares int:限制CPU使用份额; ❑ -cpus decimal:限制CPU个数; ❑ -cpuset-cpus string:允许使用的CPU核,如0-3,0,1 ❑ -cpuset-mems string:允许使用的内存块,如0-3,0,1 ❑ -kernel-memory bytes:限制使用的内核内存; ❑ -m, -memory bytes:限制使用的内存 ❑ -memory-reservation bytes:内存软限制 ❑ -memory-swap bytes:内存加上缓存区的限制,-1表示为对缓冲区无限制 ❑ -restart string:容器退出后的重启策略
# Docker数据管理
在生产环境中使用Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。 容器中的管理数据主要有两种方式: ❑ 数据卷(Data Volumes):容器内数据直接映射到本地主机环境; ❑ 数据卷容器(Data Volume Containers):使用特定容器维护数据卷。 首先介绍如何在容器内创建数据卷,并且把本地的目录或文件挂载到容器内的数据卷中。其次介绍如何使用数据卷容器在容器和主机、容器和容器之间共享数据,并实现数据的备份和恢复。
# 数据卷
数据卷(Data Volumes)是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount行为 数据卷可以提供很多有用的特性: ❑ 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效与方便 ❑ 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作 ❑ 对数据卷的更新不会影响镜像,解耦开应用和数据 ❑ 卷会一直存在,直到没有容器使用,可以安全地卸载它
# 创建数据卷
# docker volume create
创建数据卷
Docker提供了volume子命令来管理数据卷,如下命令可以快速在本地创建一个数据卷:
docker volume create -d local test-vol 创建一个本地的数据卷
//
/var/lib/docker/volumes路径下,会发现所创建的数据卷 test-vol
2
3
# docker volume inspect
(查看详细信息)
[root@localhost volumes]# docker volume inspect test-vol
[
{
"CreatedAt": "2021-01-07T16:36:32-05:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/test-vol/_data",
"Name": "test-vol",
"Options": {},
"Scope": "local"
}
]
2
3
4
5
6
7
8
9
10
11
12
# docker volume ``ls
列出已有数据卷
# docker volume prune
清理无用数据卷
# docker volume rm
删除数据卷
# 绑定数据卷
除了使用volume子命令来管理数据卷外,还可以在创建容器时将主机本地的任意路径挂载到容器内作为数据卷,这种形式创建的数据卷称为绑定数据卷 docker [container] run
命令的时候,可以使用**-mount**选项来使用数据卷。
-mount type选项支持三种类型的数据卷,包括:
❑ volume:普通数据卷,映射到主机/var/lib/docker/volumes路径下;
❑ bind:绑定数据卷,映射到主机指定路径下;
❑ tmpfs:临时数据卷,只存在于内存中
source:主机目录路径
destination:容器目录路径
type=bind,source=/path/on/host,destination=/path/in/container
type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round"
type=tmpfs,tmpfs-size=512M,destination=/path/in/container
2
3
4
5
6
7
8
docker run -itd --name centos-test --mount type=bind,source=/www,destination=/cen_www centos:latest
// 上面的命令相当下面
docker run -itd --name centos-test -v /www:/cen_www centos:latest
2
3
Docker挂载数据卷的默认权限是读写(rw),用户也可以通过ro指定为只读:
docker run -itd --name centos-test -v /www:/cen_www:ro centos:latest
# 数据卷容器
如果需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载 首先,创建一个数据卷容器dbcontainer,并在其中创建一个数据卷挂载到/dbcontainer, 然后,可以在其他容器中使用 **--volumes-from **来挂载dbcontainer容器中的数据卷,例如创建db1和db2两个容器,并从dbcontainer容器挂载数据卷:
docker run -itd --name dbcontainer -v /db_host:/dbdata centos:latest
docker run -itd --name db1 --volumes-from dbcontainer centos:latest
docker run -itd --name db2 --volumes-from dbcontainer centos:latest
2
3
此时,容器db1和db2都挂载同一个数据卷到相同的/dbdata目录,三个容器任何一方在该目录下的写入,其他容器都可以看到 可以多次使用 --volumes-from 参数来从多个容器挂载多个数据卷,还可以从其他已经挂载了容器卷的容器来挂载数据卷
# 端口映射与容器互联
Docker除了通过网络访问外,还提供了两个很方便的功能来满足服务访问的基本需求:一个是允许映射容器内应用的服务端口到本地宿主主机;另一个是互联机制实现多个容器间通过容器名来快速访问
# 从外部访问容器应用
当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p参数来指定端口映射。 当使用-P(大写的)标记时,Docker会随机映射一个49000~49900的端口到内部容器开放的网络端口 -p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。 支持的格式有
- **映射所有接口地址 **
HostPort:ContainerPort
** eg:80 8080:8080**
- 映射到指定地址的指定端口
IP:HostPort:ContainerPort
** eg:127.0.0.1:5000:5000**
- 映射到指定地址的任意端口
IP::ContainerPort
eg:127.0.0.1::5000
使用IP::ContainerPort
绑定localhost的任意端口到容器的5000端口,本地主机会自动分配一个端口
- 指定udp端口
IP:ContainerPort/udp
eg:127.0.0.1:5000/udp
# 容器互联
使用--link参数可以让容器之间安全地进行交互 ,--link参数的格式为--link name:alias,其中name是要链接的容器的名称,alias是别名
// 先创建一个容器
docker run -it --rm --name centos-1 centos:latest
// 在创建一个容器
docker run -itd --name centos-2 --link centos-1:centos-1 centos:latest
2
3
4
Docker相当于在两个互联的容器之间创建了一个虚机通道,而且不用映射它们的端口到宿主主机上。 在启动容器的时候并没有使用-p和-P标记,从而避免了暴露数据库服务端口到外部网络上。 Docker通过两种方式为容器公开连接信息:
❑ **更新环境变量 **
查看容器的环境变量 :docker exec centos-1 env
使用env命令来查看容器的环境变量
❑ 更新/etc/hosts文件
# 使用Dockerfile创建镜像
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。 Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。 一般而言,Dockerfile主体内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令
# 配置指令说明
Dockerfile中指令的一般格式为INSTRUCTION arguments
,包括“配置指令”(配置镜像信息)和“操作指令”
ARG 定义创建镜像过程中使用的变量 唯一一个可以在FROM指令之前
FROM 指定基础镜像,必须为第一个命令(在没有ARG)
LABEL LABEL指令可以为生成的镜像添加元数据标签信息。这些信息可以用来辅助过滤出特定镜像
EXPOSE 声明镜像内服务监听的端口
ENV 指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在
ENTRYPOINT 指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数
VOLUME 创建一个数据卷挂载点
USER 指定运行容器时的用户名或UID,后续的RUN等指令也会使用指定的用户身份
WORKDIR 为后续的RUN、CMD、ENTRYPOINT指令配置工作目录
ONBUILD 指定当基于所生成镜像创建子镜像时,自动执行的操作指令
STOPSIGNAL 指定所创建镜像启动的容器接收退出的信号值
HEALTHCHECK 配置所启动容器如何进行健康检查
SHELL 指定其他命令使用shell时的默认shell类型
2
3
4
5
6
7
8
9
10
11
12
13
# 操作指令
RUN 运行指定命令
CMD 用来指定启动容器时默认执行的命令
ADD 添加内容到镜像
COPY 复制内容到镜像
2
3
4
#
# 常用指令
# ARG
: 定义创建镜像过程中使用的变量
唯一一个可以在FROM指令之前的指令,ARG指令定义的参数,在docker build命令中以--build-arg a_name=a_value形式赋值。如果docker build命令传递的参数,在Dockerfile中没有对应的参数,将警告
# 格式:
ARG <name>[=<default value>]
# 示例:
ARG VERSION="7.0"
FROM centos:${VERSION}
2
3
4
5
# FROM
: 指定所创建镜像的基础镜像
tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
# 格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
#示例:
FROM mysql:5.6
2
3
4
5
6
# LABEL
: 指令可以为生成的镜像添加元数据标签信息
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像
# 格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
# 示例:
LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
LABEL author="sun@qq.com" data="2021-1-1"
2
3
4
5
# EXPOSE
: 声明镜像内服务监听的端口
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
# 格式:
EXPOSE <port> [<port>...]
# 示例:
EXPOSE 80 443
EXPOSE 8080 EXPOSE 11211/tcp 11211/udp
2
3
4
5
# ENV
: 指定环境变量
指令指定的环境变量在运行时可以被覆盖掉,如 docker run --env <key>=<value> built_image
#格式:
ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
# 示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat=fluffy
2
3
4
5
6
7
# ENTRYPOINT
: 指定镜像的默认入口命令
注ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令,在运行时,可以被--entrypoint参数覆盖掉,如 docker run --entrypoint
#格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
2
3
4
5
6
7
# VOLUME
:创建一个数据卷挂载点
# 格式:
VOLUME ["/path/to/dir"]
# 示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
2
3
4
5
6
7
8
9
10
11
12
# USER
: 指定运行容器时的用户名或UID
# 格式:
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
# 示例:
USER www
# 注:使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
2
3
4
5
6
7
8
9
10
WORKDIR 为后续的RUN、CMD、ENTRYPOINT指令配置工作目录,通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。在使用** docker run -w **
**运行容器时,可以通过-w参数覆盖构建时所设置的工作目录 **
# 格式:
WORKDIR /path/to/workdir
# 示例:
WORKDIR /a (这时工作目录为/a)
WORKDIR b (这时工作目录为/a/b)
WORKDIR c (这时工作目录为/a/b/c)
2
3
4
5
6
# ONBUILD
: 指定当基于所生成镜像创建子镜像时,自动执行的操作指令
#格式:
ONBUILD [INSTRUCTION]
#示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
# 注:当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
2
3
4
5
6
# RUN
: 运行指定命令
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行
格式:
RUN <command>
exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
2
3
4
5
6
7
8
9
10
11
12
13
14
# CMD
: 指令用来指定启动容器时默认执行的命令
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
注: CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
2
3
4
5
6
7
8
9
# ADD
:添加内容到镜像
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
2
3
4
5
6
7
8
9
# COPY
:复制内容到镜像
COPY与ADD指令功能类似,但是是不会自动解压文件,也不能访问网络资源,当使用本地目录为源目录时,推荐使用COPY 下载 nginx-1.18.0.tar.gz ,epel-release-latest-7.noarch.rpm 文件在同一目录之下 并且在当前目录下 新建 Dockerfile 文件
# This nginx Dockerfile
# Version 1.0
# Base images 基础镜像
FROM centos
#MAINTAINER 维护者信息
MAINTAINER sunwukong
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 文件放在当前目录下,拷过去会自动解压
ADD ./nginx-1.18.0.tar.gz /usr/local/
ADD ./epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx"]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Dockerfile构建镜像
docker build -t Name:Tag -f Dockerfile .
构建镜像
**
--add-host list | 添加自定义Host到ip的映射(主机:ip) |
---|---|
--build-arg list | 设置构建时的变量 |
--cache-from strings | 将镜像视为缓存源 |
--cgroup-parent string | 可选的容器父cgroup |
--compress | 使用gzip工具压缩构建的上下文 |
--console | 显示控制台输出,仅使用 buildkit,参数有:true、false、auto(默认为 auto) |
--cpu-period int | 限制CPU CFS(完全公平的调度)的周期 |
--cpu-quota int | 限制CPU CFS(完全公平的调度)的限额 |
-c, --cpu-shares int | 设置CUP的共享权重 |
--cpuset-cpus string | 允许执行的cpu个数 (0-3,0,1) |
--cpuset-mems string | 允许执行的MEM个数 (0-3,0,1) |
--disable-content-trust | 跳过镜像的验证(默认为 true) |
-f, --file string | 构建的Dockerfile的名称(默认为 ‘PATH/Dockerfile’) |
--force-rm | 总是移除中间容器 |
--iidfile string | 将镜像ID写入到指定文件 |
--isolation string | 容器隔离技术 |
--label list | 为镜像设置元数据 |
-m, --memory bytes | 内存限额 |
--memory-swap bytes | 如果启用无限交换,则交换限制等于内存加上交换:'-1'即可 |
--network string | 在构建期间为 RUN 指令设置网络模式(默认为 “default”) |
--no-cache | 在构建映像时不使用缓存(设定后,每次都会重新去拉取,默认使用缓存的) |
--platform string | 如果服务器具有多平台能力,则设置该平台 |
--pull | 总是尝试拉取该镜像的新版本 |
-q, --quiet | 镜像构建成功后禁止生成输出和打印镜像的ID |
--rm | 构建成功后删除中间容器(默认为 true) |
--security-opt strings | 安全选项 |
--shm-size bytes | 设定/dev/shm的大小 |
--squash | 将新建的镜像层压缩成一个新的镜像层 |
--stream | 将流附加到服务器以协商构建上下文 |
-t, --tag list | 名称和可选的标签(格式为 'name:tag' ) |
--target string | 设置需要构建的目标构建阶段 |
--ulimit ulimit | U 限制项 (默认为 []) |
**
# Docker 网络
默认情况下容器与容器、容器与宿主机的网络是隔离开来的,docker 网络需要解决的就是 容器于容器的之间的互通。
# 网络模式
Docker网络模式 | 配置 | 说明 |
---|---|---|
host模式 | --net=host | 容器和宿主机共享Network namespace |
container模式 | --net=container:NAME_or_ID | 容器和另外一个容器共享Network namespace,kubernetes中的pod就是多个容器共享一个Network namespace |
none模式 | --net=none | 容器有独立的Network namespace, |
但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等 | ||
bridge模式 | --net=bridge (默认为该模式) | 网络桥接模式,将自动生成独有的Network namespace |
自定义模式 | --net=自定义网络名称 |
# host模式
原理:如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。 使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
# container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信
# none模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。 这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过--network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性
# bridge模式
当Docker进程启动时,会在主机上创建一个名为docker0
的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中
从docker0
子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair
设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show
命令查看
bridge模式是docker的默认网络模式,不写--net参数,就是bridge模式。使用docker run -p
时,docker实际是在iptables做了NAT规则,实现端口转发功能。可以使用iptables -t nat -vnL
查看
veth-pair
就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着
# bridge模存在的问题
按照以下方式创建了两个容器,在通过名称互联访问时候,连接不用
docker run -itd --name centos-bdg-01 centos:latest
docker run -itd --name centos-bdg-02 centos:latest
// 会出现以下问题
docker exec -it centos-bdg-01 ping centos-bdg-02
ping: centos-bdg-02: Name or service not known
2
3
4
5
6
# 自定义模式
# docker network ls
列出本地网络模式
docker network ls
NETWORK ID NAME DRIVER SCOPE
63d9493bce38 bridge bridge local # 桥接模式
de1105dfa5a8 host host local # host模式
87441a7540aa none null local # none模式
2
3
4
5
# docker network create
创建一个网络模式
- --driver 连接的网络模式
- **--subnet 子网掩码 192.168.0.0/16 **
- --gateway 192.168.1.0 网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.1.0 mynet
336cdb202d7a5d7f1fb3f8dc087d5d6e1b7aa46b3513186c8cb35bc1125a0784
docker network ls
NETWORK ID NAME DRIVER SCOPE
63d9493bce38 bridge bridge local
de1105dfa5a8 host host local
336cdb202d7a mynet bridge local
87441a7540aa none null local
创建自定义模式的docker容器
docker run -itd --name centos-net-01 --network mynet centos:latest
docker run -itd --name centos-net-02 --network mynet centos:latest
再次执行 可以发现容器之间是互通的
docker exec -it centos-net-01 ping centos-net-02
PING centos-net-02 (192.168.0.2) 56(84) bytes of data.
64 bytes from centos-net-02.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.096 ms
64 bytes from centos-net-02.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.162 ms
64 bytes from centos-net-02.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.160 ms
64 bytes from centos-net-02.mynet (192.168.0.2): icmp_seq=4 ttl=64 time=0.181 ms
64 bytes from centos-net-02.mynet (192.168.0.2): icmp_seq=5 ttl=64 time=0.158 ms
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# docker network inspect
显示一个或多个网络上的详细信息
# docker network connect
将容器连接到网络
docker network connect [OPTIONS] NETWORK CONTAINER
目前环境中有一下几个容器
centos-bdg-xx 走原始的桥接模式的 docker0 网卡 网段实在 172.17.0.0/16 centos-net-xx 走的是自定义的mynet模式的 mynet网卡 网段 在 192.168.0.0/16
怎么实现 centos-bdg-xx 到 centos-net-- 的通信
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1573b7088604 centos:latest "/bin/bash" 6 minutes ago Up 6 minutes centos-net-02
22a4f34fb7b8 centos:latest "/bin/bash" 6 minutes ago Up 6 minutes centos-net-01
22844f330ba3 centos:latest "/bin/bash" 25 minutes ago Up 25 minutes centos-bdg-02
8f7ae3be00e3 centos:latest "/bin/bash" 25 minutes ago Up 25 minutes centos-bdg-01
docker network connect mynet centos-bdg-01
docker exec -it centos-bdg-01 ping centos-net-01
PING centos-net-01 (192.168.0.1) 56(84) bytes of data.
64 bytes from centos-net-01.mynet (192.168.0.1): icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from centos-net-01.mynet (192.168.0.1): icmp_seq=2 ttl=64 time=0.161 ms
64 bytes from centos-net-01.mynet (192.168.0.1): icmp_seq=3 ttl=64 time=0.202 ms
64 bytes from centos-net-01.mynet (192.168.0.1): icmp_seq=4 ttl=64 time=0.153 ms
docker network inspect mynet
····
"Containers": {
"1573b70886040ce5922a0366e866bd6c5ac91acd851dd53dd43b2c2fbc388389": {
"Name": "centos-net-02",
"EndpointID": "968dd40f23362c3066df4092a2be6955c8681eaf38e07e505344492bc383a8c9",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"22a4f34fb7b8becd82719d16cecf84c54ca48bc184964042aecec74d18d1c931": {
"Name": "centos-net-01",
"EndpointID": "b2c7cf4d66fdeeea5559bd81fd3166bf78e0e3064e5016e71e51ba5543c5ded4",
"MacAddress": "02:42:c0:a8:00:01",
"IPv4Address": "192.168.0.1/16",
"IPv6Address": ""
},
// 容器连接到自定义网卡中
"8f7ae3be00e349005326d1fd4ff57fd0e19867b66a23bbc73c9568c9467b7c6f": {
"Name": "centos-bdg-01",
"EndpointID": "22427d81dc7386d04c7502ae90c99b812503e8514a13c1e89207435a2ec9ebb4",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# docker network rm
移除一个网络模式
# docker network prune
删除所有未使用的网络
**
# Docker 可视化管理
docker run -itd --restart always --name portainer-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer