Terraform を運用するについて考える ~第1回 Terraformを管理する~

AWS

2022.8.25

Topics

こんにちは、クラウドリードチームのフクナガです。
みなさん「Terraform」使ってますか?
クラウド利用の拡大に伴い、多くの会社でIaC(Infrastructure as Code)を取り入れようと様々な取り組みをされているかと思います。
私も、その中の1人として約3年ほどTerraformを利用した環境構築や運用に携わってきました。

私自身の経験をもとに、複数回にわたってTerraform運用面のノウハウをご紹介したいと思います。
第1回の本記事では、「Terraformを管理する」というテーマでお話ししたいと思います。

前提

対象環境

本記事では、AWSを利用し環境を構築することを前提としております。

想定している読者

本記事は、Terraform入門記事よりも「運用」に特化しているため、丁寧な文法解説などは記載されていません。
初学者の方は、実際にハンズオン記事などでTerraformを触ってみてからご覧いただくとより理解につながるかと思います。

今回の記事のスコープ

  • Terraform開発/運用において管理すべきものを把握する

Terraformを管理するとは?

Terraformは、開発/運用をするにあたっていくつか管理しないといけないものがあります。
本記事では、管理する対象と対象ごとの管理方法をご紹介したいと思います。

1. 構築対象を管理する

providers.tf

Terraformで構築する対象のプロバイダー(AWS,GCPなど)や構築対象のリージョン、利用するTerraformのバージョンなどを定義するファイルになります。
Terraformが対応しているプロバイダーの一覧はこちらで参照ができます。
https://registry.terraform.io/browse/providers

「どのAWSアカウントでリソースを構築するのか」については利用するIAMユーザのアクセスキーを用いることで指定が可能です。(IAMロールを用いての実行なども可能)
※ファイル名は必ずしも「providers.tf」である必要はありません。

以下の内容で作成したファイルを他Terraformソースファイルと同一のディレクトリに配置しTerraformを実行することで、指定したプロバイダー、リージョンへのリソース構築が可能になります。

ファイル名:providers.tf

terraform {
  required_version ">= [利用するバージョンを記載]"
}

# プロバイダーとしてAWSを指定
provider "aws" {
  region = "[リージョン名]"
}

複数リージョンでの構築を実施する場合は、以下の手順で実施できます。

(1) providers.tfに構築対象リージョンごとにproviderを定義する
ファイル名:providers.tf

terraform {
  required_version ">= [利用するバージョンを記載]"
}

# デフォルトで構築するリージョンにはaliasを定義しない
provider "aws" {
  region = "[リージョン名]"
}

# 特定のリソースで利用するリージョンにはaliasを定義する
provider "aws" {
  region = "us-east-1"
  alias  = "virginia"
}

(2) 構築対象リソースの中にproviderを定義する
例:EC2をバージニア北部リージョンに構築する場合

resource "aws_instance" "default" {
  provider               = aws.virginia
  instance_type          = "t3.micro"
  vpc_security_group_ids = ["セキュリティグループID"]
  subnet_id              = サブネットのID
  root_block_device {
    volume_type = "gp3"
    volume_size = 8
    encrypted   = false
  }
  tags = {
    Name = "sample-ec2-server"
  }
}

2. Terraformの状態を管理する

(1) tfstateファイル

Terraformでは、「tfstate」というファイルを用いて「実環境はどういう状態になっているのか?」「現状のTerraformコードと実環境でどういう差分があるのか?」といった管理をしています。
複数人で開発を実施する際は、このtfstateファイルを共通で持つ必要があります。
AWSでは、S3を利用することで共通のtfstateファイルを用いたTerraform開発が実現できます。

[手順]

1. tfstate保管用S3バケットを作成

tfstateを管理するためのS3バケットは「CloudFormation」にて作成します。
Terraformを利用するための仕組みは「CloudFormation」、その他のAWSリソースを「Terraform」で構築することで、AWSリソース全てをコード管理することが可能になります。
CloudFormationを利用したリソース作成の経験がない方は以下記事を参照してみてください。
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/GettingStarted.Walkthrough.html

