notebook

都内でWEB系エンジニアやってます。

CircleCIでgcloudを使えるようにする(+Terraform)

この記事はCircleCI Advent Calendar 2020の13日目の記事です

2.1以上であればOrbを使うとechoで特定のファイルに書き出して…とかそういうのをよしなにやってくれるので楽できる

CircleCI Developer Hub - circleci/gcp-cli

circleci.com

準備

サービスアカウントは事前に作っておく、鍵ファイルはJSONで用意する

GCLOUD_SERVICE_KEYにJSONのキーの内容をそのまま入れる

他の記事などでbase64でエンコードしたものを入れるというのもよく見るが

少なくとも今回のOrbを使ううえではそのまま入れることでサービスアカウントのActivateが行える

あとはGOOGLE_PROJECT_IDを入力しておく

GOOGLE_COMPUTE_ZONE or GOOGLE_COMPUTE_REGIONどちらかの指定も必要

無いと次のように怒られる

if [[ -n $GOOGLE_COMPUTE_ZONE ]]; then
  gcloud --quiet config set compute/zone $GOOGLE_COMPUTE_ZONE
elif [[ -n $GOOGLE_COMPUTE_REGION ]]; then
  gcloud --quiet config set compute/region $GOOGLE_COMPUTE_REGION
else
  echo "ERROR: Set GOOGLE_COMPUTE_ZONE or GOOGLE_COMPUTE_REGION env variable" >&2
  exit 1
fi

なので最低限下記の環境変数が必要

  • GCLOUD_SERVICE_KEY
  • GOOGLE_PROJECT_ID
  • GOOGLE_COMPUTE_ZONE or GOOGLE_COMPUTE_REGION

動かしてみる

とりあえず最低限の設定を記述して動かしてみる

  • .circleci/config.yml
version: 2.1

orbs:
  gcp-cli: circleci/gcp-cli@2.1.0

jobs:
  hello:
    executor: gcp-cli/default
    steps:
      - checkout
      - gcp-cli/install
      - gcp-cli/initialize
      - run:
          name: hello
          command: |
            gcloud auth list
            gsutil ls gs://hoge/fuga
            bq query --format pretty "SELECT CURRENT_DATE()"

workflows:
  gcp_command:
    jobs:
      - hello
  • 結果
Credentialed Accounts
ACTIVE  ACCOUNT
*       hoge@******************.iam.gserviceaccount.com

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

gs://hoge/fuga/month=2020-11-01/
gs://hoge/fuga/month=2020-12-01/

Welcome to BigQuery! This script will walk you through the 
process of initializing your .bigqueryrc configuration file.

First, we need to set up your credentials if they do not 
already exist.

Credential creation complete. Now we will select a default project.

List of projects:
+---+--------------------+--------------+
| # |     projectId      | friendlyName |
+---+--------------------+--------------+
| 1 | ****************** | hgoe         |
+---+--------------------+--------------+
Found only one project, setting ****************** as the default.

BigQuery configuration complete! Type "bq" to get started.

Waiting on bqjob_r1bc557e52c29f9_0000017641d964ef_1 ... (0s) Current status: DONE   
+------------+
|    f0_     |
+------------+
| 2020-12-08 |
+------------+
CircleCI received exit code 0

実行できた

Orbの中身を見たらサービスアカウントでのActivateや特定のファイルにキー情報を入れるといった処理を行ってくれているよう

gcp-cli/install
gcp-cli/initialize

の2つをstepsに入れるだけでgcloudコマンドが使えるようになる

install_and_initialize_cliというJobも用意されているようなのでworkflowの部分で依存Jobに指定しても良さそうだが今回試していない

TerraformからGCPを扱う場合

Google Provider Configuration Reference | Guides | hashicorp/google | Terraform Registry

https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#full-referenceregistry.terraform.io

特定の環境変数にキーのファイルパスをいれれば良いのでOrbの中身を読んでどのパスにキーの情報が入っているかをみてそのパスを設定してあげればOK

ということで単純にOrbを使っているのであれば${HOME}/gcloud-service-key.jsonとなる

Terraform側では上記リンクにあるように

  • GOOGLE_CREDENTIALS
  • GOOGLE_CLOUD_KEYFILE_JSON
  • GCLOUD_KEYFILE_JSON

