高级篇 Docker Compose
内容概述
Docker Compose 项目是Docker 官方开源项目,负责实现对Docker 容器集群的的快速编排。
# 1. Docker Compose 简介
思考:dockerfile build run 手动操作,单个容器是没有任何问题的,也比较方便。那么,如果是微服务呢,假设有100个微服务, 并且它们相互之间可能存在依赖关系,如果还用dockerfile 来单个管理就比较麻烦,且费时费力。这个时候docker compose 就出现了, 利用它来轻松高效的管理容器,定义和运行多个容器。
Docker Compose 是一个用于定义和运行多容器Docker 应用程序的工具, 通过Compose 可以使用YAML 文件(默认为 docker-compose.yml)来配置应用程序需要的应用程序。 然后,使用一个命令(如 docker-compose up),就可以从YAML 文件中创建并启动所有服务。
- 定义、运行多个容器
- yml 文件配置
- 一键启动所有服务
single command.命令有哪些?
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features (opens new window).
所有的环境都可以使用compose
Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases (opens new window).
# 1.1 Docker Compose 使用三步骤
Using Compose is basically a three-step process:
- Define your app’s environment with a
Dockerfileso it can be reproduced anywhere.- 创建对应的Dockerfile 文件
- Define the services that make up your app in
docker-compose.ymlso they can be run together in an isolated environment.- 创建yml 文件,在yml 文件中编排我们的服务
- Run
docker-compose upand Compose starts and runs your entire app.- 通过docker-compose up 命令一键运行容器
作用:批量容器编排
# 1.2 理解Docker Compose
Compose 是docker 官方的开源项目,和docker 完美契合。
Dockerfile让程序在任何地方运行,web服务,redis、mysql、nginx……多个容器。
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Compose 中有两个重要的概念:
- 服务 (
service):一个应用的容器(web、redis、mysql……),实际上可以包括若干运行相同镜像的容器实例。 - 项目 (
project):由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml文件中定义。
Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。
Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker
API,就可以在其上利用 Compose 来进行编排管理。
# 2. Docker Compose 安装
最新的docker 已经集成了docker-compose 功能,无需单独安装!
# 2.1 下载
# 官方下载
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 官方慢,国内镜像下载快
$ curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` /usr/local/bin/docker-compose
2
3
4
5
# 2.2 授权
$ chmod +x /usr/local/bin/docker-compose
# 2.3 版本检查
$ docker-compose --version
$ docker-compose -v
2
# 3. Docker Compose 初体验
官方演示案例:https://docs.docker.com/compose/gettingstarted/ (opens new window)
Step 1:Set up(设置)
- 创建对应目录
$ mkdir composetest
$ cd composetest
2
- 创建Python 文件app.py
$ vim app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return f'Hello World! I have been seen {count} times.\n'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 创建requirements.txt 文件
$ vim requirements.txt
flask
redis
2
3
4
- 创建Dockerfile 文件
$ vim Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]
2
3
4
5
6
7
8
9
10
11
12
13
Step 2:在Compose 文件中定义服务(需要的环境,web、redis)
$ vim docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
2
3
4
5
6
7
8
9
10
Step 3:使用Compose 创建并启动项目
- docker-compose up
$ docker-compose up [-d]
- 访问页面
$ curl localhost:5000

# 3.1 docker-compose 工作流程
- 创建网络
Creating network "composetest_default" with the default driver
- 执行docker-compose.yml
- 启动服务 docker-compose.yml
Creating composetest_web_1 ... done
Creating composetest_redis_1 ... done
2
# 4. docker-compose 模板文件
模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。但这里面大部分指令跟 docker run 相关参数的含义都是类似的。
默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
2
3
4
5
6
7
8
注意,每个服务都必须通过 image 指令指定镜像或 build 指令(需要 Dockerfile)等来自动构建生成镜像,那么也就意味着同一个服务
image 和build指令不可以同时使用 。
如果使用 build 指令,在 Dockerfile 中设置的选项(例如:CMD, EXPOSE, VOLUME, ENV 等) 将会自动被获取,无需在
docker-compose.yml 中重复设置。
docker-compose.yml 模板内容:
# 总共3层
version: '' # 版本 1层
service: # 服务 2层
服务1: web
# 服务配置
images
build
network
......
服务2: redis
......
服务3: redis
......
# 其他配置 网络/卷、全局规则、声明 3层
volumes:
network:
configs:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
下面分别介绍各个指令的用法:
# 4.1 build
指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。
Compose 将会利用它自动构建这个镜像,然后使用这个镜像
version: '3'
services:
webapp:
build: ./dir
2
3
4
5
你也可以使用 context 指令指定 Dockerfile 所在文件夹的路径。
使用 dockerfile 指令指定 Dockerfile 文件名。
使用 arg 指令指定构建镜像时的变量。
version: '3'
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
2
3
4
5
6
7
8
9
# 4.2 command
覆盖容器启动后默认执行的命令。
version: '3'
services:
webapp:
build: ./dir
command: echo "hello world"
2
3
4
5
6
# 4.3 container_name
指定容器名称。默认命名格式: 项目名称_服务名称_序号
version: '3'
services:
webapp:
build: ./dir
command: echo "hello world"
container_name: docker-web-container
2
3
4
5
6
7
注意: 指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称, 因此推荐默认命名方式。
# 4.4 depends_on
指定容器启动依赖,解决容器的依赖、启动先后的问题。以下例子中会先启动 redis db 再启动 web
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
2
3
4
5
6
7
8
9
10
11
12
13
14
注意:
web服务不会等待redisdb「完全启动」之后才启动。
# 4.5 env_file
指定配置文件路径,从文件中获取环境变量,可以为单独的文件路径或文件列表。
如果通过 docker-compose -f FILE 方式来指定 Compose 模板文件,则 env_file 中变量的路径会基于模板文件路径。
如果有变量名称与 environment 指令冲突,则按照惯例,以后者为准。
推荐使用.env 文件命名,文件可以隐藏,安全。
env_file: .env
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
2
3
4
5
6
环境变量文件中每一行必须符合格式,支持
#开头的注释行。
# common.env: Set development environment
PROG_ENV=development
2
# 4.6 environment
设置环境变量,可以使用数组或字典两种格式。
只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄露不必要的数据。
environment:
RACK_ENV: development
SESSION_SECRET:
environment:
- RACK_ENV=development
- SESSION_SECRET
2
3
4
5
6
7
如果变量名称或者值中用到 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
# 4.7 healthcheck
通过命令检查容器是否健康运行。
healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost" ]
interval: 1m30s
timeout: 10s
retries: 3
2
3
4
5
# 4.8 image
指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试从仓库拉取镜像。
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
2
3
# 4.9 networks
配置容器连接的网络。
因为Compose 不确定网络是否存在,所以需要最下面先进行声明才能使用网络,这样Compose 会先创建网络再去使用。
如果不配置,则默认使用当前docker-compose默认网络,默认网络名格式:项目名称_default。
version: "3"
services:
some-service:
networks:
- some-network
- other-network
# 声明网络
networks:
some-network:
other-network:
2
3
4
5
6
7
8
9
10
11
12
# 4.10 ports
配置容器暴露端口信息。
使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。
ports:
- "3000"
- "8000:8000" # 常用,推荐
- "127.0.0.1:8001:8001"
2
3
4
注意:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60
并且没放到引号里,可能会得到错误结果,因为 YAML 会自动解析 xx:yy 这种数字格式为 60
进制。为避免出现这种问题,建议数字串都采用引号""包括起来的字符串格式。
# 4.11 sysctls
配置容器内核参数。
一般不推荐自定义配置,除非你的容器对内核配置有独特的要求以及你自己对内核知识有深入了解,否则可能引起性能问题。
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
2
3
4
5
6
7
# 4.12 ulimits
指定容器的 ulimits 限制值。
例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
2
3
4
5
# 4.13 volumes
数据卷所挂载路径设置。可以设置为宿主机路径(HOST:CONTAINER)或者数据卷名称(VOLUME:CONTAINER),并且可以设置访问模式 (
HOST:CONTAINER:ro)。
该指令中路径支持相对路径。
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
2
3
4
如果路径为数据卷名称,必须在文件中先声明配置数据卷。
version: "3"
services:
my_src:
image: mysql:8.0
volumes:
- mysql_data:/var/lib/mysql
# 声明数据卷
volumes:
mysql_data:
2
3
4
5
6
7
8
9
10
11
# 4.14 restart
指定docker 容器(服务)会随着docker 引擎重启而重启,简而言之就是让docker 容器(服务)总是运行。
restart:always
# 5. docker-compose 常用命令
执行 docker-compose [COMMAND] --help 或者 docker-compose help [COMMAND] 可以查看具体某个命令的使用格式。
docker-compose 命令的基本的使用格式是
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
# 5.1 命令参数选项
-f, --file FILE指定使用的 Compose 模板文件,默认为docker-compose.yml,可以多次指定。-p, --project-name NAME指定项目名称,默认将使用所在目录名称作为项目名。--x-networking使用 Docker 的可拔插网络后端特性--x-network-driver DRIVER指定网络后端的驱动,默认为bridge--verbose输出更多调试信息。-v, --version打印版本并退出。
# 5.2 命令使用说明
# up
$ docker-compose up [options] [SERVICE...]
- 该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
- 链接的服务都将会被自动启动,除非已经处于运行状态。
- 可以说,大部分时候都可以直接通过该命令来启动一个项目。
- 默认情况,
docker-compose up启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。 - 当通过
Ctrl-C停止命令时,所有容器将会停止。 - 如果使用
docker-compose up -d,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。 - 默认情况,如果服务容器已经存在,
docker-compose up将会尝试停止容器,然后重新创建(保持使用volumes-from挂载的卷),以保证新启动的服务匹配docker-compose.yml文件的最新内容
# down
- 此命令将会停止
up命令所启动的容器,并移除网络
# exec
- 进入指定的容器。
# ps
列出项目中目前的所有容器。
$ docker-compose ps [options] [SERVICE...]
选项:
-q只打印容器的 ID 信息。
# restart
重启项目中的服务。
$ docker-compose restart [options] [SERVICE...]
选项:
-t, --timeout TIMEOUT指定重启前停止容器的超时(默认为 10 秒)。
# rm
删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop 命令来停止容器。
$ docker-compose rm [options] [SERVICE...]
选项:
-f, --force强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项。-v删除容器所挂载的数据卷。
# start
启动已经存在的服务容器。
$ docker-compose start [SERVICE...]
# stop
停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。
$ docker-compose stop [options] [SERVICE...]
选项:
-t, --timeout TIMEOUT停止容器时候的超时(默认为 10 秒)。
# top
查看各个服务容器内运行的进程。
# unpause
恢复处于暂停状态中的服务。
$ docker-compose unpause [SERVICE...]