こんにちは、サービス開発課の山田です。
今回は Cloud Automator の Terraform Provider を作って公開したのでご紹介します。
この Provider を使うことで、以下が実現可能になります。
- Cloud Automator のジョブ構成をコードで管理できる - 環境毎のジョブを一つの定義ファイルで管理できる - ジョブ名に連番が付与されたジョブを作成できる - AWSアカウントを跨いでジョブをコピーする
Cloud Automator とは?
Cloud Automator はサーバーワークスが提供している、運用自動化サービスです。
EC2 の定時停止や定時起動といったことはもちろん、RDS や WorkSpaces といったAWSリソースの運用を自動化することが出来ます。
例えば、業務終了後にEC2インスタンスを自動停止したり、業務開始前にEC2インスタンスを自動起動させるといった設定をWeb上で簡単に設定することが出来ます。
詳しくはサービスサイトをご覧ください。
経緯
以前に弊社の尾崎より 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 をインストールする
公式ドキュメントにインストール方法が記載されているため、これに沿ってインストールします。
terraform version
を実行して、バージョンが表示されれば完了です。
$ terraform version Terraform v1.3.5
2. Cloud Automator の API キーを環境変数で設定する
Cloud Automator の API キーを環境変数で設定します。
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_id
とaws_account_id
を variables.tf
ファイルに定義しておいて、
variable "group_id" { default = { production = 10 test = 20 } } variable "aws_account_id" { default = { production = 11 test = 22 } }
ジョブ定義側で lookup
関数を使って実行環境毎の group_id
とaws_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_id
や aws_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チームで利用を始めたくらいの完成度なのでご利用は自己責任でお願い致します。