使用 Docker 图像和 docker-compose 构建 CICD 管道的正确方法

Proper way to build a CICD pipeline with Docker images and docker-compose

我有一个关于 DockerHub 和 GitHub 的一般性问题。我正在尝试使用 AWS 实例在 Jenkins 上构建管道,我的最终目标是部署 docker-compose.yml 我在 GitHub 上的回购具有:

version: "3"

services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_HOST: db

我在 CI/CD 管道中读到人们构建他们的图像并将它们推送到 DockerHub,但它有什么意义?

你只会推送一个单独的图像。即使您稍后在不同的实例中拉取图像,为了 运行 具有不同服务的应用程序,您将需要 运行 使用 docker-compose 的容器,而您不会拥有它除非您再次从 github 存储库中提取它或在管道上创建它,对吗?

从 Github 获取存储库并执行 docker-compose 命令不是更好更直接吗?有没有一种“更清洁”或“正确”的方法呢?提前致谢!

您应该需要复制到远程系统的唯一 文件是docker-compose.yml 文件。甚至这在技术上也是可选的,因为 Compose 只是包装了基本的 Docker 命令;您可以手动 docker network create 然后 docker run 这两个容器,根本不复制任何内容。

对于此设置,重要的是删除 volumes: 需要应用程序代码的副本来覆盖图像的内容。您也不应该需要覆盖 command:。对于部署,您需要将 build: 替换为 image:.

version: "3.8"
services:
  db: *from-the-question
  web:
    image: registry.example.com/me/web:${WEB_TAG:-latest}
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment: *web-environment-from-the-question
    # no build:, command:, volumes:

在 Compose 设置中,您可以 put the build: configuration in a parallel docker-compose.override.yml file 不会将其复制到部署系统。


那又怎样?以这种方式构建事物有几个很好的理由。

一个 forward-looking 答案涉及集群容器管理器,例如 Kubernetes、Nomad 或亚马逊的专有 ECS。在这些容器中,运行s 位于无法区分的机器集群中的某个位置, 复制应用程序代码的方法是从注册表中提取它。在这些设置中,您不会在任何地方复制任何文件,而是向集群管理器发出指令,说明图像的一些副本应该 运行 某处。

另一个很好的理由是支持回滚应用程序。在上面的 Compose 片段中,我引用了一个环境变量 ${WEB_TAG}。假设您每天推出一个版本,并给每个版本一个 date-stamped 标签; registry.example.com/me/web:20220220。但是,今天的构建出了点问题!当你弄明白的时候,你可以连接到部署机器和运行

WEB_TAG=20220219 docker-compose up -d

并立即回滚,再次不尝试签出任何内容或复制应用程序。

一般来说,使用 Docker,您希望将图像制作成 self-contained 的样子,尽管仍然承认有些东西无法“烘焙”,例如数据库凭据在”。所以确保 COPY 中的代码,不要用 volumes: 覆盖代码,请设置一个合理的 CMD。您应该能够从一个只安装 Docker 而没有其他任何东西的干净系统开始,并且 docker run 图像只需要 Docker-related 设置。您可以想象为 运行 docker 命令编写 shell 脚本,而 docker-compose.yml 文件只是该文件的声明版本。


最后记住你没有使用Docker。您可以使用 general-purpose system-management 工具(如 Ansible、Salt Stack 或 Chef)将 Ruby 安装到目标机器上并手动复制代码。这是一种 well-proven 部署方法。我发现 Docker 更简单,但假设代码及其所有依赖项实际上都在映像中,不需要单独复制。