AWS

Terrafom基礎(プロバイダ、リソース、変数、出力、データ)について

はじめに

ディーネットの牛山です。

今回は、IaCのツールで知られるTerrafomの基礎的な部分(プロバイダー、リソース、変数、出力、データ)について説明しこれらがどのような役割を持っているのかわかるようになることを目指します。

本記事で扱うトピックは次の通りです。

  • Terraformプロバイダーについて
  • Terraformリソースについて
  • Terraform変数について
  • Terraformの出力について
  • Terraformデータについて

それでは順を追って解説します。

Terraformプロバイダーについて

Terraformプロバイダーは、Terraform init(初期化コマンド)を実行したときにダウンロードされる実行可能なプラグインを指し、各種クラウド(AWS、Azure、GCP)などに対応しています。

プロバイダーに指定できるオプションはいくつかございますが、一般的に使用される形式を次の通り紹介します。

ここでは、AWSプロバイダーを使用しますのでawsを指定し、引数として、IAMユーザのアクセスキーとシークレットキーを指定します。

regionには、リソースデプロイしたいリージョンを指定します。

詳細な指定項目は、「Terraformリソースについて」セクションで紹介しているリンク先から確認可能です。

provider "aws" {
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = var.region
}

また、プロバイダーとTerrafomバージョンの記載をmain.tfというファイルに次のような形で記載することが通例かと思います。

terraform {
  # https://github.com/hashicorp/terraform/releases/latest より Terraformバージョンの確認可能です。
  required_version = "1.9.8"

  # https://registry.terraform.io/providers/hashicorp/aws/latest より Terraformプロバイダーのバージョン確認可能です。
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.74.0"
    }
  }
}

variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "region" {
  default = "us-east-1"
}

# アクセスキーやシークレットキーは秘匿にする必要があるため、 terraform.tfvars というファイルを作成しこちらに定義した情報から読み込むようにします。
provider "aws" {
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = var.region
}

terraform.tfvarsに記載する内容例を示します。

aws_access_key = {アクセスキーを指定}
aws_secret_key = {シークレットキーを指定}

このファイルについては、gitで管理する場合、管理対象外とすることをオススメします。

Terraformリソースについて

リソースはTerraformでもっとも重要なコードブロックになっており、リソースコードブロックにインフラコンポーネント(VPC、EC2、RDS)を定義することでプロバイダーAPI対してリソースの作成、削除、更新をすることが可能になっています。

書式として次の形式になります。

  • resource {作成したいリソース} {ローカル名}

Docs overview | hashicorp/aws | Terraform | Terraform Registry
 →作成したいリソースは、リンク先にありますFilterから作成したいリソース、たとえばEC2などで検索することで記述の仕方などの説明を見ることが可能です。



ローカル名は、自由に付ける事が可能となっており他のリソースから参照する時などに使用されます。

resource "aws_instance" "example" {
  ami           = "ami-xxxxxxxx"
  instance_type = "t2.micro"
  tags = {
    Name = "example-instance"
  }
}

resource "aws_eip" "example_eip" {
  domain = "vpc"

  instance   = aws_instance.example.id
}

aws_instance.example というローカル名でEC2インスタンスを定義し、 aws_eip.example_eip というローカル名でElastic IPを定義しています。

EIPリソースのinstance引数で、 aws_instance.example.id を指定することで、作成したEC2インスタンスにEIPを関連付けています。

これにより、EC2インスタンスとEIPが連携され、インスタンスに固定のパブリックIPアドレスが割り当てられます。

instance引数には {リソース名}.{ローカル名}.{属性} となり、 {属性} に指定する部分は、冒頭で記載しているリンク先から確認可能です。

念の為、キャプチャ画像を示します。



Terraform変数について

変数定義の仕方として2種類存在しており「variable」と「locals」です。

variableは外部から直接指定可能な変数となり、 localsは、外部からの指定はできず、複雑な式の結果を一度計算することやコード内で繰り返し使用される値を一箇所で定義し管理を容易にできます。

多用することはコードの可読性を損ねてしまいますので適度に使用することをオススメします。

少し複雑なコード例となりますが、CloudWatchアラームでしきい値を計算して設定し、外部から直接しきい値を指定することが可能となります。

variable "base_threshold" {
  description = "基本のしきい値"
  type        = number
  default     = 1
}

variable "threshold_multiplier" {
  description = "しきい値の乗数"
  type        = number
  default     = 1.2
}

locals {
  # map定義
  ec2_load_alarms = {
    "cnt0" = { instanceid = "{インスタンスID}", type_instance = "relative", type = "load", alarm_name = "{ホスト名}-collectd_load_midterm (LoadAverage 5min)" } }
  }

  # しきい値を計算
  calculated_threshold = var.base_threshold * var.threshold_multiplier
}

resource "aws_cloudwatch_metric_alarm" "ec2_load_alarms" {
  for_each = local.ec2_load_alarms

  actions_enabled     = true
  alarm_actions       = ["arn:aws:sns:region:account-id:topic-name"]
  alarm_description   = "The average system load over a period of the last 5 minutes."
  alarm_name          = each.value.alarm_name
  comparison_operator = "GreaterThanOrEqualToThreshold"
  datapoints_to_alarm = 1

  dimensions = {
    InstanceId    = each.value.instanceid
    type          = each.value.type
    type_instance = each.value.type_instance
  }

  evaluation_periods = 1
  metric_name        = "collectd_load_midterm"
  namespace          = "CWAgent"
  ok_actions         = ["arn:aws:sns:region:account-id:topic-name"]
  period             = 300
  statistic          = "Average"
  threshold          = local.calculated_threshold
  treat_missing_data = "missing"
  unit               = null
}

