Terraformを使ってみる

に公開

インフラをコード管理するツール、Terraformを使ってみる。

主に記載するのは

  • 各種コマンドの内容
  • 実際の運用イメージ

など

チュートリアルを進めて見る

①コマンドのインストール

homebrewでインストールできた。

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

②コマンドラインの設定

チュートリアルだとパスを通したり、コマンドの補完の設定をしているが自分の場合zshで履歴に基づいて予測候補を表示できるようにしているのでここはパス

③DockerをTerraformで動かす

ここから実践的な感じで、Dockerを実際にTerraformで動かして見る。まずはディレクトリの作成

open -a Docker
mkdir learn-terraform-docker-container
cd learn-terraform-docker-container

んで、 main.tf というファイルを作る。これがTerraformのメインの設定ファイルになるっぽい。

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

provider "docker" {}

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

resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}

んで、これを書いた状態で↓を実行するとプロジェクトが立ち上がる。(この状態ではまだリソースは動いていない)

terraform init

で、↓を実行するとリソースが実際に立ち上がる。

terraform apply

今回の場合はnginxのイメージを持っているDockerコンテナを立ち上げるような設定にしている。またポートを80:8000にしているので、localhost:8000でnginxのサーバーに接続できる。

立ち上げたリソースを停止するには↓を実行

terraform destroy

④AWSリソースをTerraformで立ち上げる

TerraformでAWSのリソースを立ち上げて見る。

Dockerの時と同様に main.tf に設定を書く。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "us-west-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-830c94e3"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}

おそらく、チュートリアルドキュメントを見る限り各設定項目の意図は↓の通り

  • required_providers...Terraformを使う上で必須となるprovider。sourceでproviderの存在する場所、versionで利用するpvoviderのバージョンを指定している

  • provider...Terraformでリソースを管理するプラットフォーム的な何か。Docker、AWS、GCPみたいな粒度の値が入る。

  • resources...provider上で実際に立ち上げるリソース。これはシンプルだね

設定ファイルを書いたら先ほど同様に↓で立ち上げる。

terraform init
terraform apply

ちなみに。設定ファイルはフォーマットや記述ミスのチェックも可能で↓で行う。CIとかで使えそうだね。

terraform fmt
terraform validate

なんかエラーに遭遇したのでメモ

terraform apply

をすると↓のエラー

aws_instance.app_server: Creating...

│ Error: creating EC2 Instance: InvalidAMIID.NotFound: The image id '[ami-830c94e3]' does not exist
│ 	status code: 400, request id: 24596a32-6f55-49d6-b205-94a0bf5078f1

│   with aws_instance.app_server,
│   on main.tf line 16, in resource "aws_instance" "app_server":
│   16: resource "aws_instance" "app_server" {



見た感じAMIがないよ!って言ってるのでいろいろ調べてたところ、リージョンによってamiのIDが異なるっぽい。
チュートリアルの main.tfus-west-2 のリージョンが使われていたが、当然お金かけたくないので ap-northeast-1 に変更した。ただ、amiのIDはそのままにしていたのでエラーになったっぽい。

aws ec2 describe-images --owners self amazon --region ap-northeast-1

こんな感じのコマンドを叩くと東京リージョンでawsm公式が持っているAMIが取得できる。と思ったんだけど取得結果が見づらいのでコンソールから調べて見る。

EC2インスタンスを立ち上げるときの画面から無料利用枠の対象となるイメージを選択。

AMIのIDがあるのでそれを main.tf にコピーして見る。

よし。無事 terraform apply に成功。やったぜ。

実際にコンソール見たら立ち上がってた。すごい。

ちなみに立ち上げたリソースの詳細をチェックするには↓を実行する。

terraform show

↓みたいな結果が表示されればOK

resource "aws_instance" "app_server" {
    ami                                  = "ami-078296f82eb463377"
    arn                                  = "arn:aws:ec2:ap-northeast-1:xxxxxxx:instance/i-yyyyyyyyy"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1x"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-yyyyyyyyyy"
    ~~~~~~~~~~~

}

一旦ここでコミットしておきましょか。

ちなみに設定の変更を反映するときも terraform apply でOK

インフラを止める

立ち上げたリソースを停止したい場合は↓を実行

terraform destroy

さっき起動中になっていたリソースが終了済みになった。

変数を渡す

terraformの設定ファイルに変数を渡して、コマンド実行ごとに違う値を渡すことができる。

variables.tf を作成して↓の通り記述

variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "ExampleAppServerInstance"
}

変数を設定ファイルに渡すときは↓のように書く

resource "aws_instance" "app_server" {
  ami           = "ami-hogefuga"
  instance_type = "t2.micro"

  tags = {
    Name = var.instance_name
  }
}

var.instance_name とすると、instance_name という変数の値をtagsのNameに渡すことができる。

変数に default = "ExampleAppServerInstance" としているので、特に値を渡さなければdefaultの値でリソースが立ち上がる。

