Cloud9 上で Terraform の実行環境を作る~Amazon Linux 2023 版~
コーヒーが好きな emi です。
私は Windows ユーザーです。一般的に Web 開発の現場では Mac が使われることが多く、Terraform の利用方法を検索しても Mac 向けの情報しか見つからずやや苦労することがあります。
そこで今回は Cloud9 上で Terraform の実行環境を作ってみました。
Cloud9 環境の作成
以下のように、デフォルト VPC に Cloud9 のプラットフォームとなる Amazon Linux 2023 を作成していきます。
Cloud9 環境は以下のように作成します。まず名前を設定し、新しい EC2 インスタンスを作成するで進みます。
インスタンスタイプですが、最近メモリ不足で止まってしまうことがあったので一番小さいインスタンスではなく、t3.medium
とやや大きめのものにしてみました。今回の検証では一番小さいインスタンスでも構いません。
ちなみに、EC2 の無料利用枠が終了している方は t2.micro
よりも t3.micro
の方が安くスペックが高いので t3.micro
にされることをお勧めします。
プラットフォームはデフォルトで Amazon Linux 2023 が選択されているのでこのまま進みます。
後の設定はこのままで、「作成」をクリックします。
作成完了したら、「開く」から IDE の画面を開きます。
開きました。画面下部がターミナルになっているのでここからコマンドを実行します。
Terraform のインストール
Cloud9 にはデフォルトで aws-cli や git がインストールされています。
AWS CLI のバージョン確認
aws --version
▼実行結果例
user.emi:~/environment $ aws --version aws-cli/2.15.32 Python/3.11.8 Linux/6.1.79-99.167.amzn2023.x86_64 exe/x86_64.amzn.2023 prompt/off user.emi:~/environment $
Git のバージョン確認
git -v
▼実行結果例
user.emi:~/environment $ git -v git version 2.40.1 user.emi:~/environment $
Terraform のバージョン管理に便利な tfenv をインストールします。
tfenv は Terraform のバージョン管理ツールです。tfenv を使うことで、プロジェクトごとに異なるバージョンの Terraform を簡単に切り替えて使うことができます。
git clone https://github.com/tfutils/tfenv.git ~/.tfenv
▼実行結果例
user.emi:~/environment $ git clone https://github.com/tfutils/tfenv.git ~/.tfenv Cloning into '/home/ec2-user/.tfenv'... remote: Enumerating objects: 2057, done. remote: Counting objects: 100% (662/662), done. remote: Compressing objects: 100% (207/207), done. remote: Total 2057 (delta 517), reused 522 (delta 446), pack-reused 1395 Receiving objects: 100% (2057/2057), 437.28 KiB | 10.41 MiB/s, done. Resolving deltas: 100% (1321/1321), done. user.emi:~/environment $
上記コマンドでは、GitHub にある tfenv のリポジトリを、ローカルの ~/.tfenv
ディレクトリにクローンしています。tfenv のソースコードが Cloud9 のローカル環境にダウンロードされました。
tfenv のパスを環境変数に追加します。
sudo ln -s ~/.tfenv/bin/* /usr/local/bin
▼実行結果例
user.emi:~/environment $ sudo ln -s ~/.tfenv/bin/* /usr/local/bin user.emi:~/environment $
このコマンドは、tfenvのバイナリファイルへのシンボリックリンクを作成し、システムのパスに追加しています。
これで tfenv のバイナリファイル(tfenv コマンドなど)へのシンボリックリンクが /usr/local/bin
に作成され、tfenv コマンドをシェルから直接実行できるようになります。
補足(クリックで展開)
1. ln -s
でシンボリックリンク(ショートカット)を作成
2. ~/.tfenv/bin/\*
は ~/.tfenv/bin/
ディレクトリ内の全てのファイルを指定
3. /usr/local/bin
はシステムのパスに含まれるディレクトリで、このディレクトリ内のコマンドはシェルから直接実行できる
tfenv のバージョンを確認します。
tfenv -v
▼実行結果例
user.emi:~/environment $ tfenv -v tfenv 3.0.0-49-g39d8c27 user.emi:~/environment $
インストール可能な Terraform のバージョンを確認します。
tfenv list-remote
▼実行結果例
user.emi:~/environment $ tfenv list-remote 1.8.0-rc1 1.8.0-beta1 1.8.0-alpha20240228 1.8.0-alpha20240216 1.8.0-alpha20240214 1.8.0-alpha20240131 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 : : : 0.1.1 0.1.0 user.emi:~/environment $
バージョン 1.7.5
が新しい GA 版であることが確認できますね。では、Terraform をインストールします。
tfenv install 1.7.5
▼実行結果例
user.emi:~/environment $ tfenv install 1.7.5 Installing Terraform v1.7.5 Downloading release tarball from https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_linux_amd64.zip ############################################################################################################################################ 100.0% Downloading SHA hash file from https://releases.hashicorp.com/terraform/1.7.5/terraform_1.7.5_SHA256SUMS Not instructed to use Local PGP (/home/ec2-user/.tfenv/use-{gpgv,gnupg}) & No keybase install found, skipping OpenPGP signature verification Archive: /tmp/tfenv_download.10sOWf/terraform_1.7.5_linux_amd64.zip inflating: /home/ec2-user/.tfenv/versions/1.7.5/terraform Installation of terraform v1.7.5 successful. To make this your default version, run 'tfenv use 1.7.5' user.emi:~/environment $
インストールできました。では、インストールした Terraform のバージョンを確認します。
tfenv list
▼実行結果例
user.emi:~/environment $ tfenv list 1.7.5 No default set. Set with 'tfenv use <version>' user.emi:~/environment $
利用する Terraform のバージョンを指定しておきます。
tfenv use 1.7.5
▼実行結果例
user.emi:~/environment $ tfenv use 1.7.5 Switching default version to v1.7.5 Default version (when not overridden by .terraform-version or TFENV_TERRAFORM_VERSION) is now: 1.7.5 user.emi:~/environment $
利用中の Terraform バージョンは以下コマンドで確認します。
terraform -v
▼実行結果例
user.emi:~/environment $ terraform -v Terraform v1.7.5 on linux_amd64 user.emi:~/environment $
Terraform を使って VPC を作成
実際に Cloud9 上で Terraform コードを作成しリソース作成します。今回は VPC とインターネットゲートウェイ(以降、IGW)を作成します。サブネットは作成しません。
まずテスト用にフォルダを作成し移動します。
mkdir test-terraform && cd test-terraform
▼実行結果例
user.emi:~/environment $ mkdir test-terraform && cd test-terraform user.emi:~/environment/test-terraform $
main.tf の作成
main.tf
を作成して、処理を記載します。
Terraform で実行・管理している状態を保存する .tfstate
ファイルは、保存先として S3 バケットを指定します。S3 バケットはあらかじめ作成しておいてください。
今回は検証のため簡易な 1 ファイルにまとめています。
user.emi:~/environment/test-terraform $ touch main.tf
################################################## # Terraform settings ################################################## terraform { # https://developer.hashicorp.com/terraform/language/settings # Terraform バージョンの指定 required_version = "~> 1.4" # AWS プロバイダーのバージョン指定 https://registry.terraform.io/providers/hashicorp/aws/latest required_providers { aws = { source = "hashicorp/aws" version = "~> 5.01" } } # tfstate ファイルを S3 に配置する(配置先の S3 は事前に作成しておく) backend s3 { bucket = "tfstate-emikitani" region = "ap-northeast-1" key = "tf-test-20240402.tfstate" } } ################################################## # Provider settings ################################################## # AWS プロバイダーの定義 provider aws { region = "ap-northeast-1" } ################################################## # VPC ################################################## # VPC https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc resource "aws_vpc" "vpc" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "vpc" } } # Internet Gateway https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.vpc.id tags = { Name = "igw" } }
terraform init
terraform init
コマンドで、ワークスペースの初期化や必要なプラグインのダウンロードをおこないます。
terraform init
▼実行結果例
user.emi:~/environment/test-terraform $ terraform init Initializing the backend... Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes. Initializing provider plugins... - Finding hashicorp/aws versions matching "~> 5.1"... - Installing hashicorp/aws v5.43.0... - Installed hashicorp/aws v5.43.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. user.emi:~/environment/test-terraform $
terraform init
は Terraform の動作に必要な初期設定を行います。
- バックエンドの初期化
backend
ブロックで指定されたバックエンド(今回は S3)の設定を読み込み、tfstate ファイル(状態ファイル)を保存するための準備を行います。
- プロバイダープラグインのダウンロード
required_providers
ブロックで指定されたプロバイダーのプラグインをダウンロードし、.terraform
ディレクトリ内に保存します。
- モジュールの取得
module
ブロックで指定された外部の Terraform コード(モジュール)を、指定されたソースからダウンロードします。今回は使用していません。
- 依存関係の解決
- Terraform のコードで使用されているリソース間の依存関係を解決し、リソースが正しい順序で作成、更新、削除されるようになります。
terraform init
は新しい Terraform プロジェクトを始める際や、プロバイダーやバックエンドの設定を変更した際に実行する必要があります。
terraform plan
terraform plan
コマンドで、実行したときのリソースの差分を確認します。
terraform plan
▼実行結果例
user.emi:~/environment/test-terraform $ terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_internet_gateway.igw will be created + resource "aws_internet_gateway" "igw" { + arn = (known after apply) + id = (known after apply) + owner_id = (known after apply) + tags = { + "Name" = "igw" } + tags_all = { + "Name" = "igw" } + vpc_id = (known after apply) } # aws_vpc.vpc will be created + resource "aws_vpc" "vpc" { + arn = (known after apply) + cidr_block = "10.0.0.0/16" + default_network_acl_id = (known after apply) + default_route_table_id = (known after apply) + default_security_group_id = (known after apply) + dhcp_options_id = (known after apply) + enable_dns_hostnames = true + enable_dns_support = true + enable_network_address_usage_metrics = (known after apply) + id = (known after apply) + instance_tenancy = "default" + ipv6_association_id = (known after apply) + ipv6_cidr_block = (known after apply) + ipv6_cidr_block_network_border_group = (known after apply) + main_route_table_id = (known after apply) + owner_id = (known after apply) + tags = { + "Name" = "vpc" } + tags_all = { + "Name" = "vpc" } } Plan: 2 to add, 0 to change, 0 to destroy. ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now. user.emi:~/environment/test-terraform $
# aws_internet_gateway.igw will be created
で IGW が作成される予定であることと、# aws_vpc.vpc will be created
で VPC が作成されることが分かります。main.tf
で明示した cidr_block
や enable_dns_hostnames
などは値が入っていますが、vpc_id
など作成されないと分からない値は (known after apply)
となっているのが分かります。
terraform apply
terraform apply
コマンドでリソースを作成します。途中で yes
と入力してください。
terraform apply
▼実行結果例
user.emi:~/environment/test-terraform $ terraform apply Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_internet_gateway.igw will be created + resource "aws_internet_gateway" "igw" { + arn = (known after apply) + id = (known after apply) + owner_id = (known after apply) + tags = { + "Name" = "igw" } + tags_all = { + "Name" = "igw" } + vpc_id = (known after apply) } # aws_vpc.vpc will be created + resource "aws_vpc" "vpc" { + arn = (known after apply) + cidr_block = "10.0.0.0/16" + default_network_acl_id = (known after apply) + default_route_table_id = (known after apply) + default_security_group_id = (known after apply) + dhcp_options_id = (known after apply) + enable_dns_hostnames = true + enable_dns_support = true + enable_network_address_usage_metrics = (known after apply) + id = (known after apply) + instance_tenancy = "default" + ipv6_association_id = (known after apply) + ipv6_cidr_block = (known after apply) + ipv6_cidr_block_network_border_group = (known after apply) + main_route_table_id = (known after apply) + owner_id = (known after apply) + tags = { + "Name" = "vpc" } + tags_all = { + "Name" = "vpc" } } Plan: 2 to add, 0 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 aws_vpc.vpc: Creating... aws_vpc.vpc: Still creating... [10s elapsed] aws_vpc.vpc: Creation complete after 11s [id=vpc-06bfd1f7689d7abbf] aws_internet_gateway.igw: Creating... aws_internet_gateway.igw: Creation complete after 1s [id=igw-031fce7a3bd8caf59] Apply complete! Resources: 2 added, 0 changed, 0 destroyed. user.emi:~/environment/test-terraform $
48 行目の Plan: 2 to add, 0 to change, 0 to destroy.
で、2 リソースの作成が計画されていることが分かります。Enter a value:
でこのままリソースの操作を進めて良いか聞かれるので、今回は yes
と入力してすすめました。無事 VPC と IGW の 2 リソースが作成されたことがわかります。
作成したリソースの確認
マネジメントコンソールから見ると、VPC と IGW が作成されているのが確認できます。
また、作成しておいた S3 バケット内には tfstate ファイルが作成され保存されていることが確認できます。
tfstate ファイルの中身の例をご参考にトグル内に貼っておきます。
tfstate ファイルの中身例(クリックで展開)
{ "version": 4, "terraform_version": "1.7.5", "serial": 5, "lineage": "93494a69-293e-0d58-0621-xxxxxxxxxx", "outputs": {}, "resources": [ { "mode": "managed", "type": "aws_internet_gateway", "name": "igw", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 0, "attributes": { "arn": "arn:aws:ec2:ap-northeast-1:123456789012:internet-gateway/igw-031fce7a3bd8caf59", "id": "igw-031fce7a3bd8caf59", "owner_id": "123456789012", "tags": { "Name": "igw" }, "tags_all": { "Name": "igw" }, "timeouts": null, "vpc_id": "vpc-06bfd1f7689d7abbf" }, "sensitive_attributes": [], "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "dependencies": [ "aws_vpc.vpc" ] } ] }, { "mode": "managed", "type": "aws_vpc", "name": "vpc", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 1, "attributes": { "arn": "arn:aws:ec2:ap-northeast-1:123456789012:vpc/vpc-06bfd1f7689d7abbf", "assign_generated_ipv6_cidr_block": false, "cidr_block": "10.0.0.0/16", "default_network_acl_id": "acl-04018a1303263c4a4", "default_route_table_id": "rtb-01b53ee4baa50416b", "default_security_group_id": "sg-013140029634d4daf", "dhcp_options_id": "dopt-0d58ff88fe0ffca9d", "enable_dns_hostnames": true, "enable_dns_support": true, "enable_network_address_usage_metrics": false, "id": "vpc-06bfd1f7689d7abbf", "instance_tenancy": "default", "ipv4_ipam_pool_id": null, "ipv4_netmask_length": null, "ipv6_association_id": "", "ipv6_cidr_block": "", "ipv6_cidr_block_network_border_group": "", "ipv6_ipam_pool_id": "", "ipv6_netmask_length": 0, "main_route_table_id": "rtb-01b53ee4baa50416b", "owner_id": "123456789012", "tags": { "Name": "vpc" }, "tags_all": { "Name": "vpc" } }, "sensitive_attributes": [], "private": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } ] } ], "check_results": null }
リソース作成済み状態で main.tf
を修正した場合は、terraform apply
を実行することでリソースの変更が行われます。
ちなみに Cloud9 のディレクトリ構成はこうなっています。
Terraform では CloudFormation スタックは生成されません。Terraform は裏で独自のプラグインを通じて AWS API を実行しリソースを作成します。
Terraform で構築したリソースを変更したい場合は、直接変更せずソースコードを修正して変更しましょう。
terraform destroy
作成したリソースを削除します。
terraform destroy
▼実行結果例
user.emi:~/environment/test-terraform $ terraform destroy aws_vpc.vpc: Refreshing state... [id=vpc-0a699bce1795848e5] aws_internet_gateway.igw: Refreshing state... [id=igw-0920414e3f5fc9bcb] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: # aws_internet_gateway.igw will be destroyed - resource "aws_internet_gateway" "igw" { - arn = "arn:aws:ec2:ap-northeast-1:123456789012:internet-gateway/igw-0920414e3f5fc9bcb" -> null - id = "igw-0920414e3f5fc9bcb" -> null - owner_id = "123456789012" -> null - tags = { - "Name" = "igw" } -> null - tags_all = { - "Name" = "igw" } -> null - vpc_id = "vpc-0a699bce1795848e5" -> null } # aws_vpc.vpc will be destroyed - resource "aws_vpc" "vpc" { - arn = "arn:aws:ec2:ap-northeast-1:123456789012:vpc/vpc-0a699bce1795848e5" -> null - assign_generated_ipv6_cidr_block = false -> null - cidr_block = "10.0.0.0/16" -> null - default_network_acl_id = "acl-027c4135ccfa90e82" -> null - default_route_table_id = "rtb-0bd574ab733579e8b" -> null - default_security_group_id = "sg-06cf8257475a7b970" -> null - dhcp_options_id = "dopt-0d58ff88fe0ffca9d" -> null - enable_dns_hostnames = true -> null - enable_dns_support = true -> null - enable_network_address_usage_metrics = false -> null - id = "vpc-0a699bce1795848e5" -> null - instance_tenancy = "default" -> null - ipv6_netmask_length = 0 -> null - main_route_table_id = "rtb-0bd574ab733579e8b" -> null - owner_id = "123456789012" -> null - tags = { - "Name" = "vpc" } -> null - tags_all = { - "Name" = "vpc" } -> null } Plan: 0 to add, 0 to change, 2 to destroy. Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes aws_internet_gateway.igw: Destroying... [id=igw-0920414e3f5fc9bcb] aws_internet_gateway.igw: Destruction complete after 1s aws_vpc.vpc: Destroying... [id=vpc-0a699bce1795848e5] aws_vpc.vpc: Destruction complete after 0s Destroy complete! Resources: 2 destroyed. user.emi:~/environment/test-terraform $
これで、作成したリソースの削除が完了しました。