👻

さくらのクラウドをTerraformを使ってVM構築

に公開

はじめに

インフラのコード化(IaC)は、現代のクラウド環境管理における重要な手法です。本記事では、さくらのクラウドでTerraformを使用してVMを構築し、Cloudflare R2にtfstateファイルを保存する方法をトライアルしたことをまとめています。また、実際に直面した問題とその解決方法についても共有します。

前提条件

  • Terraformのインストール
  • さくらのクラウドのアカウントとAPIキー
  • Cloudflareアカウントとアクセスキー(R2用)

環境構成

今回構築する環境は以下の通りです:

  • さくらのクラウド上の最小構成VM(1 CPU, 1GB RAM, 20GB SSD)
  • Ubuntu OSを使用
  • SSH公開鍵認証によるアクセス(パスワード認証は無効化)
  • tfstateファイルはCloudflare R2に保存

実装と発生した問題

1. Terraform設定ファイルの作成

基本的なディレクトリ構造は以下のとおりです:

.
├── .env                  # 環境変数ファイル(APIキーなど)
├── terraform/
│   ├── main.tf           # メイン設定ファイル
│   └── variables.tf      # 変数定義ファイル

2. Cloudflare R2バックエンドの設定

Terraformの状態ファイルをCloudflare R2に保存するための設定で、当初は以下のような問題がありました:

backend "s3" {
  bucket                      = "sakura-tfstate"
  key                         = "terraform/sakuracloud/terraform.tfstate"
  region                      = "auto"
  endpoint                    = "https://ACCOUNT_ID.r2.cloudflarestorage.com"
  skip_credentials_validation = true
  skip_region_validation      = true
  skip_metadata_api_check     = true
  force_path_style            = true
}

問題点1: endpointパラメータが非推奨で、endpointsを使うべき
問題点2: AWSアカウントIDの検証でエラーが発生

解決策:

backend "s3" {
  bucket                      = "sakura-tfstate"
  key                         = "terraform/sakuracloud/terraform.tfstate"
  region                      = "auto"
  endpoints                   = { s3 = "https://ACCOUNT_ID.r2.cloudflarestorage.com" }
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_region_validation      = true
  skip_requesting_account_id  = true  # この行を追加
  skip_s3_checksum            = true  # この行を追加 
  use_path_style              = true  # force_path_styleの代わり
}

3. さくらのクラウドリソースの設定

問題点1: SSHキーの設定方法
当初はssh_key_idsパラメータをサーバーリソースに直接指定していましたが、これが現在のAPIでサポートされていませんでした。

解決策: disk_edit_parameterブロック内で指定するように変更

resource "sakuracloud_server" "app_server" {
  # ...
  disk_edit_parameter {
    hostname        = "hostname"
    password        = var.local_password
    disable_pw_auth = true
    ssh_key_ids     = [sakuracloud_ssh_key.app_key.id]
  }
}

問題点2: アーカイブIDの指定
ハードコードされたアーカイブID(OS)が見つからないエラーが発生しました。アーカイブIDは時間経過とともに変更される可能性があります。

解決策: data sourceを使用して動的に最新のアーカイブを参照

data sakuracloud_archive "ubuntu" {
  os_type = "ubuntu"
}

resource "sakuracloud_disk" "app_disk" {
  # ...
  source_archive_id = data.sakuracloud_archive.ubuntu.id
}

4. 環境変数の管理

Terraformでは環境変数を使って機密情報を渡すことができます。TF_VAR_プレフィックスを使用することで、変数に値を設定できます。

必要な環境変数:

  • SAKURACLOUD_ACCESS_TOKEN
  • SAKURACLOUD_ACCESS_TOKEN_SECRET
  • AWS_ACCESS_KEY_ID (Cloudflare R2用)
  • AWS_SECRET_ACCESS_KEY (Cloudflare R2用)
  • TF_VAR_ssh_public_key
  • TF_VAR_local_password

dotenvxを使って環境変数を管理する場合は:

dotenvx run -- terraform plan
dotenvx run -- terraform apply

最終的なコード

main.tf

terraform {
  required_providers {
    sakuracloud = {
      source  = "sacloud/sakuracloud"
      version = "~> 2.16.0"
    }
    cloudflare = {
      source = "cloudflare/cloudflare"
      version = "~> 4"
    }
  }
  
  # Cloudflare R2をバックエンドとして使用
  backend "s3" {
    bucket                      = "sakura-tfstate"
    key                         = "terraform/sakuracloud/terraform.tfstate"
    region                      = "auto"
    endpoints = { s3 = "https://ACCOUNT_ID.r2.cloudflarestorage.com" }
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    skip_requesting_account_id  = true
    skip_s3_checksum            = true
    use_path_style              = true
  }
}

