Cloud Build で リモートサーバーにSSH 接続してデプロイするビルドタスク

GWで世間はお休みモードですが、GCPは一生懸命動いててくれて大変助かります。ありがとう。

---

GCPのCloud Buildを利用して、普通のVPSなどにデプロイする際、ssh接続がしたくなることがある。こいつをCloud Buildで実現する際には、

* 秘密鍵をKMSで暗号化
* sshのknowns host を設定
* ビルドタスク内で秘密鍵を復号化
* 復号した鍵でssh接続する

以上のようなことが実現できれば良い。
こんなことができるビルドタスクを組んでみたので公開したいと思います。

ちょくちょくCloud Buildを運用で使ってますが、なにぶん手探りなので、
もっとこうしたほうがいい、こうするべきだ的なのありましたらご教授お願いします。
質問/苦情等ありましたらコメントへよろしくお願いします。

## 事前準備

* あらかじめ、対象のサーバーに接続できるか手元で試す。
  * （リモート作業で云々するのにそもそも元から接続できませんでしたってなるとガックリするので）
* [接続に利用した鍵をKMSで暗号化する](https://qiita.com/ideodora/items/979dccf069c9e976337b)
* [接続先の情報が入ったknown_hostsを用意する](https://qiita.com/ideodora/items/cfe4a9216eddfbe9e38b)
* [tarとsshが入ったイメージを作成してsubmitしておく](https://qiita.com/ideodora/items/2e888da49bcdfbfabf14)

## APIを有効化

下記のAPIを Google Cloud Platform Console で有効にする。

* Cloud Build API

## cloudbuild.yaml

```
steps:
# ①暗号鍵を復号化する
- id: decryptkey
  name: 'gcr.io/cloud-builders/gcloud'
  args:
    - kms
    - decrypt
    - --ciphertext-file=id_rsa_some_vps.encrypted
    - --plaintext-file=/root/.ssh/id_rsa_some_vps
    - --location=global
    - --keyring=deploy
    - --key=some_vps
  volumes:
    - name: 'ssh'
      path: /root/.ssh

# ②ssh接続用設定
- id: sshconfig
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: bash
  args:
    - '-c'
    - |
      # 鍵のパーミッション設定
      chmod 600 /root/.ssh/id_rsa_some_vps
      # ssh接続用configファイルの生成
      cat <<EOF >/root/.ssh/config
      Host somevps
      HostName xxx.xxx.xxx.xxx
      User deployer
      IdentityFile /root/.ssh/id_rsa_some_vps
      IdentitiesOnly yes
      EOF
      # known_hostsの設定
      mv known_hosts /root/.ssh/known_hosts
  volumes:
    - name: 'ssh'
      path: /root/.ssh

# ③デプロイ
- id: deploy
  name: gcr.io/$PROJECT_ID/tarssh
  dir: 'src'
  entrypoint: bash
  args:
    - '-c'
    - |
      tar cvz ./ | ssh somevps tar zxv -C /home/ubuntu/dist/
  volumes:
    - name: 'ssh'
      path: /root/.ssh
```

## ①暗号鍵を復号化する

イメージには **gcr.io/cloud-builders/gcloud** を利用
事前に暗号化したファイルを **--ciphertext-file** で指定
**--plaintext-file=/root/.ssh/{ファイル名}** 出力するファイル名はなんでもいいけど、あとでマウントできるようにボリュームのパスに含めるようにする。

```

...
volumes:
    - name: 'ssh'
      path: /root/.ssh
...
```

この場合 **/root/.ssh** 後続のタスクで、このボリュームをマウントするようにして、復号化した鍵を利用する
その他、KMSのオプションについては公式参照。

## ②ssh接続用設定

ここでは、各種ssh接続用の設定を入れていく。具体的には、

* 鍵のパーミッション設定
* ssh接続用configファイルの生成
* known_hostsの設定

をbashで実行する。

注意点としては、先のタスクで作った鍵を利用したいので、先のタスクでマウントしたボリュームを同様にこのタスクでもマウントするようにすること。

```
...
volumes:
    - name: 'ssh'
      path: /root/.ssh
...
```

イメージはシェルが動かせればなんでも良いので、とりあえず、先のタスクで利用した **gcr.io/cloud-builders/gcloud** を使う。別途イメージをpullしてくるビルド時間が節約できる（と思う）
shell自体はbashを **entrypoint** に指定すればいい。

```
...
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: bash
...
```

続けて、

```
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: bash
  args:
    - '-c'
    - |
      echo "some shell command here~"
      echo "more..."
```

のように、シェルで実行するコマンドを **args** に書けるのでよしなに。


## ③デプロイ

**tar** をssh接続で実行する。

イメージにはお手製のtarとsshが入っただけ(bashも）のイメージを事前にpushしておきそれを利用する。
**gcr.io/$PROJECT_ID/tarssh**

ここでも、ボリュームをマウントして参照できるようにしておく。

```
...
volumes:
    - name: 'ssh'
      path: /root/.ssh
...
```

## 感想

ビルドタスクで一時的なファイルの置き場として適当なボリュームを作って、それをマウントして持ち回ることで、
大概のタスクはできるのではと思われる。

ビルドタスク以外の部分にもTipsが必要そうなので別記事でまとめようと思う。