Docker Compose 介绍

概述

到目前为止,我们可以很方便地运行一个容器。如果需要运行由多个容器组成的应用,直接使用 docker run 命令就会显得十分繁琐。为此,Docker 提供 docker compose 命令行工具以简化多容器应用运行流程。

docker compose 的使用方式十分简单,分三步即可:定义 Dockerfile 文件、定义 docker-compose.yml 文件、使用 docker-compose 命令运行。

Dockerfile 文件已介绍于 Dockerfile 文件介绍 之中,这篇文章主要介绍 docker-compose.yml 文件和 docker-compse 命令。

compose 文件

docker compose 之中,两个概念需要先行解释:

  • 服务 (service):运行相同镜像的若干容器实例,例如:redis 服务、mysql 服务。
  • 项目 (project):由一组关联服务组成的完整业务单元。

docker-compose.yml 文件就是一个项目,其中定义着该项目的具体组织结构。

docker-compose.yml 的典型结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 指明 compose 文件版本号
version: "3.9"
# 定义该项目所涉的各种服务
services:
...

# 定义项目所涉及的数据卷
volumes:
...

# 定义项目所涉及的网络
networks:
...

# 定义项目所涉及的配置信息
configs:
...

# 定义项目所涉及的秘密信息
secrets:
...

按照目前理解,configssecretsbind mount 没什么区别,就是再次封装而已。

接下来,我们将一一详述各部分。

services

services 部分的典型结构如下:

1
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
services:
# 某单个服务
# webapp 为服务名
webapp:
# 服务所对应镜像的若干配置信息
build:
# 指明该镜像的来源,其值为 Dockerfile 所在目录的路径或者为注册服务器上的仓库名
context: ./dir
# 若 context 内容为前者,则此处指明 Dockerfile 文件名,默认为 Dockerfile
dockerfile: Dockerfile-alternate
# 对应 Dockerfile 中基于 ARG 指令定义的变量,这里为赋初值。
args:
buildno: 1
# 指明基于 Dockerfile 制作镜像时的缓存来源
cache_from:
- alpine:latest
# 向镜像中添加元数据,与 Dockerfile 中 LABEL 指令作用相同,
labels:
- "com.example.name":"hhd"
# 设置容器实例运行时所处的网络
network: host
# 设置容器实例运行时,目录 /dev/shm 大小
shm_size: '2gb'
# 当 Dockerfile 采用 multi-stage 时,设置指定 stage,使得 Dockerfile 的构建过程停止于此 stage
target: prod

# 与 build 连用,命名根据 Dockerfile 构建得到的镜像,否则会默认生成镜像名和标签
# 如果单独使用 image,其表示所使用的镜像来源
image: webapp:tag

# 添加或移除容器实例功能(基本不使用)
cap_add:
- ALL
cap_drop:
- NET_ADMIN
# 为容器实例指定父cgroup
cgroup_parent: m-executor-abcd
# 设置 PID(与操作系统相关,暂时忽略)
pid: 'host'

# 授予当前服务对相关配置的访问权限(配置需已定义于 configs 之中)
# 短语法形式
configs:
- my_config
# 长语法形式(分别指明源配置、容器实例中的目标位置,默认为 /<source>、用户id、组id、配置的访问权限)
configs:
- source: my_config
target: /usr_config
uid:
gid:
mode:

# 授予当前服务对相关秘密的访问权限(配置需已定义于 secrets 之中)
# 短语法形式
secrets:
- my_secret
# 长语法形式(分别指明源配置、容器实例中的目标位置,默认为 /run/secrets/<source>、用户id、组id、配置的访问权限)
configs:
- source: my_secret
target: /usr_secret
uid:
gid:
mode:

# 设置服务对应的容器实例名称
container_name: my_web_container
# 设置设备映射列表
devices:
- '/dev/ttyUSB0:/dev/ttyUSB0'
# 自定义 DNS 服务列表
dns:
- 8.8.8.8
# 自定义 DNS 搜索域
dns_search:
- example.com
# 覆盖 ENTRYPOINT 指令所实施的默认操作
entrypoint: ['php','-d']
# 覆盖 CMD 指令所实施的默认操作
command: echo "hello"
# 从文件中添加容器实例的环境变量
env_file:
- ./common_env
# 直接添加环境变量
environment:
- SHOW=true
# 公布服务所对应镜像的内部端口
expose:
- '8000'
# 配置端口映射信息
# 短语法形式(两种形式,一种主机端口:容器端口,另一种容器端口)
ports:
- '3251:80'
# 长语法形式(具体包括容器端口、主机端口、所用协议、..)
ports:
- target: 80
published: 3251
protocol: tcp
mode: host
# 指明当前容器链接至哪些容器,与 docker run 命令的 --link 参数作用一样
links:
# 指明当前容器链接至哪些外部容器,与 docker run 命令的 --link 参数作用一样
external_links:
# (链接容器名:定义的别名)
- project_db_1:mysql
# 添加主机名映射信息,与 docker run 命令的 --add-host 参数作用一样
extra_hosts:
- "somehost:165.254.2.2"
# 配置健康检查操作,与 HEALTHCHECK 指令作用相同。
healthcheck:
# 容器实例内部是否运行一个初始化程序(这里涉及操作系统知识,暂时忽略)
init: true
# 指定容器实例采用的隔离技术
isolation: default
# 向容器实例中添加元数据
labels:
- "com.example.name":"hhd"
# 配置服务的日志记录信息(包括日志驱动程序、日志记录地址等信息)
logging:
driver: syslog
options:
syslog-address: "xxxx"
# 设置容器实例运行时的网络模式
network_mode: 'bridge'
# 设置容器实例运行时的网络(需已定义于 networks 之中)
networks:
- host
# 设置当前服务在此网络中的主机别名,以供同一网络内的其他服务调用
aliases:
- aliase1
# 设置当前服务在此网络中的 IP 地址
ipv4_address: 172.16.238.10
ipv6_address: 2001:3984:3989::10
# 为当前服务分配若干profile。默认情况下,执行 docker-compose 命令将启动文件中定义的所有服务
# 使用 profile 后,如果执行 docker-compose 命令时没有携带参数 `--profile frontend`,则该服务不会被启动
profile:
- frontend
# 设置容器实例的重启策略(共有 no\always\no-failure\unless-stopped 四种)
restart: no
# 使用 docker stop 命令停止容器时,它首先发送 SIGTERM 信号至容器,等待一段时间后,再发送 SIGKILL 信号停止容器
# 该字段便是设置这段时间具体有多长
stop_grace_period: 1s
# 设置停止容器的信号
stop_sigal: SIGUSR1

