gcloudでアカウントを切り替えて使用するためのdockerを使った設定方法

# 概要

dockerにgcloudの設定ファイルを作ることで、複数アカウントを切り替えてGCEインスタンスにsshできるようにする。
この方法でいつもsshしているが構築方法を忘れてしまったため、メモ書きを残す。


# 背景
日常的に複数のgoogleアカウントを使用しており、GCPのインスタンスにsshするときにアカウントを切り替える必要があるため。
ホストマシンに設定を直置きするのではなく、設定ファイルをdocker volumeに押し込んでしまえば、ホストを汚さずにgcloud CLIを使えるようにできる。


# 対象者

* 複数のgoogleアカウントを使用している
* ホストマシンに設定を直置きしたくない
* ホストマシンにgcloud CLIをインストールしたくない

一応アカウントを1つしか使用していない場合でも有効な方法ではあります。
設定をdockerに置く必要がない方は、`gcloud config set`などで良いと思います。


# 結論

まずは結論から。
結果的に↓のようなコマンドでgcloudコマンドを実行することになります。

```
docker volume create gcloud-sshkey-volume-user1
docker run -it -v gcloud-sshkey-volume-user1:/root/.ssh --name gcloud-config-user1 gcr.io/google.com/cloudsdktool/cloud-sdk gcloud auth login
docker run --rm -it --volumes-from gcloud-config-user1 gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh
```

日本語にするとこんな感じです。

1. ssh鍵を格納するためのvolumeを作成
1. 上記volumeをマウントして認証情報を格納するためのコンテナを作成
1. 上記コンテナからvolumeをマウントしてgcloudコマンドを実行


# 過程

まずは何も考えずに実行してみます。

```shell
docker run --rm -it gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh --zone=us-west1-a --project myproject hoge@my-instance
WARNING: Could not open the configuration file: [/root/.config/gcloud/configurations/config_default].
ERROR: (gcloud.compute.ssh) You do not currently have an active account selected.
Please run:

  $ gcloud auth login

to obtain new credentials.

If you have already logged in with a different account:

    $ gcloud config set account ACCOUNT

to select an already authenticated account to use.
```

設定が見つからないから `gcloud auth login` を実行しろとのことです。

```shell
docker run --rm -it gcr.io/google.com/cloudsdktool/cloud-sdk gcloud auth login
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?response_type=code&..............

Enter verification code: ......................................................

You are now logged in as [username@gmail.com].
Your current project is [None].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID


To take a quick anonymous survey, run:
  $ gcloud survey
```

言われた通りに実行しました。さあ、改めて`compute ssh`。

```shell
docker run --rm -it gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh --zone=us-west1-a --project myproject hoge@my-instance
WARNING: Could not open the configuration file: [/root/.config/gcloud/configurations/config_default].
ERROR: (gcloud.compute.ssh) You do not currently have an active account selected.
Please run:（以下省略）
```

結果は同じ。当たり前ですね、これで生成された設定ファイルはコンテナとともに消え去ってます。
では、どこにできているのかを見てみましょう。

```shell
docker run --rm -it gcr.io/google.com/cloudsdktool/cloud-sdk bash
root@08d9d117b493:/# gcloud auth login
Go to the following link in your browser:

    https://accounts.google.com/o/oauth2/auth?...................

Enter verification code: ........................................

You are now logged in as [username@gmail.com].
Your current project is [None].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID


To take a quick anonymous survey, run:
  $ gcloud survey

root@08d9d117b493:~# ls -la ~/.config/gcloud
total 56
drwxr-xr-x 5 root root  4096 Sep 28 04:25 .
drwxr-xr-x 3 root root  4096 Sep 28 04:24 ..
-rw-r--r-- 1 root root    36 Sep 28 04:25 .last_survey_prompt.yaml
-rw------- 1 root root 12288 Sep 28 04:25 access_tokens.db
-rw-r--r-- 1 root root     7 Sep 28 04:25 active_config
-rw-r--r-- 1 root root     0 Sep 28 04:25 config_sentinel
drwxr-xr-x 2 root root  4096 Sep 28 04:25 configurations
-rw------- 1 root root 12288 Sep 28 04:25 credentials.db
-rw------- 1 root root     5 Sep 28 04:24 gce
drwxr-xr-x 3 root root  4096 Sep 28 04:25 legacy_credentials
drwxr-xr-x 3 root root  4096 Sep 28 04:24 logs
```

