Circle CI 2.0を(過度に)使わない


はじめに

いきなりですが私の考える config.yml の理想形は以下になります。

version: 2
jobs:
  build:
    working_directory: /xxx/
    docker:
      - image: aaa/bbb
    steps:
      - checkout
      - run:
          command: make ci

なぜこれが理想形なのかというと、Circle CI 2.0ではソースコードの変更検知、チェックアウト、コマンド実行、結果通知だけに徹するべきであり、その他の責務については適切な他のツールが担うべきだと考えているためです。

責務を意識して適切にツールを採用していくと、以下のメリットが得られます。

  • 特定のCIツールを過度に学習する必要がなくなる
  • 特定のCIおじさんだけではなく開発者全員がメンテナンスできるようになる
  • CIツールとエンジニアから共通のスクリプトが実行される
  • その結果、スクリプトがメンテされる状況を維持できる
  • 別のCIツールに移行できる

ツールの採用

CIで実施する処理は以下になりますが、config.yml には直接書かずに適切なツールで実現します。

  • ソースコード変更検知
  • 実行環境の準備
  • 実行環境に必要なツールの準備
  • ソースコードの準備
  • ビルド、テスト、デプロイ
  • 結果通知
  • 上記の制御

ソースコードの変更検知

これはすべてのCIツールに搭載されている機能だと思います。
変更があったタイミングでCIが走ります。

実行環境の準備

実行環境はDockerイメージで実現します。
これは必ずそうなるでしょう。

実行環境に必要なツールの準備

必要なツールはDockerイメージにあらかじめインストールしておくことが大切です。
config.yml にインストール手順を記述してしまうことは、やりがちですが避けたほうがいいです。

何故ならCIを実行するたびにツールをインストールするとCIの実行完了が遅くなります。
またツールのインストールで遅くならないためにキャッシュの処理を書くことはやりがちですがやるべきではありません。これによりCircle CI 2.0への依存が大きくなりメンテナンスのコストが上がります。

さらに config.yml にインストール手順を記述してしまうと、各エンジニアの開発環境で実行環境を再現することが難しくなります。Dockerイメージを作成しておけばdocker pullするだけでCIと同様の実行環境が再現できるようになります。

以上のように実行環境の準備はDockerイメージに閉じるべきです。

続いて、鍵の情報やソースコードのようなプロジェクト固有の情報はDockerイメージに含めないことが大切です。
可能な限りこれらの情報はリポジトリに配置し、それも難しい場合にはCircle CI 2.0の環境変数として設定しましょう。
こうすることでDockerイメージが公開可能になりCircle CIからの認証が不要になるというメリットもあります。

ソースコードの準備

Githubなどからリポジトリを取得することになります。
これは必ずそうなるでしょう。

ビルド、テスト、デプロイ

具体的なビルド、テスト、デプロイ手順を config.yml に記載することは避けるべきです。

コマンドの情報や特にそのオプション引数に渡す情報は、config.yml ではなく、別途 ci.sh のようなShellscriptに記載しておき、それを実行します。
そうすることでCIで必要なフローを開発者が容易に実行可能になります。またShellscriptとして構成管理されるようになるため、処理を追いやすくなります。
もちろん状況に合わせてShellscript以外のChefやAnsibleなどの構成管理ツールを使うといいでしょう。

また別途Makefileなどを作成して、それを config.yml から実行するようにすると、各エンジニアがCIとまったく同じビルド、テスト、デプロイを1コマンドで実現することができます。

# エンジニアもCircle CIも以下のコマンドを実行することでビルド、テスト、デプロイができるようになる
make ci

結果通知

結果通知はCircle CI 2.0の通知を利用することで十分だと思います。
CIの途中で通知が必要ならば、別途スクリプトを作成してShellscriptから実行する手もあるでしょう。

構成のイメージ

ディレクトリツリー

build.shやdeploy.shはCIでも日常の開発でも利用されます。

proj
├── Makefile
├── scripts/
│   ├── build.sh
│   ├── ci.sh # build.shとdeploy.shを実行
│   ├── deploy.sh
│   └── test.sh
└── src/

Makefile

Makefileは人間のためのインターフェースとして割り切るべきです。
Makefileは手続きを書くためのツールとしては向いていないため、手続きはスクリプトに記載しましょう。

またMakefileはREADMEとしても機能します。

ci: 
  ci.sh

build:
  build.sh

test:
  test.sh

deploy_prod:
  deploy.sh prod

deploy_dev:
  deploy.sh dev

CI固有のフロー制御などがなければ以下のようになっていることが理想的です。

ci: build deploy

まとめ

責務 ツール
ソースコード変更検知 Circle CI 2.0
実行環境の準備 DockerイメージのPull
実行環境に必要なツールの準備 DockerイメージのPull
ソースコードの準備(プロジェクト固有情報) GithubからPull
ビルド、テスト、デプロイ Makefileを経由してスクリプトを実行
結果通知 Circle CI 2.0
上記の制御 Circle CI 2.0