# 挂载 tmpfs
tmpfs:
- /app
# 数据卷挂载(若希望重用某个命名数据卷,其必须定义于顶层结构的volumes 之中)
# 短语法(数据卷名称/路径名:容器路径名:mode)
volumes:
- ./cache:/user:ro
# 长语法(具体包括挂载类型、数据卷名称或路径名、容器路径名、是否只读等)
volumes:
- type: volume
source: ./cache
target: /user
read_only:

# 配置托管服务账号的凭据规范(仅用于 windows 环境,因此忽略)
credential_spec:

# 指明当前服务的依赖服务(docker 会按照此依赖顺序按序启动服务)
depends_on:
- redis
- db

# 与服务运行与部署的相关配置信息(当服务部署于 swarm 时,这些配置信息才会生效,因此忽略)
deploy:

# 还有一些参数,可以暂时忽略

# 其他服务(与上类似,故而省略)

volumes

若希望重用某个命名数据卷,其必须定义于顶层结构的 volumes 之中。

volumes 部分的典型结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
volumes:
# 定义一个命名数据卷,其余配置采用默认值
my-volume:
# 定义另一个命名数据卷,其余配置采用自定义形式
other-volume:
# 配置当前数据卷所用的驱动程序
driver: foobar
# 以键值对形式向驱动程序传递参数
driver-opt:
type: "nfs"
# 取值为 true,表明已存在此数据卷,则 compose 会查找此数据卷并挂载之;反之 compose 会尝试创建并使用之
external: true
# 为数据卷自定义一个名称
name: my-app-volume

networks

networks 部分的典型结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
networks:
# 定义一个网络
my-network:
# 指明该网络所用驱动程序
driver: bridge
# 以键值对形式向驱动程序传递参数
driver-opt:
foo: "bar"
# 当 driver=overlay 时,此字段才有用
# 取值为 true,则单个容器和服务均可连接至网络;反之仅服务可连接至网络
attachable: true
# 设置 IP地址管理(IPAM) 的若干配置,包括所用驱动程序,所处网段
ipam:
driver: default
config:
- subnet: "192.168.0.0/16"
# 取值为 true,表明已存在此网络,则 compose 会直接使用此外部网络;反之 compose 会尝试创建并使用之
external: true
# 为网络自定义一个名称
name: my-app-network

configs/secrets

configs 与 secrets 的结构一致,其典型结构如下:

1
2
3
4
5
6
7
configs/secrets:
# 定义一个 config/secret 名称
my_config:
# 该 config/secret 对应的文件路径
file: xxx
# 取值为 true,表明已存在此 config/secret,则 compose 会直接使用此;反之 compose 会尝试创建并使用之
external: true

compose 命令

docker-compose 命令完成与 Compose 相关的众多操作。在此,简单列举若干:

1
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
Sub Commands:
# 构建指定服务对应的镜像,其等价于 docker build
build Build or rebuild services
# 上传或下拉指定服务所对应的镜像,其等价于 docker pull/push
pull Pull service images
push Push service images
# 构建指定服务对应的容器实例,其等价于 docker create
create Create services
# 运行指定服务,其等价于调用 docker run
run Run a one-off command
# 依次完成构建镜像、数据卷、网络,创建容器实例,运行等操作,从而启动整个项目
up Create and start containers
# 与 up 命令相对,删除 up 命令所创建的一切
down Stop and remove containers, networks, images, and volumes

# 在指定服务的容器实例中执行指定命令,其等价于 docker exec
exec Execute a command in a running container
# 设置某服务的容器实例数量
scale Set number of containers for a service
# 杀死/暂停/取消暂停/启动/停止/重启 特定服务的容器实例,其等价于 docker ...
kill Kill containers
pause Pause services
unpause Unpause services
start Start services
stop Stop services
restart Restart services

# 验证、查看指定的 compose 文件
config Validate and view the Compose file
# 以 JSON 格式输出某服务的容器实例中的事件信息
events Receive real time events from containers
# 显示特定服务的日志输出
logs View output from containers
# 查看指定服务的容器实例的端口映射信息
port Print the public port for a port binding
# 罗列所涉容器
ps List containers
# 显示服务的进程信息
top Display the running processes

# 移除指定服务的已停止运行的容器实例
rm Remove stopped containers

可以看到 docker-compose 命令与 docker 命令基本一致,前者为后者的再次封装。

当在 shell 窗口输入 docker-compose up 命令后,客户端会将 docker-compose.yml 以及上下文环境 (主要指代 Dockerfile 的上下文环境) 发送至守护进程,守护进程依次自动完成如下事件以启动整个项目:创建数据卷和网络、依据 Dockerfile 构建镜像、按照依赖关系创建容器并将其加入相应网络。