# Docker Compose-容器单机编排
在实际生产或者项目中使用 Docker
容器时,往往不是一个容器就能满足需求的。
比如对于一个常规的 Web 应用而言,前后端,数据库均需要独立的容器,这个时候便非常需要进行容器的 “编排”
了。
Docker
为我们提供了一个工具 docker-compose,可用于 单个机器上的 Docker 容器编排
。
它允许⽤户通过⼀个单独的 docker-compose.yml
模板⽂件(YAML 格式)来定义⼀组相关联的应⽤容器为⼀个项⽬(project)。
# Docker Compose
- Docker Compose 是用于定义和运行多容器Docker应用程序的工具
- Docker Compose 可以通过一个
docker-compose.yml
文件定义多容器的 Docker 应用 - 通过一条命令就可以根据
docker-compose.yml
文件的定义去创建和管理这多个容器
Compose 中有三个重要的概念:
- Services(服务)
- Networks(网络)
- Volumes(数据卷)
# Services(服务)
一个 Service
代表⼀个应⽤的容器。可以通过 docker hub
的镜像或本地 dockerfile
构建的镜像进行创建。
Service
的启动类似于 docker run
运行一个容器。运行容器时,可以给其指定 network
和 volume
。所以我们可以给 Service
指定 network
和 volume
的引用。
# Networks(网络)
定义整个应用中的 networks
,被 services
中的服务引用。
# Volumes(数据卷)
定义整个应用中的 volumes
,被 services
中的服务引用。
# 案例说明
version: '3' # 定义compose版本
services:
wordpress:
image: wordpress # 指定镜像
ports:
- 8080:80 # 端口映射
depends_on: # 表达服务之间的依赖性
- mysql
environment: # 指定环境变量
WORDPRESS_DB_HOST: mysql #连接数据库的地址,必须要用依赖的服务的名字
WORDPRESS_DB_PASSWORD: root # 自定义的连接数据库的密码,需要和下面的mysql设置的要一致
networks:
- my-bridge # 引用 networks 中定义的 bridge 网络
mysql:
image: mysql:5.7 # 指定镜像
environment: # 指定环境变量
MYSQL_ROOT_PASSWORD: root # 指定数据库登录密码
MYSQL_DATABASE: wordpress # 指定数据库名
volumes:
- mysql-data:/var/lib/mysql # 绑定数据卷实现数据共享与持久化
networks:
- my-bridge # 引用 networks 中定义的 bridge 网络
volumes:
mysql-data: # 创建⼀个数据卷
networks:
my-bridge:
driver: bridge # 创建一个名称为 my-bridge,类型为 bridge 的网络
每个 docker-compose.yml
都需要包含一个 version
的配置,这个 version
表示 docker-compose
配置文件格式的版本,不同的版本会影响到与 Docker
版本的兼容性。
# 安装
Compose
⽀持 Linux
、macOS
、Windows 10
三⼤平台。Compose
可以通过 Python
的包管理⼯具 pip
进⾏安装,也可以直接下载编译好的⼆进制⽂件使⽤,甚⾄能够直接在 Docker 容器中运⾏。
前两种⽅式是传统⽅式,适合本地环境下安装使⽤;最后⼀种⽅式则 不破坏系统环境
,更适合 云计算场景
。
Docker for Mac
、Docker for Windows
⾃带 docker-compose
⼆进制⽂件,安装 Docker
之后可以直接使⽤。
# 二进制安装
在Linux上,您可以从官方 GitHub Release 处直接下载编译好的⼆进制⽂件即可。
运行以下命令以下载 Docker Compose
的当前稳定版本:
sudo curl -L https://github.com/docker/compose/releases/download/1.26.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
将 可执行权限
应用于二进制文件:
$ sudo chmod +x /usr/local/bin/docker-compose
# PIP 安装
注: x86_64 架构的 Linux 建议按照上边的⽅法下载⼆进制包进⾏安装,如果您计算机的架构是ARM (例如,树莓派),再使⽤ pip 安装。
Docker Compose
是一个由 Python
编写的软件,在拥有 Python
运行环境的机器上,我们可以直接运行它,不需要其它的操作。
我们也能够通过 Python
的包管理工具 pip
来安装 Docker Compose
。
$ sudo pip install docker-compose
# 容器中执⾏
sudo curl -L --fail https://github.com/docker/compose/releases/download/1.26.2/run.sh -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 安装补全工具
为了方便我们输入命令,也可以安装 Docker 的补全提示工具帮忙我们快速输入命令
# 卸载
如果是二进制包方式安装的,删除二进制⽂件即可。
$ sudo rm /usr/local/bin/docker-compose
如果是通过 pip 安装的,则执⾏如下命令即可删除。
$ sudo pip uninstall docker-compose
如果是在容器中安装,直接删除容器即可。
# 快速上手
使用 Compose
基本上包括三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
下面我们用 Python 来建⽴⼀个能够记录页面访问次数的 web ⽹站。 新建⽂件夹,在该⽬录中编写 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 'Hello World! I have been seen {} times.\n'.format(count)
接着编写 Dockerfile
⽂件,内容为:
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
然后是编写 docker-compose.yml
⽂件。
version: '3'
services:
web:
build: . # 使用从当前目录中的Dockerfile构建的镜像
ports:
- "5000:5000" # 端口映射
volumes:
- .:/code # 将当前目录挂载到容器的/code目录,从而使您可以即时修改代码,而不必重建镜像
redis:
image: "redis:alpine"
运行 compose 项⽬:
$ docker-compose up
此时访问本地 5000 端⼝,每次刷新页面,计数就会加 1。
# docker-compose.yml 模板文件常用配置选项
# version
指定本 yml 依从的 compose 哪个版本制定的。
# build
在构建时应用的配置选项,Compose 会利用它自动构建镜像,然后启动服务容器。该值可以是一个路径,
version: "3.7"
services:
webapp:
build: ./dir
或者,也可以是一个对象,用于指定 Dockerfile 参数:
version: "3.7"
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
labels:
- "com.example.description=Accounting webapp"
- "com.example.department=Finance"
- "com.example.label-with-empty-value"
target: prod
- context:上下文路径。
- dockerfile:指定构建镜像的 Dockerfile 文件名。
- args:添加构建参数,这是只能在构建过程中访问的环境变量。
- labels:设置构建镜像的标签。
- target:定义构建指定的阶段。有关详细信息,请参见多阶段构建文档。
# command
覆盖容器启动后默认执行的命令。
# 方式1
command: bundle exec thin -p 3000
# 方式2
command: [bundle, exec, thin, -p, 3000]
# container_name
自定义容器名称,而不是使用默认生成的名称。
container_name: my-web-container
# depends_on
在使用Compose时,最大的好处就是减少少打启动命令,但一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动应用容器,应用容器会因为找不到数据库而退出。
depends_on
标签用于解决容器的依赖、启动先后的问题。
- docker-compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。
- docker-compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中,docker-compose up web 还将创建并启动 db 和 redis。
- docker-compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止。
version: "3.8"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
注意:web 服务不会等待 redis db 完全启动 之后才启动。
在以docker stack deploy方式,基于 version 3
版本部署时,将忽略depends_on选项。
# env_file
从文件中添加环境变量。
env_file: .env
也可以是列表格式:
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
# environment
添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。
在 environment
部分中声明的环境变量将覆盖 env_file
中申明的这些值。
environment:
RACK_ENV: development
SHOW: 'true'
# expose
公开端口,但是不将其映射到宿主机。只允许能被连接的服务访问。只能指定内部端口。
expose:
- "3000"
- "8000"
# extra_hosts
添加主机名映射。类似 docker client --add-host
。
extra_hosts:
- "somehost:162.242.195.82"
- "otherhost:50.31.209.229"
以上会在此服务的内部容器中 /etc/hosts
创建一个具有 ip 地址和主机名的映射关系:
162.242.195.82 somehost
50.31.209.229 otherhost
# healthcheck
对 docker 服务是否健康运行进行检测。
有关运行状况检查如何工作的详细信息,请参阅HEALTHCHECK Dockerfile instruction。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
interval: 1m30s # 设置检测间隔
timeout: 10s # 设置检测超时时间
retries: 3 # 设置重试次数
start_period: 40s # 启动后,多少秒开始启动检测程序
# image
指定容器运行的镜像。以下格式都可以:
image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd # 镜像id
# logging
对服务的日志记录进行配置。
driver:指定服务容器的日志记录驱动程序,默认值为 json-file
。有以下三个选项
- driver: "json-file"
- driver: "syslog"
- driver: "none"
默认驱动程序 json-file
具有限制存储日志量的选项,可以使用以下参数,限制日志的数量和大小。
logging:
driver: json-file
options:
max-size: "200k" # 单个文件大小为200k
max-file: "10" # 最多10个文件
当达到文件限制上限,会自动删除旧的文件。
驱动程序为 syslog
时,可以使用 syslog-address
指定日志接收地址。
logging: driver: syslog options: syslog-address: "tcp://192.168.0.42:123"
# network_mode
设置网络模式。
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
# networks
配置容器连接的网络,引用 services
同级目录 networks
下的条目 。
ervices:
some-service:
networks:
some-network:
aliases:
- alias1
other-network:
aliases:
- alias2
networks:
some-network:
# 使用自定义驱动程序
driver: custom-driver-1
other-network:
# 使用需要特殊选项的自定义驱动程序
driver: custom-driver-2
aliases :同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务。
# restart
- no:是默认的重启策略,在任何情况下都不会重启容器。
- always:容器总是重新启动。
- on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
- unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
注:swarm 集群模式,请改用 restart_policy。
# secrets
存储敏感数据,例如密码:
version: "3.1"
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
secrets:
- my_secret
secrets:
my_secret:
file: ./my_secret.txt
# volumes
将主机的 数据卷
或 主机⽬录
挂载到容器里。
实现 数据共享
与 持久化
。
version: "3.7"
services:
db:
image: postgres:latest
volumes:
- "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
- "/localhost/data:/var/lib/postgresql/data"
# Compose 常用命令
docker-compose
命令的基本的使⽤格式是:
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
命令选项:
-f, --file FILE
指定使⽤的 Compose 模板⽂件,默认为 docker-compose.yml,可以多次指定。
-p, --project-name NAME
指定项⽬名称,默认将使⽤所在⽬录名称作为项⽬名。--x-networking
使⽤ Docker 的可拔插⽹络后端特性--x-network-driver DRIVER
指定⽹络后端的驱动,默认为 bridge--verbose
输出更多调试信息。-v, --version
打印版本并退出。
# 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 停⽌容器时候的超时(默认为 10 秒)。
# start
格式为 docker-compose start [SERVICE...]
,启动已经存在的服务容器。
# stop
格式为 docker-compose stop [options] [SERVICE...]
,停⽌已经处于运⾏状态的容器,但不删除它。
通过 docker-compose start
可以再次启动这些容器。
# down
此命令将会停⽌ up 命令所启动的容器,并移除⽹络
# build
build 格式为 docker-compose build [options] [SERVICE...]
。
构建(重新构建)项⽬中的服务容器。服务容器⼀旦构建后,将会带上⼀个标记名,例如对于 web 项⽬中的⼀个 db 容器,可能是 web_db。
可以随时在项⽬⽬录下运⾏ docker-compose build
来重新构建服务。选项包括:
- --force-rm 删除构建过程中的临时容器。
- --no-cache 构建镜像过程中不使⽤ cache(这将加⻓构建过程)。
- --pull 始终尝试通过 pull 来获取更新版本的镜像。
# config
验证 Compose ⽂件格式是否正确,若正确则显示配置,若格式错误显示错误原因。
# exec
进⼊指定的容器。
# help
获得⼀个命令的帮助。
# images
列出 Compose ⽂件中包含的镜像。
# kill
格式为 docker-compose kill [options] [SERVICE...]
。
通过发送 SIGKILL
信号来 强制停⽌服务容器
。⽀持通过 -s
参数来指定发送的信号,例如通过如下指令发送 SIGINT
信号。
$ docker-compose kill -s SIGINT
# logs
格式为 docker-compose logs [options] [SERVICE...]
,查看服务容器的输出。默认情况下,docker-compose
将对不同的服务输出使⽤不同的颜⾊来区分。
可以通过 --no-color
来关闭颜⾊。该命令在调试问题的时候⼗分有⽤。
# pause
格式为 docker-compose pause [SERVICE...]
,暂停⼀个服务容器。
# port
格式为 docker-compose port [options] SERVICE PRIVATE_PORT
,打印某个容器端⼝所映射的公共端⼝。选项:
- --protocol=proto 指定端⼝协议,tcp(默认值)或者 udp。
- --index=index 如果同⼀服务存在多个容器,指定命令对象容器的序号(默认为 1)。
# ps
格式为 docker-compose ps [options] [SERVICE...]
,列出项⽬中⽬前的所有容器。选项:
- -q 只打印容器的 ID 信息。
# pull
格式为 docker-compose pull [options] [SERVICE...]
,拉取服务依赖的镜像。选项:
- --ignore-pull-failures 忽略拉取镜像过程中的错误。 push:推送服务依赖的镜像到 Docker 镜像仓库。
# push
推送服务依赖的镜像到 Docker 镜像仓库。
# restart
格式为 docker-compose restart [options] [SERVICE...]
,重启项⽬中的服务。选项:
- -t, --timeout TIMEOUT 指定重启前停⽌容器的超时(默认为 10 秒)。
# rm
格式为 docker-compose rm [options] [SERVICE...]
,删除所有(停⽌状态的)服务容器。
推荐先执行 docker-compose stop
命令来停⽌容器。
选项:
- -f, --force 强制直接删除,包括⾮停⽌状态的容器。⼀般尽量不要使⽤该选项。
- -v 删除容器所挂载的数据卷。
# 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 的指令将⽆法运⾏。
# scale
格式为 docker-compose scale [options] [SERVICE=NUM...]
,设置指定服务运⾏的容器个数。用于实现 水平扩展
。通过 service=num
的参数来设置数量。例如:
$ docker-compose scale web=3 db=2
将启动 3 个容器运⾏ web 服务,2 个容器运⾏ db 服务。
⼀般情况下,当指定数⽬多于该服务当前实际运⾏容器,将新创建并启动容器;反之,将停⽌容器。选项:
- -t, --timeout TIMEOUT 停⽌容器时候的超时(默认为 10 秒)。
选项:
- -t, --timeout TIMEOUT 停⽌容器时候的超时(默认为 10 秒)。
# top
查看各个服务容器内运⾏的进程。
# unpause
格式为 docker-compose unpause [SERVICE...]
,恢复处于暂停状态中的服务。