CI/CDツールのDaggerを動かす
はじめに
CICDのパイプラインを記述する際はツールごとに独自のフォーマットや記述方法で記述する必要があるため移植性が低かったり、ローカルで試しに実行するのがなかなか難しかったりすることが多いと思います。DaggerはCICDの開発キッドで上記のような課題を削減することができます。 今回はこのDaggerをつかって簡単なパイプラインを作成し、ローカルで実行してみたいと思います。
Daggerとは
上記のようにDaggerはCICDのための開発キッドでCICDのパイプラインをCUEと呼ばれるようなGoogleで開発されて宣言的な言語で記述します。また特徴的なのが一度パイプラインを記述するとおおよそメジャーなCI環境で動かすことができます。そのため、CIのロックインを減らすことができます。また、ローカルマシーンで記述したパイプラインのテストやデバックを行うこともできます。
今回は他CIとのインテグレーションの機能は試しません。そちらについて知りたい人はこちらをご確認ください。
動かしてみる
動作環境
$ uname -srvmpio Linux 5.14.0-1033-oem #36-Ubuntu SMP Mon Apr 4 15:15:49 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.4 LTS Release: 20.04 Codename: focal $ docker version Client: Docker Engine - Community Version: 20.10.14 API version: 1.41 Go version: go1.16.15 Git commit: a224086 Built: Thu Mar 24 01:48:02 2022 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.14 API version: 1.41 (minimum version 1.12) Go version: go1.16.15 Git commit: 87a90dc Built: Thu Mar 24 01:45:53 2022 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.5.11 GitCommit: 3df54a852345ae127d1fa3092b95168e4a88e2f8 runc: Version: 1.0.3 GitCommit: v1.0.3-0-gf46b6ba docker-init: Version: 0.19.0 GitCommit: de40ad0
インストール
インストールは以下のコマンドで行います。
$ cd /usr/local $ curl -L https://dl.dagger.io/dagger/install.sh | sudo sh $ dagger version dagger 0.2.11 (0088c621) linux/amd64
これでDaggerのインストールは完了しました。
もし、Daggerを/user/local
以外の場所にインストールしたい場合は、単純に自分がインストールしたいロケーションにcd
してください。
また、特定のバージョンをインストールしたい場合やLinux以外でのインストールを行いたい場合はこちらを確認してください。
コアコンセプト
Daggerのパイプラインははアクションと呼ばれるベーシックなブロックから構成されます。アクションは複雑な自動化の部分をカプセル化し抽象化することでシンプルなソフトウェアコンポーネントとして動作し、安全にシェアすることができます。
Actionはdagger do
で実行することもできますし、もっと複雑なコンポーネントから実行することともできます。
Actionにはcore action
とcomposite action
と呼ばれる2種類のActionが存在します。
core action
はプリミティブにDaggerエンジンに実装されているActionです。よりハイレベルなActionから利用されます。このActionを利用する場合はdagger.io/dagger/core
パッケージをインストールする必要があります。core action
のリファレンスはこちらを参照ください。
composite action
は他のActionから構成されるActionです。このActionはcore
、composite
両方のActionから構成されることがあります。
Actionのライフサイクル
composite action
の以下のような4つのライフサイクルで実行されます。
- Definition
- Integration
- Discovery
- Execution
Definition
ActionはCUE Definitionと呼ばれるテンプレートで記述されます。
DefinitionはActionのインプットとアウトプット、サブアクションを定義します。
package main import ( "dagger.io/dagger" "dagger.io/dagger/core" ) // Write a greeting to a file, and add it to a directory #AddHello: { // The input directory dir: dagger.#FS // The name of the person to greet name: string | *"world" write: core.#WriteFile & { input: dir path: "hello-\(name).txt" contents: "hello, \(name)!" } // The directory with greeting message added result: write.output }
上記のサンプルはcore.#WriteFile
と呼ばれるサブアクションを含んでいます。1つのActionは複数のサブアクションを組み込むことができます。
input
はその名と通りインフットで、Integration
のタイミングで値が決定します。外部からの入力を受け取ることができます。上記の例ではdir
やname
がインプットにあたります。
output
は逆に値を生成します。その値はIntegration
のタイミングで他のActionなどから参照することができます。上記の例ではresult
がアウトプットにあたります。
dir
やresult
などのフィールドの名前に成約はありません。
Integration
Action definitionは直接実行できず、plan
に統合される必要があります。
plan
は実行コンテキストで、いかのようなことが定義します。
- エンドユーザに提供されるAction
- それらのタスクの依存関係
- タスクと client システム(ローカルマシンとのインテグレーション)の相互作用
Actionの各CUEファイルはplan
の CUR definitionにマージされ統合されます。
以下にplan
の definition例を示します。
package main import ( "dagger.io/dagger" ) dagger.#Plan & { // Say hello by writing to a file actions: hello: #AddHello & { dir: client.filesystem.".".read.contents } client: filesystem: ".": { read: contents: dagger.#FS write: contents: actions.hello.result } }
上記の例では@AddHello
が直接plan
に統合されており、そして、core.#WriteFile
は間接的に統合されています。
Planの詳細に関しては、後述します。
Discovery
plan
に統合されたActionはエンドユーザから利用することができます。
(ここではまだ下記のコマンドは実行できませんが、後ほど実行してみます)
$ dagger do --help Usage: dagger do [flags] Options Available Actions: hello Say hello by writing to a file (省略)
plan
にとうごうされたhello action
がDagger側から認識されます。
Execution
daggerから認識されたactionは、以下のように実行できます。
(ここではまだ下記のコマンドは実行できませんが、後ほど実行してみます)
$ dagger do hello
Hello WorldのActionを動かしてみる
コアコンセプトで利用したHello Worldのdefinitionを実行してみたいと思います。 まずはプロジェクトを初期化する必要があります。
$ mkdir helloworld && cd helloworld $ dagger project init Project initialized! To install dagger packages, run `dagger project update`
次にdagger packageをインストールするためにdagger project update
コマンドを実行します。
$ dagger project update 10:21PM INF system | installing all packages... 10:21PM INF system | installed/updated package dagger.io@0.2.11 10:21PM INF system | installed/updated package universe.dagger.io@0.2.11
ここまでで準備が完了です。
先程のコアコンセプトで利用したActionとplan
のDefinitionをそれぞれhello.cue
とplan.cue
という名前で保存します。
するとDagger側からAction
を認識できるようになります。
d$ dagger do --help Usage: dagger do [flags] Options Available Actions: hello Say hello by writing to a file (省略)
実際にActionを実行してみます。
$ dagger do hello 10:35PM INF upgrading buildkit have host network=true version=v0.10.3 [✔] client.filesystem.".".read 0.1s [✔] actions.hello.write 0.0s [✔] client.filesystem.".".write 0.0s
すると、hello-world.txt
というファイルが作成されます。
$ ls cue.mod hello-world.txt hello.cue plan.cue $ cat hello-world.txt hello, world!
次はplan
を少しだけ書き換えて、greetする人を変えてみます。
plan.cue
を以下のように変更します。
package main import ( "dagger.io/dagger" ) dagger.#Plan & { // Say hello by writing to a file actions: hello: #AddHello & { dir: client.filesystem.".".read.contents //ここを追加 name: "henoheno" } client: filesystem: ".": { read: contents: dagger.#FS write: contents: actions.hello.result } }
再度Actionを実行してみます。
$ dagger do hello [✔] client.filesystem.".".read 0.1s [✔] actions.hello.write 0.0s [✔] client.filesystem.".".write 0.0s $ ls cue.mod hello-henoheno.txt hello-world.txt hello.cue plan.cue $ cat hello-henoheno.txt hello, henoheno!