1 个稳定版本

1.0.0 2023年10月2日

#1401命令行工具

MIT 许可证

63KB
1.5K SLoC

Wheelsticks:Docker Compose 的零停机部署

Wheelsticks 是 Docker Compose 的一个扩展,有助于实现服务的零停机更新。

动机

Docker Compose 提供了简单的声明式编排容器化应用程序。

当使用 docker compose up 更新 Docker Compose 中的服务容器时,旧容器会在新容器启动之前被停止(stop-first 情况)

    Old container          Stop
┄┄┄┄───────────────────────┤
                                           Start       New container
                                           ├────────────────────────┄┄┄┄

这会导致服务中断,因为在某个时刻两个容器都不可用。

想象一下,如果我们能使得容器的生命周期重叠(start-first 情况)

    Old container                          Stop
┄┄┄┄───────────────────────────────────────┤
                           Start                       New container
                           ├────────────────────────────────────────┄┄┄┄

如果反向代理无缝地将流量从旧容器切换到新容器,那么就可以实现零停机部署。

实际上,Compose 规范定义了区分这两种情况的可选选项:stop-first(默认)和start-first。但是,对这个规范部分的支持是可选的,普通的 Docker Compose 总是应用stop-first,而不考虑您的 Compose 文件中有什么。

然而,Wheelsticks 支持这两种选项。只需将 wheelsticks deploy 替换为 docker compose up。无需更改任何其他 Docker 或 Docker Compose 工作流程。

安装

先决条件

  • Docker 或 Podman
  • Docker Compose

安装

请参阅 发行版 以获取预编译的可执行文件。

或者,使用 cargo install wheelsticks 从源代码构建。

Docker CLI 插件

可选地,可以将 Wheelsticks 配置为 Docker CLI 插件。这样,可以使用 docker deploy 代替 wheelsticks deploy,这可能是某些人的首选。示例 设置

mkdir --parents ~/.docker/cli-plugins
ln --symbolic "$(which wheelsticks)" ~/.docker/cli-plugins/docker-deploy

使用

快速入门

对于在更新期间容器生命周期应重叠的服务,按照以下方式配置它们的更新顺序

# compose.yaml
services:
  greet:
    deploy:
      update_config:
        order: start-first # Most important line.
    #

请参考example/compose.yaml以查看示例。它定义了一个名为greet的服务,通过reverse-proxy在localhost:8080上提供。

    localhost:8080    ╭───────────────╮        ╭───────────────╮
──────────────────────┤ reverse-proxy ├────────┤ greet         │
                  :80(stop-first):80(start-first) │
                      ╰───────────────╯        ╰───────────────╯

这种设计使得服务即使在更新期间也保持可用。您可以按照以下方式操作:

cd example
wheelsticks deploy --wait
curl localhost:8080 # … prints "Hi from A"

export GREET_VERSION=B
wheelsticks deploy --wait
curl localhost:8080 # … prints "Hi from B"

docker compose down

要查看上述部署的实际效果,请使用独立的shell会话运行以下命令:

while true; do curl --fail --max-time 0.2 localhost:8080; sleep 0.01s; done

服务更新的条件

默认情况下,只有当服务的服务配置哈希更改时,才会更新服务。此哈希是对Compose文件中除builddeploy.replicaspull_policyscale之外的所有服务字段进行计算的(请参阅源代码)。

请注意,服务配置哈希依赖于容器镜像内容,而只是依赖于image字段。因此,重新使用像latest这样的标签不会导致更新。

使用--force-recreate始终更新服务,无论配置哈希是否更改。

命令 效果
wheelsticks deploy 更新所有配置哈希更改的服务
wheelsticks deploy--dry-运行 不进行任何更新,但显示将发生哪些更改
wheelsticks deploy x 如果服务的配置哈希更改,则更新服务x
wheelsticks deploy--force-recreate 始终更新所有服务
wheelsticks deploy--force-recreate x 始终更新服务x
docker compose config--hash'*' 显示Compose文件的服务的配置哈希

服务更新过程

服务按字母顺序(更精确地说,按Unicode代码点字典顺序)更新。

对于每个服务,容器先停止后启动(stop-first,默认),或者先启动后停止,然后对副本重复此操作。以下是对具有3个副本的服务的过程的视觉表示。

stop-first情况

               1. Stop old
