Docker Compose是Docker官方推出的一种容器编排服务,可以快速在集群中部署分布式应用。本文主要参考官方的快速入门示例来总结一下Docker Compose的简单使用。示例的场景是构建一个运行在Docker Compose上的简单Python Web应用程序。该应用程序使用Flask框架,在Redis中维护一个计数器,并将统计的结果返回。至于Docker Compose的安装,可以参考Docker Compose在Linux上的安装。

一、Docker Compose简介

Docker Compose是Docker官方开源项目,实现了对Docker容器集群的快速编排。Compose定位是定义和运行多个Docker容器的应用程序。通过Compose,可以使用YAML文件来配置应用服务。然后通过一个命令,就可以从配置中创建并启动所有服务。Compose可以应用于开发、测试、CI工作流和生产等所有环境。

Compose中有两个重要的概念:

  • 服务(service):一个应用的容器集合,一个服务可以横向扩展为多个容器实例。
  • 项目(project):由一组关联的应用容器组成的一个完整业务单元,一个YAML文件定义的就是一个项目。

Compose的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。而一个项目可以由多个服务关联而成。

Compose的使用基本分为三个步骤:

  1. 使用Dockerfile定义应用环境以便可以在任何地方再现它。
  2. docker-compose.yml中定义组成应用程序的服务,以便它们可以在隔离的环境中一起运行。
  3. 通过docker-compose up命令启动并运行整个应用程序。

二、环境信息

本文所使用的环境如下:

  • 操作系统:CentOS Linux release 8.1.1911
  • Docker:19.03.11
  • Docker Compose:1.26.0

三、创建Web应用

创建项目目录:

mkdir composetest
cd composetest

在项目目录中创建一个名为app.py的文件,内容如下:

import time

import redis
from flask import Flask

app = Flask(__name__)
# redis容器的主机名为redis,端口使用默认的6379端口
cache = redis.Redis(host='redis', port=6379)


# 如果redis服务不可用,此重试循环使我们可以多次尝试请求
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)

在项目目录中创建另一个名为requirements.txt的文件,内容如下:

flask
redis

四、创建Dockerfile

在项目目录中创建一个名为Dockerfile的文件,内容如下:

# 指定基础镜像为python:3.7-alpine
FROM python:3.7-alpine
# 指定工作目录为/code
WORKDIR /code
# 指定环境变量FLASK_APP的值为app.py
ENV FLASK_APP app.py
# 指定环境变量FLASK_RUN_HOST的值为0.0.0.0
ENV FLASK_RUN_HOST 0.0.0.0
# 安装gcc,以便诸如MarkupSafe和SQLAlchemy之类的Python包可以编译加速
RUN apk add --no-cache gcc musl-dev linux-headers
# 复制requirements.txt到容器文件系统的requirements.txt
COPY requirements.txt requirements.txt
# 安装Python依赖项
RUN pip install -r requirements.txt
# 将项目的当前目录复制到镜像工作目录
COPY . .
# 指定容器启动时的默认命令
CMD ["flask", "run"]

五、使用Compose文件定义服务

在项目目录中创建一个名为docker-compose.yml的文件,内容如下:

# 指定docker-compose的版本
version: '3'
# 定义项目里所有的服务信息
services:
  # 服务名
  web:
    # 指定Dockerfile文件的路径,这里指定的docker-compose.yml所在路径
    build: .
    # 指定端口映射,这里将宿主机的5000端口映射到容器的5000端口
    ports:
      - "5000:5000"
  redis:
    # 指定Docker镜像
    image: "redis:alpine"

该Compose文件定义了两个服务:webredis

  • web:该服务使用当前目录中的Dockerfile文件构建了镜像,将宿主机的5000端口映射到容器的5000端口。
  • redis:该服务容器使用Docker Hub拉取的官方镜像创建。

六、构建并运行应用

在项目目录中执行以下命令启动应用:

docker-compose up

如果出现下图错误:

docker compose flink 设置参数 docker compose links_compose基本操作


