CircleCI をジョブとして使った話

<a href="https://twitter.com/riita10069"><img src="https://img.shields.io/badge/Author-riita10069-4FC08D.svg?logo=&style=plastic"></a>

CircleCI Advent Calendar 2021 の7日目を担当するのは、[株式会社Journey](https://journey-inc.studio.site/)でホテル予約サービスを開発しているりいたです。

CircleCIのTシャツが欲しいので、CircleCIを使った用途と実際のそのyamlを公開することにしました。

KPI分析で使っている、データ基盤の3分類を支えるジョブとしてCircleCIを使った話をします。



## 現状

- Cloud Composerを使ってデータ基盤の3分類を実現している。
    - BigQueryには、ProductionのMySQLから毎朝8:00にバッチでデータがダンプされる
    - その直後に、Airflowのdagを使って、データ基盤のデータが更新される
    - 行動ログはサイドカーのfluentdによって、stackdriver経由でリアルタイムに集計できる
    - 行動ログはリアタイで集計できるけれど、どうせProductionのMySQLのデータが必要なので、Composerのdagは1日に一回しか動いていない。

## 解決したい課題

- Cloud ComposerはKubernetesのマネージドであり、共用CPUが使えず、Zonalクラスタも使えない。
- 結果、3zoneでn1-standard-1を立てることになり、月に3万円程度かかってしまう。年間で36万円程度かかりシリーズAのスタートアップにとっては地味に出費

## どのように解決するのか

1日に一回30分くらいで終わるJobのために一日中Composerを立てておくのはもったいない。
dagでは、09:00に実行されることになっているので、テキトーに08:50くらいにComposerを立てて、09:30くらいにComposerを無くせばいいかな。
30分で終わらないくらいまでスケールしたら、10:00に変更すればいいだけのことなので、わざわざジョブの終了を厳密に扱う必要はないかなという判断。(運用でカバー)



### 08:45

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309507/57abeb37-e6ab-d586-d892-a820a8e1b580.png)


### 09:30

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309507/61d3a057-d17f-51f5-efd4-54318f31d027.png)


## CircleCI & Terraform で実現することにした

そもそも、Cloud ComposerはTerraformで管理されていた。
なら、Terraformを使って、同じ設定のCloud Composerは簡単に生やせる。
Terraform Applyをするためのコンテナにお金をかけていたら意味がないので、Cicle CIのジョブを使えば解決ではってなった。


```.circleci/config.yml
version: 2
jobs:
  create:
    working_directory: ~/bluemoon
    docker:
      - image: hashicorp/terraform:0.14.3
    steps:
      - checkout
      - run:
          name: Slack notification
          command: sh start_slack.sh
          working_directory: .
      - run:
          name: Init terraform
          command: terraform init
          working_directory: tf/cloud-composer
      - run:
          name: Apply terraform
          command: terraform apply -auto-approve 
          working_directory: tf/cloud-composer

  destroy:
    working_directory: ~/bluemoon
    docker:
      - image: hashicorp/terraform:0.14.3
    steps:
      - checkout
      - run:
          name: Slack notification
          command: sh end_slack.sh
          working_directory: .
      - run:
          name: Init terraform
          command: terraform init
          working_directory: tf/cloud-composer

      - run:
          name: Destroy terraform
          command: terraform destroy -auto-approve
          working_directory: tf/cloud-composer

  deploy:
    working_directory: ~/bluemoon
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run:
          name: initialize gcloud
          command: |
            gcloud auth activate-service-account --key-file=tf/cloud-composer/account.json
            gcloud --quiet config set project -----------
      - run:
          name: import sql files 
          command: gcloud composer environments storage plugins  import --location us-central1 --environment cloud-composer  --source sql/
      - run:
          name: import dag files 
          command: gcloud composer environments storage dags import --location us-central1 --environment cloud-composer  --source dag/
      - run:
workflows:
  version: 2
  start_workflow:
    triggers:
      - schedule:
          cron: "45 23 * * *"
          filters:
            branches:
              only:
                - master
    jobs:
      - create
      - deploy:
          requires:
            - create
          filters:
            branches:
              only: master
  end_workflow:
    triggers:
      - schedule:
          cron: "30 0 * * *"
          filters:
            branches:
              only:
                - master
    jobs:
      - destroy
```


## 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309507/8d404906-05f9-482b-879a-86814935a3c1.png)

めっちゃ上手くいった。
なんだかんだ1年以上これで運用していますが、この仕組み自体には、大きな問題が起きたことはなかったです。