ちなみにここで特にinstance IDを指定していないからなのか、先ほどとは違うインスタンスが立ち上がった。(一度destroyしているからっぽい?)

次にコマンド実行時に変数を渡す。

terraform apply -var "instance_name=YetAnotherName"

こうすると、以下のようなログが流れNameの値が変わったことがわかる。

Terraform will perform the following actions:

  # aws_instance.app_server will be updated in-place
  ~ resource "aws_instance" "app_server" {
        id                                   = "i-hogefuga"
      ~ tags                                 = {
          ~ "Name" = "ExampleAppServerInstance" -> "YetAnotherName"
        }
      ~ tags_all                             = {
          ~ "Name" = "ExampleAppServerInstance" -> "YetAnotherName"
        }
        # (29 unchanged attributes hidden)

        # (7 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

実際にコンソール上でも値が変わっていることがわかる。

リソース情報を出力できるようにする

Terraform上でどんなリソースが立ち上がっているのかをコマンドラインから確認できるようにする。
こうすると共同作業者が使いやすかったりAWSコンソールから探しやすかったりのメリットがありそう。

outputs.tf を作成し、↓のように記述

output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.app_server.id
}

output "instance_public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_instance.app_server.public_ip
}

設定内容は↓のコマンドで確認できる。

terraform output

実行結果

tomolico@mourifuyusatorunoMacBook-Air learn-terraform-aws-instance % terraform output
instance_id = "i-hogefuga"
instance_public_ip = "0.0.0.0.0"

Terraform Cloudにリソース情報を保存

terraformのコードから作られるリソース情報をcloud上に管理しておくことができる。GUIから見れるっぽくて便利だね。

maim.tf に↓の記述を追加

cloud {
    organization = "organization-name"
    workspaces {
      name = "learn-tfc-aws"
    }
  }

origanizationはサインインするときに設定する。nameは任意の名前でOK。今回は↓のようにした。

cloud {
    organization = "moritania"
    workspaces {
      name = "aws-tutorial"
    }
  }

CLIとterraform cloudを連携する。↓のコマンドを実行。

terraform login

↓のようにAPIのtokenを入力するように求められるので、web上で発行したトークンを入力する。

Generate a token using your browser, and copy-paste it into this prompt.

Terraform will store the token in plain text in the following file
for use by subsequent commands:
    /Users/tomolico/.terraform.d/credentials.tfrc.json

Token for app.terraform.io:
  Enter a value: 

ちなみにトークンは個別発行もできる。

そのまま立ち上げようとすると以下のようなエラーに遭遇。どうやら環境変数でAWSのクレデンシャルを渡さないといけないらしい。

Initializing plugins and modules...

│ Error: error configuring Terraform AWS Provider: no valid credential sources for Terraform AWS Provider found.

│ Please see https://registry.terraform.io/providers/hashicorp/aws
│ for more information about providing credentials.

workspaceのvariablesってところで設定できるので設定しておく。ちなみにこの画面に辿り着くには先に空のワークスペースを立ち上げておく必要がありそう。おそらくcloudで接続していないときはデフォルトでコマンドラインで設定した環境変数を読み込む設定になっていたのだろうけど、cloud連携した結果読み込み先が変わったって話かなと思う。

ちなみに普通にインスタンスを立ち上げようとすると↓みたいな警告が出てくる。

Changes to Outputs:
  + instance_id        = (known after apply)
  + instance_public_ip = (known after apply)

│ Warning: Value for undeclared variable

│ The root module does not declare a variable named "AWS_SECRET_ACCESS_KEY"
│ but a value was found in file
│ "/home/tfc-agent/.tfc-agent/component/terraform/runs/run-ufJR9wYcwnidho6D/terraform.tfvars".
│ If you meant to use this value, add a "variable" block to the
│ configuration.

│ To silence these warnings, use TF_VAR_... environment variables to provide
│ certain "global" settings to all configurations in your organization. To
│ reduce the verbosity of these warnings, use the -compact-warnings option.


│ Warning: Value for undeclared variable

│ The root module does not declare a variable named "AWS_ACCESS_KEY_ID" but a
│ value was found in file
│ "/home/tfc-agent/.tfc-agent/component/terraform/runs/run-ufJR9wYcwnidho6D/terraform.tfvars".
│ If you meant to use this value, add a "variable" block to the
│ configuration.

│ To silence these warnings, use TF_VAR_... environment variables to provide
│ certain "global" settings to all configurations in your organization. To
│ reduce the verbosity of these warnings, use the -compact-warnings option.

放置しておいても動くのだけど、環境変数ファイルとかから読み込ませるなりしておいた方がいいのかな。

今後やること

とりあえず、チュートリアルらしいチュートリアルはここで終わりっぽい。

今後は↓のあたりをやってみたい。

  • Terraformを使った実例の調査
  • 簡単な個人アプリのインフラ作成(VPCとEC2くらい用意できれば一旦OKかな?RDSもいけるといいか?)
GitHubで編集を提案

Discussion