错误原因是docker-compose.yml文件中的缩进部分使用了Tab而非两个空格,改成两个空格即可。YAML格式要求得比较严格,所以要特别注意。然后再次启动。本地没有基础镜像会自动拉取:

docker compose flink 设置参数 docker compose links_compose基本操作_02


如果出现下图错误:

docker compose flink 设置参数 docker compose links_compose配置文件_03


先试一下是不是alpine官方源连接不上的问题,尝试换国内源,可以试试阿里云,在Dockerfile的安装gcc的指令之前添加以下指令:

RUN echo "https://mirrors.aliyun.com/alpine/v3.12/main/" >> /etc/apk/repositories
RUN echo "https://mirrors.aliyun.com/alpine/v3.12/community/" >> /etc/apk/repositories

如果还是出错,如下图:

docker compose flink 设置参数 docker compose links_docker_04


更换为国内源还是连接不上可能是容器内访问外部网络出现问题,执行以下命令创建容器并ping一下外网:

docker run -it python:3.7-alpine ping www.baidu.com
docker run -it python:3.7-alpine ping 114.114.114.114

果然ping不通百度,容器内访问外部网络出现问题:

docker compose flink 设置参数 docker compose links_compose基本操作_05


容器要想访问外部网络,需要本地系统的转发支持。所以解决办法是打开IP转发。首先打开/etc/sysctl.conf文件(或者/usr/lib/sysctl.d/00-system.conf文件,这个文件没试过):

vim /etc/sysctl.conf

添加以下内容:

net.ipv4.ip_forward=1

重启network服务,CentOS8使用以下命令(CentOS7使用systemctl restart network):

nmcli c reload

查看是否修改成功:

sysctl net.ipv4.ip_forward

如果返回“net.ipv4.ip_forward = 1”则表示成功了。然后重启Docker:

systemctl restart docker

再次ping百度发现能ping通:

docker compose flink 设置参数 docker compose links_compose入门_06


如果还不行可以重启主机系统再试。再次启动:

docker compose flink 设置参数 docker compose links_docker_07


docker compose flink 设置参数 docker compose links_compose配置文件_08


docker compose flink 设置参数 docker compose links_docker_09


从启动日志可知Docker Compose完成了镜像的构建和容器的创建运行。切换到另一个终端,输入docker image ls查看本地镜像:

docker compose flink 设置参数 docker compose links_compose入门_10


输入docker ps查看运行中的容器:

docker compose flink 设置参数 docker compose links_docker-compose_11


访问http://MACHINE_VM_IP:5000,其中MACHINE_VM_IP为Docker主机ip,然后不断刷新,结果如下:

docker compose flink 设置参数 docker compose links_compose基本操作_12


每刷新一次页面,计数就增加了1,说明Docker Compose运行应用成功。在原始终端中按CTRL + C来停止应用,或在另一个终端进入项目目录执行以下命令停止应用:

docker-compose down

docker compose flink 设置参数 docker compose links_docker-compose_13

七、修改Compose文件以添加目录挂载

修改docker-compose.yml文件,内容如下:

# 指定docker-compose的版本
version: '3'
# 定义项目里所有的服务信息
services:
  # 服务名
  web:
    # 指定Dockerfile文件的路径,这里指定的docker-compose.yml所在路径
    build: .
    # 指定端口映射,这里将宿主机的5000端口映射到容器的5000端口
    ports:
      - "5000:5000"
    # 将宿主机项目目录(当前目录)下的/code目录挂载到容器,这样修改代码后不必重新构建镜像
    volumes:
      - .:/code
    # 设置FLASK_ENV环境变量,该变量指示flask run在开发模式下运行并在更改时重新加载代码,该模式仅应在开发中使用
    environment:
      FLASK_ENV: development
  redis:
    # 指定Docker镜像
    image: "redis:alpine"

然后使用更新的Compose文件构建应用并运行:

docker compose flink 设置参数 docker compose links_compose配置文件_14


在浏览器中访问应用,刷新计数正常增加。然后修改app.py文件中的输出内容,修改如下:

return 'Hello Docker Compose! I have been seen {} times.\n'.format(count)

然后在浏览器中刷新访问页面,发现返回的内容已变更,并且计数仍在增加,如下图:

