メインコンテンツへスキップ
  1. 記事一覧/

CI/CDのロジックはプラットフォーム固有のYAMLではなくDocker Composeに

· loading · loading ·
仁才徳
著者
仁才徳
韓国ソウル在住のリーダー兼ソフトウェアエンジニア

ビルドやテストの手順をGitHub ActionsのYAMLに直接書いているチームは多いと思います。それで普通に動くのですが、同じビルドを手元のマシンで実行したくなったり、「GitLabに移行しようか」という話が出たりした瞬間に、パイプライン全体が特定ベンダーの設定形式にがっちり溶接されていることに気づきます。私のやり方はかなり地味です。本当のロジックはDocker Composeに置いて、CIツールにはそれを呼び出すことだけをさせます。

ビルドロジックをActionsのYAMLに書かない理由
#

わかりやすい問題はロックインです。ActionsのワークフローはGitLabにもBitbucketにもJenkinsにも通用しないので、ビルド手順がワークフローファイルの中にあると、プラットフォームを変えるときに全部書き直しです。その作業に工数を確保するチームを、私はまだ見たことがありません。

もうひとつ、地味に効いてくる問題があります。パイプラインをローカルで実行できないことです。ビルドの変更を試す方法が「コミットをプッシュしてActionsのタブを眺める」しかないと、gitの履歴が「fix ci」「fix ci again」「頼む」で埋まっていきます。Composeファイルなら手元でもランナー上でも同じように動くので、「自分のマシンでは動くんですけど」という議論も始まる前にほぼ消えます。

そしてYAMLは育ちます。最初は整った20行だったものが、キャッシュの工夫や条件分岐が加わって300行になり、開発者は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ツールの仕事はビルドとプッシュの2つだけになりました。理解する価値のある部分はすべて、どのプラットフォームでも、新しく入ったメンバーでも、そのまま実行できるファイルの中にあります。

イメージのプッシュ
#

Composeファイルのうれしい副作用として、プッシュがとても簡単になります。Dockerはイメージ名からプッシュ先を判断します。image: myprivaterepo.com/image:latestなら、プッシュ先はmyprivaterepo.comです。プライベートレジストリの場合はアクセストークンが必要なので、そこは利用しているレジストリのドキュメントを確認してください。

いまGitHub Actionsで満足しているなら、急いで変える必要はありません。ただ、いつかプロバイダーを乗り換える日が来たとき、移行作業が「300行のYAMLの移植」ではなく「コマンド2つのコピー」で済みます。そしてその日までは、ビルドのデバッグを手元で落ち着いてやれるわけです。