CI ツールシリーズ第3弾。Concourse は Pivotal が開発した CI ツールです。概要についてはこのスライドが参考になります。
チュートリアルも日本語に翻訳されています。
concoursetutorial-ja.cfapps.io
macOS / Windows では Docker Desktop で簡単に導入できます*1。GitHub から concourse-docker をクローンまたはダウンロードして、docker-compose up -d するだけ。
EC2 などのサーバで試すには、docker-compose.yml の 環境変数 CONCOURSE_EXTERNAL_URL
を環境変数から取得するようにしておくとよいでしょう。
concourse-web: image: concourse/concourse : environment: : - CONCOURSE_EXTERNAL_URL=${CONCOURSE_EXTERNAL_URL}
起動前に環境変数を設定しておけば、ローカルのブラウザからパイプラインの状況を監視できます。
$ export CONCOURSE_EXTERNAL_URL=http://$(curl -s ifconfig.me):8080
Concourse の特徴である fly コマンドは Go で書かれたクロスプラットフォームな CLI ツールで*2、セットアップされたサイトのトップページからダウンロードできます。/usr/local/bin
など PATH の通ったディレクトリに配置して起動できるようにします。
sudo mkdir -p /usr/local/bin sudo mv ~/Downloads/fly /usr/local/bin sudo chmod 0755 /usr/local/bin/fly
fly コマンドで作業するには Concourse API を叩くためのトークンを得るためにログインが必要です。
$ fly --target tutorial login --concourse-url http://127.0.0.1:8080
ここでは、tutorial という名前でセッションを作っています。ログイン用の URL が表示されますので、ブラウザで開いてログインを完了させます。Concourse を localhost で起動している場合は URL を叩くだけで完了します。リモートの場合は、画面に表示されるコピーボタンを押してクリップボードにトークンをコピーし、ターミナルのプロンプトに貼り付けます。
今回も Spring Boot サンプルアプリをターゲットにパイプラインを作ってみます。
Concourse では Git のリポジトリや Docker レジストリなどを外部のリソースとして使用することができます。今回作成するパイプラインは、ビルド対象のプロダクトとは別の Git リポジトリで管理するようにしました。こうすることでパイプラインの変更とビルド対象のコードの変更を分離できます。
前回の GitLab CI はプロダクトのリポジトリに CI の定義を配置するため、パイプラインの修正のたびにコミットが発生します。一発で成功することが分かっている場合を除き、フィーチャーブランチで作業して成功したら MR を作成するという開発スタイルになるでしょう。Concourse CI ではパイプライン専用のリポジトリを作ることができます。
今回作成したパイプラインのディレクトリ構造は以下のようにしています。
└── workspace ├── pipeline.yml └── tasks ├── build.sh ├── build.yml ├── deploy.sh └── deploy.yml
pypeline.yml がリソース・ジョブのオーケストレーションを記述するメインのファイルです。
今回定義した pipeline.yml は次のようになっています。ジョブは build-sb-sample
という名前の1つだけで、ジョブ内でビルドとデプロイは別タスクに分けています。デプロイではコンテナをビルドして Docker in Docker 構成で起動するため privileged: true
を指定しています。
resources: # プロダクトのリポジトリ - name: sb-sample-service type: git source: uri: https://github.com/kondoumh/sb-sample-service.git branch: master # パイプラインのリポジトリ - name: pipelines type: git source: uri: https://github.com/kondoumh/pipelines.git branch: master jobs: - name: build-sb-sample public: true plan: # 2つのリポジトリを取得 - get: sb-sample-service - get: pipelines # プロダクトのビルドタスク - task: Build project file: pipelines/concourse/workspace/tasks/build.yml # プロダクトのデプロイタスク - task: Deploy service privileged: true file: pipelines/concourse/workspace/tasks/deploy.yml
タスクの定義は専用の YAML に切り出しています。
build.yml の定義。Java:8 のコンテナを使って、ビルド用のシェルを実行します。inputs としてパイプラインのプロダクトの両リポジトリを使うため2つとも指定。プロダクトのディレクトリ内(の target ディレクトリ) にビルド成果物である JAR ファイルを出力するため、outputs にもプロダクトのリポジトリを指定しています。Maven Central リポジトリから多くの依存ライブラリをダウンロードするため、Maven のローカルリポジトリ (.m2) をキャッシュに指定しました。
platform: linux image_resource: type: docker-image source: {repository: java, tag: 8} inputs: - name: pipelines - name: sb-sample-service outputs: - name: sb-sample-service caches: - path: .m2/ run: path: "pipelines/concourse/workspace/tasks/build.sh"
build.sh では、取得したリポジトリ内の mvnw コマンドでビルド・単体テスト・パッケージングを行います。
#!/bin/sh -xe cd sb-sample-service ./mvnw package
deploy.yml の定義。inputs として、前のタスクの outputs である (JAR が生成された) プロダクトリポジトリとパイプラインリポジトリを指定しています。
platform: linux image_resource: type: docker-image source: {repository: quay.io/cosee-concourse/dind, tag: latest} inputs: - name: sb-sample-service - name: pipelines run: path: "pipelines/concourse/workspace/tasks/deploy.sh"
デプロイで使用する docker イメージは Docker in Docker での docker-compose に対応した dind のイメージを使いました。
deploy.sh では、Docker サービスを起動して、プロダクトのリポジトリ内の docker-compose.yml を使ってコンテナをビルド・起動し、curl で API を叩いて動作確認しています。
#!/bin/sh -xe source /docker-lib.sh start_docker cd sb-sample-service docker-compose up -d sleep 30 docker ps curl -X POST "http://localhost:18888/api/user/" -H "accept: */*" -H "Content-Type: application/json" -d "{ \"id\": 1, \"name\": \"Mike\"}" curl -X GET "http://localhost:18888/api/usr/1" -H "accept: */*" docker-compose down
このようにして作成したパイプラインを fly コマンドを使って Concourse に設定 (set-pipeline)、ポーズ解除 (unpause-pipeline)、ジョブ起動 (trigger-job) します。
$ fly -t tutorial set-pipeline -c pipeline.yml -p build-sb-sample $ fly -t tutorial unpause-pipeline -p build-sb-sample $ fly -t tutorial trigger-job -j build-sb-sample/build-sb-service -w
set-pipeline
は sp
、unpause-pipeline
は up
のように短縮名もありますので打鍵量を減らすことができます。
trigger-job で watch オプション (-w) を付けることで、そのままターミナルに実行ログが流れていきます。
もちろん Web UI でもパイプラインを起動して実行の様子を眺めることができます。右側の build-sb-sample
が実行中になっています。
実行されているジョブの様子。2つのリソースがジョブに繋がって実行中であることがわかります。
成功して完了した画面。
Web UI でも実行ログを確認できます。タスクごとにセクションが分かれています。
Elm で書かれたという UI はシンプルでリアクティブにアニメーションします。
fly watch でターミナルを見ているだけでも実行状態を監視できるので Web UI は触らなくても作業が進みます。チュートリアルにもこうあります。
fly watch コマンドは、ラップトップPCのバッテリーの節約になります。実は、Concourse Web UI で実行されているJobを見ていると、ターミナルでfly watchを実行するよりもバッテリー消費量が多いことが分かりました。あなたのPCでは、状態が異なる場合があるかもしれませんが。
実際、今回は外出先の待ち時間でパイプラインの動作確認をしていたのですが、EC2 インスタンスで起動した Concourse に fly コマンドを叩いて実行を確認、YAML ファイルとシェルを編集し Git リポジトリに push という作業フローだったので、Pixel 3 の Termux だけで完結してしまいました。
以上のように Concourse はターミナル操作がメインになるので、マニアックというか地味ですが、Jenkins と比べると覚えることが少なくシンプルな CI ツールに仕上がっています。
Maven や NPM のような各プログラミング言語専用のビルドツールの枠を超えて、開発者の手元で簡単に流せる CI ツールとして採用するのもよいでしょう。
ジョブ、タスクのような単位でビルドを管理できるため、多数のモジュールの依存関係を管理する複雑で巨大なパイプラインにもスケールアウト可能になっていると思います。