æ¬è¨äºã¯
AWSã¢ã¯ã¼ãè¨å¿µï¼å¤ã®ã¢ããã³ãã«ã¬ã³ãã¼
14æ¥ç®ã®è¨äºã§ãã
ðð
13æ¥ç®
â¶â¶ æ¬è¨äº â¶â¶
15æ¥ç®
ðð
ã«ã©ã¹ã«è¥²ããããããã°ãããã®ä»è¿ã«ã¯è¿ã¥ãã¦ãã¾ããã䏿ã§ãã
Terraformã®ã©ã¤ã»ã³ã¹å¤æ´ããã£ãããããããã©ããªãã®ãå¿é ãã¦ãã¾ããããIBMãHashiCorpãè²·åãããã¨ãçºè¡¨ãããããè½ã¡çãããã§å®å¿ãã¦ãã¾ããä»å¾ãååãæ³¨è¦ãã¦ããã¾ãã
æ¬è¨äºã§ã¯Terraformã®çµã¿è¾¼ã¿é¢æ°templatefileã«ã¤ãã¦ãç´¹ä»ãã¾ãã
templatefile颿°ã¨ã¯
æå®ããããã¹ã«ãããã³ãã¬ã¼ããã¡ã¤ã«ãèªã¿åãããã®å
容ããã³ãã¬ã¼ãã¨ãã¦ã¬ã³ããªã³ã°ãããã¨ã§ããã¹ããã¡ã¤ã«ãè¨å®ãã¡ã¤ã«ãåçã«çæãããã¨ãã§ãã¾ãã
ãã®ããç°å¢æ¯ã«å°ãç°ãªããã¡ã¤ã«ã使ç¨ããå¿
è¦ãããå ´åãªã©ã«é常ã«ä¾¿å©ãªé¢æ°ã§ãã
developer.hashicorp.com
AWSç°å¢ã«ãããtemplatefile颿°ã®æ´»ç¨æ¹æ³ãããã¤ããç´¹ä»ãã¾ãã
1. ã¦ã¼ã¶ã¼ãã¼ã¿
ã¦ã¼ã¶ã¼ãã¼ã¿ã¯EC2ã¤ã³ã¹ã¿ã³ã¹èµ·åæã®åæè¨å®ããã¹ã¯ãªãããèªåå®è¡ããããã«ä½¿ç¨ããã¾ãã
ãã®ã¦ã¼ã¶ã¼ãã¼ã¿ãtemplatefile颿°ã§çæãããã¨ãå¯è½ã§ãã
ãã£ã¬ã¯ããªæ§é ããã¡ã¤ã«å 容ã¯ä»¥ä¸ã®ããã«ãã¦ãã¾ãã
- ãã£ã¬ã¯ããªæ§é
project/
âââ modules/
â âââ ec2/
â âââ main.tf
â âââ init.tpl
âââ env/
âââ prod/
â âââ ec2/
â âââ main.tf
âââ stage/
âââ ec2/
âââ main.tf
- modules/ec2/main.tf
- user_dataã§templatefile颿°ã使ç¨ãã¾ãã
- åãã£ã¬ã¯ããªä¸ã®ãã³ãã¬ã¼ããã¡ã¤ã«init.tplãæå®ããpackagesã¨file_contentã夿°ã«ãã¦ãã¾ãã
- user_dataã§templatefile颿°ã使ç¨ãã¾ãã
provider "aws" {
region = "ap-northeast-1"
}
variable "packages" {
type = list(string)
}
variable "file_content" {
type = any
}
resource "aws_instance" "example" {
ami = "ami-061a125c7c02edb39"
instance_type = "t2.micro"
iam_instance_profile = "MySessionManagerRole"
user_data = templatefile("${path.module}/init.tpl", {
packages = join(" ", var.packages)
file_content = var.file_content
})
}
- modules/ec2/init.tpl
- user_dataã§ä½¿ç¨ãããã³ãã¬ã¼ããã¡ã¤ã«ã§ããcloud-configå½¢å¼ã«ãã¦ãã¾ãã
- ä»åã®ä¾ã§ã¯write_files:ãruncmd:ã使ç¨ãã¦ãã¾ãããusers:ã§ã¦ã¼ã¶ã¼ä½æãããã¨ãå¯è½ã§ãã
- init.tplã«cloud_final_modules:ãè¨å®ãããã¨ã§ãã¦ã¼ã¶ã¼ãã¼ã¿ãå©ç¨ãã¦ä½æãããã¡ã¤ã«ãåé¤ããããããã±ã¼ã¸ãã¢ã³ã¤ã³ã¹ãã¼ã«ããã¨ãã¦ãåèµ·åæã«ã¯å使ã»åã¤ã³ã¹ãã¼ã«ãããã¨ãã§ãã¾ãã
â»æ¢åã®EC2ã¤ã³ã¹ã¿ã³ã¹ã®æ§æã夿´ããããã«ããã®ãã³ãã¬ã¼ããã¡ã¤ã«ãä¿®æ£ãã¦terraform applyãåå®è¡ããå ´åãã¦ã¼ã¶ã¼ãã¼ã¿ãä¿®æ£ããã¾ããå®è¡ã¯ããã¾ããã æ°ããã¦ã¼ã¶ã¼ãã¼ã¿ãå®è¡ãããå ´åã«ã¯ãEC2ã¤ã³ã¹ã¿ã³ã¹ä¸ã§cloud-init cleanãå®è¡ãã¦cloud-initã®ãã£ãã·ã¥ããªã»ããããããã§ãåèµ·åããå¿ è¦ãããã¾ãã
- init.tplã«cloud_final_modules:ãè¨å®ãããã¨ã§ãã¦ã¼ã¶ã¼ãã¼ã¿ãå©ç¨ãã¦ä½æãããã¡ã¤ã«ãåé¤ããããããã±ã¼ã¸ãã¢ã³ã¤ã³ã¹ãã¼ã«ããã¨ãã¦ãåèµ·åæã«ã¯å使ã»åã¤ã³ã¹ãã¼ã«ãããã¨ãã§ãã¾ãã
- ä»åã®ä¾ã§ã¯write_files:ãruncmd:ã使ç¨ãã¦ãã¾ãããusers:ã§ã¦ã¼ã¶ã¼ä½æãããã¨ãå¯è½ã§ãã
- user_dataã§ä½¿ç¨ãããã³ãã¬ã¼ããã¡ã¤ã«ã§ããcloud-configå½¢å¼ã«ãã¦ãã¾ãã
#cloud-config
cloud_final_modules:
- [scripts-user, always]
- [write-files, always]
write_files:
- path: /etc/welcome.txt
permissions: '0644'
owner: root:root
content: |
${file_content}
runcmd:
- yum install -y ${packages}
- env/prod/ec2/main.tf
- prodç°å¢ã®EC2ã¤ã³ã¹ã¿ã³ã¹ã§ä½æãããã¡ã¤ã«ã®å 容ãã¤ã³ã¹ãã¼ã«ããã±ã¼ã¸ãè¨è¿°ãã¦ãã¾ãã
module "ec2-instance" {
source = "../../../modules/ec2"
packages = ["amazon-cloudwatch-agent", "git"]
file_content = <<EOF
Welcome to prod server!
EOF
}
- env/stage/ec2/main.tf
- packages, file_content以å¤ã¯env/prod/main.tfã¨åæ§ã®å 容ã§ãã
module "ec2-instance" {
source = "../../../modules/ec2"
packages = ["git"]
file_content = <<EOF
Welcome to stage server!
EOF
}
env/prod/ec2/ã§terrafom applyãå®è¡ãã¦EC2ã¤ã³ã¹ã¿ã³ã¹ã使ãã¾ãã
以ä¸ã¯prodç°å¢ã®EC2ã¤ã³ã¹ã¿ã³ã¹ã®ã¦ã¼ã¶ã¼ãã¼ã¿ã»ãã¡ã¤ã«ã»ããã±ã¼ã¸ã®ç¢ºèªçµæã§ãã

