Cloud Automator の Terraform Provider を使ってジョブ構成をコードで管理できるようになりました

記事タイトルとURLをコピーする

こんにちは、サービス開発課の山田です。

今回は Cloud Automator の Terraform Provider を作って公開したのでご紹介します。
この Provider を使うことで、以下が実現可能になります。

- Cloud Automator のジョブ構成をコードで管理できる
- 環境毎のジョブを一つの定義ファイルで管理できる
- ジョブ名に連番が付与されたジョブを作成できる
- AWSアカウントを跨いでジョブをコピーする

Cloud Automator とは?

Cloud Automator はサーバーワークスが提供している、運用自動化サービスです。
EC2 の定時停止や定時起動といったことはもちろん、RDS や WorkSpaces といったAWSリソースの運用を自動化することが出来ます。
例えば、業務終了後にEC2インスタンスを自動停止したり、業務開始前にEC2インスタンスを自動起動させるといった設定をWeb上で簡単に設定することが出来ます。

詳しくはサービスサイトをご覧ください。

https://cloudautomator.com/

経緯

以前に弊社の尾崎より Cloud Automator SREチームの紹介 という記事でご紹介させていただいたのですが、Cloud Automator にはSREチームがあり、私自身もSREチームの一員としてサービスの障害発生を未然に防ぐべく活動しています。

SREチームの活動成果の一つに「ステージング環境で負荷試験が行われるようにした」というものがあり、これは「毎日特定の時間に短時間でジョブを集中的に実行する」もので、SREチーム発足時に最初に取り組んだのですが、1年経過した今でもサービスの安定提供に大きく寄与しています。

その負荷試験で実行される Cloud Automator のジョブは全体でおよそ数百ジョブあり、負荷試験の種類毎に複数の YAML ファイルにジョブの情報を記載して管理しています。

そのため、例えば負荷試験で「20:00 に同時実行するジョブ数を100増やしたい」という要望が出てきた場合、

1. 追加するジョブの情報を YAML ファイルに追記する
  - 追加するジョブの個数分だけ追記する必要がある
2. (1) の YAML ファイルを Ruby スクリプトに流して UPSERT することでジョブを追加する
3. ジョブが参照するAWSリソースは CloudFormation で管理しているため、
   必要に応じて CloudFormation の YAML ファイルも更新する

といった手順を踏む必要があり、この管理方法だと

- YAML ファイル、Ruby スクリプトのメンテナンス作業が属人化する
- AWSリソースとジョブの依存関係が分かりづらくなる
  - ジョブが利用するAWSリソースは CloudFormation で管理しているため、
    ジョブとAWSリソース間の情報受け渡しができないので依存関係を把握しづらい

という感じで、これからサービスの成長に合わせて負荷試験ジョブが増えていくことを考えると、メンテナンスにかかる運用負荷も増え続けていくことが予想されていました。

これら負荷試験ジョブの管理作業をSREチームで使い慣れている Terraform で管理できるようになったら色々と捗りそう、Cloud Automator の API は公開されているし無いなら作ろう、というのが動機で Cloud Automator の Terraform Provider を作成しました。

作ったもの

Cloud Automator の各種リソースを Terraform で管理するための、Custom Provider を開発しました。

terraform-provider-cloudautomator - GitHub
terraform-provider-cloudautomator - Terraform Registry

使い方

1. Terraform をインストールする

公式ドキュメントにインストール方法が記載されているため、これに沿ってインストールします。

Install Terraform

terraform version を実行して、バージョンが表示されれば完了です。

$ terraform version
Terraform v1.3.5

2. Cloud Automator の API キーを環境変数で設定する

Cloud Automator の API キーを環境変数で設定します。
API キーの発行方法はマニュアルをご参照ください。

Cloud Automator APIの利用方法

$ export CLOUD_AUTOMATOR_API_KEY="abcdefghijklmnopqrstuvwxyz123456789"

3. 作業環境を作成する

適当なディレクトリを作成して、その中に main.tf ファイルを作成してください。
以降は、作成した main.tf ファイルに追記していく形で作業を進めます。

$ mkdir ~/cloudautomator
$ cd ~/cloudautomator
$ touch main.tf

4. 利用する Provider を宣言する

Terraform Provider for Cloud Automator をインストールして使用できるようにするため、main.tf ファイルに required_providers を書いて宣言します。

terraform {
  required_providers {
    cloudautomator = {
      source = "CloudAutomator/cloudautomator"
    }
  }
}

5. Terraform Provider for Cloud Automator をインストールする

terraform init を実行して、Terraform Provider for Cloud Automator をインストールします。
Terraform has been successfully initialized! が表示されれば成功です。

6. ジョブの定義を書く

続いて、これから作成するジョブの定義を main.tf ファイルに書いていきます。
今回の例では以下のジョブを作成します。

※ その他アクションやトリガーの定義例については、GitHub リポジトリの example ディレクトリに格納しているので、詳細はこちらをご確認ください。

