check-lastlogというmackerel監視pluginを作ってるのですが、
こちらは /var/log/lastlog
を読むために一部cgoを使っています。mackerelのpluginなので一つ前の記事で紹介した方法で
リリースしたいところなのですが、GoReleaserでは、cgoへの依存があるプロジェクトのクロスコンパイルがサポートされていないため、ひと工夫必要になります。
check-lastlogではこちらのxgoを使う方法でクロスコンパイルし、GoReleaserでGitHub Releaseにアップロードをしています。
出来上がったGitHub Actionsのワークフローはこちら
https://github.com/kazeburo/check-lastlog/blob/master/.github/workflows/release.yml
xgoでのクロスコンパイル
xgo はGoのクロスコンパイルの環境がはいったDockerのイメージと各環境をターゲットとしたビルドを行うコマンドを提供しています。
check-lastlogではGitHub Actionが用意されているこちら
を使いました。こちらはforkしたxgoを使っているようです。
check-lastlogのワークフロー、.github/workflows/release.yml
の前半ではxgoを使ってクロスコンパイルしています。
name: release on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+" jobs: goreleaser: runs-on: ubuntu-latest env: BIN_NAME: check-lastlog steps: - name: Checkout uses: actions/checkout@v2 with: fetch-depth: 0 - name: Set tag to environment variable id: set-tag run: echo ::set-output name=version::${GITHUB_REF#refs/*/} - name: Build with xgo uses: crazy-max/ghaction-xgo@v1 with: xgo_version: latest go_version: 1.15.x dest: build prefix: ${{ env.BIN_NAME }} targets: linux/amd64,linux/arm64 v: true x: false ldflags: -s -w -X main.version=${{ steps.set-tag.outputs.version }} - name: Check build dir run: ls -lR build
ghaction-xgo のパラメータは次のようになってます。
- dest: ビルドしたバイナリを格納するディレクトリ
- prefix: バイナリのファイル名。後ろに
-${OS}-${Arch}
がつきます - targets: クロスコンパイルするターゲット。カンマで区切る
- v: ビルドしたファイル名の表示
- x: ビルドの際のコマンドなどの表示
また、GoReleaser ではldflagsをデフォルトでいくつか設定してくれますが、xgoはそうではないので、-w -s
と -X main.version
を追加しています。
これでビルドが完了すると、dest
で指定したディレクトリにバイナリができます。
> Run ls -lR build build: total 3428 -rwxr-xr-x 1 runner docker 1806024 Dec 2 09:12 check-lastlog-linux-amd64 -rwxr-xr-x 1 runner docker 1703448 Dec 2 09:12 check-lastlog-linux-arm64
アーカイブ作成とGitHub Releaseへのアップロード
あとは、GitHub Releaseへのアップロードだけではあるのですが、check-lastlog はmackerel監視プラグインなので、mkr plugin install
対応をさせます。
mkr plugin install
対応するためにはファイル名が {{ .ProjectName }}_{{ .Os }}_{{ .Arch }}.zip
でzipでアーカイブする必要があります。なのでShellで頑張ってzipをつくりました。
- name: Zip binaries run: | cd build for file in ./* ; do mkdir $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}') && cp ${file} $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}')/${{ env.BIN_NAME }} && zip $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}').zip -j $(echo ${file}|awk -F- '{print "${{ env.BIN_NAME }}_"$(NF-1)"_"$(NF)}')/${{ env.BIN_NAME }} ../README.md ../LICENSE; done shasum -a 256 *.zip > ${{ env.BIN_NAME }}_${{ steps.set-tag.outputs.version }}_checksums.txt ls -lR ./
バイナリだけではなく、README.mdやLICENSEファイルもアーカイブに同梱しています。また、checksum用のファイルも作っています。GoReleaserのchecksumがsha256なので、同じようにshasumコマンドを使ってみました。
そして最後にGitHub Releaseにアップロードするのですが、CHANGESも作ってくれるGoReleaserを使います。
まず、GoReleaserの設定ファイル .goreleaser.yml
# Use for generating CHANGELOG builds: - binary: check-lastlog skip: true release: github: owner: kazeburo name: check-lastlog extra_files: - glob: "build/*.zip" - glob: "build/*_checksums.txt"
ビルド(builds)は skip:true で止めることができました。成果物がない場合、archiveの作成も行われないようでした。GoReleaserで作ったパッケージのかわりに、xgoとShellで作ったzipとchecksumファイルをextra_filesに指定してアップロードしてもらいます。
GitHub Actionsのワークフローは goreleaser/goreleaser-action
を使いました。
- name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 with: version: latest args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GoReleaser 便利
まとめ
xgoを使うとGoReleaserのみでクロスコンパイルする場合にくらべて実行時間は伸びてしまいますが、cgoを使っているGo Projectでもlinuxのamd64, arm64に対応したパッケージを作ることができました。