秘密鍵の受け渡し
RailsのRspecを実行する時に必要になるのがsecrets.yml
とRAILS_MASTER_KEY
です。
通常、Gitリポジトリに含まれない内容なのでCloud Buildを実行する時に渡してあげる必要があります。
Cloud BuildではKMSを利用します。 暗号化されたリソースの使用
KMS(Key Management Service)
暗号鍵のマネージドサービスです。
キーリングを作成します
gcloud kms keyrings create [KEYRING-NAME] \
--location=global
暗号鍵を作成します
gcloud kms keys create [KEY-NAME] \
--location=global \
--keyring=[KEYRING-NAME] \
--purpose=encryption
Cloud Buildサービスアカウントに暗号鍵へのアクセス権を付与します
gcloud kms keys add-iam-policy-binding \
[KEY-NAME] --location=global --keyring=[KEYRING-NAME] \
--member=serviceAccount:[SERVICE-ACCOUNT]@cloudbuild.gserviceaccount.com \
--role=roles/cloudkms.cryptoKeyDecrypter
上記コマンドを実行したところ、以下のエラーが発生しました。
ERROR: (gcloud.kms.keys.add-iam-policy-binding) PERMISSION_DENIED: Permission 'cloudkms.cryptoKeys.setIamPolicy' denied for resource 'projects/develop-xxx/locations/global/keyRings/rails-test/cryptoKeys/test'.
原因はAPIの権限がなかったため、GCPコンソールから権限を付与しました。
secrets.ymlを暗号化する
gcloud kms encrypt \
--plaintext-file=config/secrets.yml \
--ciphertext-file=config/secrets.cloudbuild.yml \
--location=global \
--keyring=[KEYRING-NAME] \
--key=[KEY-NAME]
secrets.yml.enc
だと名前が被るのでsecrets.cloudbuild.yml
にしました。
RAILS_MASTER_KEY
を暗号化する
echo -n $RAILS_MASTER_KEY | gcloud kms encrypt \
--plaintext-file=- \ # - reads from stdin
--ciphertext-file=- \ # - writes to stdout
--location=global \
--keyring=[KEYRING-NAME] \
--key=[KEY-NAME] | base64
cloudbuild.yaml
secrets:
- kmsKeyName: projects/[PROJECT-ID]/locations/global/keyRings/[KEYRING-NAME]/cryptoKeys/[KEY-NAME]
secretEnv:
RAILS_MASTER_KEY: <base64-encoded encrypted secret>
上記ファイルを使用して、Cloud Buildを実行したところ以下のエラーが発生しました。
ERROR: (gcloud.builds.submit) INVALID_ARGUMENT: invalid build: invalid .secrets field: secretEnv "RAILS_MASTER_KEY" is used without being defined
試しに、RAILSENVMASTERを使用している箇所を消してみたところ、次は以下のエラーが発生しました。
ERROR: (gcloud.builds.submit) INVALID_ARGUMENT: invalid build: invalid .secrets field: secretEnv "RAILSMasterKey" is defined without being used
エラー内容を見てみると、RAILSMasterKey
となっていてアンスコが消えてました。
ネットで色々調べてみたところ、glcoudのバグのようでした。
https://github.com/GoogleCloudPlatform/cloud-builders/issues/413
既に修正済みのようでしたので、gcloudをアップデートして解消しました。
テストに必要なミドルウェア
RSpecのテストにMySQLとRedisが必要だったので、docker/composeを利用してコンテナを起動しました。
docker-compose.yml
version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
redis:
image: redis:alpine
ports:
- 6379:6379
networks:
default:
external:
name: cloudbuild
networksの指定がないとコンテナにアクセスできないので注意です。
cloudbuild.yaml
- name: 'docker/compose:1.23.2'
args: ['-f', 'docker-compose.yml',
'up', '-d']
高速化
Dockerイメージのキャッシュを利用する
--cache-from
を指定するとキャッシュが利用できます。
- name: 'gcr.io/cloud-builders/docker'
args: ['build',
'-t', 'gcr.io/$PROJECT_ID/rails-test',
'--cache-from', 'gcr.io/$PROJECT_ID/rails-test',
'.']
ステップを並列で動かす
waitFor
を利用することで並列にステップを実行することができます。
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build',
'-t', 'gcr.io/$PROJECT_ID/rails-test',
'.']
id: 'setup'
- name: 'gcr.io/$PROJECT_ID/rails-test'
entrypoint: 'sh'
args: ['-c', 'yarn test']
waitFor: ['setup']
- name: 'gcr.io/$PROJECT_ID/rails-test'
entrypoint: 'sh'
args: ['-c', 'rspec']
waitFor: ['setup']
上記のように書くとyarn test
とrspec
が並列に実行されます。
ちなみに、waitFor: ['-']
と記述すると他のステップを待たずに即実行されます。