`gcloud`の設定は`/root/.config/gcloud`に保存されています。
なので、設定が消えないように`/root/.config/gcloud`にvolumeをマウントしましょう。

```shell
$ docker volume create gcloud-config-volume-user1
gcloud-config-volume-user1
```
`gcloud-config-volume-user1` というvolumeを作成しました。
これをマウントして再度`gcloud auth login`を行います。

```shell
% docker run --rm -it -v gcloud-config-volume-user1:/root/.config/gcloud gcr.io/google.com/cloudsdktool/cloud-sdk bash

root@ada340aff4ba:/# ls -la /root/.config/gcloud
total 16
drwxr-xr-x 3 root root 4096 Sep 28 06:42 .
drwxr-xr-x 3 root root 4096 Sep 28 06:42 ..
-rw-r--r-- 1 root root   37 Dec 15  2020 .last_survey_prompt.yaml
drwxr-xr-x 3 root root 4096 Sep 28 06:42 logs

root@ada340aff4ba:/# gcloud auth login
（省略）

root@ada340aff4ba:/# ls -la /root/.config/gcloud
total 56
drwxr-xr-x 5 root root  4096 Sep 28 06:44 .
drwxr-xr-x 3 root root  4096 Sep 28 06:42 ..
-rw-r--r-- 1 root root    37 Sep 28 06:44 .last_survey_prompt.yaml
-rw------- 1 root root 12288 Sep 28 06:44 access_tokens.db
-rw-r--r-- 1 root root     7 Sep 28 06:44 active_config
-rw-r--r-- 1 root root     0 Sep 28 06:44 config_sentinel
drwxr-xr-x 2 root root  4096 Sep 28 06:44 configurations
-rw------- 1 root root 12288 Sep 28 06:44 credentials.db
-rw------- 1 root root     5 Sep 28 06:44 gce
drwxr-xr-x 3 root root  4096 Sep 28 06:44 legacy_credentials
drwxr-xr-x 3 root root  4096 Sep 28 06:44 logs

root@ada340aff4ba:/# exit
```

設定ファイルを生成したところで、一旦コンテナを作り直してみましょう。

```shell
% docker run --rm -it -v gcloud-config-volume-user1:/root/.config/gcloud gcr.io/google.com/cloudsdktool/cloud-sdk bash

root@00ccfd7340e0:/# ls -la /root/.config/gcloud
total 56
drwxr-xr-x 5 root root  4096 Sep 28 06:44 .
drwxr-xr-x 3 root root  4096 Sep 28 06:47 ..
-rw-r--r-- 1 root root    37 Sep 28 06:44 .last_survey_prompt.yaml
-rw------- 1 root root 12288 Sep 28 06:44 access_tokens.db
-rw-r--r-- 1 root root     7 Sep 28 06:44 active_config
-rw-r--r-- 1 root root     0 Sep 28 06:44 config_sentinel
drwxr-xr-x 2 root root  4096 Sep 28 06:44 configurations
-rw------- 1 root root 12288 Sep 28 06:44 credentials.db
-rw------- 1 root root     5 Sep 28 06:44 gce
drwxr-xr-x 3 root root  4096 Sep 28 06:44 legacy_credentials
drwxr-xr-x 3 root root  4096 Sep 28 06:44 logs
```

作り直しても設定ファイルが消えていないことが分かります。
それでは、最初の`gcloud compute ssh`にvolumeを追加してやり直してみましょう。

```shell
% docker run --rm -it -v gcloud-config-volume-user1:/root/.config/gcloud gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh --zone=us-west1-a --project myproject hoge@my-instance
WARNING: The private SSH key file for gcloud does not exist.
WARNING: The public SSH key file for gcloud does not exist.
WARNING: You do not have an SSH key for gcloud.
WARNING: SSH keygen will be executed to generate a key.
This tool needs to create the directory [/root/.ssh] before being able
 to generate SSH keys.

Do you want to continue (Y/n)?  Y

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/google_compute_engine.
Your public key has been saved in /root/.ssh/google_compute_engine.pub.

（略）
```

```shell
hoge@my-instance ~ $
```

無事にログインできました！🎉
しかし、これではsshするたびに鍵を生成することになってしまいます。
そこで、`/root/.ssh`もvolumeにしていきましょう。

```shell
% docker volume create gcloud-sshkey-volume-user1
gcloud-sshkey-volume-user1

% docker run --rm -it -v gcloud-config-volume-user1:/root/.config/gcloud -v gcloud-sshkey-volume-user1:/root/.ssh gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh --zone=us-west1-a --project myproject hoge@my-instance
```

これでssh鍵を一度生成すれば、その後はすぐに接続できるようになりました。
ただ、これでは長すぎて手打ちするのはしんどいですね。
そこで、`volume container`と呼ばれるものを使用して、少し簡潔にかけるようにしましょう。

1. さきほど作成したssh鍵を持つvolumeをマウントしたコンテナで`auth login`を行い、コンテナを削除しないで置いておく
2. 上記のコンテナからvolumeをマウントして、`gcloud　CLI`を使用する

という流れでやっていきます。

```shell
% docker run -it -v gcloud-sshkey-volume-user1:/root/.ssh --name gcloud-config-user1 gcr.io/google.com/cloudsdktool/cloud-sdk gcloud auth login

% docker run --rm -it --volumes-from gcloud-config-user1 gcr.io/google.com/cloudsdktool/cloud-sdk gcloud compute ssh
```

なぜこれでssh鍵の生成も要らず、`auth login`も必要ないのかは`docker inspect`でMountを確認してみると分かります。

まずは`--rm`オプションを削除してコンテナが破棄されないようにして、適当に`gcloud-sdk`という名前を付けて起動してみます。
その後、`docker inspect`でMountを確認しましょう。

```shell
% docker run --name gcloud-sdk --volumes-from gcloud-config-user1 gcr.io/google.com/cloudsdktool/cloud-sdk id

% docker inspect -f '{{json .Mounts}}' gcloud-sdk | jq
```

```json
[
  {
    "Type": "volume",
    "Name": "xxxxxxxxxxxxxxxxx",
    "Source": "/var/lib/docker/volumes/xxxxxxxxxxxxxxxxx/_data",
    "Destination": "/root/.config",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  },
  {
    "Type": "volume",
    "Name": "gcloud-sshkey-volume-user1",
    "Source": "/var/lib/docker/volumes/gcloud-sshkey-volume-user1/_data",
    "Destination": "/root/.ssh",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  },
  {
    "Type": "volume",
    "Name": "zzzzzzzzzzzzzz",
    "Source": "/var/lib/docker/volumes/zzzzzzzzzzzzzz/_data",
    "Destination": "/root/.kube",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]
```

実行中のコンテナでは3つのvolumeがマウントされていることが分かります。
まず、ssh鍵の生成が要らない件については`gcloud-sshkey-volume-user1`がマウントされているからですね。
そして、`auth login`が要らない件は`/root/.config`がマウントされているからです。
これはどこから来ているかというと、`gcloud-config-user1`の volume container を作成したときに指定しているイメージの`cloud-sdk`で`VOLUME命令`が指定されているからです。[ソース](https://github.com/GoogleCloudPlatform/cloud-sdk-docker/blob/master/Dockerfile#L48)

ということで、手打ちが現実的なレベルまで簡素化しつつdockerで完結できました。🚀