[08] Docker基础(下)
1. Docker Network
Docker's networking subsystem is pluggable, using drivers.
https://docs.docker.com/network/
1.1 Overview
容器网络实质上是由 Docker 为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作系统的网络环境中独立出来,形成容器自有的网络设备、IP 协议栈、端口套接字、IP 路由表、防火墙等与网络相关的模块。
a. CNM
Container Network Model,它是 Docker 网络架构采用的设计规范。只要符合该模型的网络接口就能被用于容器之间通信,而通信的过程和细节可以完全由网络接口来实现。
CNM 的网络组成:
- Sandbox:提供容器的虚拟网络栈,即端口套接字、IP 路由表、iptables 配置、DNS 等。用于隔离容器网络和宿主机网络;
- Network:Docker 虚拟网络,与宿主机网络隔离,只有参与者能够通信;
- Endpoint:容器内的虚拟网络接口,负责与 Docker 虚拟网络连接。
b. Libnetwork
CNM 的标准实现,由 Golang 开发,它实现了 CNM 定义的全部三个组件,还实现了本地服务发现,基于 Ingress 的容器负载均衡,及网络控制层和管理层功能。
c. Drivers
- 宿主机内部:bridge,host,container,none
- 跨主机:overlay,macvlan(适合 swarm 等容器编排工具)
- 第三方:flannel,weave,calico
d. Tips
- Network Namespace:用于隔离容器网络资源(IP、网卡、路由等)。netns 可确保同一主机上的两个容器无法相互通信,甚至不能与主机本身进行通信,除非配置为通过 Docker 网络进行通信。CNM 网络驱动程序为每个容器实现单独的 netns。但是,容器可以共享相同的 netns,甚至可以是主机的 netns 的一部分;
- Veth Pair:用于不同 Network Namespace 间进行通信。
veth
是全双工链接,在每个名称空间中都有一个接口,充当两个网络名称空间之间的连接线,负责将一个 netns 数据发往另一个 netns 的veth
。如当容器连接到 Docker 网络时,veth
的一端放置在容器内部(通常视为ethX
接口),而另一端连接到 Docker 网络(vethXXX);
- iptables:包过滤、端口映射和负载均衡。
1.2 网络模式
$ docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5edf46553116 bridge bridge local
3f0e974cff7d host host local
016c2058322a none null local
a. 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 做了 DNAT 规则,实现端口转发功能。可以使用 iptables -t nat -vnL
查看。bridge 模式如下图所示:
从上图中我们可以看到,可以看到容器内部和 Linux 主机都会创建一个新的网卡,而这两个网卡都是成对的。使用的技术就是 veth-pair。veth-pair 就是一对的虚拟设备接口,他们是成对出现的,一段连着协议,一段彼此相连。veth-pair 充当一个桥梁,连接各种虚拟网络设备。
Docker 容器完成 bridge 网络配置的过程如下:
- 在主机上创建一对虚拟网卡 veth pair 设备。veth 设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth 设备常用来连接两个网络设备;
- Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0。另一端放在主机中,以
vethb22db1b4
这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中; - 从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。
宿主机和 Docker 容器之间是可以进行网络连接的,同样的,Docker 容器和容器之间也可以直接进行网络连接。
[root@haha docker_web]# docker exec -it a52bd646da1f ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.193 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.134 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.132 ms
[root@haha docker_web]# docker exec -it 386ffc29485d ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.146 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.137 ms
容器 1 和容器 2,都使用公用的路由器 docker0。所有的容器在不指定网络情况下,都是由 docker0 路由的,Docker 会给我们容器默认分配一个随机的可用 IP 地址,这些 IP 地址之间是可以进行网络交互的,交互模型图如下:
- e.g.
docker run -d -p 5601:5601 --network elk --name kibana kibana:6.8.0
- 一旦在启动容器时指定了网桥,之后可以在任何与这个网桥关联的容器中使用容器名字与其他容器通信;
- 使用
docker run
指定--network <网桥>
时,网桥必须存在(不会自动创建)。
b. host
如果启动容器时使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡、配置自己的 IP 等,而是使用宿主机的 IP 和端口。但容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再用了,网络的隔离性不好。
c. container
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。
新创建的容器不会创建自己的网卡、配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信
d. none
使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。这种网络模式下容器只有 lo 回环网络,没有其他网卡。
none 模式可以在容器创建时通过 --network=none
来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
1.3 容器互联
在没有使用 connect 命令的情况下,不同网络间的容器是无法进行网络连接的。
不同 Docker 网络之间的容器想要连接的话,需要把该容器注册到另一个容器所在的网络上,使用 docker connect
命令。
docker network connect mynet centos01
connect 设置成功后,我们可以看到新注册进来的容器信息:
接下来进行容器双向连接测试:
# centos-net-01 ping centos01 连接成功
[root@haha ~]# docker exec -it centos-net-01 ping centos01
PING centos01 (192.168.0.4) 56(84) bytes of data.
64 bytes from centos01.mynet (192.168.0.4): icmp_seq=1 ttl=64 time=0.183 ms
64 bytes from centos01.mynet (192.168.0.4): icmp_seq=2 ttl=64 time=0.139 ms
64 bytes from centos01.mynet (192.168.0.4): icmp_seq=3 ttl=64 time=0.136 ms
^C
# centos01 ping centos-net-01 连接成功
[root@haha ~]# docker exec -it centos01 ping centos-net-01
PING centos-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from centos-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from centos-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.135 ms
64 bytes from centos-net-01.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.141 ms
^C
# 未连接到 mynet 的容器还是无法访问
[root@haha ~]# docker exec -it centos-net-01 ping centos02
ping: centos02: Name or service not known
摘自:
https://blog.csdn.net/elihe2011/article/details/122638566
https://blog.csdn.net/CSDN1csdn1/article/details/123961079
2. Dockerfile
2.1 构建命令
Dockerfile 是一个用来构建镜像的文本文件。
$ docker build -t myNginx:v1 .
- 最后的
.
代表本次执行的上下文路径,指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build
命令得知这个路径后,会将路径下的所有内容打包; - 如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置;Dockerfile 中所用的所有文件一定要和 Dockerfile 文件在同一目录下;上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢;
- Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以在 Dockerfile 中一定要惜字如金,能写到一行的指令,一定要写到一行,原因是分层构建,联合挂载这个特性!
- 由于 docker 的运行模式是 C/S:我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
2.2 指令详解
a. COPY
COPY 指令将从构建上下文目录中 <源路径>
的文件或目录,复制到新的一层的镜像内的 <目标路径>
位置。
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=<user>:<group>]
:可选参数,用户改变复制到容器内文件的拥有者和属组;<源路径>
:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:COPY hom* /mydir/ COPY hom?.txt /mydir/
<目标路径>
:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用,特别是构建相关文件都在使用 Git 进行管理的时候。
b. ADD
用来从上下文复制新文件、目录或远程文件 url,并将它们添加到位于指定路径的映像文件系统中。
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- 可以让你使用 URL 作为
<src>
参数。当遇到 URL 时候,可以通过 URL 下载文件并且复制到<dest>
(容器中目标路径); - 有自动解压文件的能力。如果
<src>
参数是一个可识别压缩格式(tar, gzip, bzip2…)的本地文件(注:无法实现同时下载并解压),就会被解压到指定容器文件系统的路径<dest>
下。
【提示】
ADD 的最佳用途是将本地压缩包文件自动提取到镜像中!但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。
【优点】
在执行 <源文件>
为 tar 压缩文件的话,压缩格式为 gzip、bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>
。
【缺点】
- 在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定;
- 官方建议我们当需要从远程复制文件时,最好使用 curl 或 wget 命令来代替 ADD 命令。原因是,当使用 ADD 命令时,会创建更多的镜像层,当然镜像的 size 也会更大。
c. CMD
【区分】类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在
docker run
时运行 - RUN 是在
docker build
时运行
【作用】为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run
命令行参数中指定要运行的程序所覆盖。
【注意】如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
【格式】
CMD <shell 命令>
CMD ["<可执行文件或命令>", "<param1>", "<param2>", ...]
CMD ["<param1>", "<param2>", ...]
=> 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数~
推荐使用第 2 种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
d. ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run
的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是,如果运行 docker run
时使用了 --entrypoint
选项,将覆盖 ENTRYPOINT 指令指定的程序。
# ls /data/abc
docker run --entrypoint=ls myNginx:v1 /data/abc
【优点】在执行 docker run
的时候可以指定 ENTRYPOINT 运行所需的参数。
【注意】如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
【格式】ENTRYPOINT ["<executeable>", "<param1>", "<param2>", ...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
【案例1】假设已通过 Dockerfile 构建了 nginx:test 镜像
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
(1)不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
(2)传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(假设容器内已有此文件 /etc/nginx/new.conf)
nginx -c /etc/nginx/new.conf
【案例2】
e. ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
【格式】
ENV <key> <value> ...
ENV <key1>=<value1> <key2>=<value2> ...
以下示例设置 NODE_VERSION = 7.2.0
, 在后续的指令中可以通过 $NODE_VERSION
引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
f. ARG
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build
的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build
中可以用 --build-arg <参数名>=<值>
来覆盖。
【格式】ARG <参数名>[=<默认值>]
g. VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
【作用】
- 避免重要的数据,因容器重启而丢失,这是非常致命的;
- 避免容器不断变大。
【格式】
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run
的时候,我们可以通过 -v
参数修改挂载点。
h. EXPOSE
仅仅只是声明端口。
【作用】
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
- 在运行时使用随机端口映射时,也就是
docker run -P
时,会自动随机映射 EXPOSE 的端口。
【格式】EXPOSE <端口1> [<端口2>...]
i. WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
docker build
构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
【格式】WORKDIR <工作目录路径>
j. USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
【格式】USER <用户名>[:<用户组>]
k. HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
【格式】
HEALTHCHECK [选项] CMD <命令>
:设置检查容器健康状况的命令(这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法);HEALTHCHECK NONE
:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令。
l. ONBUILD
用于延迟构建命令的执行。
简单地说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
【格式】ONBUILD <其它指令>
m. LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
比如我们可以添加镜像的作者:LABEL org.opencontainers.image.authors="runoob"
3. Docker Compose
Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。
3.1 概述&安装
从功能上看,跟 OpenStack 中的 Heat 十分类似。其代码目前在 https://github.com/docker/compose 上开源。
Compose 定位是 “定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)”,其前身是开源项目 Fig,目前仍然兼容 Fig 格式的模板文件。
通过之前的介绍,我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。
Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
Compose 中有两个重要的概念:
- 【服务(service)】一个应用的容器,实际上可以包括若干运行相同镜像的容器实例;
- 【项目(project)】由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
可见,一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理,通过子命令对项目中的一组容器进行便捷地生命周期管理。
Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。
使用 Compose基本上也就分成 3 步:
- 利用 Dockerfile 定义运行环境;
- 使用 docker-compose.yml 定义组成应用的各服务;
- 运行
docker-compose up
启动应用。
从 Github 上下载 docker-compose 二进制文件安装:
sudo curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
若是 GitHub 访问太慢,自己去想办法从 GitHub 官网上下下来文件,然后放到 /usr/local/bin 下。别忘了赋予文件可执行权限。
$ mv docker-compose-Linux-x86_64 docker-compose
$ chmod +x docker-compose
3.2 命令说明
【基本格式】
$ docker-compose --help
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the
name specified in the client certificate
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent
--env-file PATH Specify an alternate environment file
Commands:
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。
【命令选项】
-f, --file FILE
指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定;-p, --project-name NAME
指定项目名称,默认将使用所在目录名称作为项目名;--x-networking
使用 Docker 的可拔插网络后端特性(需要 Docker 1.9 及以后版本);--x-network-driver DRIVER
指定网络后端的驱动,默认为 bridge(需要 Docker 1.9 及以后版本);--verbose
输出更多调试信息;-v, --version
打印版本并退出。
a. up
docker-compose up [options] [SERVICE...]
该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
链接的服务都将会被自动启动,除非已经处于运行状态。
可以说,大部分时候都可以直接通过该命令来启动一个项目。
默认情况,docker-compose up
启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。当通过 Ctrl-C
停止命令时,所有容器将会停止。
如果使用 docker-compose up -d
,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。
默认情况,如果服务容器已经存在,docker-compose up
将会尝试停止容器,然后重新创建(保持使用 volumes-from
挂载的卷),以保证新启动的服务匹配 docker-compose.yml
文件的最新内容。如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate
。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。如果用户只想重新部署某个服务,可以使用 docker-compose up --no-deps -d <SERVICE_NAME>
来重新创建服务并后台停止旧服务,启动新服务,并不会影响到其所依赖的服务。
选项:
-d
在后台运行服务容器;--no-color
不使用颜色来区分不同的服务的控制台输出;--no-deps
不启动服务所链接的容器;--force-recreate
强制重新创建容器,不能与--no-recreate
同时使用;--no-recreate
如果容器已经存在了,则不重新创建,不能与--force-recreate
同时使用;--no-build
不自动构建缺失的服务镜像;-t, --timeout TIMEOUT
停止容器时候的超时(默认为 10s)。
b. run
docker-compose run [options] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
在指定服务上执行一个命令。
例如:docker-compose run ubuntu ping docker.com
,将会启动一个 ubuntu 服务容器,并执行 ping docker.com 命令。
默认情况下,如果存在关联,则所有关联的服务将会自动被启动,除非这些服务已经在运行中。
该命令类似启动容器后运行指定的命令,相关卷、链接等等都将会按照配置自动创建。
两个不同点:
- 给定命令将会覆盖原有的自动运行命令;
- 不会自动创建端口,以避免冲突。
如果不希望自动启动关联的容器,可以使用 --no-deps
选项,例如:
$ docker compose run --no-deps web python manage.py shell
将不会启动 web 容器所关联的其它容器。
选项:
-d
后台运行容器;--name NAME
为容器指定一个名字;--entrypoint CMD
覆盖默认的容器启动指令;-e KEY=VAL
设置环境变量值,可多次使用选项来设置多个环境变量;-u, --user=""
指定运行容器的用户名或者 uid;--no-deps
不自动启动关联的服务容器;--rm
运行命令后自动删除容器,d 模式下将忽略;-p, --publish=[]
映射容器端口到本地主机;--service-ports
配置服务端口并映射到本地主机;-T
不分配伪 tty,意味着依赖 tty 的指令将无法运行。
c. build
docker-compose build [options] [SERVICE...]
构建(重新构建)项目中的服务容器。
服务容器一旦构建后,将会带上一个标记名,例如对于 "web" 项目中的一个 db 容器,可能是 "web_db"。
可以随时在项目目录下运行 docker-compose build
来重新构建服务。
选项包括:
--force-rm
删除构建过程中的临时容器;--no-cache
构建镜像过程中不使用 cache(这将加长构建过程);--pull
始终尝试通过 pull 来获取更新版本的镜像。
d. logs
docker compose logs [options] [SERVICE...]
查看服务容器的输出。默认情况下,docker compose
将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color
来关闭颜色。
该命令在调试问题的时候十分有用。
e. start/restart
# 启动已经存在的服务容器
docker compose start [SERVICE...]
# 重启项目中的服务
docker compose restart [options] [SERVICE...]
# `-t, --timeout TIMEOUT` 指定重启前停止容器的超时(默认为 10s)
f. pause/unpause
# 暂停一个服务容器
docker compose pause [SERVICE...]
# 恢复处于暂停状态中的服务
docker compose unpause [SERVICE...]
g. stop
docker compose stop [options] [SERVICE...]
停止已经处于运行状态的容器,但不删除它。通过 docker compose start
可以再次启动这些容器。
选项:-t, --timeout TIMEOUT
停止容器时候的超时(默认为 10s)。
h. kill
docker compose kill [options] [SERVICE...]
通过发送 SIGKILL 信号来强制停止服务容器。
支持通过 -s
参数来指定发送的信号,例如通过如下指令发送 SIGINT 信号。
docker-compose kill -s SIGINT
i. rm
格式为 docker-compose rm [options] [SERVICE...]。
删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop 命令来停止容器。
选项:
-f, --force
强制直接删除,包括非停止状态的容器(一般尽量不要使用该选项)。-v
删除容器所挂载的数据卷。
j. scale
docker-compose scale [options] [SERVICE=NUM...]
设置指定服务运行的容器个数。
通过 service=num 的参数来设置数量。例如:
# 将启动 3 个容器运行 web 服务、2 个容器运行 db 服务
docker-compose scale web=3 db=2
一般地,当指定数目多于该服务当前实际运行容器,将新创建并启动容器;反之,将停止容器。
选项:-t, --timeout TIMEOUT
停止容器时候的超时(默认为 10s)。
k. port
docker-compose port [options] SERVICE PRIVATE_PORT
打印某个容器端口所映射的公共端口。
选项:
--protocol=proto
指定端口协议,tcp(默认值)或者 udp。--index=index
如果同一服务存在多个容器,指定命令对象容器的序号(默认为 1)。
l. ps
docker-compose ps [options] [SERVICE...]
列出项目中目前的所有容器。
选项:-q
只打印容器的 ID 信息。
3.3 模板文件
docker-compose.yml 分为 3 个主要部分:services、networks、volumes。
- services:定义各个容器;
- networks:定义 services 使用到的 network;
- volumes:定义 services 使用到的 volume。
version "3.2"
services:
服务名1:
image: xxx # 使用的镜像
container_name: xxx # 服务启动后的容器名称
ports:
- "xxxx:xxxx"
- "yyyy:yyyy"
volumes: # 用来指定数据卷映射
- /xxx/yyy:/xxx/yyy
- zzz:/xxx/yyy # 如果该卷名不存在,会被自动创建(命名:'项目名_'+指定卷名)
networks:
- abc # 如果该网络不存在,会被自动创建(命名:'项目名_'+指定网络名)
environment: # 用来给容器中某些环境变量赋值
- XXX_YYY_ZZZ=...
env_file: # 将环境变量的赋值转移到配置文件
- mysql.env
command: ...
healthcheck: # 对容器做健康检查
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
sysctls: # 修改容器内系统参数
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
ulimits: # 用来修改容器内系统的最大进程数
nproc: 65535
nofile:
soft: 20000
hard: 40000
depends_on: # 指明当前服务依赖哪些服务,按依赖顺序启动
- 其他服务名
- ...
服务名2:
...
volumes: # 声明容器卷
zzz:
networks: # 声明网络
abc:
a. version
Docker 和 Docker-Compose 模板文件版本的对应关系:
https://docs.docker.com/compose/compose-file/compose-file-v3/
版本 2 扩展了 Compose 的语法,同时尽量保持跟版本 1 的兼容,除了可以声明网络和存储信息外,最大的不同一是添加了版本信息,另一个是需要将所有的服务放到 services 根下面。
b. build
如果使用 build 指令,在 Dockerfile 中设置的选项(例如:CMD, EXPOSE, VOLUME, ENV 等) 将会自动被获取,无需在 docker-compose.yml 中再次设置。
指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。 Compose 将会利用它自动构建这个镜像,然后使用这个镜像。
version: '3'
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
-
context
指令指定Dockerfile
所在文件夹的路径; -
dockerfile
指令指定Dockerfile
文件名; -
arg
指令指定构建镜像时的变量; -
cache_from
指定构建镜像的缓存。build: context: . cache_from: - alpine:latest - corp/web_app:3.14
c. image
指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose
将会尝试拉取这个镜像。
services:
web: # 服务名称,用户自定义
image: busybox # 镜像名称/镜像ID,如果本地不存在compose会拉取镜像
# 以下格式都可以:
# - images: redis
# - images: mysql:latest
# - images: example-registry.com:4000/postgresql
d. container_name
指定容器名。默认将会使用 项目名称_服务名称_序号
这样的格式。
container_name: myRedis
指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称。
e. ports
暴露端口信息。使用宿主端口 : 容器端口 (HOST:CONTAINER)
格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
当使用 HOST:CONTAINER
格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 YAML
会自动解析 xx:yy
这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。
f. expose
暴露端口,但不映射到宿主机,只有连接到本容器的容器可以访问。宿主机无法访问。
expose:
- "8080"
- "8088"
g. environment
设置环境变量。你可以使用数组或字典两种格式。
只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄露不必要的数据。
environment:
RACK_ENV: development
SESSION_SECRET:
############################
environment:
- RACK_ENV=development
- SESSION_SECRET
如果变量名称或者值中用到 true|false,yes|no
等表达 布尔 (opens new window)含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。这些特定词汇,包括:y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
。
h. env_file
从文件中获取环境变量,可以为单独的文件路径或列表。
如果通过 docker compose -f FILE
方式来指定 Compose 模板文件,则 env_file
中变量的路径会基于模板文件路径。
如果有变量名称与 environment
指令冲突,则按照惯例,以后者为准。
env_file: .env
#####################
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
环境变量文件中每一行必须符合格式,支持 #
开头的注释行。
# common.env: Set development environment
PROG_ENV=development
i. volumes
数据卷所挂载路径设置。可以设置为宿主机路径(HOST:CONTAINER
)或者数据卷名称(VOLUME:CONTAINER
),并且可以设置访问模式 (HOST:CONTAINER:ro
)。
该指令中路径支持相对路径。
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
如果路径为数据卷名称,必须在文件中配置数据卷。
version: "3"
services:
my_src:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
j. networks
配置容器连接的网络。
version: "3"
services:
some-service:
networks:
- some-network
- other-network
networks: # compose 文件中出现的 network 都需要在这里进行声明,无论外界是否已存在。
some-network:
driver: bridge # or host or none or overlay
internal: true # 外部网络隔离
name: my-app-net
other-network:
external: true # 声明此网络为外部已存在的网络,所以 up 前必须保证已存在!
由 compose 自动创建的 network 的命名格式:项目名_<NetworkName>
。
k. depends_on
解决容器的依赖、启动先后的问题。以下例子中会先启动 redis
db
再启动 web
:
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
web
服务不会等待 redis
db
「完全启动」之后才启动。
l. command
覆盖容器启动后默认执行的命令。
command: ["java", "-jar", "demo.jar"]
m. sysctls
配置容器内核参数。
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
##################################
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
n. ulimits
指定容器的 ulimits 限制值。
例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
o. healthcheck
通过命令检查容器是否健康运行。配置运行的检查以确定此服务的容器是否“健康”。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
interval
、timeout
和 start_period
都是持续时间。test
必须是字符串或列表。如果是列表,则第一项必须是 NONE
、CMD
、CMD-SHELL
。如果是字符串,则相当于指定 CMD-SHELL
后跟该字符串。
# Hit the local web app
test: ["CMD", "curl", "-f", "http://localhost"]
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
test: curl -f https://localhost || exit 1
如果需要禁用镜像的所有检查项目,可以使用 disable:true
,相当于 test:["NONE"]
healthcheck:
disable: true
4. Docker 可视化
Portainer 是一个可视化的容器镜像的图形管理工具,利用 Portainer 可以轻松构建、管理和维护 Docker 环境。 而且完全免费,基于容器化的安装方式,方便高效部署。
# 拉取镜像
docker pull portainer/portainer-ce:latest
# 启动容器
docker run -d
--name portainer
-p 9000:9000
-v /var/run/docker.sock:/var/run/docker.sock
-v /app/portainer_data:/data
--restart always
--privileged=true portainer/portainer-ce:latest
初次安装后登陆需要配置账号密码。