variableで定義されているものは次のコマンドで上書き可能です。

  • terraform plan -var 'base_threshold=2'
  • TF_VAR_base_threshold=1 terraform plan

Terraformの出力について

Terraformにおける出力では、リソース/モジュール/データの戻り値を指し、ユースケースとして他のリソースから参照し、環境別にリモートステートを管理するなど発展的な管理をおこなっている場合に環境別のリソースを参照したいなどの要望に対応することが可能になります。

VPCリピアリングソースを作成するTerraformコード例から作成したVPCピアリングリソースを出力し、これを利用する内容を紹介します。

発展的な内容となるため複雑なコード例になりますが一例として参考になれば幸いです。

## VPCリピアリングソースの作成およびVPCピアリングリソースの出力
# stg/vpc.tf
resource "aws_vpc_peering_connection" "aws_vpc_peering_connection-prod-vpc01" {
  peer_vpc_id = data.terraform_remote_state.terraform_remote_state_prod.outputs.output_aws_vpc_prod-vpc01_id # アクセプタ
  vpc_id      = aws_vpc.stg-vpc01.id                                                                         # リクエスタ
  auto_accept = true                                                                                                 # ピアアリングを受け入れる(両方のVPCが同じAWSアカウントとリージョンにある必要があります)。

  accepter {
    allow_remote_vpc_dns_resolution = true # ローカルVPCが、ピアVPC内のインスタンスから問い合わせを受けたときに、パブリックDNSホスト名をプライベートIPアドレスに解決できるようにします。
  }

  requester {
    allow_remote_vpc_dns_resolution = true # ローカルVPCが、ピアVPC内のインスタンスから問い合わせを受けたときに、パブリックDNSホスト名をプライベートIPアドレスに解決できるようにします。
  }
}

# stg/outputs.tf
output "output_aws_vpc_peering_connection_prod-vpc01_id" {
  value = aws_vpc_peering_connection.aws_vpc_peering_connection-prod-vpc01.id
}

## 上記で作成したリソースを他環境より参照
# prod/vpc.tf
resource "aws_route" "prod-public-rtb01-rule-02" {
  route_table_id            = aws_route_table.prod-public-rtb01.id
  destination_cidr_block    = "10.10.1.0/24"
  vpc_peering_connection_id = data.terraform_remote_state.terraform_remote_state_stg.outputs.output_aws_vpc_peering_connection_prod-vpc01_id
  depends_on                = [aws_route_table.prod-public-rtb01]
}

# prod/data.tf
data "terraform_remote_state" "terraform_remote_state_stg" {
  backend = "local"

  config = {
    path = "../stg/terraform.tfstate"
  }
}

このコードはAmazon VPCピアリング接続を設定し、異なる環境間でのネットワーク通信を可能にしています。主な処理内容は次の通りです。

  1. VPCピアリング接続の作成

    • aws_vpc_peering_connectionリソースを使用して、ステージング環境(stg)と本番環境(prod)のVPC間にピアリング接続を確立します。
    • auto_accept = trueを設定し、同一AWSアカウントとリージョン内でのピアリング接続を自動的に承認します。
    • DNSホスト名解決を両方向で有効にしています。
  2. ピアリング接続IDの出力

    • 作成したVPCピアリング接続のIDをoutputブロックで出力し、他の環境から参照できるようにします。
  3. リモートステートの参照

    • terraform_remote_stateデータソースを使用して、異なる環境のTerraform状態ファイルから情報を取得します。
  4. ルートテーブルの設定

    • 本番環境のパブリックルートテーブルに、ステージング環境のCIDRブロックへのルートを追加します。
    • このルートは、VPCピアリング接続を使用して通信するように設定されています。

Terraformデータについて

データソースを使用すると、外部データを参照でき、前セクションで記載しているterraform_remote_stateを使用した他環境のステートを参照し最新のAMIを動的に取得した内容を参照することも可能になります。

少し複雑ですが、次のコードでは、最新のAlamaLinuxのAMIをfilterなど使って検索条件に指定し、most_recentで最新のAMIを取得しています。

# AlmaLinux AMIを検索するためのデータソース
data "aws_ami" "almalinux" {
  # 最新のAMIを取得
  most_recent = true
  owners = ["679593333241"]

  # フィルタを使用して特定のAlmaLinux AMIを検索
  filter {
    name   = "name"
    values = ["AlmaLinux OS 9*"] # AlmaLinux 9系列のAMIを検索
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"] # HVM (Hardware Virtual Machine) タイプのAMIのみを検索
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"] # EBSをルートデバイスとして使用するAMIのみを検索
  }

  filter {
    name   = "architecture"
    values = ["x86_64"] # x86_64アーキテクチャのAMIのみを検索
  }
}

# 取得したAMI IDを使用してEC2インスタンスを作成する例
resource "aws_instance" "example" {
  ami           = data.aws_ami.almalinux.id # 取得したAMI IDを使用
  instance_type = "t2.micro"
}

おわりに

いかがでしたでしょうか、発展的な内容を含んでおり初見だと難しく感じるかと思いますが、なれるととても便利な機能なので各セクションの意味など1つでも持ち帰っていただければ幸いです。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA