プログラミング学習サイト

プログラミングの学習を開始される方を対象としたプログラミング入門サイトです。

TerraformでEC2インスタンスサーバーを立ち上げる【Terraform入門】

参考 : https://developer.hashicorp.com/terraform/language

参考 : https://developer.hashicorp.com/terraform/tutorials/cli/plan

Terraform言語の特徴

TerraformはHCL(HashiCorp Configuration Language)という独自の宣言型言語を使用します。

Terraform言語の主な目的は、インフラストラクチャオブジェクトを表すリソースを宣言することです。 他のすべて言語機能は、インフラリソースの定義をより柔軟にするためにのみ存在します。

Terraformが宣言的な記述であるということは「Terraformの構成ディレクトリは、インフラリソースの完全なドキュメントである」という意味です。 Terraform言語の構文は、いくつかの基本要素のみで構成されています。

resource "aws_vpc" "main" {
  cidr_block = var.base_cidr_block
}
<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
  # Block body
  <IDENTIFIER> = <EXPRESSION> # Argument
}
  • {}ブロックはコンテンツであり、通常インフラリソースのような何らかのオブジェクトの構成を表します。
  • インフラリソースには引数が存在し、値を割り当てることでインフラリソースの設定が可能です。それらはブロック内に書き込むことができます。

Terraform言語は宣言的であり、C言語プログラミングのように意図された目標への手段を説明するのではなく、 あるべき状態のみが記述されています。

リソース間の構成順序を決定するときでも、手続き型ではなく暗黙的に構成されます。

Terraform実行前

TerraformがAWSアカウントに対して変更を加えられるようにするためには、以前に取得したAWSアカウントの認証情報を、 AWS_ACCESS_KEY_IDAWS_SECRETACCESS_KEYという環境変数として設定しておく必要があります。 それぞれのOSで、以下のようなコマンドを実行して環境変数を設定してください。

export AWS_ACCESS_KEY_ID=<あなたのアクセスキー>
export AWS_SECRETACCESS_KEY=<あなたのシークレットアクセスキー>
  • Windowsのコマンドターミナルでは次のように設定します。
set AWS_ACCESS_KEY_ID=<あなたのアクセスキー>
set AWS_SECRETACCESS_KEY=<あなたのシークレットアクセスキー>

これらのコマンドは.bashrc$PROFILE先のスクリプトに記述しておく必要があります。

AWSリソースの作成のためにはこれらの設定が必須となりますが、AzureやGCPなど別のプロバイダーを使用するためにはまた別の設定が必要になります。

ソースコード

次の例は、AWS EC2インスタンスの作成を表しています。

以下のコードをmain.tfとして保存してください

# プロバイダの設定
provider "aws" {
  region = "us-west-2"
}

# EC2インスタンスの設定
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI
  instance_type = "t2.micro"

  # セキュリティグループの設定
  vpc_security_group_ids = [aws_security_group.example.id]

}

# セキュリティグループの設定
resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Example security group"

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

プロバイダの設定

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

このセクションでは、AWSプロバイダを設定しています。regionパラメータは、リソースがデプロイされるAWSリージョンを指定します。

EC2インスタンスの設定

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
  vpc_security_group_ids = [aws_security_group.example.id]

  tags = {
    Name = "example-instance"
  }
}
  • resource "aws_instance" "example" は、EC2インスタンスを作成するためのリソースブロックです。 amiやインスタンスタイプからEC2の設定がわかると思います。
  • vpc_security_group_idsは、このインスタンスに関連付けるセキュリティグループのIDを指定します。別のブロックで宣言しているセキュリティグループをここでは参照しています。

ターミナルを起動

terraform init

ターミナルを起動してmain.tfを保存したファイルがあるフォルダーで以下のコマンドを実行してください。

terraform init
  • 実行例
Initializing the backend...
Initializing modules...
- ec2-instance in modules/aws-ec2-instance
Downloading registry.terraform.io/joatmon08/hello/random 6.0.0 for hello...
- hello in .terraform/modules/hello

Initializing provider plugins...
- Reusing previous version of hashicorp/random from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v5.7.0...
- Installed hashicorp/aws v5.7.0 (signed by HashiCorp)
- Installing hashicorp/random v3.5.1...
- Installed hashicorp/random v3.5.1 (signed by HashiCorp)

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.

