七、Docker Compose 入门实践


本文是《Docker必知必会系列》第七篇,原文发布于个人博客:悟尘纪

上一篇:Docker必知必会系列(六):基于多阶段构建减小镜像体积降低复杂度

一、Docker Compose 概述

1、Docker Compose 是什么

Compose 项目是 Docker 官方支持的开源项目,基于 Python 编写,用于定义和运行多容器Docker应用程序。Compose 使用 YAML 文件来配置应用程序的服务。然后,使用一个命令,就可以从配置中创建并启动所有服务。

使用 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。Compose 刚好可以满足这样的需求。

Compose 有着用于管理应用程序整个生命周期的各种命令:

  • 启动、停止和重建服务
  • 查看正在运行的服务的状态
  • 实时查看运行服务的日志输出
  • 仅执行一次命令即可运行整个服务

2、Compose 使用步骤

使用 Compose 基本上有三个步骤:

  1. 使用 Dockerfile 定义应用程序的环境,这样它就可以在任何地方复制。
  2. docker-compose. yml 定义组成应用程序的服务,使其可以在一个独立的环境中一起运行。
  3. 运行 docker-Compose up ,Compose 启动并运行您的整个应用程序。

3、典型 docker-compose 文件示例

使用 docker-compose 您主要的任务是编写 docker-compose.yml 文件。以下是一个 WordPress 的 yaml 文件模板:

version: '3'        # 定义版本,不指定默认为版本 1

services:           # 定义容器,就像 docker run
   db:              # 容器名称,也是 network 中 DNS 名称
     image: mysql:5.7   # 镜像,如果自定义镜像可以不指定这个参数,而用 build
     volumes:       # 定义数据卷,类似 -v
       - db_data:/var/lib/mysql
       - .:/lxl80   # 挂载当前目录到容器中的 /lxl80 目录
     restart: always  # 类似 --restart。'no' 默认,不自动重启;always 总是自动重启; on-failure 当失败时自动重启;unless-stopped 除非手动停止,否者一直重启
     environment:   # 定义环境变量,类似 -e
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:      # 第二个容器
     labels:       # 为容器添加 Docker 元数据(metadata)信息。
       cn.lixl.title: "This label will appear on all containers for the web service"
     depends_on:   # 定义容器之间的关系。启动 wordpress 时会先启动 db
       - db
     image: wordpress:latest
     ports:        # 端口,类似 -p
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress

volumes:          # 可选,需要创建的数据卷,类似 docker volume create
  db_data:

networks:         # 可选,需要创建的网络,类似 docker network create

二、Compose安装及卸载

1、安装 Compose

Docker Desktop for Mac/Windows 自带 docker-compose 二进制文件,安装 Docker 之后可以直接使用。

$ docker-compose --version
docker-compose version 1.24.1, build 4667896b

在 Linux 上的也安装十分简单,从 官方 GitHub Release 处直接下载编译好的二进制文件即可。

例如,在 Linux 64 位系统上直接下载对应的二进制包。

sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

2、卸载 Compose

如果基于 curl 安装,通过以下命令卸载Docker Compose :

sudo rm /usr/local/bin/docker-compose

如果基于 pip 安装,通过以下命令卸载Docker Compose :

pip uninstall docker-compose

三、Docker Compose 入门

关键术语

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

可见,一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。

示例应用介绍

接下来,将构建一个运行在 Docker Compose 上的简单 Python web 应用程序。 该应用程序使用了 Flask 框架,并在 Redis 维护了一个点击计数器。

首选,需要确保已经安装了 Docker 引擎和 Docker Compose。 不需要安装 Python 或 Redis,因为它们都是由 Docker 镜像提供的。

第一步:设置

定义应用程序的依赖关系:

1、为项目创建一个目录:

mkdir composetest
cd composetest

2、在项目目录中创建一个名为 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。

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

flask
redis

第二步:创建一个Dockerfile

在这个步骤中,将编写一个 Dockerfile 来构建一个 Docker 镜像。镜像包含 Python 应用程序所需的所有依赖项,包括 Python 本身。

在项目目录中,创建一个名为 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"]

这告诉 Docker:

  • 基于 Python 3.7 镜像构建
  • 将工作目录设置为 /code
  • 设置 flask 命令使用的环境变量
  • 安装 gcc,以便诸如 MarkupSafe 和 SQLAlchemy 之类的 Python 包可以加速编译
  • 复制 requirements.txt 并安装 Python 依赖项
  • 将主机上的项目目录(当前目录)复制到镜像中的 . 工作目录
  • 将容器的默认命令设置为 flask run

第三步:用 Compose 文件定义服务

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

version: '3'
services:
  web:
    build: .   # 相当于 docker build .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

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

web服务使用从当前目录中的 Dockerfile 构建的镜像。然后将容器和主机绑定到公开端口 5000。 此示例服务使用 Flask web 服务器的默认端口5000。