┄┄┄┄───────────┤

                       2. Start new
                       ├────────────────────────────────────────────┄┄┄┄

                               3. Stop old
┄┄┄┄───────────────────────────┤

                                       4. Start new
                                       ├────────────────────────────┄┄┄┄

                                               5. Stop old
┄┄┄┄───────────────────────────────────────────┤

                                                       6. Start new
                                                       ├────────────┄┄┄┄

start-first情况

               1. Start new
               ├────────────────────────────────────────────────────┄┄┄┄

                       2. Stop old
┄┄┄┄───────────────────┤

                               3. Start new
                               ├────────────────────────────────────┄┄┄┄

                                       4. Stop old
┄┄┄┄───────────────────────────────────┤

                                               5. Start new
                                               ├────────────────────┄┄┄┄

                                                       6. Stop old
┄┄┄┄───────────────────────────────────────────────────┤

Podman支持

通过传递--container-engine podman来使用Podman而不是Docker。

由于目前缺少一些必需的功能,如服务配置哈希的计算(docker compose config --hash '*'),因此不支持Podman Compose。

替代方案

适用于单节点环境的其他轻量级选项

命令行参数参考

wheelsticks-h

Zero-downtime deployments for Docker Compose

Usage: wheelsticks [OPTIONS] <COMMAND>

Commands:
  deploy  Create or update services
  help    Print this message or the help of the given subcommand(s)

Options:
      --config <CONFIG>        Location of client config files
  -c, --context <CONTEXT>      Name of the context to use to connect to the
                               daemon (overrides DOCKER_HOST env var and default
                               context set with "docker context use")
  -D, --debug                  Enable debug mode [aliases: verbose]
  -H, --host <HOST>            Daemon socket to connect to
  -l, --log-level <LOG_LEVEL>  Set the logging level [possible values: debug,
                               info, warn, error, fatal]
      --tls                    Use TLS; implied by --tlsverify
      --tlscacert <TLSCACERT>  Trust certs signed only by this CA
      --tlscert <TLSCERT>      Path to TLS certificate file
      --tlskey <TLSKEY>        Path to TLS key file
      --tlsverify              Use TLS and verify the remote
  -h, --help                   Print help
  -V, --version                Print version

wheelsticks deploy-h

Create or update services

Usage: wheelsticks deploy [OPTIONS] [SERVICE_NAMES]...

Arguments:
  [SERVICE_NAMES]...

Options:
      --ansi <ANSI>
          Control when to print ANSI control characters [possible values: never,
          always, auto]
      --compatibility
          Run compose in backward compatibility mode
      --dry-run
          Execute command in dry run mode
      --env-file <ENV_FILE>
          Specify an alternate environment file
  -f, --file <FILE>
          Compose configuration files
      --parallel <PARALLEL>
          Control max parallelism, -1 for unlimited
      --profile <PROFILE>
          Specify a profile to enable
      --progress <PROGRESS>
          Set type of progress output [possible values: auto, tty, plain, quiet]
      --project-directory <PROJECT_DIRECTORY>
          Specify an alternate working directory (default: the path of the,
          first specified, Compose file)
  -p, --project-name <PROJECT_NAME>
          Project name
      --build
          Build images before starting containers
  -d, --detach
          This has no effect as detached mode is always on; for migration only
      --force-recreate
          Recreate containers even if their configuration hasn't changed
      --no-build
          Don't build an image, even if it's missing
      --no-start
          Don't start the services after creating them
      --pull <PULL>
          Pull image before running [possible values: always, missing, never]
      --quiet-pull
          Pull without printing progress information
      --remove-orphans
          Remove containers for services not defined in the Compose file
  -V, --renew-anon-volumes
          Recreate anonymous volumes instead of retrieving data from the
          previous containers
  -t, --timeout <TIMEOUT>
          Use this timeout in seconds for container shutdown when containers are
          already running
      --wait
          Wait for services to be running|healthy
      --wait-timeout <WAIT_TIMEOUT>
          timeout in seconds waiting for application to be running|healthy
      --compose-engine <COMPOSE_ENGINE>
          Compose engine to use; Podman Compose is not supported due to missing
          features [default: "docker compose"] [possible values: docker-compose,
          "docker compose"]
      --container-engine <CONTAINER_ENGINE>
          Container engine to use [default: docker] [possible values: docker,
          podman]
  -h, --help
          Print help (see more with '--help')

依赖

~3–13MB
~158K SLoC