の順に見ていくようなので好きなものに設定すれば良い

Orbで認証情報をセットアップしてTerraform経由でGCPのリソースにアクセスできるかどうかだけを確認したいので次のようなファイルで既存にあるGCSのオブジェクトを参照させるようにした

tfstateもローカルにしてしまっている

  • terraform/main.tf
terraform {
  required_version = "0.14.0"
  required_providers {
    google = {
      version = "~> 3.45.0"
    }
  }
}

variable project {}

provider google {
  project = var.project
  region  = "asia-northeast1"
}

data "google_storage_bucket_object" "sample" {
  name = "sample.txt"
  bucket = "hoge"
}

output "sample_object_hash" {
  value = data.google_storage_bucket_object.sample.md5hash
}
  • .circleci/config.yml
version: 2.1

orbs:
  gcp-cli: circleci/gcp-cli@2.1.0

jobs:
  apply:
    executor: gcp-cli/default
    steps:
      - checkout
      - gcp-cli/install
      - gcp-cli/initialize
      - run:
          name: install terraform
          command: |
            curl -LO https://releases.hashicorp.com/terraform/0.14.0/terraform_0.14.0_linux_amd64.zip
            sudo unzip ./terraform_0.14.0_linux_amd64.zip -d /usr/local/bin/
      - run:
          name: terraform apply
          command: |
            cd terraform
            export GOOGLE_CREDENTIALS=${HOME}/gcloud-service-key.json
            terraform init
            terraform apply -var="project=${GOOGLE_PROJECT_ID}" -auto-approve
workflows:
  deploy:
    jobs:
      - apply

CircleCI経由で実行してみる

  • 結果
Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/google versions matching "~> 3.45.0"...
- Installing hashicorp/google v3.45.0...
- Installed hashicorp/google v3.45.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

sample_object_hash = "UXeljcZcihTckMads7890g=="

参照しているだけなのでadded,changed,destroyedともないが読み取れていることはわかった

manual approval

planapplyの間にapprovalを挟めばデプロイ前にplanで確認してからデプロイするといったことも可能になる

  • .circleci/config.yml
version: 2.1

orbs:
  gcp-cli: circleci/gcp-cli@2.1.0

commands:
  install_terraform:
    steps:
      - run:
          name: install terraform
          command: |
            curl -LO https://releases.hashicorp.com/terraform/0.14.0/terraform_0.14.0_linux_amd64.zip
            sudo unzip ./terraform_0.14.0_linux_amd64.zip -d /usr/local/bin/

jobs:
  setup_and_plan:
    executor: gcp-cli/default
    steps:
      - checkout
      - gcp-cli/install
      - gcp-cli/initialize
      - run:
          name: hello
          command: |
            gcloud auth list
            gsutil ls gs://swfz-timetracker/toggl
            bq query --format pretty "SELECT CURRENT_DATE()"
            ls ${HOME}
      - install_terraform
      - run:
          name: terraform plan
          command: |
            cd terraform
            export GOOGLE_CREDENTIALS=${HOME}/gcloud-service-key.json
            terraform init
            terraform plan -var="project=${GOOGLE_PROJECT_ID}"
  apply:
    executor: gcp-cli/default
    steps:
      - checkout
      - gcp-cli/install
      - gcp-cli/initialize
      - install_terraform
      - run:
          name: terraform apply
          command: |
            cd terraform
            export GOOGLE_CREDENTIALS=${HOME}/gcloud-service-key.json
            terraform init
            terraform apply -var="project=${GOOGLE_PROJECT_ID}" -auto-approve
workflows:
  deploy:
    jobs:
      - setup_and_plan
      - approval:
          type: approval
          requires:
            - setup_and_plan
      - apply:
          requires:
            - approval

f:id:swfz:20201214011138p:plain

approveすると後続のapplyが走るように設定できた

まとめ

  • gcp-cliのOrbを用いてサービスアカウントでgoogle-cloud-sdkのコマンドを使えるようにした
  • Terraformが参照するGCP用の環境変数をセットしGCPに対してTerraformを実行できるようにした

GCP系のOrbだと他にgcp-gcr,gcp-cloud-run,gcp-gkeなどがあるので別の機会で触ってみたい

ちょっと調べただけだとOrbを使ってGCPへみたいな記事があまりなかったのでお役に立てれば嬉しいなと思います