Docker Compose 快速入门

本教程旨在通过指导您完成基本 Python Web 应用程序的开发来介绍 Docker Compose 的基本概念。

该应用程序使用Flask框架,在Redis中提供了命中计数器,为Docker Compose如何在Web开发场景中应用提供了实际示例。

即使您不熟悉 Python,这里演示的概念也应该是可以理解的。

这是一个非规范示例,仅突出显示您可以使用 Compose 执行的关键操作。

先决条件

确保您有:

  • 安装了最新版本的 Docker Compose
  • 对 Docker 概念以及 Docker 工作原理有基本了解

第 1 步:设置

  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 容器的主机名和默认端口。6379

    笔记

    get_hit_count请注意该函数的编写方式。如果 Redis 服务不可用,此基本重试循环会多次尝试请求。这在应用程序上线时启动时非常有用,而且如果 Redis 服务需要在应用程序的生命周期内随时重新启动,这也会使应用程序更具弹性。在集群中,这还有助于处理节点之间的瞬时连接丢失。

  3. requirements.txt在项目目录中创建另一个名为的文件,并将以下代码粘贴到:

    flask
    redis
  4. 创建一个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"]

    这告诉 Docker:

    • 从 Python 3.10 映像开始构建映像。
    • 将工作目录设置为/code.
    • 设置命令使用的环境变量flask
    • 安装gcc和其他依赖项
    • 复制requirements.txt并安装 Python 依赖项。
    • 向镜像添加元数据以描述容器正在侦听端口 5000
    • .将项目中的当前目录复制到.镜像中的workdir。
    • 将容器的默认命令设置为flask run --debug

    重要的

    检查是否Dockerfile没有像.txt.某些编辑器可能会自动附加此文件扩展名,这会在您运行应用程序时导致错误。

    有关如何编写 Dockerfile 的更多信息,请参阅Docker 用户指南Dockerfile 参考

步骤 2:在 Compose 文件中定义服务

Compose 简化了对整个应用程序堆栈的控制,使您可以在单个易于理解的 YAML 配置文件中轻松管理服务、网络和卷。

compose.yaml在项目目录中创建一个名为的文件并粘贴以下内容:

services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

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

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

redis服务使用 从 Docker Hub 注册表中提取的公共Redis映像。

有关该compose.yaml文件的更多信息,请参阅 Compose 的工作原理

第 3 步:使用 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:8000/以查看应用程序正在运行。

    如果这不能解决问题,您也可以尝试http://127.0.0.1:8000

    您应该在浏览器中看到一条消息:

    Hello World! I have been seen 1 times.
    浏览器中的你好世界
  3. 刷新页面。

    该数字应该增加。

    Hello World! I have been seen 2 times.
    浏览器中的你好世界
  4. 切换到另一个终端窗口,然后键入docker image ls以列出本地图像。

    此时列出图像应该返回redisweb

    $ docker image ls
    
    REPOSITORY        TAG           IMAGE ID      CREATED        SIZE
    composetest_web   latest        e2c21aa48cc1  4 minutes ago  93.8MB
    python            3.4-alpine    84e6077c7ab6  7 days ago     82.5MB
    redis             alpine        9d8fa9aa0e5b  3 weeks ago    27.5MB
    

    您可以使用 检查图像docker inspect <tag or id>

  5. 停止应用程序,可以通过docker compose down 在第二个终端的项目目录中运行,也可以通过点击CTRL+C启动应用程序的原始终端来停止。

步骤 4:编辑 Compose 文件以使用 Compose Watch

编辑compose.yaml要使用的项目目录中的文件watch,以便您可以预览正在运行的 Compose 服务,这些服务会在您编辑和保存代码时自动更新:

services:
  web:
    build: .
    ports:
      - "8000:5000"
    develop:
      watch:
        - action: sync
          path: .
          target: /code
  redis:
    image: "redis:alpine"

每当文件发生更改时,Compose 都会将文件同步到/code容器内的相应位置。复制后,捆绑程序将更新正在运行的应用程序,而无需重新启动。

有关 Compose Watch 工作原理的更多信息,请参阅 使用 Compose Watch。或者,请参阅 管理容器中的数据了解其他选项。

笔记

为了使该示例正常工作,该--debug选项被添加到Dockerfile. Flask 中的选项--debug可以自动重新加载代码,从而可以在后端 API 上工作,而无需重新启动或重建容器。更改.py文件后,后续 API 调用将使用新代码,但在这个小示例中浏览器 UI 不会自动刷新。大多数前端开发服务器都包含与 Compose 配合使用的本机实时重新加载支持。

第 5 步:使用 Compose 重新构建并运行应用程序

从项目目录中,键入docker compose watchdocker compose up --watch来构建并启动应用程序并启动文件监视模式。

$ docker compose watch
[+] Running 2/2
 ✔ Container docs-redis-1 Created                                                                                                                                                                                                        0.0s
 ✔ Container docs-web-1    Recreated                                                                                                                                                                                                      0.1s
Attaching to redis-1, web-1
         ⦿ watch enabled
...

再次检查Hello WorldWeb 浏览器中的消息,然后刷新以查看计数增量。

第 6 步:更新应用程序

要查看 Compose Watch 的运行情况:

  1. 更改问候语app.py并保存。例如,将Hello World! 消息更改为Hello from Docker!

    return 'Hello from Docker! I have been seen {} times.\n'.format(count)
  2. 在浏览器中刷新应用程序。问候语应该更新,并且计数器应该仍然递增。

    浏览器中的你好世界
  3. 完成后,运行docker compose down

第 7 步:拆分您的服务

使用多个 Compose 文件可以让您针对不同的环境或工作流程自定义 Compose 应用程序。这对于可能使用数十个容器且所有权分布在多个团队的大型应用程序非常有用。

  1. 在您的项目文件夹中,创建一个名为infra.yaml.

  2. 从文件中剪切 Redis 服务compose.yaml并将其粘贴到新infra.yaml文件中。确保services在文件顶部添加顶级属性。您的infra.yaml文件现在应如下所示:

    services:
      redis:
        image: "redis:alpine"
  3. 在您的compose.yaml文件中,添加include顶级属性以及文件路径infra.yaml

    include:
       - infra.yaml
    services:
      web:
        build: .
        ports:
          - "8000:5000"
        develop:
          watch:
            - action: sync
              path: .
              target: /code
  4. 运行docker compose up以使用更新的 Compose 文件构建应用程序,然后运行它。您应该Hello world在浏览器中看到该消息。

这是一个简化的示例,但它演示了基本原理include以及如何更轻松地将复杂应用程序模块化为子 Compose 文件。有关include多个 Compose 文件和使用多个 Compose 文件的更多信息,请参阅 使用多个 Compose 文件

第 8 步:尝试其他一些命令

  • 如果您想在后台运行服务,您可以将标志-d(用于“分离”模式)传递给docker compose up并使用docker compose ps来查看当前正在运行的内容:

    $ docker compose up -d
    
    Starting composetest_redis_1...
    Starting composetest_web_1...
    
    $ 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:8000->5000/tcp
    
  • 运行docker compose --help以查看其他可用命令。

  • 如果您使用 启动 Compose docker compose up -d,请在完成服务后停止它们:

    $ docker compose stop
    
  • 您可以使用该命令关闭所有内容,完全删除容器docker compose down

下一步go哪里