Terraform でインスタンススケジュールを構築・VM に適用し、スケジュールの付け替えは手動変更を許容する
はじめに
こんにちは、クラウドエース株式会社 第三開発部の小薗です。
先日、実務で Google Cloud のインスタンススケジュールを Terraform で構築しました。
インスタンススケジュールとは、指定した時間に VM インスタンスを自動的に起動・停止できる機能で、開発環境やテスト環境のコスト最適化に有効です。
構築を進める中で、ひとつ考慮が必要なポイントがありました。
インスタンススケジュールの設定は、運用中にコンソールから手動で変更したいケースがあるという点です。
例えば、「今日は作業が長引くので停止スケジュールを一時的に外したい」「別のスケジュールに付け替えたい」といった場面です。
Terraform で構築したリソースは、手動で変更すると次回の terraform plan で差分として検出され、terraform apply で元に戻されてしまいます。
この問題を解決するために、lifecycle ブロックの ignore_changes を活用しました。
本記事では、Terraform によるインスタンススケジュールの構築と、コンソールからの手動変更を許容する設計について解説します。
本記事の対象読者と前提知識
対象読者
本記事は以下の方を対象としています。
- インスタンススケジュールを Terraform で構築したい方
- Terraform で構築したリソースの一部属性を Terraform の管理対象外にしたい方
-
lifecycleブロックのignore_changesの実践的な活用方法を知りたい方
前提知識
本記事では以下の知識を前提として解説を進めます。
- Google Cloud の基本的な知識
- Terraform の基本知識(コードの読み書き、init/plan/apply コマンド)
インスタンススケジュールとは
インスタンススケジュールは、VM インスタンスの起動・停止を自動化できる機能です。
例えば、以下のようなユースケースで活用できます。
- 開発環境のコスト削減:業務時間外(21 時以降など)に自動停止し、停止忘れによる課金を防ぐ
- テスト環境の管理:平日の業務時間帯のみ稼働
VM インスタンスに対してインスタンススケジュールをアタッチすることで、指定した時間に自動的に起動・停止が実行されます。
なお、1 つの VM インスタンスに設定できるインスタンススケジュールは 1 つのみです。そのため、起動用と停止用で別々のスケジュールを作成し、それぞれを VM に適用することはできません。1 つのスケジュール内で起動スケジュールと停止スケジュールを定義する必要があります。
インスタンススケジュールのコンソールでの作成や、VM インスタンスへの適用手順については、公式ドキュメント を参照してください。
本記事では Terraform での構築方法を紹介します。
Terraform による構築
まずはインスタンススケジュールの構築と、それを適用した VM インスタンスの Terraform コードを紹介します。
設計上の考慮点や ignore_changes の解説については、後半のセクションで詳しく説明します。
インスタンススケジュールの作成
まず、google_compute_resource_policy リソースを使用して、インスタンススケジュールを作成します。
# インスタンススケジュール(毎日21時に自動停止)
resource "google_compute_resource_policy" "daily_stop" {
name = "daily-stop-at-21"
region = "asia-northeast1"
project = "your-project-id"
instance_schedule_policy {
vm_stop_schedule {
schedule = "0 21 * * *"
}
time_zone = "Asia/Tokyo"
}
}
instance_schedule_policy ブロック内で vm_stop_schedule を定義しています。
schedule には cron 式を指定し、time_zone でタイムゾーンを設定します。
この例では、毎日 21 時(日本時間)に VM インスタンスを自動停止するインスタンススケジュールを定義しています。各項目の詳細は Terraform の公式ドキュメント(google_compute_resource_policy) を参照してください。
VM インスタンスの作成
続けて、インスタンススケジュールを適用した VM インスタンスを定義します。以下の例では、e2-micro(東京リージョン)、Debian 12、20GB のブートディスクを持つ VM インスタンスを、インスタンススケジュール付きで作成します。サンプルでは network = "default" を使用していますが、本番環境では専用の VPC の利用を推奨します。
resource "google_compute_instance" "example" {
name = "example-instance"
machine_type = "e2-micro"
zone = "asia-northeast1-a"
project = "your-project-id"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
size = 20
}
}
network_interface {
network = "default"
subnetwork = "default"
}
# インスタンススケジュールを適用
resource_policies = [google_compute_resource_policy.daily_stop.self_link]
lifecycle {
ignore_changes = [resource_policies]
}
}
ポイントは 2 つです。
-
resource_policiesにインスタンススケジュールのself_linkを指定し、VM インスタンスに適用 -
lifecycleのignore_changesにresource_policiesを指定して、手動変更を許容
lifecycle ブロックの詳細については、次のセクションで解説します。
ignore_changes による手動変更の許容
ここからは、前のセクションのコードで使用した lifecycle ブロックの ignore_changes について、その必要性や、設定しない場合に発生する問題点を詳しく解説します。
課題:Terraform 管理と運用の柔軟性の両立
Terraform でインフラを管理する大きなメリットは、コードによる一元管理と再現性です。
しかし、すべての属性を厳密に Terraform で管理すると、運用上の柔軟性が失われるケースがあります。
インスタンススケジュールの場合、以下のような運用シーンが考えられます。
| シーン | 操作内容 |
|---|---|
| 作業延長 | 「今日は 21 時以降も作業するのでスケジュールを一時的に外したい」 |
| スケジュール変更 | 「別の停止時間に変更したい」 |
| 一時的な解除 | 「メンテナンス中はスケジュールを無効にしたい」 |
これらの変更のたびに Terraform コードを修正して apply するのは、運用負荷が高くなります。
特にインスタンススケジュールの一時的な変更は緊急性が高いケースもあり、迅速な対応が求められます。
ignore_changes を設定しない場合の問題
ignore_changes を設定しない場合、以下のような問題が発生します。
- コンソールからインスタンススケジュールを手動で外す
- 次回の
terraform planでインスタンススケジュールの差分が検出される -
terraform applyを実行すると、手動で外したインスタンススケジュールが再び適用される
実際に ignore_changes を設定せずに、コンソールからインスタンススケジュールを外した後に terraform plan を実行すると、以下のような差分が検出されます。
# google_compute_instance.example will be updated in-place
~ resource "google_compute_instance" "example" {
name = "example-instance"
~ resource_policies = [
+ "https://www.googleapis.com/compute/v1/projects/your-project-id/regions/asia-northeast1/resourcePolicies/daily-stop-at-21",
]
...
}
Plan: 0 to add, 1 to change, 0 to destroy.
コンソールでインスタンススケジュールを外したにもかかわらず、Terraform は「コードで定義されたインスタンススケジュールが適用されていない」と判断し、インスタンススケジュールを再度適用しようとします。
この状態で terraform apply を実行すると、手動で外したインスタンススケジュールが意図せず元に戻されてしまいます。
解決策:ignore_changes の活用
この課題を解決するために、lifecycle ブロックの ignore_changes を使用します。
ignore_changes は、Terraform の lifecycle ブロック内で使用できる設定で、指定した属性を Terraform の差分検出の対象外にします。
リソースの初回作成時にはコードの値が反映されますが、作成後に手動で変更されても Terraform はその変更を検知しません。
今回のケースでは、resource_policies を ignore_changes に指定します。
lifecycle {
ignore_changes = [resource_policies]
}
これにより、コンソールや gcloud コマンドでインスタンススケジュールを手動変更しても、次回の terraform plan で差分として検出されず、terraform apply で元に戻されることもありません。
ignore_changes 使用時の注意点
ignore_changes は便利な機能ですが、以下の点に注意が必要です。
1. 初回作成時の値は反映される
ignore_changes は初回作成後の変更を無視する設定です。
terraform apply でリソースを初めて作成する際は、コードに記述した値が正しく反映されます。
つまり、初回構築時にインスタンススケジュールが適用された状態で VM インスタンスが作成され、その後の手動変更のみが無視されます。
2. Terraform の状態と実際の状態が乖離する可能性
手動変更を許容するということは、Terraform の tfstate に記録された状態と、実際のリソースの状態が異なる可能性があることを意味します。
この乖離を許容できる属性のみ ignore_changes に設定してください。
3. コード上の変更も無視される
ignore_changes を設定した属性は、Terraform コード上で値を変更しても反映されません。
コードでインスタンススケジュールを変更する場合は、一度 ignore_changes から resource_policies を外し、terraform apply を実行する必要があります。
Terraform 管理と手動変更の使い分け
ignore_changes を活用することで、Terraform 管理と運用の柔軟性を以下のように使い分けることができます。
| 区分 | 対象属性 | 変更方法 |
|---|---|---|
| Terraform で厳密に管理 |
name, machine_type など |
Terraform コードを変更して apply
|
| 手動変更を許容 | resource_policies |
コンソールから即座に変更可能(terraform plan で差分なし) |
この使い分けにより、インフラの一貫性を保ちながら、現場の運用ニーズにも柔軟に対応できます。
おわりに
本記事では、Terraform によるインスタンススケジュールの構築と、lifecycle ブロックの ignore_changes を活用してコンソールからの手動変更を許容する設計について解説しました。
Terraform ですべてを厳密に管理することが理想的ではありますが、実際の運用では柔軟性が求められる場面もあります。
「何を Terraform で管理し、何を手動変更可能にするか」を明確に設計することで、管理の一貫性と運用の柔軟性を両立できます。
最後までご覧いただき、ありがとうございました。
Discussion