provider "cloudflare" {
  # token pulled from $CLOUDFLARE_API_TOKEN
}

provider "sakuracloud" {
  # 環境変数 SAKURACLOUD_ACCESS_TOKEN と SAKURACLOUD_ACCESS_TOKEN_SECRET で認証情報を設定
  zone = var.zone
}

# サーバー (VM) の作成
resource "sakuracloud_server" "app_server" {
  name        = var.server_name
  core        = var.server_core
  memory      = var.server_memory
  disks       = [sakuracloud_disk.app_disk.id]
  description = "Application server created by Terraform"
  tags        = ["app", "terraform"]

  network_interface {
    upstream = "shared"
  }

  disk_edit_parameter {
    hostname        = "hostname"
    password        = var.local_password
    disable_pw_auth = true
    ssh_key_ids     = [sakuracloud_ssh_key.app_key.id]
  }
}

# ディスクの作成
resource "sakuracloud_disk" "app_disk" {
  name              = "${var.server_name}-disk"
  size              = var.disk_size
  plan              = "ssd"
  source_archive_id = "${data.sakuracloud_archive.ubuntu.id}"
}

# SSHキーの登録
resource "sakuracloud_ssh_key" "app_key" {
  name       = "${var.server_name}-key"
  public_key = var.ssh_public_key
}

data sakuracloud_archive "ubuntu" {
  os_type = "ubuntu"
}

# 出力定義
output "server_ip" {
  value = sakuracloud_server.app_server.ip_address
}

output "server_id" {
  value = sakuracloud_server.app_server.id
}

variables.tf

variable "zone" {
  description = "対象ゾーン"
  type        = string
  default     = "is1b"  # 石狩第2ゾーン
}

variable "server_name" {
  description = "サーバー名"
  type        = string
  default     = "app-server"
}

variable "server_core" {
  description = "CPUコア数"
  type        = number
  default     = 1
}

variable "server_memory" {
  description = "メモリサイズ(GB)"
  type        = number
  default     = 1
}

variable "disk_size" {
  description = "ディスクサイズ(GB)"
  type        = number
  default     = 20
}

variable "ssh_public_key" {
  description = "SSHの公開鍵"
  type        = string
}

variable "local_password" {
  description = "ログインパスワード(SSHでは無効)"
  type        = string
}

.env例

SAKURACLOUD_ACCESS_TOKEN=your_sakura_cloud_token
SAKURACLOUD_ACCESS_TOKEN_SECRET=your_sakura_cloud_token_secret
AWS_ACCESS_KEY_ID=your_cloudflare_r2_access_key
AWS_SECRET_ACCESS_KEY=your_cloudflare_r2_secret_key
TF_VAR_ssh_public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
TF_VAR_local_password="secure_password_here"

得られた教訓

  1. 動的なリソース参照: ハードコードされたIDではなく、data sourceを使って動的にリソースを参照することで、リソースIDの変更に対して堅牢になります。

  2. バックエンド設定の注意点: S3互換ストレージ(Cloudflare R2など)を使用する場合は、AWS固有の機能に関連するバリデーションをスキップするパラメータが重要です。

  3. APIの変更に注意: さくらのクラウドのAPIは更新されることがあるため、最新のTerraformプロバイダーのドキュメントを参照することが重要です。

  4. 環境変数の効果的な活用: TF_VAR_プレフィックスと組み合わせることで、機密情報をコードに含めずに管理できます。

まとめ

Terraformを使ってさくらのクラウドのVMを構築し、Cloudflare R2に状態ファイルを保存する方法について解説しました。実際に直面した問題とその解決方法を共有することで、同様の環境構築を行う際の参考になれば幸いです。

インフラのコード化は、一度設定すれば繰り返し使用できる再現性の高い環境構築を可能にします。また、バージョン管理システムと組み合わせることで、インフラの変更履歴も管理できます。

今回の実装では、最小構成のVMを作成しましたが、この基盤をもとに、より複雑なインフラ(ロードバランサー、複数のサーバー、DNS設定など)へと拡張していくことも可能です。

参考リンク

Discussion