terraform / packer / kubectl などのコマンドラインツールのバージョンを環境変数から指定できるラッパーコマンド versenv を作った
## まえがき
複数のプロジェクトにまたがって DevOps していると、以下のような状況によく出くわします。
- プロジェクト A は Kubernetes 1.23 使ってるけど、プロジェクト B はまだ 1.19 使ってる
- プロジェクト A は Terraform 1.2.5 使ってるけど、プロジェクト B はまだ 0.15.5 使ってる
- A は eksctl 0.107.0 使ってるけど、 B はまだ 0.91.0 使ってる
- Helm が…
- Packer が…
このような状況に苦労せず対処できるように、 versenv というツールを作りました。
## versenv とは
> https://github.com/versenv/versenv
> versenv/versenv: versenv is a set of wrapper scripts to simplify the installation and versioning of executables such as kubectl, Terraform and Packer.
[versenv](https://github.com/versenv/versenv) は、 terraform / packer / kubectl などのコマンドラインツールのバージョンを環境変数から指定できるラッパースクリプト集です。
例えば terraform 1.0.2 と 1.2.6 を切り替えたい場合、以下だけでそれが可能です。
```console
$ # terraform 用 versenv スクリプトをダウンロード
$ curl --tlsv1.2 -#fLR https://raw.githubusercontent.com/versenv/versenv/HEAD/bin/terraform -o ./terraform && chmod +x ./terraform
$ # terraform v1.0.2 を実行
$ TERRAFORM_VERSION=1.0.2 ./terraform version
Terraform v1.0.2
on darwin_arm64
$ # terraform v1.2.6 を実行
$ TERRAFORM_VERSION=1.2.6 ./terraform version
Terraform v1.2.6
on darwin_arm64
```
また、 versenv スクリプトを実行した際、指定したバージョンのバイナリが存在しない場合、自動でそれをダウンロードします。
```console
$ TERRAFORM_VERSION=1.2.6 terraform version
2022-08-09T15:45:59+09:00 [ NOTICE] Download https://releases.hashicorp.com/terraform/1.2.6/terraform_1.2.6_darwin_arm64.zip
2022-08-09T15:45:59+09:00 [ INFO] $ curl --tlsv1.2 --connect-timeout 2 --progress-bar -fLR https://releases.hashicorp.com/terraform/1.2.6/terraform_1.2.6_darwin_arm64.zip -o /Users/ginokent/.cache/versenv/terraform/1.2.6/tmp/terraform_1.2.6_darwin_arm64.zip
######################################################################################################################################################################################################### 100.0%
2022-08-09T15:46:01+09:00 [ NOTICE] Install /Users/ginokent/.cache/versenv/terraform/1.2.6/tmp/terraform_1.2.6_darwin_arm64.zip to /Users/ginokent/.cache/versenv/terraform/1.2.6/bin/terraform
2022-08-09T15:46:01+09:00 [ INFO] $ bash -c 'unzip -p -o "/Users/ginokent/.cache/versenv/terraform/1.2.6/tmp/terraform_1.2.6_darwin_arm64.zip" "terraform" > "/Users/ginokent/.cache/versenv/terraform/1.2.6/tmp/terraform"'
2022-08-09T15:46:01+09:00 [ INFO] $ mv -f /Users/ginokent/.cache/versenv/terraform/1.2.6/tmp/terraform /Users/ginokent/.cache/versenv/terraform/1.2.6/bin/terraform
2022-08-09T15:46:01+09:00 [ INFO] $ chmod +x /Users/ginokent/.cache/versenv/terraform/1.2.6/bin/terraform
Terraform v1.2.6
on darwin_arm64
```
2022-08-07 時点で、以下をサポートしています。
- direnv
- eksctl
- fzf
- ghq
- golangci-lint
- helm
- kubectl
- packer
- stern
- terraform
## versenv の目指す世界観
versenv は、 DevOps リポジトリの `bin` ディレクトリなどに copy & paste & git commit しておいて、 **_`git pull` さえしたら他のセットアップは一切不要で指定バージョンのコマンドが使える_** という世界観を目指しています。
そのため versenv スクリプトは、 Git リポジトリにそのまま放り込んで問題ないように非常に薄い bash スクリプトになっています。例えば、 terraform の versenv スクリプトは [242 行の bash スクリプト](https://github.com/versenv/versenv/blob/main/bin/terraform) になっています。
また versenv は、環境変数でバージョンを切り替えるという仕組み上、 [direnv](https://github.com/direnv/direnv) と非常に相性のいいツールです。
DevOps リポジトリに、以下のように `.envrc` ファイルをコミットしておけば、そのリポジトリに `cd` しさえすればそのバージョンのコマンドが使える、という状態を実現できます。
```console
$ cat -n .envrc
1 # リポジトリの bin 配下に versenv スクリプトを配置しておき、ここで PATH に追加する。
2 export PATH="$(git rev-parse --show-toplevel)/bin:$PATH"
3 # バージョンを指定
4 export KUBECTL_VERSION=1.24.3
5 export TERRAFORM_VERSION=1.2.6
$ # 環境変数を読み込み
$ direnv allow
direnv: loading ~/go/src/github.com/you/DevOps/.envrc
direnv: export +KUBECTL_VERSION +TERRAFORM_VERSION ~PATH
$ # kubectl v1.24.3 が利用されている
$ kubectl version --client=true
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.3", GitCommit:"aef86a93758dc3cb2c658dd9657ab4ad4afc21cb", GitTreeState:"clean", BuildDate:"2022-07-13T14:30:46Z", GoVersion:"go1.18.3", Compiler:"gc", Platform:"darwin/arm64"}
Kustomize Version: v4.5.4
$ # terraform v1.2.6 が利用されている
$ terraform version
Terraform v1.2.6
on darwin_arm64
```
## インストール方法
インストールは、 versenv リポジトリの bin ディレクトリから必要なコマンドラインツール用スクリプトをダウンロードして、任意の場所に設置するだけです。
```
$ # terraform 用 versenv スクリプトを ./bin ディレクトリにインストール
$ curl --tlsv1.2 -#fLR https://raw.githubusercontent.com/versenv/versenv/HEAD/bin/terraform -o ./bin/terraform && chmod +x ./bin/terraform
```
また、インストールを多少楽にするためのスクリプト [install.sh](https://github.com/versenv/versenv/blob/main/install.sh) を用意しています。
以下は、 `./bin` ディレクトリに `kubectl` / `packer` / `terraform` の 3 種類のスクリプトをインストールする例です。
```console
$ curl --tlsv1.2 -fLRSs https://raw.githubusercontent.com/versenv/versenv/HEAD/install.sh | VERSENV_SCRIPTS=kubectl,packer,terraform VERSENV_PATH=./bin bash
2022-08-09T16:34:57+09:00 [ NOTICE] Start downloading versenv scripts (kubectl packer terraform) to ./bin
2022-08-09T16:34:57+09:00 [ INFO] $ mkdir -p ./bin
2022-08-09T16:34:57+09:00 [ INFO] $ curl --tlsv1.2 --connect-timeout 2 --progress-bar -fLR https://raw.githubusercontent.com/versenv/versenv/HEAD/bin/kubectl -o ./bin/kubectl
######################################################################## 100.0%
2022-08-09T16:34:57+09:00 [ INFO] $ curl --tlsv1.2 --connect-timeout 2 --progress-bar -fLR https://raw.githubusercontent.com/versenv/versenv/HEAD/bin/packer -o ./bin/packer
######################################################################## 100.0%
2022-08-09T16:34:58+09:00 [ INFO] $ curl --tlsv1.2 --connect-timeout 2 --progress-bar -fLR https://raw.githubusercontent.com/versenv/versenv/HEAD/bin/terraform -o ./bin/terraform
######################################################################## 100.0%
2022-08-09T16:34:58+09:00 [ NOTICE] Complete!
```
## あとがき
versenv を使うようになって以来、些事に時間を取られることがなくなって非常に DevOps が楽になりました。
拙作ではありますが、最低限おすすめできるものになってはいるかなと思います。