terraform initコマンドはコードをスキャンして、どのプロバイダを使うのか判断し、そのプロバイダに関するコードをダウンロードする必要があります。 基本的にはスクラッチディレクトリである.terraformフォルダにダウンロードされます。

このコマンド terraform initコマンドは何度実行しても問題ないです。

ここまででプロバイダの情報がダウンロードされたので、次のコマンドを実行します。

terraform plan

以下のコマンドを使うと、実際に変更を加える前にTerraformが何を実行するのか、どのプロバイダーにどんなことをするのかの確認をします。

terraform plan

このコマンドを実行することで、AWSリソースの利用料の発生やサービスの更新など、現実の世界に変更が起きる前の確認ができます。

コマンドの表現はgitの差分チェックと同じと考えて良いです。

$ terraform plan -out "tfplan"
data.aws_ami.ubuntu: Reading...
data.aws_ami.ubuntu: Read complete after 0s [id=ami-055744c75048d8296]

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:

  # random_pet.instance will be created
  + resource "random_pet" "instance" {
      + id        = (known after apply)
      + length    = 2
      + separator = "-"
    }

  # module.ec2-instance.aws_instance.main will be created
  + resource "aws_instance" "main" {
## ...

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

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

terraform apply

実際にインスタンスを作成するには、以下のコマンドを実行します。

terraform apply

applyコマンド実行時にはplan実行時と同じ確認画面が出力されます。 確認して問題なければyesと入力しましょう。

ここまででAWSアカウント内にEC2、セキュリティグループの構築ができました。

Terraformコードに変更を加える

ここまではTerraformコードを使用してAWSリソースを構築する方法を紹介しました。

このあとはTerraformコードを変更してみたいと思います。 EC2インスタンスにタグがついていないので、タグをつけて名前を追加したいと思います。

# プロバイダの設定
provider "aws" {
  region = "us-west-2"
}

# EC2インスタンスの設定
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI
  instance_type = "t2.micro"

  # セキュリティグループの設定
  vpc_security_group_ids = [aws_security_group.example.id]

  tags = {
    Name = "terraform-example"
  }

}

# セキュリティグループの設定
resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Example security group"

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

ファイルの変更が済んだらterraform applyを実行してみます。

Terraformはすでに作成されたリソースファイルの情報を保持しているため、terraform applyを実行することで リソースの変更が可能になります。 (実行した後は、Refreshing state...と出力されます)

AWSコンソールからEC2を確認すると、Nameタグがついているのが確認できると思います。

EC2インスタンスの初期セットアップ

# プロバイダの設定
provider "aws" {
  region = "us-west-2"
}

# EC2インスタンスの設定
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 AMI
  instance_type = "t2.micro"

  # セキュリティグループの設定
  vpc_security_group_ids = [aws_security_group.example.id]

  user_data = <<-EOF
            #!/bin/bash
            echo "Hello World" > index.html
            nohup busybox httpd -f -p 8080 &
            EOF
  
  user_data.replace_on_change = true

  tags = {
    Name = "terraform-example"
  }

}

# セキュリティグループの設定
resource "aws_security_group" "example" {
  name        = "example-sg"
  description = "Example security group"

  ingress {
    from_port   = 8080
    to_port     = 8080
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

<<- EOFEOFは、\nを入れなくても複数行に弥文字列を渡せる、Terraformのヒアドキュメントです。 user_data 属性に初期スクリプトを書き込むことができます。

今回のスクリプトbusyboxと呼ばれるツールでポート8080でWebサーバを立ち上げ、index.htmlを配信することができます。

暗黙的依存

現在、EC2とセキュリティグループの間には変数を使用した参照が行われています。

  # セキュリティグループの設定
  vpc_security_group_ids = [aws_security_group.example.id]

このように、あるリソースから他のリソースへ参照を追加すると、暗黙的依存が設定されます。 Terraformはこれらの依存をパースし、そこから依存グラフを作成してリソースをどの順番で作成するべきかを決めます。

今回だとEC2でセキュリティグループの設定を行なっているため、先にセキュリティグループを作成してその後にEC2インスタンスを立てる必要があるのです。

この依存グラフは以下のコマンドで表示させることができます。

terraform graph

グラフはコマンドラインインターフェース上に出現しますが、dotコマンドを使用することで画像として出力することも可能です。

terraform graph -type=plan | dot -Tpng >graph.png

https://developer.hashicorp.com/terraform/language

page:https://minegishirei.hatenablog.com/entry/2024/06/04/175213