- タイマートリガー
  - 毎週、月曜日、日曜日 の 9:00 に実行
  - 実行日と日本の祝日が重なっていた場合スキップする
  - ジョブ実行をスキップする日付
    - 2023-01-01
    - 2023-01-02
    - 2022-01-03
  - ジョブの開始が遅延した場合に実行の開始をキャンセルする遅延時間
    - 30分
- 指定時間待機アクション
  - 15分

ジョブの定義が以下になります。

resource "cloudautomator_job" "cron-job" {
  name           = "example-cron-job"

  group_id       = 1076

  rule_type = "cron"
  cron_rule_value {
    hour          = "9"
    minutes       = "0"
    schedule_type = "weekly"
    weekly_schedule = [
      "monday",
      "sunday"
    ]
    national_holiday_schedule = "true"
    dates_to_skip = [
      "2023-01-01",
      "2023-01-02",
      "2023-01-03"
    ]
    start_timeout_minutes = "30"
    time_zone             = "Tokyo"
  }

  action_type = "delay"
  delay_action_value {
    delay_minutes = 15
  }
}

7. 作成するジョブの情報を確認する

terraform plan を実行して、これから作成するジョブの情報を確認します。

8. ジョブを作成する

terraform apply を実行してジョブを作成します。
Apply complete! と表示されれば成功です。

9. ジョブを確認する

ジョブ一覧ページを表示して、Terraform で作成したジョブを確認してみましょう。

ジョブ定義で宣言した同じ名前のジョブが作成されており、

タイマートリガーの設定とアクションの設定も、ジョブ定義と同じ設定になっていることを確認できました。

便利な使い方

Terraform で Cloud Automator のジョブを管理すると、以下のような使い方が可能になります。

環境毎のジョブを一つの定義ファイルで作成する

Terraform の Workspace (環境毎に state を分けて管理する機能) と lookup 関数を組み合わせることで、一つのジョブ定義ファイルで複数環境のジョブを作成できます。

例えば、以下のように「本番環境」と「テスト環境」で group_idaws_account_idvariables.tf ファイルに定義しておいて、

variable "group_id" {
  default = {
    production = 10
    test       = 20
  }
}

variable "aws_account_id" {
  default = {
    production = 11
    test       = 22
  }
}

ジョブ定義側で lookup 関数を使って実行環境毎の group_idaws_account_id を読み込むようにすることで、ディレクトリを分けなくても環境毎のジョブ定義をDRYに記述することが可能です。

resource "cloudautomator_job" "example-count-job" {
  name           = "cron-job"

  group_id       = lookup(var.group_id, terraform.workspace)
  aws_account_id = lookup(var.aws_account_id, terraform.workspace)

...

連番のジョブを作成する

Terraform メタ引数である count を使うことで、一つのジョブ定義で複数個のジョブリソースを一括作成できます。

resource "cloudautomator_job" "example-count-job" {
  count = 10
  name = "example-cron-job-${count.index}"


...

上記のように、ジョブ名にインデックスを埋め込むことで

  • example-cron-job-0
  • example-cron-job-1
  • example-cron-job-2
  • example-cron-job-3
  • example-cron-job-4

のような連番のジョブをサクッと作成できます。

アカウントを跨いでジョブをコピーする

これは「ジョブを最初から Terraform で管理していること」ことが前提の話になってしまうのですが、例えば Cloud Automator の組織Aから組織Bに数百ジョブを移行したいという要件があった際に、以下のようなジョブを定義して管理していた場合、

resource "cloudautomator_job" "example-cron-job" {
  name           = "cron-job-hoge"

  group_id       = var.group_id
  aws_account_id = var.aws_account_id

...
}

resource "cloudautomator_job" "example-cron-job" {
  name           = "cron-job-fuga"

  group_id       = var.group_id
  aws_account_id = var.aws_account_id

...
}

group_idaws_account_id を組織Bの ID に変更して terraform apply するだけで、ジョブの設定情報をそのままに組織Bへジョブを一括でコピーすることができます。

既存のジョブを import する

Terraform 以外で作成していたジョブを Terraform の管理下に置くことも可能です。

以下のような既存ジョブを import したい場合、

このジョブと同じパラメータを持ったリソースを宣言した .tf ファイルを作成して、

resource "cloudautomator_job" "delay-job" {
  name      = "delay-job"
  group_id  = 1234

  rule_type = "immediate_execution"

  action_type = "delay"
  delay_action_value {
    delay_minutes = 15
  }
}

上記ファイルで宣言したリソースタイプと名前、そしてジョブIDを指定して terraform import すると、既存のジョブを Terraform の管理下に置くことができます。

まとめ

ジョブのバージョン管理で困っていた方はこの機会に是非試してみてください。
ただし、これは私の個人プロジェクトから始まり、最近やっとサービス開発課のSREチームで利用を始めたくらいの完成度なのでご利用は自己責任でお願い致します。