既存のリソース上にTerraformでリソースを追加してみた

既存のリソース上にTerraformでリソースを追加してみた

Clock Icon2024.11.13

はじめに

既存のVPC上にTerrafromで管理するEC2を立てるなど、既存のリソースとTerraformで管理するリソースを関連づけたいという状況がありました。
IaCの考え方として、このリソースは手動、このリソースはIaC、というように管理を分けることは推奨されないと思いますが、業務の都合上どうしても分けなければいけないケースも存在すると思います。

今回は手動で作成したVPC上にTerraformで管理するEC2を立ててみたいと思います。
イメージ図はこんな感じです。
image1

検証に使用した環境は以下の通りです。

$ terraform --version
Terraform v1.9.5
main.tf
terraform {
  required_version = "~> 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~>5.63.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

VPCの作成

まずはVPCを作成します。
今回はAWS CLIを使っています。

aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=demo_vpc}]'

次にサブネットを作成します。

aws ec2 create-subnet \
  --vpc-id {VPCのID} \
  --cidr-block 10.0.0.0/24 \
  --availability-zone ap-northeast-1a
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=demo_subnet}]'

コンソール画面からVPCとサブネットが作成されていることを確認します。
image2

TerraformでEC2を作成

作成したVPC上にTerraformでEC2を作成するためにはVPC上のサブネットのIDを指定する必要があります。
サブネットIDの指定には以下の方法があります。

  • 直接サブネットIDを指定
  • 変数を使ってサブネットIDを指定
  • Data Sourcesで既存のサブネットIDを取得して指定

直接サブネットIDを指定するパターンは、説明は不要かと思いますので今回は割愛します。

変数に代入

既存サブネットIDを変数に代入する方法をやってみます。
まずは既存VPCのIDを調べます。

$ aws ec2 describe-vpcs --filters Name=tag:Name,Values=demo_vpc --query 'Vpcs[*].VpcId' --output text 

vpc-03fb25adbfa800687

取得したVPC IDからサブネットIDを取得します。(コンソール画面でも確認できます)

$ aws ec2 describe-subnets --filters Name=vpc-id,Values=vpc-03fb25adbfa800687 --query 'Subnets[*].SubnetId' --output text

subnet-069203c44d7574802

取得したサブネットのIDを変数として代入してEC2を作成します。

ec2.tf
#####################################################
# Variable
#####################################################
# Subnet ID
variable "subnet_id" {
  type = string
  default     = "subnet-069203c44d7574802"
}

####################################################
# EC2
####################################################
# EC2
resource "aws_instance" "ec2" {
  ami                         = "ami-08ce76bae392de7dc"
  instance_type               = "t3.nano"
  availability_zone           = "ap-northeast-1a"
  subnet_id                   = var.subnet_id
}

それでは上記のEC2をデプロイします。

$ terraform plan
$ terraform apply

コンソール画面から確認してみましょう。
image3

手動で作成したVPC上にEC2が立ち上がっていますね。

Data Sources

次にTerraformのData Sources機能を使ってみます。
Data SourcesはTerraformの外部で定義された情報を使用するための機能です。
今回はVPCの情報とサブネットの情報を取得して使用します。

それぞれ以下のドキュメントを参考にタグ名でフィルタリングしています。
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc
https://registry.terraform.io/providers/hashicorp/aws/4.2.0/docs/data-sources/subnet

ec2.tf
######################################################################################
# Data Sources
######################################################################################
# VPC
data "aws_vpc" "main" {
  filter {
    name = "tag:Name"
    values = ["demo_vpc"]
  }
}

# Subnet
data "aws_subnet" "main" {
  vpc_id = data.aws_vpc.main.id
  filter {
    name = "tag:Name"
    values = ["demo_subnet"]
  }
}

######################################################################################
# EC2
######################################################################################
# EC2
resource "aws_instance" "main" {
  ami                         = "ami-08ce76bae392de7dc"
  instance_type               = "t3.nano"
  availability_zone           = "ap-northeast-1a"
+ subnet_id                   = data.aws_subnet.main.id
}

EC2のsubnet_idの部分にData Sourcesで取得したサブネットのIDを指定しています。
では、これでEC2をデプロイします。

$ terraform plan
$ terraform apply

既存のVPC上にEC2が起動していることが確認できますね。
image4

Data Sourcesを使うことで、動的に既存リソースの情報を取得して利用することができました。

outputで取得した情報を確認

念の為、outputを指定してサブネットIDが取得できていることも確認しておきます。

ec2.tf
######################################################################################
# Data Sources
######################################################################################
# VPC
data "aws_vpc" "main" {
  filter {
    name = "tag:Name"
    values = ["demo_vpc"]
  }
}

# Subnet
data "aws_subnet" "main" {
  vpc_id = data.aws_vpc.main.id
  filter {
    name = "tag:Name"
    values = ["demo_subnet"]
  }
}

+# Subnet idを出力
+output "subnet" {
+  value = data.aws_subnet.main.id
+}

######################################################################################
# EC2
######################################################################################
# EC2
resource "aws_instance" "main" {
  ami                         = "ami-08ce76bae392de7dc"
  instance_type               = "t3.nano"
  availability_zone           = "ap-northeast-1a"
  subnet_id                   = data.aws_subnet.main.id
}

outputを追加して terraform output します。

$ terraform output

subnet = "subnet-069203c44d7574802"

想定通りサブネットのIDが取得できていますね。

まとめ

既存リソースの値を参考にTerraformでリソースを追加する場合ってどうやるんだっけ?と疑問に思ったのでやってみました。
個人的には毎回変数を代入するのは面倒なのでData Sourcesを使うのが便利だと思いました。
また、Data Sourcesを使うと複数のサブネット情報をまとめて取得することもできるので、そういったプログラマチックな仕組みを作れるのもData Sourcesのメリットかなと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.