CIで利用するCLIツールをaquaで管理してみよう
Kubernetes向けのカスタムコントローラーやアプリケーションを開発する際には、kubectl, kustomize, helm, kind, kubebuilderなど様々なCLIツールを利用します。
これらのCLIツールは定期的にアップデートすることになりますが、なるべく少ない手間で更新したいですよね。
今回はaquaというツールを利用して、CIで利用するCLIツールをメンテナブルに管理する方法を紹介したいと思います。
これまでの管理方法
まずは、CLIツールをどのように管理しているのか、いくつかのOSSを調べてみました。
多くの場合は以下のようにMakefileやシェルスクリプト内にCLIツールのバージョンとセットアップの処理を書いていました。
KUSTOMIZE_VERSION = 4.4.1
HELM_VERSION = 3.7.1
KUSTOMIZE := $(shell pwd)/bin/kustomize
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE):
mkdir -p bin
curl -fsL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv$(KUSTOMIZE_VERSION)/kustomize_v$(KUSTOMIZE_VERSION)_linux_amd64.tar.gz | \
tar -C bin -xzf -
HELM := $(shell pwd)/bin/helm
.PHONY: helm
helm: $(HELM) ## Download helm locally if necessary.
$(HELM):
mkdir -p $(BIN_DIR)
curl -L -sS https://get.helm.sh/helm-v$(HELM_VERSION)-linux-amd64.tar.gz \
| tar xz -C $(BIN_DIR) --strip-components 1 linux-amd64/helm
しかし、この方式ではあまりメンテしやすくはありません。
Makefile内に埋め込まれているバージョン番号を見つけて手動で更新する必要がありますし、Makefileの記述も長くなりがちです。
一方、Argo CDでは以下のような専用のインストールスクリプトを用意しています。
Makefile内に直書きするのに比べるとメンテしやすくなってますが、こういったスクリプトを用意するのはなかなか大変です。
また、私は以前asdfというツールを利用してCLIツールを管理する仕組みを構築しようとしました。
しかし、インストールするCLIごとにプラグインをインストールする必要があるなど、あまり使い勝手のよいものではありませんでした。
aquaによるCLIツールの管理
CLIツールの管理方法を模索していたところ、以下のような記事を見つけました。
aquaを利用すると、私が課題に感じていたことを解決できそうです。そこでaquaを利用してCLIツールを管理してみようと思います。
まずは下記のページの通り、aquaのインストールをおこないます。
次に対象のリポジトリで初期化をおこないます。下記のコマンドを実行するとaqua.yaml
が生成されます。
$ aqua init
次にaqua g
コマンドでインストールしたいツールを検索し、aqua.yaml
に追加していきます。
$ aqua g >> aqua.yaml
最終的なaqua.yaml
は以下のような内容になりました。
---
# aqua - Declarative CLI Version Manager
# https://aquaproj.github.io/
registries:
- type: standard
ref: v0.13.1 # renovate: depName=aquaproj/aqua-registry
packages:
- name: kubernetes/kubectl@v1.23.0
- name: kubernetes-sigs/kubebuilder@v3.2.0
- name: kubernetes-sigs/kustomize@kustomize/v4.4.1
- name: kubernetes-sigs/kind@v0.11.1
- name: tilt-dev/tilt@v0.23.4
- name: tilt-dev/ctlptl@v0.7.0
ローカルで開発する場合は、以下のコマンドを実行することでCLIツールが利用できるようになります。
$ aqua i -l
GitHub ActionsでCLIツールのセットアップ
続いて、GitHub ActionsでCLIツールをセットアップします。
Actionが用意されているのでこれを利用しましょう。
以下のように、uses: aquaproj/aqua-installer
と記述するだけで、aqua.yaml
に記述したツールがインストールされます。
name: CI
jobs:
test:
name: Test
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: aquaproj/aqua-installer@v0.6.0
with:
aqua_version: v0.10.0
- run: make test
ツールのパスはGITHUB_PATH
環境変数に追加されているので、以降のステップではkubectlやkustomizeなどのCLIが実行できます。
CLIツールのキャッシュ
CIを実行するたびにCLIツールをダウンロードしていると、実行時間が長くなることもあるでしょう。
そこで一度ダウンロードしたツールはキャッシュしておきます。
name: CI
jobs:
test:
name: Test
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Cache Tools
id: cache-tools
uses: actions/cache@v2
with:
path: ~/.local/share/aquaproj-aqua
key: cache-tools-${{ hashFiles('aqua.yaml') }}
- uses: aquaproj/aqua-installer@v0.6.0
with:
aqua_version: v0.10.0
aqua_opts: ""
- run: make test
このようにaqua.yaml
のハッシュ値をキーにして、~/.local/share/aquaproj-aqua
ディレクトリをキャッシュしておけば、CLIツールのバージョンが同一であればキャッシュが利用されるようになります。
また、aqua-installerではデフォルトでaqua i
コマンドに-l
オプション[1]が付与されており、実際にツールを利用するまでダウンロードが遅延されるようになっています。
そのためキャッシュを利用する場合は、aqua_opts
に空文字を指定して-l
オプションを取り除くようにしておきます。
ただし-l
オプションを取り除くと、CI内で利用していないツールもダウンロードされてしまうので、余計に時間がかかってしまう場合もあります。キャッシュの有無は状況に応じて使い分けるようにしてください。
Renovateによる自動更新
aquaはRenovateにも対応しています。
Renovateを導入済みであれば[2]、renovate.json
に以下のような設定を追加するだけです。
{
"extends": [
"config:base",
"github>aquaproj/aqua-renovate-config#0.1.8"
]
}
CLIツールの新しいバージョンがリリースされると、以下のようなPRが自動生成されます。
これをマージするだけで、CLIツールの更新が完了します。
まとめ
aquaを利用することで、いいかんじにCLIツールの管理ができるようになりました。
GitHub ActionsやRenovateに対応しているので非常に導入しやすいですね。
以下のリポジトリにaquaを利用したツール管理の仕組みを取り入れたので、よろしければ参考にしてみてください。
-
詳しくは以下のページを参照: https://aquaproj.github.io/docs/tutorial-basics/install-only-link ↩︎
-
Renovateの導入方法については公式ページをご覧ください: https://github.com/marketplace/renovate ↩︎
Discussion
素晴らしい記事をありがとうございます!一点だけ訂正させてください。
aqua-installer の GitHub Actions の input は v0.4.0 で
version
からaqua_version
に変更されました。これは、 Renovate によって aqua を自動で update するためです。
GitHub Actions は input の名前が間違っていていも warning を出力するだけで失敗してくれません。
そのため version の値に関わらず、デフォルトで aqua の最新バージョンが使われてしまいます。
以下は
version: v0.8.11
を指定しているにも関わらず最新の v0.8.13 が使われてしまっている例です。ご指摘ありがとうございます!
修正しておきます。
CLIツールのキャッシュ
に少々問題があることに気づきました。if: steps.cache-tools.outputs.cache-hit != 'true'
を消せば正常に動くはずです。これがなくても aqua はツールがキャッシュに含まれている場合、インストールがスキップされるので install はすぐ終わるはずです(試しにローカルで
aqua i
を2回連続で実行してみれば、2回目が即座に終わるのが確認できるはずです)。aqua でインストールしたツールを実行するには、 aqua 自体が必要です。
これはツールの実行時に aqua が設定ファイルを読んで動的にどのツールのどのバージョンを実行するか決めるからです。
aqua の仕組みに関しては https://aquaproj.github.io/docs/reference/lazy-install が参考になるかもしれません。
そして aqua-installer はデフォルトで /usr/local/bin/aqua に aqua をインストールするので、 aqua はキャッシュには含まれません。
aqua-installer の実行をスキップすると、 aqua 自体がインストールされないので、後続のステップでツールを実行しようとしても実行できません。
なるほど。
確かに
if: steps.cache-tools.outputs.cache-hit != 'true'
は必要なさそうですね。ただ、aqua-installerを実行しなくてもキャッシュから読み出したツールは実行できているようです。
aqua本体がなくても、aqua-proxyがあればツールの実行はできると思っていたのですが、そういうわけではないのでしょうか?
いや、ないはずです。なぜなら aqua-proxy が
aqua exec
を実行しているからです。aqua-installer が skip されると GITHUB_PATH に ~/.aqua/bin が追加されないので、 aqua でインストールしたツールが呼ばれません。
GitHub Actions の ubuntu には kubectl や kind などを含め様々なツールがインストールされているので、それが使われていると思われます。
ありがとうございます。
確かに手元の環境で試してみたところaquaなしでは動きませんでした。
ブログの内容は修正しました。
テストが通ってたのは、使ってるツールが最初からインストール済みだったんですね…😓
aqua-installerを呼び出さないと、GITHUB_PATHも追加されないですね…。
あとキャッシュする場合の注意点としては、
aqua-installer はデフォルトで
-l
option をつけてaqua i
を実行します。-l
はシンボリックリンクだけ作ってツールのダウンロードをスキップするオプションです(ツールの実行時に自動でインストールされます)。-l
option について: https://aquaproj.github.io/docs/tutorial-basics/install-only-linkなのでキャッシュが生成される build でたまたまあるツールが実行されなかった場合、そのツールはキャッシュされないので、キャッシュが効かない場合があります。
確実にキャッシュが効くようにするには
-l
option を取る必要がありますが、-l
option を取ると必要ないツールまで余計にインストールされる場合もあるし、キャッシュサイズが大きくなる場合もあるので、どうすべきか一概には言えない気もします。
個人的には最近はキャッシュせずに
-l
オプションをつけるようにしていますが、これがベストかは分かりません。ユースケースにもよるかもしれません。
なるほどー。
ダウンロード時間がそれほど長くないのであれば、
-l
オプションで毎回インストールしてもよさそうですね。aqua v0.10.0 がリリースされました。
デフォルトの install 先が変わり、 XDG Base Directory Specification に従うようになりました。
なので、 cache する場合は、 cache するディレクトリのパスを修正してください。
ありがとうございます。修正しておきました。