Docker で十全に gcloud や aws 、cdk コマンドなどを使う方法

インフラエンジニア、 SRE などをしていると `gcloud` や `aws` を両方利用するようなことも多いと思います。

それぞれ python 環境に依存しているため、場合によってインストールやアップデート時に苦労したり、 普段 python を使わないがゆえに毎回「venv とは・・・」みたいな気持ちになることもあります。

そこで試しに本記事で紹介する方法で一通りのコマンドを Docker 化してみたところ便利だったので、共有します。

全体としては以下がポイントです

- aliasではなくシェルスクリプトを$PATHの通ったところに置く
- uid, gid を引き継ぐ
- 必要なディレクトリをもれなくマウントしておく
- ホストとコンテナ上のパスの違いを吸収する
- ユーザ、または非ユーザとして認証する場合の両方に対応する
- 公式イメージがないものは docker build も自動実行するようにしておく

aliasを使わないのは、別のコマンド、シェルスクリプト内から読んだ場合にも動作させるためです。

また、 docker や今回ご紹介した方法に限った話ではないですが、場合によって重要な情報にアクセスできるような認証情報をコンテナに渡すことになるため、信頼できないソースからビルドしたイメージやコマンドを実行しないようにだけ気をつけてください。

この記事では `aws`, `gcloud`, おまけで `cdk` について紹介します。

> この流れでなぜ　`terraform` がないの？と思われるかもしれませんが、シングルバイナリで完結するツールなので、ホストを汚さないというメリットがない分、それほど意味がないと思ったため紹介していません。
> とはいえ、インストール方法を統一できるという利点はありそうなので、興味がある方は試してみてください!

## gcloud

PATH の通った適当な場所に以下のような内容で bash スクリプトを置いておきます

```shell:$HOME/bin/gcloud
#!/usr/bin/env bash

docker run \
  -u `id -u`:`id -g` \
  -v ${HOME}/.config/gcloud:/home/cloudsdk/.config/gcloud \
  -v $(pwd):$(pwd) \
  --workdir $(pwd) -it --rm \
  gcr.io/google.com/cloudsdktool/cloud-sdk:latest gcloud "${@}"
```

```shell
chmod +x $HOME/bin/gcloud

export PATH=$HOME/bin:$PATH
```

これで、ホスト上の python 環境を触らずに、ホスト上に直接 `gcloud` コマンドをインストールしたような使用感が得られます。

```shell
$ gcloud auth login
$ gcloud auth list
$ gcloud config set account $ACCOUNT
# ...

#
# Service Accountもローカル同様に利用できます
#

$ gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS
$ gcloud auth list
# ...
```

`docker` で `gcloud` を実行する手順はよく Qiita でも話題になっていますが、完全にホスト上にインストールしたのと同じ使用感のものは見当たらなかったり、サービスアカウントが前提になっているものが多かったので、「以前試したけどうまくいかなかった！」という方はこの方法を試してみていただくといいかもしれませんね。

## awscli

awscli や AWS CDK の`aws` や `cdk` コマンドも同様に Docker 化しておくと、ホストを汚さずにすみ、バージョン管理も楽になったりするのでおすすめです。

`aws` コマンドの場合は以下のようにしておくと、 `aws eks update-kubeconfig` コマンドのように $HOME 以下 (`$HOME/.kube/config`)に書き込むようなコマンドにも対応できます。

```shell:$HOME/bin/aws
#!/usr/bin/env bash

docker run \
  -u `id -u`:`id -g` \
  -v ~/.aws:/aws \
  -v $(pwd):$(pwd) \
  --workdir $(pwd) --rm -it \
  -e AWS_CONFIG_FILE=/aws/config \
  -e AWS_SHARED_CREDENTIALS_FILE=/aws/credentials \
  -e AWS_DEFAULT_REGION \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_PROFILE \
  -e AWS_ROLE_ARN \
  -e AWS_WEB_IDENTITY_TOKEN_FILE \
  -e AWS_ROLE_SESSION_NAME \
  -e AWS_SESSION_TOKEN \
  -e KUBECONFIG=$(pwd)/aws/.kube/config \
  amazon/aws-cli:latest \
  "$@"
```

## おまけ: cdk

AWS CDK の `cdk` コマンドのように、公式にはイメージが配布されていないようなものについては、 `docker build` のワンライナーを添えておくと、普段どおりコマンドを打つだけでビルドと実行が可能なので便利です。

```shell:$HOME/bin/cdk
#!/usr/bin/env bash

tempdir=$(mktemp -d) || exit 1

cat <<DOCKERFILE | docker build $tempdir -t cdk -f -
FROM node:14

RUN npm install -g aws-cdk

RUN apt-get update -y && apt-get install less -y

RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    ./aws/install

ENTRYPOINT [ "cdk" ]
DOCKERFILE

docker run \
  -u `id -u`:`id -g` \
  -v ~/.aws:/aws \
  -v $(pwd):$(pwd) \
  --workdir $(pwd) --rm -it \
  -e AWS_CONFIG_FILE=/aws/config \
  -e AWS_SHARED_CREDENTIALS_FILE=/aws/credentials \
  -e AWS_DEFAULT_REGION \
  -e AWS_ACCESS_KEY_ID \
  -e AWS_SECRET_ACCESS_KEY \
  -e AWS_PROFILE \
  -e AWS_ROLE_ARN \
  -e AWS_WEB_IDENTITY_TOKEN_FILE \
  -e AWS_ROLE_SESSION_NAME \
  -e AWS_SESSION_TOKEN cdk "$@"
```

`cdk` コマンドのようにカレントディレクトリ以下のファイルを読み書きするようなコマンドの場合、 `-v $(pwd):$(pwd)` や `-u` オプションでカレントディレクトリ以下にカレントユーザと同じ uid, gid でアクセスできる点が効いてきます。