åæ§ã«env/stage/ec2/ã§terrafom applyãå®è¡ãã¾ãã
以ä¸ã¯stageç°å¢EC2ã¤ã³ã¹ã¿ã³ã¹ã®ã¦ã¼ã¶ã¼ãã¼ã¿ã»ãã¡ã¤ã«ã»ããã±ã¼ã¸ã®ç¢ºèªçµæã§ãã

2. IAMããªã·ã¼ããã¼ã«
main.tfã«IAMããªã·ã¼ããã¼ã«ãè¨è¿°ããã¨è¿½å ãããã³ã«ãã¡ã¤ã«ãè¥å¤§åãã¦ãããç®å½ã¦ã®ããªã·ã¼ã»ãã¼ã«ãæ¢ããã¨ãæéã«ãªãã¾ãã
ãããé¿ããããã«templatefile颿°ã使ç¨ãã¾ãã
- ãã£ã¬ã¯ããªæ§é
project/
âââ modules/
â âââ iam/
â âââ main.tf
â âââ iam_policy.json.tpl
â âââ iam_role.json.tpl
âââ env/
âââ prod/
â âââ iam/
â âââ main.tf
âââ stage/
âââ iam/
âââ main.tf
- modules/ec2/main.tf
- aws_iam_policyãªã½ã¼ã¹ã®policyã¨ãaws_iam_roleãªã½ã¼ã¹ã®assume_role_policyã§templatefile颿°ã使ç¨ãã¾ãã
- åãã£ã¬ã¯ããªä¸ã®ãã³ãã¬ã¼ããã¡ã¤ã«iam_policy.json.tplã¨iam_role.json.tplãæå®ããiam_policy.json.tplã¯actionsã¨resourcesã夿°ã«ãiam_role.json.tplã¯serviceã夿°ã«ãã¦ãã¾ãã
- aws_iam_policyãªã½ã¼ã¹ã®policyã¨ãaws_iam_roleãªã½ã¼ã¹ã®assume_role_policyã§templatefile颿°ã使ç¨ãã¾ãã
variable "policies" {
description = "List of IAM policies"
type = list(object({
name = string
actions = list(string)
resources = list(string)
}))
}
variable "roles" {
description = "List of IAM roles"
type = list(object({
name = string
service = string
policies = list(string)
}))
}
resource "aws_iam_policy" "example" {
for_each = { for p in var.policies : p.name => p }
name = each.value.name
policy = templatefile("${path.module}/iam_policy.json.tpl", {
actions = jsonencode(each.value.actions)
resources = jsonencode(each.value.resources)
})
}
resource "aws_iam_role" "example" {
for_each = { for r in var.roles : r.name => r }
name = each.value.name
assume_role_policy = templatefile("${path.module}/iam_role.json.tpl", {
service = each.value.service
})
}
resource "aws_iam_role_policy_attachment" "example" {
for_each = { for r in var.roles : r.name => r }
role = aws_iam_role.example[each.key].name
policy_arn = lookup({ for p in var.policies : p.name => aws_iam_policy.example[p.name].arn }, each.value.policies[0])
}
- modules/iam/iam_policy.json.tpl
- policyã§ä½¿ç¨ãããã³ãã¬ã¼ããã¡ã¤ã«ã§ãã
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ${actions},
"Resource": ${resources}
}
]
}
- modules/iam/iam_role.json.tpl
- assume_role_policyã§ä½¿ç¨ãããã³ãã¬ã¼ããã¡ã¤ã«ã§ãã
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "${service}"
},
"Action": "sts:AssumeRole"
}
]
}
- env/prod/iam/main.tf
- prodç°å¢ã§ä½æããIAMããªã·ã¼ããã¼ã«ãè¨è¿°ãã¦ãã¾ãã
module "iam" {
source = "../../../modules/iam"
policies = [
{
name = "prod_policy_1"
actions = ["s3:ListBucket", "s3:GetObject"]
resources = ["arn:aws:s3:::prod-bucket-name", "arn:aws:s3:::prod-bucket-name/*"]
},
{
name = "prod_policy_2"
actions = ["ec2:DescribeInstances"]
resources = ["*"]
}
]
roles = [
{
name = "prod_role_1"
service = "ec2.amazonaws.com"
policies = ["prod_policy_1"]
},
{
name = "prod_role_2"
service = "lambda.amazonaws.com"
policies = ["prod_policy_2"]
}
]
}
- env/stage/iam/main.tf
- stageç°å¢ã§ä½æããIAMããªã·ã¼ããã¼ã«ãè¨è¿°ãã¦ãã¾ãã
module "iam" {
source = "../../../modules/iam"
policies = [
{
name = "stage_policy_1"
actions = ["s3:ListBucket", "s3:GetObject"]
resources = ["arn:aws:s3:::stage-bucket-name", "arn:aws:s3:::stage-bucket-name/*"]
},
{
name = "stage_policy_2"
actions = ["ec2:DescribeInstances"]
resources = ["*"]
}
]
roles = [
{
name = "stage_role_1"
service = "ec2.amazonaws.com"
policies = ["stage_policy_1"]
},
{
name = "stage_role_2"
service = "lambda.amazonaws.com"
policies = ["stage_policy_2"]
}
]
}
env/prod/iam/ã§terrafom applyãå®è¡ãã¦IAMããªã·ã¼ããã¼ã«ã使ãã¾ãã
以ä¸ã¯prodç°å¢IAMããªã·ã¼ããã¼ã«ã®ç¢ºèªçµæã§ãã


