Docker compose (以下简称为 compose)可用于定义和运行多容器 docker 应用程序。
通过 compose,我们可以使用 YAML 文件来配置应用程序的服务(services),然后只需要通过一个命令,就可以将配置的所有服务启动起来。
使用 compose 只需要三步:
Dockerfile
定义应用的环境,以便于可以任何地方复制应用的环境docker-compose.yml
定义构成应用的服务,以便于它们可以在隔离的环境中一起运行docker-compose up
命令,这时 compose 会启动并运行整个应用程序对于 Mac 系统 和 Windows 系统,安装 docker 桌面端时, compose 已经捆绑安装了。对于 Linux 系统安装 compose 也不麻烦,可以参考官方安装文档 https://docs.docker.com/compose/install/。
可以通过以下命令来测试 compose 安装是否成功:
docker-compose --version
输出:
docker-compose version 1.24.1, build 4667896b
我们以一个 Flask 应用程序为例,说明如何使用 compose 来配置相关的服务。
composetest
mkdir composetest
cd composetest
创建 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)
上述的代码中,redis
是 redis 容器的主机名称,且 redis 的监听端口为 6379
。对于 compose 来说,可以使用容器名称来作为主机名称来访问其他容器,具体可以参考 compose 网络。
注意,如果使用 compose 运行 app.py
,则 redis 的主机地址不能使用 127.0.0.1
,否则会出现无法连接 redis 的报错。
创建 requirements.txt
文件,里面包含应用程序依赖的 python 包。
flask
redis
接下来,我们编写 Dockerfile 文件来构建 docker 镜像。这个镜像包含了 flask 应用程序的依赖环境。
在 composetest
目录创建 Dockerfile
文件:
FROM python:3.7-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
COPY . .
CMD ["flask", "run"]
这个 Dockerfile 文件作用包括:
python:3.7-alpine
/code
requirements.txt
文件到工作目录,以便于安装有关 python 依赖/code
有关 Dockerfile 的使用,请参考官方文档 Dockerfile 官方文档。
接下来,我们编写 docker-compose.yml
。在 composetest
目录创建 docker-compose.yml
文件:
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
在 docker-compose.yml
文件定义了两个服务:web
和 redis
。
web
服务的镜像由 Dockerfile
来指定构建。另外,我们还指定的宿主机和容器间端口的映射关系 5000:5000redis
服务的镜像从 docker 镜像仓库拉取注意每个服务都必须通过 image
指定镜像或 build
指令(需要 Dockerfile)来自动构建生成镜像。
最后,composetest
目录内的文件如下图所示:
进入 composetest
目录,执行命令:
docker-compose up
接下来,compose 会构建 web
镜像,拉取 redis
镜像,并启动服务。
启动完毕,打开浏览器,输入地址 http://localhost:5000/
,会看到以下输出:
Hello World! I have been seen 1 times.
刷新一下页面,会看到数据不断地增加 1。
使用命令 docker images
可以观察到当前的镜像,使用命令 docker ps -a
可以观察当前正在运行的容器,有需要的话,还可以使用命令 docker exec -it xxx /bin/sh
进入容器。
为了关闭并删除 compose 启动的容器,可以执行命令:
docker-compose down
修改 docker-compose.yml
文件,往 web
服务添加 bind mount:
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
通过 volumes
关键字我们将当前目录 composetest
挂载到容器内的 /code
目录,这样一来,我们就可以随时修改应用程序的源代码,而不需要重新构建镜像。
同时,我们增加了新的环境变量 FLASK_ENV
(值为 development
),这使得可以修改 flask 应用的代码随即生效,而不需要对 flask 应用进行重启。
有关 bind mount 的使用,可以参考文章 《Docker 数据持久化》。
重新执行命令 docker-compose up
,启动应用程序。打开浏览器,输入地址,看到输出
Hello World! I have been seen 1 times.
这时,修改本地 composetest
目录的 app.py
源代码,调整问候语,然后保存。
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello from Docker! I have been seen {} times.\n'.format(count)
再刷新浏览器,可以看到输出的问候语已更新,说明由于 bind mount 的使用,通过修改本地源代码而不需要重新构建镜像,应用程序就已经得到了更新。
Hello from Docker! I have been seen 2 times.