Dagger Go SDKでCI/CDパイプラインを作成する
はじめに
今回はDagger Go SDKと AWS を利用して CI/CD パイプラインを構築したいと思います。
Dagger
については以下が参考になります
こちらは私が簡単に翻訳した日本語の公式マニュアルとなります。
こちらは秋に行われた Go conference の資料となります。
この資料がきっかけで Dagger というツールを知りました。まさかのこの数日後に Go バージョンが発表されるとは思いませんでした
環境
VSCode
Ubuntu 20.04 (WSL2)
Docker 20.10.12
docker-compose version v2.2.3
git version 2.25.1
Dagger で CI/CD パイプラインを作成する
こちらのリポジトリを今回は利用します
このリポジトリではローカルにDocker
とdocker-compose
の環境があればどなたでも Dagger Go SDK が利用できるような環境を提供しています
$ git cone https://github.com/jinwatanabe/dagger_go_docker
$ cd dagger_go_docker/
$ cd chapter2
まずローカルで CI/CD を作成してテストとビルドが動くかを確かめます
今回 CI/CD の実行対象にするリポジトリは以下のリポジトリを利用します
あとでこちらのリポジトリを利用します
まずは CI/CD パイプラインの構築を行います。main.go
を以下に編集します
package main
import (
"context"
"fmt"
"os"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
// クライアントの用意、ログを出力するように追加で設定
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout))
if err != nil {
panic(err)
}
defer client.Close()
// リポジトリをクローン(mainブランチの内容)
src := client.
Git("https://github.com/jinwatanabe/go_lambda_cicd").
Branch("main").Tree()
if err != nil {
panic(err)
}
// CI/CDの実行環境をGoイメージを使うように設定(Goをテスト/ビルドするため)
// 環境変数を設定する (今回は必要はないが環境変数を設定することもできる)
golang := client.Container().From("golang:latest").WithEnvVariable("MESSAGE", "CI/CDが成功しました")
// コンテナの/appにリポジトリの内容をコピー
// カレントディレクトリを/app/srcに変更(srcにGoのコードがあるため)
golang = golang.WithMountedDirectory("/app", src).WithWorkdir("/app/src")
// コンテナの上でコマンドを実行
// テストコマンド
// ビルドコマンド
// ビルド結果を表示(mainがあることを確認)
// 環境変数を利用してを表示
golang = golang.Exec(dagger.ContainerExecOpts{
Args: []string{"sh", "-c", "go test"},
}).
Exec(dagger.ContainerExecOpts{
Args: []string{"sh", "-c", "env CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags='-s -w' -o bin/main handler/main.go"},
}).
Exec(dagger.ContainerExecOpts{
Args: []string{"sh", "-c", "ls -la bin"},
}).
Exec(dagger.ContainerExecOpts{
Args: []string{"sh", "-c", "echo $MESSAGE"},
})
// CI/CDに失敗したらここでエラーがでて停止する
if _, err := golang.ExitCode(ctx); err != nil {
panic(err)
}
fmt.Println("Success!!")
}
コードに関してはコメントで説明させていただきました
実際に CI を動かしていきます
$ docker-compose up
# 別ターミナルを開く
$ docker exec -it dagger sh
$ go run main.go
#17 sh -c ls -la bin
#17 0.174 total 10248
#17 0.174 drwxr-xr-x 1 root root 4096 Nov 19 08:24 .
#17 0.174 drwxr-xr-x 1 root root 4096 Nov 19 08:02 ..
#17 0.174 -rwxr-xr-x 1 root root 10481664 Nov 19 08:24 main
#17 DONE 0.2s
このようなメッセージがでていれば成功です
Gitlab-runner で実行する
以下のファイルを用意しました
(省略)
build:
script:
- echo "Start CI/CD"
- docker-compose -f docker-compose.ci.yml up -d
- echo "Start Docker Engine"
- sleep 10
- docker exec cicd sh -c "go run main.go"
- docker-compose -f docker-compose.ci.yml down -v
- echo "Success"
only:
- main
このファイルを gitlab-runner 上で動かすことで Dagger が実行できました
ポイントとしてはsleep 10
でDocker in Docker
であるコンテナのDockerデーモン
が起動するのを待っていることです。起動していない状態でgo run main.go
をすると Go で利用しているライブラリttrpc
でコンテナ起動ができないためエラーになってしまいます。
CodeBuild で実行する
はじめに CodeBuild 上で実行するスクリプトを作成します
buildspec.yml
というファイルを作成して以下の内容を追加します
version: 0.2
env:
variables:
GO_VERSION: 1.19.3
phases:
install:
commands:
- apt-get update
- apt-get install wget
- wget https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz
- tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz
- export PATH="/usr/local/go/bin:$PATH" && export GOPATH="$HOME/go" && export PATH="$GOPATH/bin:$PATH"
build:
commands:
- cd chapter2
- go run main.go
次に GitHub にリポジトリを作成します。
次に AWS コンソールを開きます
「codebuild」を検索してクリックします
「ビルドプロジェクトを作成する」をクリック
以下の設定をします
項目 | 値 |
---|---|
プロジェクト名 | dagger-ci |
ソースプロバイダ | GitHub |
リポジトリ | GitHub アカウントのリポジトリ |
GitHub リポジトリ | 作成したリポジトリを選択 |
オペレーティングシステム | Ubuntu |
イメージ | 最新のものを選択 |
イメージのバージョン | 最新のものを選択 |
特権付与 | ☑ |
「ビルドプロジェクトを作成する」をクリック
作成出来たら「ビルドを開始」をクリック
以下のようになれば成功です
おまけ: CodeBuild 上で Go コンテナを起動してそのうえで Dagger を起動する
現在エラーを解決が発生して解決できておりません
buildspec.yml
を以下で作成しました
version: 0.2
phases:
build:
commands:
- cd chapter2
- docker-compose up -d
- sleep 10
- docker exec dagger sh -c "go run main.go"
現在ここでエラーが発生しています
現在調査中で進捗はこちらのスクラップで記載しています
CodeBuild 上で Docker in Docker のイメージからコンテナを作成した際にネットワークがつながらなくなるようです。
この方法を用いなくても問題なく利用することはできますが、気になるので調査を続けます。
もしわかる方がいればコメントいただきたいです。
おわりに
Dagger Go SDK を使って以下のようなメリット/デメリットを感じました
メリット
- Go で CI/CD がかける
- ローカルでパイプラインを実行できるのでマージして CI/CD 回して修正しての手間から解放される
- ツールに依存する yml ファイルが少ないコマンドで終わるので楽
- Go なので外部からモジュールインポートができる
デメリット
- 今回は docker in docker でやったのでリソースを多く消費する
- dagger でもコンテナを起動するためイメージ取得の時間が追加出かかる
私としては何度も CI/CD を回してエラーを解決する手間がなくなったのがとてもありがたいと思いました。
ちなみに CodeBuild で Dagger を実行するのですら何度もマージしたりと手間がかかりました。更にコマンドが本来ならあるのでより時間がかかります。。
更に発展させる場合は Go には強力な並列処理があるのでうまく利用することで CI/CD の時間を短縮することも可能です
Discussion