ファイル名:tfstate-s3bucket.yml

AWSTemplateFormatVersion: 2010-09-09
Description: CodePipeline For Lambda Deploy

Parameters:
  BucketNameTfstate:
    Type: String
    Default: [固有の名前を定義]-tfstate
    Description: S3 Name for Artifact

Resources:
  tfstateBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref BucketNameTfstate
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

2. providers.tfを作成

Terraformソースコードが配置されているディレクトリにproviders.tfを以下の内容で作成する

ファイル名:providers.tf

terraform {
  required_version ">= [利用するバージョンを記載]"
  backend "s3" {
    # 作成したS3バケット
    bucket = "[S3バケット名]"
    region = "[リージョン名]"
    # tfstateファイル名
    key = "terraform.tfstate"
    encrypt = true
  }
}

provider "aws" {
  region = "[リージョン名]"
}

(2) tfstateファイル同時書き込みの防止

Terraformでの環境構築実行時には、tfstateファイルへ内容を書き込む必要があります。多数のユーザが同時に書き込みに行くと。。。どうなるか想像つきますよね??
Terraform利用時には、tfstateファイルへの同時操作を禁止する必要があります。
AWSでは、DynamoDBテーブルを利用することでtfstateファイルの利用状況を管理することが可能です。

[手順]

1. tfstate管理用DynamoDBテーブルを作成

tfstate操作状況を管理するためのDynamoDBテーブルは「CloudFormation」にて作成

ファイル名:tfstate-dynamodb.yml

AWSTemplateFormatVersion: 2010-09-09
Description: CodePipeline For Lambda Deploy

Parameters:
  TableNameTfstate:
    Type: String
    Default: [固有の名前を定義]-dynamodbTfstate
    Description: DynamoDB Table Name

  tfstateDynamoDB:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: !Ref TableNameTfstate
      AttributeDefinitions:
        - AttributeName: "LockID"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "LockID"
          KeyType: "HASH"
      ProvisionedThroughput:
        ReadCapacityUnits: "1"
        WriteCapacityUnits: "1"

2. providers.tfを以下の内容に変更

ファイル名:providers.tf

terraform {
  required_version ">= [利用するバージョンを記載]"
  backend "s3" {
    # 作成したS3バケット
    bucket = "[S3バケット名]"
    region = "[リージョン名]"
    # tfstateファイル名
    key = "terraform.tfstate"
    encrypt = true
    # 作成したDynamoDBテーブル
    dynamodb_table = "[DynamoDBテーブル名]"
  }
}

provider "aws" {
  region = "[リージョン名]"
}

3. Terraformソースコードを管理する

「Infrastructure as Code」なので、ソースコードの管理は必須になってきます。GitHubやSubversionなどのバージョン管理システムを用いてソースコードのバージョン管理を実施しましょう。
また、Terraformでは「実環境に何が反映されているのか」を管理することが重要です。
「このブランチへマージされたら必ずterraform applyを実行し、環境にソースコードを適用する。」といった約束事を案件メンバー内で策定しましょう。

AWSでは、CodeCommitを利用することでソースコードのバージョン管理を実現することが可能です。
CodeCommitは、CodePipelineなどのCICDサービスと連携が可能であるため、Terraform用CICDパイプラインの構築が可能です。(ここは、近いうちに別の記事を出し詳細にご説明予定です!)
https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/action-reference-CodeCommit.html

また、GitHubでも「GitHub Actions」を利用することでTerraform用CICDパイプラインの構築が可能ですので、興味のある方はこちらをご一読してみてください。
Automate Terraform with GitHub Actions

まとめ

今回の記事では、「Terraformを管理する」について書いていきました。
次回の記事では、今回の記事で取り上げたtfstateやソースコードの管理を実現するために私が作成した「Terraform利用環境構築テンプレート」を利用したハンズオン記事を書こうと思います。

フクナガ

AWS、Google Cloud中心に気になったトピックを発信していきます!

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら