はじめに

コーヒーを注文する場面を想像してください。メニューに「コーヒー」としか書かれていなければ、毎回ブラックコーヒーが出てくるかもしれません。しかし、「サイズ」や「ミルクの種類」などの選択肢があれば、組み合わせごとにバリスタが新しいレシピを覚えなくても、注文をカスタマイズできます。

Terraform では、変数を使うことで、ファイル全体を書き直さずに入力値を変更でき、構成を再利用できるようになります。

出力を使うと、ID、名前、アドレスなど、作成結果として得られる重要な値を Terraform から報告できます。変数と出力を組み合わせることで、Terraform の構成はよりモジュール化され、実用的になります。

この実験を終えると、必要に応じて異なる名前のコンテナを作成できる柔軟な Terraform 構成が完成します。

変数を使うと、構成のロジックと環境固有のデータを分離できます。出力はその逆の役割を持ち、作成結果として得られた有用な値をユーザーや後続の自動化処理に返します。

変数ファイルを作成する

優れた料理人は、調理を始める前に材料を整理します。Terraform でも、カスタマイズするオプション(変数)は、メインのレシピとは別のファイルに保存するのがベストプラクティスです。

このファイルの標準的な名前は variables.tf です。このファイルを作成しても Terraform の動作は変わりません。Terraform はフォルダー内のすべての .tf ファイルを、1 冊の大きな本のように読み込みます。ただし、ファイルを分けることで構成を整理しやすくなります。

この整理方法は IaC で重要です。実際の構成はすぐに大きくなるためです。変数、リソース、出力を明確に分けておくと、後の保守がずっと簡単になります。

プロジェクトフォルダーに移動して、このファイルを作成しましょう。

cd ~/project
touch variables.tf

定義を追加するための空のファイルができました。次のステップでは、このファイルに内容を追加します。

変数を定義する

次に、利用できるオプションを宣言します。これは、注文フォームに「名前」欄を追加するようなものです。

nano を使って variables.tf を開きます。

nano variables.tf

次のブロックを追加します。これは Terraform に対して、「container_name という名前のオプションがあり、テキスト(string)を受け取り、ユーザーが何も指定しなければ ExampleNginxContainer という名前を使う」と伝えます。

variable "container_name" {
  description = "Value of the name for the Docker container"
  type        = string
  default     = "ExampleNginxContainer"
}

nano で保存して終了します(Ctrl+O、Enter、Ctrl+X)。

フォームの入力欄を作成したので、次はレシピの中でその値を使います。この変数を使用する main.tf ファイルを作成します。

main.tf を作成します。

nano main.tf

次のコードを貼り付けます。name = var.container_name に注意してください。これが、構成の中で変数を使用する方法です。

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.1"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.image_id
  name  = var.container_name
  ports {
    internal = 80
    external = 8000
  }
}

忘れずに nano で保存して終了してください。

var.container_name を使うことで、「名前を直接書き込まず、container_name 変数に設定されている値を取得して使う」と Terraform に指示しています。

出力を定義する

何かを購入すると、レシートを受け取ります。Terraform では、出力がレシートのような役割を果たし、作成したものに関する重要な詳細を表示します。

出力は、リソースが作成されるまで分からない情報を取得する場合に特に便利です。たとえば、システムによって割り当てられるランダムな ID やパブリック IP アドレスなどです。

また、あるインフラストラクチャの構成要素から人間のオペレーター、別の Terraform モジュール、または後続の自動化ステップに情報を渡す必要がある場合にも、出力は役立ちます。

これらの戻り値を整理するために、outputs.tf というファイルを作成します。nano で開きます。

nano outputs.tf

次のブロックを追加します。これは Terraform に対して、「処理が完了したら、nginx コンテナの ID を表示する」と伝えます。

output "container_id" {
  description = "ID of the Docker container"
  value       = docker_container.nginx.id
}

nano で保存して終了します。

それでは、コードを実行しましょう。

まず、プロジェクトを初期化します。Docker provider がダウンロードされます。

terraform init

次に、構成を適用します。コンテナ名は指定しないため、デフォルト値(ExampleNginxContainer)が使われます。-auto-approve を指定すると、「yes」の確認プロンプトを省略できるため、時間を短縮できます。

terraform apply -auto-approve

出力の一番下を確認してください。Outputs: に続いて container_id が表示されます。

変数を上書きする

変数の本当の利点は、コードを書き直さずに値を変更できることです。別の名前で 2 つ目のコンテナを起動したい場合を考えてみましょう。main.tf を編集する必要はありません。

-var フラグを使ってデフォルト値を上書きするよう Terraform に伝えるだけで済みます。これは、バリスタに「やはりラージサイズにしてください」と伝えるようなものです。

次のコマンドを実行します。

terraform apply -var="container_name=MyDynamicContainer" -auto-approve

出力を注意深く確認してください。Terraform によって、docker_container.nginx must be replaced と表示されます。

なぜでしょうか。Docker では、実行中のコンテナの名前を簡単に変更できないためです。名前を変更するために、Terraform は古いコンテナを Destroy(-)し、新しい名前のコンテナを Create(+)する必要があると判断します。これは Immutable Infrastructure の重要な原則です。既存のものをその場で修正するのではなく、置き換えます。

新しいコンテナが実行中であることを確認します。

docker ps --format "{{.Names}}"

MyDynamicContainer と表示されます。

まとめ

おめでとうございます。Terraform のコードを動的にできました。

この実験では、次のことを学びました。

  • 変数:variables.tf を使って、コードに柔軟な「フォーム入力欄」を作成する方法。
  • 参照:var.variable_name を使って、これらの値をメインの構成に組み込む方法。
  • 出力:outputs.tf を使って、実行後に重要なデータ(「レシート」)を表示する方法。
  • 上書き:-var を使ってコマンドラインから新しい値を入力し、同じコードを異なる状況で再利用する方法。