さくらのクラウドを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_TOKENSAKURACLOUD_ACCESS_TOKEN_SECRET-
AWS_ACCESS_KEY_ID(Cloudflare R2用) -
AWS_SECRET_ACCESS_KEY(Cloudflare R2用) TF_VAR_ssh_public_keyTF_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"
得られた教訓
-
動的なリソース参照: ハードコードされたIDではなく、data sourceを使って動的にリソースを参照することで、リソースIDの変更に対して堅牢になります。
-
バックエンド設定の注意点: S3互換ストレージ(Cloudflare R2など)を使用する場合は、AWS固有の機能に関連するバリデーションをスキップするパラメータが重要です。
-
APIの変更に注意: さくらのクラウドのAPIは更新されることがあるため、最新のTerraformプロバイダーのドキュメントを参照することが重要です。
-
環境変数の効果的な活用:
TF_VAR_プレフィックスと組み合わせることで、機密情報をコードに含めずに管理できます。
まとめ
Terraformを使ってさくらのクラウドのVMを構築し、Cloudflare R2に状態ファイルを保存する方法について解説しました。実際に直面した問題とその解決方法を共有することで、同様の環境構築を行う際の参考になれば幸いです。
インフラのコード化は、一度設定すれば繰り返し使用できる再現性の高い環境構築を可能にします。また、バージョン管理システムと組み合わせることで、インフラの変更履歴も管理できます。
今回の実装では、最小構成のVMを作成しましたが、この基盤をもとに、より複雑なインフラ(ロードバランサー、複数のサーバー、DNS設定など)へと拡張していくことも可能です。
Discussion