CI/CDツールConcourseのパイプラインのアーキテクチャ
概要
継続的インテグレーション、継続的デリバリー(CI/CD : Continuous Integration /Continuous Derivery)を実現するためのツールの1つであるConcourseについて、筆者が特にパイプラインを構成するアーキテクチャが面白いと思ったのでまとめてみました。
Concourseとは
Concourseとは、継続的インテグレーション、継続的デリバリー(CI/CD : Continuous Integration /Continuous Derivery)を実現するためのツールの1つです。
公式ドキュメントでは、
- 設定がソースコードのように扱える
- YAMLファイル形式
- パイプラインの処理の流れが可視化される
- 処理の流れがグラフ構造としてWeb UI上に表れる
- 再現性があり、デバッグも容易なビルド
- あらゆる処理がコンテナ上で実行されていて、専用CLIツールを用いてコンテナ内に入って検証できる(例えば失敗したビルドの原因の調査など)
などが特徴としてあげられています。
今回はその中でもConcourseのパイプラインを構築する上で重要な、 「Resource」という概念が面白いと思ったのでまとめてみます。
Concourseにおけるパイプライン
Concourseにおいて、パイプラインは以下の要素で構成されます。
- Job
- 複数のTask、及びResrouceの入出力の組
- Task
- 実際の計算処理(例:ソースコードのビルドなど)
- Resource
- Concourse内外の入出力を表すオブジェクト
特に私が面白いと感じているのはこのResourceの存在です。
Concourseのドキュメントでも触れられているのですが、Concourseにはいわゆるプラグインのようなシステムではなく、代わりにそのパイプラインで注力したい さまざまな入出力をResourceとして抽象化 しています。
Concourse does not have a complex plugin system. Instead, it focuses on a single strong abstraction: resource, which are implemented by resource types.
The pipeline.resources field configures external artifacts that your pipeline will monitor for changes, fetch from, and push to.
例えば、GitのリポジトリやDockerのレジストリ、Amazon S3やGoogle Cloud Storageなどのストレージなど、多種多様なResourceが存在します。
例えば、Git をcloneして ls -la
するのみ、というパイプラインが例として
公式に https://concourse-ci.org/git-trigger-example.html で紹介されています。ここでは、 git clone https://github.com/concourse/docs
が get: concourse-docs-git
で表現されています。
ここでは新しいコミットがあるたびに git clone
、 ls -la
が実行される設定になっています。
一方、出力操作は put
として表現します。例えば、docker push
がそれにあたります。
例えば、git clone
した後、そのリポジトリ内のDockerfileを使って docker build
、 docker push
を行うパイプラインは以下のようになります。
resources:
- name: sample-git-repo # git repositoryを表すresource
type: git
icon: github # (オプション) https://materialdesignicons.com/ 上のicon名を指定すると後述の画面上に表示される
source:
uri: <git repository URL>
- name: sample-docker-repo # docker repositoryを表すresource
type: docker-image
icon: docker
source:
repository: <docker registry URL>
jobs:
- name: build
plan:
- get: sample-git-repo
trigger: true
- put: sample-docker-repo
# docker-imageの場合はput時に docker build`, docker push が行われる。
# docker build -f sample-git-repo/Dockerfile sample-git-repo/ 相当
params:
build: sample-git-repo/
dockerfile: sample-git-repo/Dockerfile
tag_file: sample-git-repo/tag_file # tag名をあらかじめファイルに書いておく必要がある
本稿で詳細を述べていませんが、公式CLIツール fly
を使って既存のConcourseサーバ上に展開すると以下のような画面になります。
パイプライン設定のResourceとJobの関係を表したグラフになっています。
Jobが実行されると次のような画面になり、図中の黄色に強調されている部分がまさに実行中のjobを表しています。
さらにこのbuildをクリックすると、詳細のTask(get/put含む)の様子を知ることができます。
ここでも細かくどの処理が実行中なのか確認することができます。
(図中では tag_file
がないリポジトリを使ったため、tag_file
を生成するtask、create-tag-file
をput前に追加しています。また、実際はsample-git-repoのコミットハッシュが表示されるのですが省略しています。)
正常終了したJobは緑色に変化します。失敗したJobは赤色になるため、複数Jobがある場合は成功したJobと失敗したJobの違いが可視化されます。
さまざまなResource
私が特にこのResourceの仕組みの面白いと思っているところは、 定期的に実行する、という設定やSlackへの通知もこのResourceの仕組みに基づいている ことです!
Slack
Slackへの投稿もConcourseから見た入出力の方向は docker push
と同様なため、putで表現できます。例えば、以下のような設定になります。
# resource設定は省略
put: sample-notification
params:
attachments: |
[
{
"text": "sample notification",
}
]
time resource
定期実行の設定を実現するのは time resource です。
例えば、30秒ごとに echo "Hello world!"
する例が公式に
https://concourse-ci.org/time-trigger-example.html で紹介されています。
定期実行の処理がResourceで実現できるのは以下のような仕組みになっているからです。
実はResourceはversion情報を含んでいるのですが、Concourseは各Resourceに対して定期的に新しいversionがあるかどうか確認します。そして、新しいversion情報が検出されればジョブを実行するように設定できます。
例えばgitの場合は「コミット」がversion情報に該当するのですが、time の場合は設定に基づいた新しい「ジョブ開始時間」がそれにあたります。
※ 設定に基づいた:ここでは30秒おき、という設定。他には特定の時刻、といった設定も可能
ここで、Gitは開発者よってコミット(version情報)が更新されるResourceであるのに対し、 定期的に実行する = 定期的にジョブ開始時間(version情報)が更新される、と考えられるため、同じResourceという仕組みに抽象化できます。
つまり、Gitの場合は新しいコミットがあるたびにジョブを実行するような設定が実現できたように、time の場合も新しいジョブ開始時間が得られた場合にジョブを実行するような設定が実現できるため、定期実行も同じ仕組みのもとに実現できます。
まとめ
CI/CDツール Concourseのパイプラインでは、以下のようにさまざまな入出力がResourceとして抽象化されています。
Resource名\操作 | get | put |
---|---|---|
Git | clone(checkout) | push |
Docker | pull | build & push |
Google Cloud Storage | download | upload |
Slack | - | 投稿 |
time | (定期的な)時刻情報 | - |
Concourseが公式にサポートしているResourceはResource Typesにまとめられているのですが、このようにCI/CDを行う上で欠かせない入出力が他の処理(e.g. 上記の例では ls -la
や echo
。他には make
のようなビルドなど)と別の概念になっているところが面白いと思っています。