なんか良さそうなのでやってみます。
公式のGetting Startedをベースに書きます。英語が読める人はそっちの方が良いかもしれません。
あと以下はMacでの手順なので、Mac以外の人もできれば公式サイトを見てください。
僕もDagger歴1日なので、不正確な点もあるかもしれませんが、誤りを見つけた場合は優しく教えてもらえると助かります。
インストール
brew install dagger/tap/dagger
Homebrewでインストールできます。
手順
Daggerのリポジトリにはサンプルアプリが入っているので、今回はこれを利用します。Daggerのリポジトリをcloneして、一応後で変更が入っても大丈夫なようにv0.2.4
のブランチに移動しておきます。
git clone https://github.com/dagger/dagger
cd dagger
git checkout v0.2.4
サンプルのディレクトリ(今回はcreate-react-app
コマンドで作成されたであろうToDoアプリ)に移動して、早速ビルドしてみましょう。あ、事前にDocker Desktopは起動しておいてくださいね。
cd pkg/universe.dagger.io/examples/todoapp
dagger do build
しばらく待つとビルドが完了して、_build/index.html
が作成されます。
[✔] actions.build.run.script
0.1s
[✔] actions.deps
0.1s
[✔] client.filesystem."./".read
0.2s
[✔] actions.test.script
0.1s
[✔] actions.test
0.7s
[✔] actions.build.run 5.4s
[✔] actions.build.contents
0.0s
[✔] client.filesystem."./_build".write
0.2s
見ての通り、依存関係が良い感じに解決され、テストも良い感じに実行され、最後に良い感じにビルドされています。
ビルドが完了したら、open _build/index.html
でもブラウザにドラッグ&ドロップでも何でも良いですが、表示できることを確認しておきましょう。
クールですね。
遅く感じるかもしれませんが気にしないでください。Linuxだと8倍早く動きます。
さて、1コマンドで良い感じにビルドまで動きましたが、まだ疑問はあるでしょう。次の2つです。
- 他のCIツールと比べて、これの何が嬉しいの?
- 設定はどうなってるの?
前者は単純で一番大きいのはDockerさえ動けば、どこでも動かせるというものです。開発チームの方針やプラットフォームの料金が変わって違うCIツールに乗り換えたいと思ったとき、GitHub ActionsやCircleCIやGitLabの使い方を1から覚え直す必要はありません。例えば、GitHub ActionsでDaggerを用いたいならアプリケーションルートに.github/workflows/todoapp.yml
を置いて、以下のように書けば大丈夫です。
name: todoapp
on:
push:
# Trigger this workflow only on commits pushed to the main branch
branches:
- main
# Dagger plan gets configured via client environment variables
env:
# This needs to be unique across all of netlify.app
APP_NAME: todoapp-dagger-europa
NETLIFY_TEAM: dagger
jobs:
dagger:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v2
# You need to run `dagger project init` locally before and commit the cue.mod directory to the repository with its contents
- name: Deploy to Netlify
uses: dagger/dagger-for-github@v2
# See all options at https://github.com/dagger/dagger-for-github
with:
version: 0.2
# To pin external dependencies, you can use `project update github.com/[package-source]@v[n]`
cmds: |
project update
do deploy
env:
# Get one from https://app.netlify.com/user/applications/personal
NETLIFY_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
少し長いですが気にしないでください。これは公式ページから引用したものです。見ての通り、アプリケーション特有のものはほとんどありません。強いて言えば、アプリ名と環境変数くらいです。他はどんなアプリケーションでも共通の設定を使い回すことができます。GitHubアクション以外でももちろん同様ですし、公式ページには各プラットフォーム用の設定ファイルが置いてあるので、自分で考える必要はありません。
さらにメリットを言えば、Daggerはローカルでも動きます。CIツールの設定のデバッグにかかる時間は目に見えて減少するでしょう。もっと言えば、開発環境でもDaggerのパイプラインを用いたって良いのです。
さて、問題は「Dagger自体の設定ファイルをどうするか」ですね。
今回使ったサンプルアプリの設定ファイルを見てみましょう。
package todoapp
import (
"dagger.io/dagger"
"dagger.io/dagger/core"
"universe.dagger.io/alpine"
"universe.dagger.io/bash"
"universe.dagger.io/docker"
"universe.dagger.io/netlify"
)
dagger.#Plan & {
_nodeModulesMount: "/src/node_modules": {
dest: "/src/node_modules"
type: "cache"
contents: core.#CacheDir & {
id: "todoapp-modules-cache"
}
}
client: {
filesystem: {
"./": read: {
contents: dagger.#FS
exclude: [
"README.md",
"_build",
"todoapp.cue",
"node_modules",
]
}
"./_build": write: contents: actions.build.contents.output
}
env: {
APP_NAME: string
NETLIFY_TEAM: string
NETLIFY_TOKEN: dagger.#Secret
}
}
actions: {
deps: docker.#Build & {
steps: [
alpine.#Build & {
packages: {
bash: {}
yarn: {}
git: {}
}
},
docker.#Copy & {
contents: client.filesystem."./".read.contents
dest: "/src"
},
bash.#Run & {
workdir: "/src"
mounts: {
"/cache/yarn": {
dest: "/cache/yarn"
type: "cache"
contents: core.#CacheDir & {
id: "todoapp-yarn-cache"
}
}
_nodeModulesMount
}
script: contents: #"""
yarn config set cache-folder /cache/yarn
yarn install
"""#
},
]
}
test: bash.#Run & {
input: deps.output
workdir: "/src"
mounts: _nodeModulesMount
script: contents: #"""
yarn run test
"""#
}
build: {
run: bash.#Run & {
input: test.output
mounts: _nodeModulesMount
workdir: "/src"
script: contents: #"""
yarn run build
"""#
}
contents: core.#Subdir & {
input: run.output.rootfs
path: "/src/build"
}
}
deploy: netlify.#Deploy & {
contents: build.contents.output
site: client.env.APP_NAME
token: client.env.NETLIFY_TOKEN
team: client.env.NETLIFY_TEAM
}
}
}
まだ普及していない形式の設定ファイル用の言語ですので、初めて見るという方も多いのではないでしょうか。
こんなことを告げるのは非常に心苦しくはあるのですが、Daggerを使うにはこのCUEという言語を覚える必要があります。
僕も最初は「余計なことしやがって」と思いましたが、JSONやYAML、TOMLなどには無い利点もあり一概に否定はできません。大きな特徴は
- 型と値が同じように扱える
- Goのような文法で外部のCUEファイルをimportできる(実はJSONやYAMLもimportできる)
という点でしょう。
テクニックとして便利なものもいくらかあって、例えば
docker.#Copy & {
contents: client.filesystem."./".read.contents
dest: "/src"
},
という箇所が途中でありますが、この2行目のclientというのはその前にこのファイル内で定義したものです。
このように同一ファイル内で責任を分離して繰り返し同じ記述をするのを避けたり、変更に強くしたりできます。
このようにCUE言語が便利なのは確かですし、Daggerが流行ればCUE言語を使う機会も増えると思うので、先行投資だと思って覚えておきましょう。CUE言語の公式ドキュメントもかなりクオリティが高いです。
さて、それでは設定ファイルの書き方の解説を……と行きたいところですが、ぶっちゃけ見たまんまです。
重要なのは以下の部分です。
- 最初にpackage名(なんでも大丈夫)を宣言して、importしたいパッケージを選択します。細かいパッケージの詳細は省略します。公式サイトを読んでください。
-
client
はdagger.#Plan
が持っているフィールドなので名前は変更できません。ざっくり言えばホストと通信できるもので、今回のようにファイルや環境変数を読んだりできます -
actions
内に好きなようにアクションが定義できます。dagger do アクション名
とすれば設定ファイルのactions
内のアクションを良い感じに依存を解決しながら実行できます。input
で指定しているものに依存しているので、先んじてそれが実行されるイメージですね。
できることはサンプルに載っている事以外にもあるのですが、全部は説明できないのでこのくらいにしておきます。
この設定ファイルを書く部分がDaggerを使う上での一番の障害になってくると思うので、まずは小さい用途でCUE言語を使ってみて慣れていくのが良いと思います。
まとめ
- Daggerは便利!
- CI/CDにかけていた時間が大幅に減るかも
- CIプラットフォームを変更するコストもかからないよ
- CUE言語を頑張って習得しよう!!
ということでCuetorialsというシャレの効いたCUE入門サイトのリンクを貼っておくので、この記事を読み終えた方は今すぐ入門しに行きましょう。
ほな。