既存AWS環境をTerraformで素早く複製する

この記事を書いたメンバー:

Anna

既存AWS環境をTerraformで素早く複製する

目次

こんにちは。BeeXの粥川です。
皆さんあるある話だとは思いますが、最近複数の案件で既に構築済みのProduction環境からStaging環境をすぐ作って!PerformanceTest環境もよろしく!という話が多数ありました。プラットフォームはどれもAWSなので、最初からCloudFormationやTerraformでデプロイしてるからすぐできます!なら楽なのですが、実際のプロジェクトだとGUI、CLIで構築しているケースはまだまだ多く、パパっとデプロイできない・・・一からGUIで作るか・・・と地道な作業となることも。
ただ今後もさらに複製環境が増える場合や、一度作って削除してを繰り返す場合も考えられます。そこで、本記事ではインフラ構成管理ツールであるTerraform+terraformingでProduction環境をインポート、コード化して複製したStaging環境を提供してみます。

実際に作業する前に

少し用語の説明を。

Terraformとは

HashiCorp社が開発している、インフラ構成管理ツールです。
ググればいろんな方が説明されているので、ポイントだけ。
・構築するインフラの定義ファイル(.tfファイル)を記述していく。
・定義ファイルを記述後、いざデプロイすると記述通りのインフラが出来上がる。
・構築されたインフラの状態は、状態ファイル(tfstateファイル)に記述されている。

terraformingとは

dtan4さんがメンテナンスされている、Terraformの定義ファイル(.tfファイル)を自動で作成してくれるツールです。

なぜterraformingを使うのか

実は、Terraformには公式で提供するimportというコマンドがあります。importコマンドを使うことで、既に構築済みのインフラをimportしTerraformの管理対象とすることが可能です。しかしここで問題なのが、importコマンドは定義ファイル(.tfファイル)を作成してくれないということです。importコマンドは状態ファイル(tfstateファイル)に現在の状態を記述してくれるのですが、そこから定義ファイルを作成する部分が手動になってしまいます。そこで、定義ファイルも自動で作成してくれるterraformingの出番!ということですね。

事前準備

Production環境の複製を始める前に、作業環境を整えます。

Terraform、terraformingのインストール

Terraformのパッケージマネージャーであるtfenvを使ってインストールします。今回はバージョン0.12.6をインストールしています。

$ brew installtfenv
$ tfenv install 0.12.6

terraformingをgemでインストールします。

$ gem install terraforming

ここで、作業ディレクトリも作成しておきます。Production環境とStaging環境でフォルダを分けました。まずProduction環境のインポートを行うので、prodディレクトリに移動します。

mkdir-p tfdemo/prod
mkdir -p tfdemo/stg
cd tfdemo/prod

Credentialsの指定

AWSのAPIをコールするため、Credentialsを環境変数にセットします。
今回はAdministratorAccess権限をもったIAMユーザを使用しています。
リージョンはフランクフルトを指定しました。

exportAWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export AWS_DEFAULT_REGION=eu-central-1

構築済みインフラ環境の確認

インポート作業をする前に、インポートする環境(仮想のProduction環境)を構築しておきます。作業手順は割愛しますが、下記環境を構築しました。

ALBでhttpsアクセスを受けてEC2上の静的コンテンツを返すだけのWebサイトです。1VPCにPublic、Private Subnetがそれぞれ2つずつ、Public Subnet内のALBからPrivate SubnetのEC2にhttpでルーティングする構成になっています。
ただのテキストですが、、アクセスするとこんなページが表示されます。

Production環境のインポート

それでは、事前準備が終わりましたので、terraformingでProduction環境をインポートし、.tfファイルを作成します。

terraforming実行

初めにvpcを指定してインポートしてみます。
terraformingでは以下のようにサービスを指定すると、リージョン内の情報を一括で定義ファイル(.tfファイル)形式で出力します。

$ terraforming vpc
resource "aws_vpc" "vpc-prod" {
 cidr_block = "172.20.0.0/16"
 enable_dns_hostnames = true
 enable_dns_support = true
 instance_tenancy = "default"
 
 tags {
 "Name" "vpc-prod"
 }
}
 
resource "aws_vpc" "vpc-331efa5a" {
 cidr_block = "172.31.0.0/16"
 enable_dns_hostnames = true
 enable_dns_support = true
 instance_tenancy = "default"
 
 tags {
 }
}

同じようにSubnetやSecurityGroupも定義ファイル化し、作業ディレクトリ配下はこのようになりました。

prod
├── alb.tf
├── ec2.tf
├── eip.tf
├── igw.tf
├── nacl.tf
├── natgw.tf
├── route53.tf
├── rt.tf
├── sg.tf
├── subnet.tf
└── vpc.tf

上記で元となる.tfファイルの作成が完了しました。今回Production環境はTerraform管理下におかず、複製環境のみコード化します。Staging環境用のフォルダに上記ファイルを全てコピーします。