docker compose flink 设置参数 docker compose links_compose配置文件_15

八、Docker Compose基本操作

查看Docker Compose基本命令和用法:

docker-compose --help

查看结果如下:

docker compose flink 设置参数 docker compose links_compose入门_16


docker compose flink 设置参数 docker compose links_compose配置文件_17


查看Docker Compose版本信息:

docker-compose version

创建并运行服务:

# 交互式启动
docker-compose up
# 后台启动
docker-compose up -d
# 指定Compose配置文件启动,默认为docker-compose.yml
docker-compose up -f mycompose.yaml

查看项目中目前的所有容器:

docker-compose ps

查看结果如下:

docker compose flink 设置参数 docker compose links_docker_18


列出Compose文件中包含的镜像:

docker-compose images

查看结果如下:

docker compose flink 设置参数 docker compose links_compose配置文件_19


停止运行中的服务容器,这里停止web服务:

docker-compose stop web

docker compose flink 设置参数 docker compose links_docker_20


启动已存在的服务容器,这里启动web服务:

docker-compose start web

docker compose flink 设置参数 docker compose links_compose配置文件_21


重启项目中的服务容器,这里重启web服务:

docker-compose restart web

docker compose flink 设置参数 docker compose links_compose配置文件_22


暂停服务容器,这里暂停web服务:

docker-compose pause web

docker compose flink 设置参数 docker compose links_docker_23


恢复处于暂停状态的服务,恢复暂停的web服务:

docker-compose unpause web

docker compose flink 设置参数 docker compose links_compose基本操作_24


进入指定服务容器,这里进入web服务容器并ping百度:

docker-compose exec web ping www.baidu.com

docker compose flink 设置参数 docker compose links_docker-compose_25


查看服务容器的输出日志,这里查看的web服务:

docker-compose logs web

查看结果如下:

docker compose flink 设置参数 docker compose links_compose配置文件_26


查看某个服务容器端口所映射的公共端口,这里指定web服务容器:

docker-compose port web 5000

查看结果如下:

docker compose flink 设置参数 docker compose links_compose配置文件_27


查看各个服务容器内运行的进程:

docker-compose top

查看结果如下:

docker compose flink 设置参数 docker compose links_docker_28


在指定服务上执行一个命令,这里在web服务查看环境变量:

docker-compose run web env

查看结果如下:

docker compose flink 设置参数 docker compose links_docker-compose_29


通过发送SIGKILL信号来强制停止服务容器,这里发送SIGINT信号来强制停止服务容器:

docker-compose kill -s SIGINT

docker compose flink 设置参数 docker compose links_compose基本操作_30


验证Compose配置文件格式是否正确,正确会输出文件内容,错误则显示原因:

docker-compose config

验证结果如下:

docker compose flink 设置参数 docker compose links_compose配置文件_31


删除所有停止状态的服务容器:

docker-compose rm

docker compose flink 设置参数 docker compose links_compose入门_32


构建或重新构建项目中的容器:

docker-compose build

docker compose flink 设置参数 docker compose links_compose基本操作_33


删除所有服务容器,同时删除网络和挂载目录的数据:

docker-compose down --volumes

docker compose flink 设置参数 docker compose links_compose基本操作_34


置指定服务运行的容器个数,例如:

docker-compose scale web=2 worker=3

不推荐使用该命令,更推荐使用up命令的--scale选项来指定服务运行的容器个数。

拉取服务依赖的镜像,该服务依赖的镜像需要在Compose配置文件中指定,例如:

docker-compose pull db

该命令需在Compose配置文件目录中执行,Compose配置文件中指定db服务依赖镜像,例如:

services:
  db:
    image: postgres

推送服务依赖的镜像到镜像仓库,例如:

docker-compose push localhost:5000/yourimage
docker-compose push youruser/yourimage

Compose配置文件中指定服务依赖镜像,例如:

services:
  service1:
    build: .
    image: localhost:5000/yourimage  # 推送至本地仓库

  service2:
    build: .
    image: youruser/yourimage  # 推送至你的DockerHub仓库