Docker 命令 之 docker compose

摘要

docker compose 是什么?

  • Docker Compose是一个用于定义和运行多容器应用程序的工具。

  • Compose简化了对整个应用程序堆栈的控制,便于在单个YAML配置文件中管理服务、网络和卷。然后,通过一个命令,您从配置文件中创建并启动所有服务。

  • Docker Compose 的优势:

优点 描述
简化控制 Docker Compose 允许在单个 YAML 文件中定义和管理多容器应用程序,简化了服务编排与协调,使环境管理和复制更容易。
高效的协作 配置文件易于共享,促进开发人员、运营团队和其他利益相关者之间的协作,从而提升工作流程效率和问题解决速度。
快速应用程序开发 Compose 利用缓存重复使用未更改服务的容器,加快环境变更速度,提高开发效率。
跨环境的可移植性 支持在 Compose 文件中使用变量,使配置能根据不同环境或用户进行自定义,增强了可移植性。
广泛的社区和支持 拥有活跃的社区,提供丰富的资源、教程和技术支持,有助于持续改进与高效排障。

docker compose 安装

  • 同docker一起安装

1
2
# 安装docker同时安装docker compose,这里 docker-compose-plugin 就是docker compose
sudo dnf install docker-ce-3:26.1.3-1.el8 docker-ce-cli-3:26.1.3-1.el8 containerd.io docker-buildx-plugin docker-compose-plugin -y
  • 单独安装

1
2
# 若安装docker时没有安装 docker-compose-plugin ,则需要单独安装
sudo dnf install docker-compose-plugin -y
  • 查看版本

1
docker compose version

直接下载docker-compose的命令文件

1
2
3
4
5
6
# Install Docker Compose,注意通过这种方式安装的compose的使用方式为 `docker-compose`,而非标准的 `docker compose`
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# Make the docker-compose command available
sudo chmod +x /usr/local/bin/docker-compose
# Check Docker Compose version
docker-compose version

docker compose 命令

命令 中文说明 示例
attach 连接到服务的运行中容器的标准输入、输出和错误流 docker compose attach web
build 构建或重新构建服务 docker compose build
config 解析并标准化 Compose 文件 docker compose config
cp 在服务容器与本地文件系统之间复制文件/文件夹 docker compose cp web:/app/file.txt ./file.txt
create 为服务创建容器,但不启动 docker compose create
down 停止并移除容器、网络等资源 docker compose down
events 实时接收容器事件 docker compose events
exec 在运行中的容器中执行命令 docker compose exec web ls /app
images 列出已创建容器所使用的镜像 docker compose images
kill 强制停止服务容器 docker compose kill
logs 查看服务容器的日志输出 docker compose logs
ls 列出当前运行的 Compose 项目 docker compose ls
pause 暂停服务容器 docker compose pause
port 显示某端口映射的公网地址 docker compose port web 80
ps 列出服务的容器 docker compose ps
pull 拉取服务使用的镜像 docker compose pull
push 推送服务镜像到仓库 docker compose push
restart 重启服务容器 docker compose restart
rm 移除已停止的服务容器 docker compose rm
run 在服务上运行一次性命令 docker compose run web echo Hello
scale 扩展服务实例数量 docker compose up --scale web=3
start 启动已存在但已停止的服务容器 docker compose start
stats 实时显示容器资源使用情况 docker compose stats
stop 停止运行中的服务容器 docker compose stop
top 显示容器内的运行进程 docker compose top
unpause 取消暂停服务容器 docker compose unpause
up 创建并启动服务容器 docker compose up
version 显示 Docker Compose 版本信息 docker compose version
wait 阻塞直到第一个服务容器停止 docker compose wait
watch 监听服务构建上下文变更并重新构建/刷新容器 docker compose watch

docker compose 常用命令

  • 启动与关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 启动并运行,默认使用当前目录的 docker-compose.yml 文件
docker compose up
# 后台运行
docker compose up -d
# 指定compose文件
docker compose -f docker-compose.yml up -d
# 启动时重建服务,当修改了 compose 文件时
docker compose up --build
# 停止service
docker compose stop
# 强制停止service,当 stop 命令无法停止时
docker compose kill
# 重启service
docker compose restart
# 删除service,-s 参数表示删除前先停止容器
docker compose rm -s
# 停止并删除service,同时删除网络,但不会删除卷
docker compose down
  • 监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 列出当前运行的 Compose 项目
docker compose ls
# 查看service状态,-a 显示所有service
docker compose ps -a
# 解析并标准化 compose 文件,这个命令可以检查 docker-compose.yml 文件语法是否正确
docker compose config
# 查看使用的镜像
docker compose images
# 查看进程
docker compose top
# 查看service资源使用情况
docker compose stats
# 查看service日志,-f 表示持续跟踪
docker compose logs -f
# 查看指定service的日志
docker compose logs -f service_name
# 进入指定的service容器
docker compose exec service_name bash
  • 升级镜像

1
2
3
4
5
6
# 先停止所有service
docker compose down
# 拉取最新镜像
docker compose pull
# 启动service
docker compose up -d --build

docker-compose.yml 的语法

  • 常用指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: "3.8" # 定义版本,表示当前使用的 docker compose 语法的版本,已过时 ,新版 Docker 会使用最新的 Compose Specification 自动解析
name: "project_name" # 项目名,默认 docker-compose.yml 文件所在的目录名,不推荐设置
services: # 服务列表
servicename: # 服务名字,只能包含小写字母、数字、下划线、中划线,必须以字母或数字开头
build: # 基于Dockerfile构建目录,如果同时设置了 image 选项,则image指定的就是构建后的镜像名称
image: # 镜像的名字,默认从远程仓库拉取,如果配置了 build 选项,则image指定的就是构建后的镜像名称
command: # 可选,如果设置,则会覆盖默认镜像里的 CMD 命令
environment: # 可选,等价于 docker container run 里的 --env 选项设置环境变量
volumes: # 可选,等价于 docker container run 里的 -v 选项 绑定数据卷
networks: # 可选,等价于 docker container run 里的 --network 选项指定网络
ports: # 可选,等价于 docker container run 里的 -p 选项指定端口映射
expose: # 可选,指定容器暴露的端口
depends_on: # 服务依赖的其它服务
env_file: # 环境变量文件,生产环境更推荐这种方式
servicename2:
image:
command:
networks:
ports:
servicename3:
#...

volumes: # 可选,等价于 docker volume create
networks: # 可选,等价于 docker network create

volumes

  • 卷是由容器引擎实现的持久数据存储。Compose 为服务提供了一种中立的挂载卷的方式,并通过配置参数将卷分配给基础架构。顶级volumes声明允许您配置可在多个服务之间重复使用的命名卷。

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
backend:
image: example/database
volumes: # 挂载卷映射
- db-data:/etc/data # 挂载到容器的/etc/data目录

backup:
image: backup-service
volumes:
- db-data:/var/lib/backup/data # 一个卷可以被多个服务使用

volumes: # 存储卷配置
db-data: # 创建一个名为db-data的卷,实际的网络名称是 容器组名称_这里的名称

volumes 的属性

  • driver: 卷类型,默认为local,指定应使用哪个卷驱动程序。如果该驱动程序不可用,Compose 将返回错误并且不会部署该应用程序。

1
2
3
4
volumes:
db-data: # 声明一个名为db-data的卷
driver: local # 指定卷类型,这个是默认值,可以不配置
db-data2: # 声明一个名为db-data2的卷,这是最简单的 volumes 配置
  • driver_opts: 卷类型参数,指定要传递给此卷驱动程序的选项列表(以键值对的形式)。这些选项与驱动程序相关。

1
2
3
4
5
6
volumes:
db-data:
driver_opts: # 卷类型参数,指定要传递给此卷驱动程序的选项列表(以键值对的形式)
type: "nfs" # 卷类型,指定应使用哪个卷驱动程序,这里是nfs
o: "addr=10.40.0.199,nolock,soft,rw" # nfs参数,addr为nfs服务器地址,nolock为不锁定文件,soft为软链接,rw为读写权限
device: ":/docker/example" # nfs挂载路径
  • external: 卷是否为外部卷,默认为false

1
2
3
volumes:
db-data:
external: true # true 表示不会创建,而是使用已存在的,即会去volumes中查找(docker volume ls) 容器组名称_da-data ,默认为false
  • name: 卷的名称,默认为 容器组名称_声明的名称

1
2
3
4
volumes:
db-data:
name: db-data # 创建一个名为db-data的卷,实际的卷名称就是 db-data,不会再加上容器组名称前缀
external: true # name 属性经常与 external: true 一起使用
  • labels: 用于向卷添加元数据,可以添加任意的键值对

1
2
3
4
5
6
volumes:
db-data:
labels:
com.example.description: "Database volume"
com.example.department: "IT/Ops"
com.example.label-with-empty-value: ""

networks

  • 网络使服务能够相互通信。默认情况下,Compose 会为您的应用设置单个网络。服务的每个容器都会加入默认网络,并且该网络上的其他容器都可以访问,并且可以通过服务名称发现。顶级networks元素允许您配置可在多个服务之间重复使用的命名网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