åæ§ã«env/stage/iam/ã§terrafom applyãå®è¡ãã¾ãã
以ä¸ã¯stageç°å¢IAMããªã·ã¼ããã¼ã«ã®ç¢ºèªçµæã§ãã


3. Terraformè¨å®ãã¡ã¤ã«
Terraformè¨å®ãã¡ã¤ã«ã®æ¡å¼µåã¯.tfã§ãããã¤ã³ãã©ãªã½ã¼ã¹ãå®ç¾©ããmain.tfã夿°å®£è¨ãè¡ãvariables.tfãåºåå¤ãå®ç¾©ããoutputs.tfãªã©ãããã¾ãã
templatefile颿°ã使ç¨ãããã¨ã§Terraformè¨å®ãã¡ã¤ã«(tfãã¡ã¤ã«)èªä½ãåçã«ä½æãããã¨ãå¯è½ã§ãã
â»Terraformã¯ãã£ã¬ã¯ããªå
ãã¹ã¦ã®tfãã¡ã¤ã«ãèªã¿åããããæ¡å¼µåã.tfã§ããã°ãã¡ã¤ã«åã¯èªç±ã«å¤æ´å¯è½ã§ãã
- ãã£ã¬ã¯ããªæ§é
project/
âââ modules/
â âââ s3/
â âââ main.tf
â âââ s3.tf.tpl
âââ env/
âââ prod/
â âââ s3/
â âââ main.tf
âââ stage/
âââ s3/
âââ main.tf
- modules/s3/main.tf
- local_fileãªã½ã¼ã¹ã®contentã§templatefile颿°ã使ç¨ãã¾ãã
- åãã£ã¬ã¯ããªä¸ã®ãã³ãã¬ã¼ããã¡ã¤ã«s3.tf.tplãæå®ããbucket_nameã夿°ã«ãã¦ãã¾ãã
- local_fileãªã½ã¼ã¹ã®contentã§templatefile颿°ã使ç¨ãã¾ãã
provider "aws" {
region = "ap-northeast-1"
}
variable "bucket_names" {
type = list(string)
}
variable "file_path" {
type = string
}
resource "local_file" "s3_buckets" {
count = length(var.bucket_names)
filename = "${var.file_path}/s3_${var.bucket_names[count.index]}.tf"
content = templatefile("${path.module}/s3.tf.tpl", {
bucket_name = var.bucket_names[count.index]
})
}
- modules/s3/s3.tf.tpl
- contentã§ä½¿ç¨ãããã³ãã¬ã¼ããã¡ã¤ã«ã§ãã
resource "aws_s3_bucket" "${bucket_name}" {
bucket = "${bucket_name}"
acl = "private"
}
- env/prod/s3/main.tf
- prodç°å¢ã§ä½æããs3ãã±ãããè¨è¿°ãã¦ãã¾ãã
module "s3" {
source = "../../../modules/s3"
bucket_names = ["prod-bucket-example-1", "prod-bucket-example-2", "prod-bucket-example-3"]
file_path = "."
}
- env/stage/s3/main.tf
- stageç°å¢ã§ä½æããs3ãã±ãããè¨è¿°ãã¦ãã¾ãã
module "s3" {
source = "../../../modules/s3"
bucket_names = ["stage-bucket-example-1", "stage-bucket-example-2", "stage-bucket-example-3"]
file_path = "."
}
env/prod/s3/ã§terrafom applyãå®è¡ããã¨Terraformè¨å®ãã¡ã¤ã«ï¼prod-bucket-example-1.tfãprod-bucket-example-2.tfãprod-bucket-example-3.tfï¼ã使ããã¾ãã
ããã¦å度terraform applyãå®è¡ããã¨ä½æããããã¡ã¤ã«ãèªã¿åããS3ãã±ããã使ãã¾ãã
以ä¸ã¯prodç°å¢s3ãã±ããã®ç¢ºèªçµæã§ãã

åæ§ã«env/stage/s3/ã§terrafom applyã2åå®è¡ãã¾ãã
以ä¸ã¯stageç°å¢s3ãã±ããã®ç¢ºèªçµæã§ãã

æå¾ã«
templatefile颿°ã®æ´»ç¨æ¹æ³ã3ã¤ãç´¹ä»ãã¾ããããã»ãã«ãæ§ã
ãªæ´»ç¨æ¹æ³ããããã¨æãã¾ãã
æ¬è¨äºãTerraformã使ç¨ããçæ§ã®åèã¨ãªããtemplatefile颿°ã®æ°ããæ´»ç¨æ¹æ³ãè¦ã¤ããããã®å©ãã¨ãªãã¾ããã幸ãã§ãã