跳过正文
  1. 文章/

用 Docker Compose 做 CI/CD,别把逻辑写进平台专属的 YAML

· loading · loading ·
仁才德
作者
仁才德
居住在韩国首尔的领导者和软件工程师

很多团队把构建和测试步骤直接写进 GitHub Actions 的 YAML 里。平时用着没问题,直到某天你想在自己的笔记本上跑一遍同样的构建,或者有人提议迁去 GitLab,才发现整条流水线已经焊死在某家供应商的配置格式上了。我现在的做法很朴素:真正的逻辑放进 Docker Compose,CI 工具只负责调用它。

为什么我不把构建逻辑写进 Actions YAML
#

最明显的问题是绑定。Actions 的工作流对 GitLab、Bitbucket、Jenkins 来说毫无意义,构建步骤要是写在工作流文件里,换平台就得全部重写。我还没见过哪个团队真会给这种事排期。

更隐蔽的问题是流水线没法在本地跑。如果验证构建改动的唯一办法是推一个提交、盯着 Actions 页面等结果,git 历史很快就会塞满 “fix ci”“fix ci again” 这样的提交。Compose 文件在我的笔记本上和在 runner 上跑起来一模一样,“在我机器上是好的” 这类争论基本也就消失了。

还有,YAML 会一直长。一开始是整洁的二十行,加上缓存技巧和条件判断后很快变成三百行,开发者除了 Git 还得学一门 CI 方言。一个脚本本该只做一件事,而庞大的工作流文件往往什么都揽。

用 Compose 之后分工就清楚了:构建和测试归 Compose 文件管,CI 平台只是在每次推送时把它跑一遍的角色。

具体做法
#

  1. 先写一个 Dockerfile,让镜像的构建方式只有一个出处:
# 使用官方Node.js运行时作为基础镜像
FROM node:14

# 设置容器中的工作目录
WORKDIR /app

# 将package.json和package-lock.json文件复制到容器
COPY package*.json ./

# 安装依赖
RUN npm install

# 将其余应用程序代码复制到容器
COPY . .

# 暴露应用程序运行的端口
EXPOSE 3000

# 定义运行应用程序的命令
CMD ["npm", "start"]
  1. 再写一个 docker-compose.build.yaml,定义构建和测试所需的服务。

    services:
      app:
        image: myprivaterepo.com/image:latest
        build: .
        volumes:
          - .:/app
        command: sh -c "npm install && npm test"
  2. 先在本地跑一遍,这正是这套做法的意义所在:

    docker compose -f docker-compose.build.yaml build
  3. 本地跑通之后,GitHub Actions 的工作流(换成别的 CI 平台也一样)就缩成了一个编排器:

    name: CI/CD Pipeline
    on: [push, pull_request]
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2
          - name: Set up Docker Buildx
            uses: docker/setup-buildx-action@v1
          - name: Build and Test with Docker Compose
            run: docker compose -f docker-compose.build.yaml build
          - name: Push the image referenced in the docker compose file
            run: docker compose -f docker-compose.build.yaml push

现在 CI 工具只做两件事:构建和推送。所有值得看懂的东西都在几个文件里,任何平台、任何新同事都能直接运行。

推送镜像
#

Compose 文件还有个顺带的好处:推送镜像变得非常简单。Docker 根据镜像名判断推送目标,image: myprivaterepo.com/image:latest 就意味着推到 myprivaterepo.com。私有仓库需要访问令牌,这部分请查你所用仓库服务的说明。

如果你现在用 GitHub Actions 用得很顺,不必急着改。但哪天真要换供应商,迁移工作就从“移植三百行 YAML”变成“复制两条命令”。而在那天到来之前,你可以体面地在本地调试构建。