All Articles

Cloud BuildでRSpecを実行したときにつまづいた点

秘密鍵の受け渡し

RailsのRspecを実行する時に必要になるのがsecrets.ymlRAILS_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 testrspecが並列に実行されます。 ちなみに、waitFor: ['-']と記述すると他のステップを待たずに即実行されます。