🐈

Github ActionsでCloud BuildとCloud Runを実行する

2022/04/16に公開

これは何か

Great Expectationsとdbtとairflowでロバストなデータパイプラインを構築するで作成したデータパイプラインを、Github Actionsを用いて自動でGCPにデプロイできるようにしたので、その時の調査内容とコードをまとめる。

前提

普通はAirflowをデプロイするならCloud Composerを使うか、GKEでデプロイすると思うが、サーバーが常駐してしまってコストが発生してしまうのと、今回はあくまで自分の練習用なので、あえて一つのコンテナにまとめてデプロイしてみる。

業務要件

  • mainブランチへのpushをトリガーに、GCP上に自動でコンテナのdeployを行う
  • デプロイされたコンテナは、Airflowでタスクがスケジューリングされ、データのバリデーションとロードを定期実行する

機能要件

  • mainブランチにpushされると、GithubActionsがコンテナのデプロイを行う
  • コンテナのデプロイは、CloudBuildとCloudRunを用いて、リポジトリ内のDockerfileを読み取って行う
  • デプロイに必要なサービスアカウントキーや、AirflowがGCP内のリソースを扱うために必要なサービスアカウントキーはGithubActionsのsecretsに保存して渡す

構成

.
├── prod # デプロイに必要なファイル 
│   ├── Dockerfile.prod
│   ├── airflow.conf
│   └── cloudbuild.yaml
└── scr # 各種ソースコード
    ├── dag
    ├── dbt
    └── great_expectations

コード

Dockerfile.prod
ARG GCP_AIRFLOW_SA_KEY
RUN echo -n ${GCP_AIRFLOW_SA_KEY} | base64 --decode > /tmp/gcp_secret.json
cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/***/prod_data_pipeline', '--build-arg', 'GCP_AIRFLOW_SA_KEY=${_GCP_AIRFLOW_SA_KEY}', '-f', './prod/Dockerfile.prod', '.']
substitutions:
  _GCP_AIRFLOW_SA_KEY: foobar
options:
    substitution_option: 'ALLOW_LOOSE'
ci.yaml
on:
  push:
    branches:
      - main

name: Build and Deploy a Container
env:
  PROJECT_ID: ${{ secrets.GCP_PROJECT }}
  GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
  GCP_AIRFLOW_SA_KEY: ${{ secrets.GCP_AIRFLOW_SA_KEY }}
  SERVICE: datapipeline
  REGION: us-central1
  IMAGE: gcr.io/${{ secrets.GCP_PROJECT }}/prod_data_pipeline
  PORT: 8080
  MEMORY: 2G

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Cloud SDK
        uses: google-github-actions/setup-gcloud@v0.2.0
        with:
          project_id: ${{ env.PROJECT_ID }}
          service_account_key: ${{ secrets.GCP_SA_KEY }}
          export_default_credentials: true 
      
      - name: Configure Docker
        run: |
          gcloud auth configure-docker

      - name: Deploy to Cloud Build
        run: |
          gcloud builds submit --config ./prod/cloudbuild.yaml --substitutions=_GCP_AIRFLOW_SA_KEY=${{ env.GCP_AIRFLOW_SA_KEY }}

      - name: Deploy to Cloud Run
        run: |
          gcloud run deploy ${{ env.SERVICE }} --project ${{ env.PROJECT_ID }} --region ${{ env.REGION }} --image ${{ env.IMAGE }} --port ${{ env.PORT }} --memory ${{ env.MEMORY }}

ややこしい構成としては、AirflowのconnectionでKey Json Pathを指定する必要があり、DockerfileにGithub Actionsのsecretsに登録したキーJSONの中身をどのように渡すか迷ったため、
①secretsにencodeした文字列を登録
②ci.yamlでcloudbuild.yamlの実行時に、substitutionsとして①を注入
③cloudbuild.yamlでdockerfileに--build-argとして渡す
④dockerfile上で受け取ったargをdecodeしてjsonファイルを作成・配置
という流れになった。
もう少し賢いやり方を考えたい。

実行

deployには成功した模様。途中ではまった要因としては、
https://towardsdatascience.com/deploy-to-google-cloud-run-using-github-actions-590ecf957af0
で書かれているように、gcloudのサービスアカウントのIAMを適切に設定しなければ、buildに成功してもGithub Actions上で失敗してしまうこと。

CloudRunでAirflowの挙動を確かめてみたところ、webserverは正常に立ち上がり、ジョブを動かすことに成功した。

Discussion