services:
frontend:
image: example/webapp
networks: # 网络映射
- front-tier # 加入front-tier网络
- back-tier
db:
image: postgres
networks:
- backend

networks: # 网络配置
front-tier: # 创建一个名为front-tier的网络,实际的网络名称是 容器组名称_front-tier
back-tier:
  • 如果 Compose 文件未显式声明网络,Compose 将使用隐式default网络。

1
2
3
4
5
6
7
8
9
10
11
12
services:
some-service:
image: foo

# 这个例子实际上等同于:
services:
some-service:
image: foo
networks:
default: {}
networks:
default: {}

networks 的属性

  • driver: 网络类型,默认为bridge

1
2
3
networks:
gitea:
driver: bridge
  • driver_opts: 网络类型参数,指定要传递给此网络驱动程序的选项列表(以键值对的形式)。这些选项与驱动程序相关。

1
2
3
4
5
networks:
frontend:
driver: bridge
driver_opts:
com.docker.network.bridge.host_binding_ipv4: "127.0.0.1" # 设置容器端口绑定到主机的哪个 IP(如 "127.0.0.1",绑定到本地)

driver_opts 常见配置项(针对 bridge 网络驱动)

选项键名(driver_opts 说明
com.docker.network.bridge.name 指定桥接网络的名称(默认是随机生成,如 br-xxxxx
com.docker.network.bridge.enable_icc 是否允许容器之间的通信(truefalse
com.docker.network.bridge.enable_ip_masquerade 是否启用 IP 假冒(NAT,通常用于外网访问)
com.docker.network.bridge.host_binding_ipv4 设置容器端口绑定到主机的哪个 IP(如 "127.0.0.1",绑定到本地)
com.docker.network.bridge.default_bridge 是否将该网络设置为默认 bridge 网络(truefalse
com.docker.network.driver.mtu 设置网络的最大传输单元(MTU,例如 "1500"
com.docker.network.bridge.allow_non_default_bridge 是否允许容器加入非默认的 bridge 网络(较少使用)
  • attachable: 如果为true,则允许将其它独立容器也加入到此网络。默认值为false。如果独立容器连接到此网络,它可以与同样连接到此网络的服务和其他独立容器进行通信。

1
2
3
networks:
gitea:
attachable: true
  • external: true 表示不会创建新的网络,回去networks中查找(docker network ls),默认为false

1
2
3
networks:
gitea:
external: true
  • name: 网络名称,不会再加上容器组名称前缀

1
2
3
4
networks:
gitea:
name: gitea
external: true # name 属性经常与 external: true 一起使用
  • labels: 用于向网络添加元数据,可以添加任意的键值对

1
2
3
4
5
6
networks:
mynet1:
labels:
com.example.description: "Financial transaction network"
com.example.department: "Finance"
com.example.label-with-empty-value: ""
  • internal: 默认情况下,Compose 提供网络的外部连接。internal当设置为 时true,可让您创建与外部隔离的网络。

1
2
3
networks:
gitea:
internal: true

services

  • 服务是应用程序中计算资源的抽象定义,可以独立于其他组件进行扩展或替换。服务由一组容器支持,由平台根据复制要求和布局约束运行。由于服务由容器支持,因此它们由 Docker 镜像和一组运行时参数定义。服务中的所有容器都使用这些参数以相同的方式创建。

  • service 包含的属性非常多,具体请参考services顶级元素,这里只介绍比较常用的属性,以giteadocker-compose.yml为例

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
# version: '3.8' # 配置文件版本,已过时,配置上会告警但不会报错
# name: gitea # 容器组名称,默认使用所在目录的名称,不推荐使用
networks: # 网络配置
gitea: # 创建一个名为gitea的网络,实际的网络名称是 gitea_gitea,即 容器组名称_这里的名称
external: false # 如果为true,则表示此网络不会由compose创建,而是使用已有的网络,默认为false
driver: bridge # 网络类型,默认为bridge

volumes: # 存储卷配置
gitea: # 创建一个名为gitea的存储卷,实际的卷名称是 gitea_gitea,即 容器组名称_这里的名称
driver: local # 存储卷类型,默认为local

services: # 服务配置,这里可以定义一组容器
server: # 定义一个名为server的服务,注意这个不是容器名称
# build: . # 构建镜像,使用当前目录下的Dockerfile
image: gitea/gitea:latest # 镜像名称
# container_name: gitea # 容器名称,默认为 “容器组名称-服务名称-索引”,不推荐配置,因为 水平扩展(--scale) 时,容器名称不能重复
environment: # 定义环境变量
- USER_UID=1000 # key=value
- USER_GID=1000
- DB_TYPE=mysql
- DB_HOST=db:3306 # 这里配置的 db 就是 下面的服务名称,相同 network 下的服务名称,docker compose会自动解析为容器的ip地址
- DB_NAME=gitea
- DB_USER=gitea
- DB_PASSWD=gitea
# env_file: .gitea.env # 从 .gitea.env 文件读取环境变量,生产环境更推荐
restart: always # 容器启动时,自动重启
networks: # 网络关联
- gitea # 网络名称,就是上面创建的gitea网络
volumes: # 数据卷关联
- gitea:/data # volume映射,数据卷名称:/容器路径
- /etc/timezone:/etc/timezone:ro # 路径映射,宿主机路径:/容器路径:读写权限
- /etc/localtime:/etc/localtime:ro
ports: # 端口映射
- "3000:3000" # 宿主机端口:容器端口
depends_on: # 启动依赖,就是依赖的服务启动后才能启动本服务
db: # 启动db服务
condition: service_healthy # 服务通过健康检查,也可以配置为 service_started:服务启动,这个是默认值

db: # 数据库服务
image: mysql:8 # 镜像
environment: # 环境变量
- MYSQL_ROOT_PASSWORD=gitea
- MYSQL_USER=gitea
- MYSQL_PASSWORD=gitea
- MYSQL_DATABASE=gitea
restart: always # 启动策略
networks: # 网络映射
- gitea # 映射到gitea网络
volumes: # 卷映射
- ./mysql:/var/lib/mysql # 宿主机路径:/容器路径,这里宿主机支持相对路径
healthcheck: # 健康检查
test: ["CMD-SHELL", "mysql -u root -pgitea", "-e 'SELECT 1;'"] # 执行命令,如果返回0,则健康检查通过,这里不支持上面的环境变量,test只支持 CMD-SHELL 和 CMD
interval: 10s # 健康检查间隔
timeout: 5s # 健康检查超时时间
retries: 3 # 健康检查重试次数
  • build: 构建镜像

1
2
3
4
services:
server:
build: . # Dockerfile的目录,“.” 表示使用当前目录下的Dockerfile
image: example/webapp # 镜像名称,如果有build,则该名称就是build后的镜像名称,如果没有build,则就会从远程仓库拉取
1
2
3
4
5
6
7
8
9
10
11
12
13
services:
server:
build:
context: ./webapp # Dockerfile的目录,默认是当前目录
dockerfile: Dockerfile # 构建镜像的Dockerfile名称,默认是Dockerfile
platforms: # 构建镜像的架构
- linux/amd64 # 构建镜像的架构,默认是当前架构
args: # 构建镜像的参数
- FOO=bar
labels: # 构建镜像的标签
com.example.description: "Accounting webapp"
com.example.department: "Finance"
com.example.label-with-empty-value: ""
  • command: 覆盖容器映像声明的默认命令

1
2
3
4
services:
server:
command: ["python", "app.py"]
image: example/webapp
  • entrypoint: 声明服务容器的默认入口点,这覆盖了服务Dockerfile中的ENTRYPOINT指令。

1
2
3
4
5
6
7
8
9
10
11
12
services:
server:
image: example/webapp
entrypoint:
- php
- -d
- zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
- -d
- memory_limit=-1
- vendor/bin/phpunit
# 如果值为null,则使用图像的默认入口点。 entrypoint: null
# 如果值是 [](空列表)或 ''(空字符串),图像声明的默认入口点被忽略,或者换句话说,被覆盖为空。 entrypoint: []
  • depends_on: 服务启动依赖,就是依赖的服务启动后才能启动本服务

1
2
3
4
5
6
7
8
9
10
services:
web:
build: .
depends_on:
- db # 短语法
- redis
redis:
image: redis
db:
image: postgres
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
web:
build: .
depends_on:
db: # 长语法
condition: service_healthy # 满足的条件
restart: true # 当设置为true,Compose在更新依赖服务后重新启动此服务。
redis:
condition: service_started
redis:
image: redis
db:
image: postgres

## condition:设置依赖性被视为满足的条件
# service_started:相当于之前描述的简短语法
# service_healthy:指定在启动依赖服务之前,依赖预期为“健康”(如healthcheck所示)。
# service_completed_successfully:指定在启动依赖服务之前,依赖项预计将运行到成功完成。

  • environment: 定义环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
server:
image: example/webapp
environment:
- FOO=bar
- BAZ=qux
# 或者
services:
server:
image: example/webapp
environment:
FOO: bar
BAZ: qux
  • env_file: 用于指定一个或多个包含要传递到容器的环境变量的文件。

1
2
3
4
5
6
services:
server:
image: example/webapp
env_file:
- ./a.env # 列表中的文件是从上到下处理的。对于两个环境文件中指定的相同变量,列表中最后一个文件的值是有效的。
- ./b.env
1
2
3
4
5
6
7
8
services:
server:
image: example/webapp
env_file:
- path: ./default.env
required: true # default
- path: ./override.env
required: false # 当required设置为false且.env文件缺失时,Compose会忽略
  • restart: 定义平台在容器终止时适用的策略

1
2
3
4
5
6
7
8
services:
server:
image: example/webapp
restart: "no" # 默认重启策略。在任何情况下,它都不会重新启动容器。
# restart: always # 策略总是重新启动容器,直到它被移除。
# restart: on-failure # 如果退出代码表明错误,策略将重新启动容器。
# restart: on-failure:3 # 如果退出代码表明错误,策略将重新启动容器。但仅尝试重启3次。
# restart: unless-stopped # 无论退出代码如何,策略都会重新启动容器,但当服务停止或删除时,策略会停止重新启动。
  • healthcheck: 健康检查。

1
2
3
4
5
6
7
8
9
10
services:
server:
image: example/webapp
healthcheck: # 健康检查
test: ["CMD", "curl", "-f", "http://localhost"] # 监控检查时执行的命令
interval: 1m30s # 健康检查的间隔,默认值为 30s
timeout: 10s # 健康检查的超时时间,默认值为 30s
retries: 3 # 健康检查的尝试次数,默认值为 3
start_period: 40s # 启动宽限期:在此期间,失败不会计入重试次数(仅用于判断服务是否启动完毕)
start_interval: 5s # 启动宽限期内检查的频率,本示例为在前 40 秒内每 5 秒检查一次

test定义Compose运行的命令来检查容器运行状况。它可以是字符串,也可以是列表。如果是列表,第一个项目必须是NONE、CMD或CMD-SHELL。如果它是一个字符串,它等同于指定CMD-SHELL后跟该字符串。

1
2
3
4
test: ["CMD", "curl", "-f", "http://localhost"]
# 使用CMD-SHELL运行配置为字符串的命令,使用容器的默认外壳(Linux的/bin/sh)。以下两种形式是等价的
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
test: curl -f https://localhost || exit 1

test 中的 CMD 和 CMD-SHELL 是两种不同的执行方式,它们的主要区别在于:

项目 CMD CMD-SHELL
用途 直接执行命令(不通过 shell) 通过 shell(如 /bin/sh -c)执行命令
🧾 写法格式 ["CMD", "executable", "arg1", "arg2"] ["CMD-SHELL", "command string"]
🔧 是否使用 shell
🧠 是否支持 shell 语法 ❌ 否
(不能使用 &&||\$VAR 等)
✅ 是
(支持管道、重定向、变量、命令组合)
🛡️ 安全性/可移植性 ✅ 更安全,执行更明确 ⚠ 依赖容器中存在 shell(如 /bin/sh
⚙️ 执行效率 ✅ 稍快,因无需 shell 解析 ⚠ 稍慢,需通过 shell 启动
📦 推荐使用场景 - 简单健康检查命令
- 安全环境
- 精简镜像
- 需要使用逻辑控制(||, &&
- 复杂检查逻辑
📌 示例 ["CMD", "curl", "-f", "http://localhost"] ["CMD-SHELL", "curl -f http\://localhost || exit 1"]
  • volumes: 挂载数据卷。

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
# 长语法格式
services:
backend:
image: example/backend
volumes:
- type: volume # 安装类型。可以是是volume、bind、tmpfs、image、npipe、cluster
source: db-data # 挂载的源、绑定挂载的主机上的路径、映像挂载的Docker映像引用或顶层volumes键中定义的卷名称。不适用于tmpfs支架。
target: /data # 容器中装载卷的路径。
volume: # 配置其他卷选项
nocopy: true # 在创建卷时禁用从容器复制数据的标志,默认值为false。
subpath: sub # 挂载卷的子目录。即 db-data/sub
- type: bind # bind 表示挂载主机上的路径
source: /var/run/postgres/postgres.sock
target: /var/run/postgres/postgres.sock

volumes: # 声明数据卷
db-data:

######################################################################################

# 短语法格式
services:
backend:
image: example/backend
volumes:
- db-data:/data # 这种语法不支持 subpath 和 nocopy
- /var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock

volumes:
db-data:
  • networks: 配置网络。

1
2
3
4
5
6
7
8
9
services:
some-service:
networks: # 配置网络
- some-network # 关联网络
- other-network

networks: # 声明网络
some-network:
other-network: