2022.11.28[Mon]

GCP Cloud Build で普通のVMにrsyncする

  • CI/CD

目次

こんにちは。Webエンジニアの茄子です。

GCP Cloud Buildで、ファイルを直接デプロイする際、Cloud Storageには gsutil rsync、Compute Engineには gcloud compute scp が利用できますが、Compute Engine へのrsyncはCloud Buildの標準としては用意されていません。今回、普通のVMにrsyncをしたいケースがあったため、方法と注意点を紹介します。

環境

gcloud: core 2022.08.26 Google Cloud SDK 400.0.0 

前提

・ビルド&デプロイを行いたいアプリケーション等のレポジトリがある
・gcloud をインストール済み
・Cloud Buildの基本的な使い方 (yamlファイル, step, ビルダー) を理解している

上記3点を完了していることを前提として進めます。
Cloud Buildのガイドはこちら https://cloud.google.com/build/docs/automate-builds?hl=ja

rsyncビルダーと問題点

rsyncはコミュニティ提供のビルダーから利用できます。
「コミュニティ提供のビルダーとカスタム ビルダーの使用」( https://cloud.google.com/build/docs/configuring-builds/use-community-and-custom-builders?hl=ja ) ページのガイドに従って rsync ビルダーを作成し、プロジェクトにsubmitすることで、Cloud Buildのビルドステップとして利用可能になります。しかしながら、このrsyncビルダーには2点問題があります。

1. -e オプションが効かない

READMEのサンプルargsに書いてあるにも関わらず、sshのオプションを指定する -e が効きません。ここでの主な問題は -i による鍵の指定ができないことと、StrictHostKeyChecking=no とできないためプロンプトが出てしまうことです。ちなみに、rsyncから渡されるものはダメですが、sshを直接使う場合は問題ないようです。

2. --exclude が効かない 

--exclude/include オプションがなぜか効きません。Cloud Buildでは /workspace に展開されたレポジトリのファイルを元にステップを進めていきますが、その中には送信したくないファイルもあるので必要になります。

これらの問題を解消しつつ、rsyncを行う手順を解説します。
解説は例として、目的のサーバーのIPアドレス X0.0.172.56 、ubuntuユーザーの /home/ubuntu/your-app-dist/ ディレクトリにrsyncするという仮定で進めます。

下準備

ビルダー作成の前に、下準備としてCloud Build上で必要になる鍵を登録・配置しておきます。

キーペアの作成

接続に使用する鍵を作成します。既に今回用の鍵がある方は必要ありません。(アルゴリズム等、必要に応じて変更してください。)

ssh-keygen -t rsa -b 4096 -C "your-email@address.jp"

Secret Managerに秘密鍵を登録

公式ドキュメント: https://cloud.google.com/build/docs/securing-builds/use-secrets?hl=ja
Secret Managerに登録することで、Cloud Buildの中で鍵を利用することができます。GCPでSecret Managerを開き、上部の 「+シークレットを作成」ボタンから鍵を登録します。「シークレットの値」は、先程のキーペアの秘密鍵(.pubではない方)を貼り付けて下さい。細かい設定は基本デフォルトで問題ありません。

行き先のサーバーに公開鍵の設置

行き先のサーバーに公開鍵を設置します。先程のキーペアの.pubファイルの中身をコピーし、行き先のサーバーの /home/ubuntu/.ssh/authorized_keys に追加します。

行き先サーバーのホストを取得(任意)

無視することも可能ですが、より望ましいやり方として接続先ホストキーを取得し予め known_hosts に入れておくこともできます。以下のコマンドでそのための出力を得られます。後ほど使います。

ssh-keyscan -t ecdsa X0.0.172.56

rsyncビルダーを作成・問題点1の解消

まず、ドキュメント通りに community-builderをcloneします。

git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git

ドキュメントではこのままビルド&プッシュするのですが、冒頭の問題点1の解消の為ここでひと手間加えます。 ssh -e の問題を避ける為に、行き先のホスト情報をビルダーの設定ファイルに入れてしまいます。
以下の内容で ssh_config というファイルを用意します。 ( cloud-builders-community/rsync/ssh_config )

Host your-target-host
HostName X0.0.172.56
User ubuntu
IdentityFile "/workspace/<Secret Managerに登録した鍵>"
UserKnownHostsFile /dev/null
StrictHostKeyChecking no

「行き先サーバーのホストを取得(任意)」をやっている場合、UserKnownHostsFile、StrictHostKeyChecking の二行は不要です。また、その場合 known_hosts ファイルも作成します。中身は先程の ssh-keyscan の出力値です。(例↓)

X0.0.172.56 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPi3wZEh3zzECNTHUteHRoTwweo32nRhTriGRVgqitsm2SYdmfpziCSGL9XX3F7ptAZwe048jVbcdPqoDlaU=

次にDockerfileを変更します。

FROM launcher.gcr.io/google/ubuntu16_04

RUN apt-get -q update && \
  apt-get install -qqy rsync ssh 

## ↓この二行を追加 
COPY ssh_config /etc/ssh/ssh_config 
RUN chmod 644 /etc/ssh/ssh_config 

## 「行き先サーバーのホストを取得(任意)」をやっている場合、この二行も追加 
COPY known_hosts /root/.ssh/known_hosts 
RUN chmod 600 /root/.ssh/known_hosts 

ENTRYPOINT [ "rsync" ]

この状態で、ビルダーをsubmitします。

cd cloud-builders-community/rsync
gcloud builds submit 

# (ガイドではこの後クローンしたレポジトリを消すコマンドが入っていますが、無理に消す必要はありません。勿論、消してもいいですが。 )

これで、rsyncビルダーがCloud Buildで利用できるようになりました。

設定ファイルの編集・問題点2の解消

ここから、アプリケーションのレポジトリの方を変更していきます。
冒頭の問題点2は、コマンドラインオプションではなくファイルで指定するようにするとうまく反映されます。そのための送信から除外するファイル・フォルダのリストを作成します。中身は送信先のサーバーで必要無いファイルやフォルダを羅列したものです。ファイル名はなんでもいいですが、今回は cloudbuild.exclude とします。.env等、サーバー側で更新せず保持しなければいけないファイルも、--deleteによって消されないようにここに加える必要があります。(↓は一例)

.env
.git
*.md
cloudbuild.yaml
package-lock.json
yarn.lock
src

次に、cloudbuild.yamlにrysncのstepをこのように追加します。PROJECT_IDのところには、ビルダーをsubmitしたプロジェクトの名前が入ります。( 現在使用中のプロジェクトを確認するには gcloud config configurations list )

  - name: "gcr.io/$PROJECT_ID/rsync"
    args: [
        ## CI上でビルドすると常にタイムスタンプは新しいので、ビルドキャッシュを使用しない場合はchecksumにします。
        --checksum,
        ## tがあるとタイムスタンプによってすべて更新されてしまうため、抜いておきます。(= -aを使わない)
        "-rlpgoDhmv",
        "--delete",
        "--exclude-from=/workspace/cloudbuild.exclude",
        # お好みで
        # "--progress", 
        # "-n",
        "./",
        "your-target-host:/home/ubuntu/your-app-dist/",
      ]

確認

全て完了したら、アプリケーションのレポジトリにプッシュし、Cloud Buildを発火させて確認します。ついでに適当なファイルに一つ変更を加えておきます。

Cloud Buildのログを確認し、rsyncが完了していて変更したファイルがリストアップされていれば成功です。

何かエラーが出るときは、手前に下記のように接続をテストするステップを追加して確認してみてください。

  - name: "gcr.io/$PROJECT_ID/rsync"
    entrypoint: ssh
    args: ["-v", "your-target-host", "exit"]

Share

Next.js 13 next/imageでサイズ指定せずにアスペクト比を保って表示するLexicalで自作プラグインを作りリッチテキストエディターをカスタマイズする