Redis 服务使用从 dockerhub 注册表中提取的公共 Redis 镜像。

第四步:用 Compose 构建和运行应用

1、在项目目录中,通过运行 docker-compose up 启动应用程序。

$ docker-compose up
Creating network "composetest_default" with the default driver
Creating composetest_web_1 ...
Creating composetest_redis_1 ...
Creating composetest_web_1
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
redis_1  | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
web_1    |  * Restarting with stat
redis_1  | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.
redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
web_1    |  * Debugger is active!
redis_1  | 1:M 17 Aug 22:11:10.483 # Server initialized
redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
web_1    |  * Debugger PIN: 330-787-903
redis_1  | 1:M 17 Aug 22:11:10.483 * Ready to accept connections

Compose 会拉取一个 Redis 镜像,为您的代码构建一个镜像,并启动您定义的服务。 在这种情况下,代码会在构建时静态复制到镜像中。

2、在浏览器中输入 http://localhost:5000/ ,查看该应用程序的运行情况。

您应该在浏览器中看到一条消息,内容为:

Hello World! I have been seen 1 times.

3、刷新页面,数字应该会递增。

Hello World! I have been seen 2 times.

4、切换到另一个终端窗口,键入 docker image ls 查看本地镜像。此时列出的镜像应返回 rediscomposetest_web

5、要停止应用程序,可以在另一个终端中进入项目目录运行 docker-compose stop,或者在启动应用程序的原始终端中按 ctrl + c。如果要停止并清除数据,以便再次启动后重新计数,可以执行 ``docker-compose down`。

第五步:编辑 Compose 文件添加挂载

在项目目录中编辑 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 配置,将主机上的项目目录(当前目录)安装到容器内部的 /code 目录,使您可以即时修改代码,而不必重建镜像。新增 environment 键设置了 FLASK_ENV 环境变量,指示 flask run 要在开发模式下运行并在更改时重新加载代码。此模式仅应在开发中使用。

第六步:重新构建并运行

从项目目录中,先输入 docker-compose stop 停止营业,然后输入 docker-Compose up 以构建带有更新的 Compose 文件的应用程序,并运行它。

$ docker-compose stop
Stopping composetest_web_1   ... done
Stopping composetest_redis_1 ... done
$ docker-compose up
Recreating composetest_web_1 ... done
Starting composetest_redis_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 17 Apr 2020 02:25:49.466 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
......
web_1    |  * Serving Flask app "app.py" (lazy loading)
web_1    |  * Environment: development
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 143-909-154

再次检查浏览器中的 Hello World 提示消息,并刷新以查看计数增量。

如果出现运行时错误指示找不到应用程序文件,拒绝卷安装或服务无法启动,请尝试启用文件或驱动器共享。有关更多信息,请参阅 Docker for Mac 上的 文件共享 章节。

第七步:更新应用程序

因为现在应用程序代码是使用卷安装到容器中的,所以可以对代码进行更改并立即生效,而无需重建镜像。

  1. 更改 app.py 中的提示语并保存。例如,将 Hello World! 更改为 Hello from Docker!

    return 'Hello from Docker! I have been seen {} times.\n'.format(count)
  2. 在浏览器中刷新应用。会发现提示语已更新,并且计数器仍在增加。

第八步:尝试其它命令

如果要让服务在后台运行,可以将 -d 参数(用于“分离”模式)传递给 docker-compose up ,并用 docker-compose ps 查看当前正在运行的内容:

$ docker-compose up  -d
Starting composetest_web_1   ... done
Starting composetest_redis_1 ... done
$ docker-compose ps
       Name                      Command               State           Ports
-------------------------------------------------------------------------------------
composetest_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
composetest_web_1     flask run                        Up      0.0.0.0:5000->5000/tcp

docker-compose run 命令允许为服务运行一次性命令。 例如,查看 web 服务可用的环境变量:

$ docker-compose run web env
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=4b3f1e39dc5d
......
FLASK_APP=app.py
FLASK_RUN_HOST=0.0.0.0
HOME=/root

请参阅 docker-compose --help 以查看其他可用命令。您还可以为 bash 和 zsh shell 安装 命令补全 功能,这将自动提示可用的命令。

相关文章


文章作者: 悟尘
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议,转载请注明来源 悟尘纪 !
评论
 上一篇
附录5、Kubectl 命令行界面 附录5、Kubectl 命令行界面
本文是《Docker必知必会系列》第十三篇,原文发布于个人博客:悟尘纪。 上一篇:Docker必知必会系列(附录4):Docker-compose 配置文件编写 一、概述Kubectl ...
2020-02-28
下一篇 
六、基于多阶段构建减小镜像体积降低复杂度 六、基于多阶段构建减小镜像体积降低复杂度
本文是《Docker必知必会系列》第六篇,原文发布于个人博客:悟尘纪。 上一篇:Docker必知必会系列(五):Docker 数据持久化存储与性能调优 一、引言如何减小...
2020-02-27
  目录