cp-p prod/* stg/
cd stg

Staging環境のデプロイ

Staging環境用に..tfファイルを修正し、Terraformでデプロイします。

TFSTATEファイルの管理場所指定

.tfファイルを修正する前に、tfstateファイルの管理場所を指定しておきます。tfstateファイルをローカル管理にしてしまうと、複数人で共有することができなくなります。そこで今回はS3バケットを指定しました。

# config.tf
provider "aws" {
  region = "eu-central-1"
}
 
terraform {
  backend "s3" {
    bucket = "tfconf.example.com"
    key = "stg.tfstate"
    region = "eu-central-1"
  }
}

作業ディレクトリ直下に上記ファイルを作成後、以下コマンドを実行し、tfstateファイルの保管先を認識させます。

$ terraform init

Terraform has been successfully initialized! と表示されれば完了です。

.tfファイルの修正

terraformingで作成した.tfファイルは、Production環境の各リソースid等ユニークな値が入っています。そこで、それらを変数に修正しました。例としてsubnet.tfファイルを以下のように修正しています。

# subnet.tf
resource "aws_subnet" "vpc-stg-pub-sub02" {
    vpc_id                  = "${aws_vpc.vpc-stg.id}"
    cidr_block              = "172.21.102.0/24"
    availability_zone       = "eu-central-1c"
    map_public_ip_on_launch = false
 
    tags = {
        Name = "vpc-stg-pub-sub02"
    }
}
 
resource "aws_subnet" "vpc-stg-pri-web-sub02" {
    vpc_id                  = "${aws_vpc.vpc-stg.id}"
    cidr_block              = "172.21.2.0/24"
    availability_zone       = "eu-central-1c"
    map_public_ip_on_launch = false
 
    tags = {
        Name = "vpc-stg-pri-web-sub02"
    }
}
 
resource "aws_subnet" "vpc-stg-pub-sub01" {
    vpc_id                  = "${aws_vpc.vpc-stg.id}"
    cidr_block              = "172.21.101.0/24"
    availability_zone       = "eu-central-1a"
    map_public_ip_on_launch = false
 
    tags = {
        Name = "vpc-stg-pub-sub01"
    }
}
 
resource "aws_subnet" "vpc-stg-pri-web-sub01" {
    vpc_id                  = "${aws_vpc.vpc-stg.id}"
    cidr_block              = "172.21.1.0/24"
    availability_zone       = "eu-central-1a"
    map_public_ip_on_launch = false
 
    tags = {
        Name = "vpc-stg-pri-web-sub01"
    }
}

他のリソースも同様に修正します。Staging環境のデプロイが完了すると同時に、stg-www.example.comへアクセスできるよう、route53.tfファイルでALIASレコードを追加しています。

# route53.tf
resource "aws_route53_record" "stg-www" {
  name = "stg-www"
  type "A"
  zone_id = "XXXXXXXXXXXXXX"
 
  alias {
    evaluate_target_health = false
    name = "${aws_alb.stg-alb-web01.dns_name}"
    zone_id = "${aws_alb.stg-alb-web01.zone_id}"
  }
}

実行計画の確認

他の.tfファイルの修正が完了したら、デプロイする前に実行計画を確認します。
新たにStaging環境用のリソースを作成するため、全て+ createになっています。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
 
 
------------------------------------------------------------------------
 
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 + create
 
Terraform will perform the following actions:
 
 # aws_alb.stg-alb-web01 will be created
 + resource "aws_alb" "stg-alb-web01" {
 + arn = (known after apply)
 + arn_suffix = (known after apply)
 + dns_name = (known after apply)
 + enable_deletion_protection = false
 + enable_http2 = true
 id = (known after apply)
 + idle_timeout = 60
 + internal = false
 + ip_address_type = (known after apply)
 + load_balancer_type = "application"
 + name = "stg-alb-web01"
 + security_groups = (known after apply)
 + subnets = (known after apply)
 + tags = {
 "Name" "stg-alb-web01"
 }
 + vpc_id = (known after apply)
 + zone_id = (known after apply)
 
 + subnet_mapping {
 + allocation_id = (known after apply)
 + subnet_id = (known after apply)
 }
 }
 
 
Plan: 25 to add, 0 to change, 0 to destroy.

デプロイ実行

実行計画を確認しましたので、デプロイを実行します。

$ terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
 + create
 
Terraform will perform the following actions:
 
 # aws_alb.stg-alb-web01 will be created
 + resource "aws_alb" "stg-alb-web01" {
 + arn = (known after apply)
 + arn_suffix = (known after apply)
 
 
Apply complete! Resources: 25 added, 0 changed, 0 destroyed.

デプロイが無事完了しました!では、stg-www.example.comへアクセスしてみます。

想定通り、ページが表示されました!デプロイするEC2のuserdataで、コンテンツを差し替えていたので、ページの内容もStaging環境用に変更されています。
Subnet等も、もちろん自動で作成されています。

今回デプロイしたStaging環境を図示すると、下記のようになります。
赤枠部分がデプロイした箇所です。

まとめ

Terraform+terraformingを使って既存のProduction環境からStaging環境をデプロイしました。複製する環境用に一から.tfファイルを書いてもよいのですが、terraformingを使うことで、.tfファイルの作成を短縮化しました。
一度作成してしまえば、今後同様に他の環境を作りたい!となったときも、少し修正するだけですぐにデプロイできてしまいますね。
また、デプロイした環境は terraform destroy を実行すれば一式削除できますので、デプロイ&削除を繰り替えすような環境にも最適です。
今回はTerraformを使用しましたが、AWSではいえばCloudFormationもありますし、最近リリースされたAWS CDKもあります。既存環境のインポートなんかはAWS CDKを使えば自作できそうなので、今後検証してみます。

カテゴリー
タグ

この記事を書いたメンバー

SAPシステムや基幹システムのクラウド移行・構築・保守、
DXに関して
お気軽にご相談ください

03-6260-6240 (受付時間 平日9:30〜18:00)