AWS
redshift
CloudFormation
Terraform
Hashicorp

TerraformでCloudFormationを実行

More than 3 years have passed since last update.


課題

HashiCorpのTerraformではInfrastructure as a Codeを容易に記述できるが、各種providerではまだ未実装のモノが多い。

例えば、Redshift (2015/11/27現在)

https://github.com/hashicorp/terraform/pull/3862


解決法

しかし、Terraform v0.6.7では最近CloudFormationのproviderに対応した為、CloudFormation templateを埋め込んで機能を補完できるようになった!(ついこの間まではHEADにしか入ってなかったので、goでコンパイルする必要があったけど)


TF files

こんな感じで。


vpc.tf

# VPC

resource "aws_vpc" "test" {
cidr_block = "172.7.0.0/16"
enable_dns_hostnames = true

tags {
Name = "test"
}
}

# subnets
resource "aws_subnet" "test-1a" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "172.7.0.0/20"
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true

tags {
Name = "1a"
}
}

resource "aws_subnet" "test-1c" {
vpc_id = "${aws_vpc.test.id}"
cidr_block = "172.7.16.0/20"
availability_zone = "ap-northeast-1c"
map_public_ip_on_launch = true

tags {
Name = "1c"
}
}



security-group.tf

resource "aws_security_group" "test-redshift" {

vpc_id = "${aws_vpc.test.id}"
name = "test-redshift"
description = "redshift SG (test)"
tags {
Name = "redshift"
}

ingress {
from_port = 5439
to_port = 5439
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}



redshift.tf

resource "aws_cloudformation_stack" "redshift" {

name = "redshift"
template_body = <<STACK
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters" : {
"DatabaseName" : {
"Description" : "The name of the first database to be created when the cluster is created",
"Type" : "String",
"Default" : "mydwh",
"AllowedPattern" : "([a-z]|[0-9])+"
},
"ClusterType" : {
"Description" : "The type of cluster",
"Type" : "String",
"Default" : "multi-node",
"AllowedValues" : [ "single-node", "multi-node" ]
},
"NumberOfNodes" : {
"Description" : "The number of compute nodes in the cluster. For multi-node clusters, the NumberOfNodes parameter must be greater than 1",
"Type" : "Number",
"Default" : "2"
},
"NodeType" : {
"Description" : "The type of node to be provisioned",
"Type" : "String",
"Default" : "dc1.large",
"AllowedValues" : [ "dc1.large", "dc1.8xlarge", "ds2.large", "ds2.8xlarge" ]
},
"MasterUsername" : {
"Description" : "The user name that is associated with the master user account for the cluster that is being created",
"Type" : "String",
"Default" : "dbuser",
"AllowedPattern" : "([a-z])([a-z]|[0-9])*"
},
"MasterUserPassword" : {
"Description" : "The password that is associated with the master user account for the cluster that is being created.",
"Type" : "String",
"Default" : "dbpassword",
"NoEcho" : "true"
},
"PortNumber" : {
"Description" : "The port number on which the cluster accepts incoming connections.",
"Type" : "Number",
"Default" : "5439"
},
"VpcId" : {
"Description" : "The VPC ID to launch the cluster",
"Type" : "AWS::EC2::VPC::Id",
"Default" : "${aws_vpc.test.id}"
},
"SecurityGroupId" : {
"Description" : "The Security Group ID(s) to launch the cluster",
"Type" : "List<AWS::EC2::SecurityGroup::Id>",
"Default" : "${aws_security_group.test-redshift.id}"
},
"Subnets" : {
"Description" : "The Subnet ID(s) to include in the subnet group",
"Type" : "List<AWS::EC2::Subnet::Id>",
"Default" : "${aws_subnet.test-1a.id},${aws_subnet.test-1c.id}"
}
},
"Conditions" : {
"IsMultiNodeCluster" : {
"Fn::Equals" : [{ "Ref" : "ClusterType" }, "multi-node" ]
}
},
"Resources" : {
"RedshiftCluster" : {
"Type" : "AWS::Redshift::Cluster",
"Properties" : {
"ClusterType" : { "Ref" : "ClusterType" },
"NumberOfNodes" : { "Fn::If" : [ "IsMultiNodeCluster", { "Ref" : "NumberOfNodes" }, { "Ref" : "AWS::NoValue" }]},
"NodeType" : { "Ref" : "NodeType" },
"DBName" : { "Ref" : "DatabaseName" },
"MasterUsername" : { "Ref" : "MasterUsername" },
"MasterUserPassword" : { "Ref" : "MasterUserPassword" },
"ClusterParameterGroupName" : { "Ref" : "RedshiftClusterParameterGroup" },
"VpcSecurityGroupIds" : { "Ref" : "SecurityGroupId" },
"ClusterSubnetGroupName" : { "Ref" : "RedshiftClusterSubnetGroup" },
"PubliclyAccessible" : "true",
"Port" : { "Ref" : "PortNumber" }
}
},
"RedshiftClusterParameterGroup" : {
"Type" : "AWS::Redshift::ClusterParameterGroup",
"Properties" : {
"Description" : "Cluster parameter group",
"ParameterGroupFamily" : "redshift-1.0",
"Parameters" : [{
"ParameterName" : "enable_user_activity_logging",
"ParameterValue" : "true"
}]
}
},
"RedshiftClusterSubnetGroup" : {
"Type" : "AWS::Redshift::ClusterSubnetGroup",
"Properties" : {
"Description" : "Cluster subnet group",
"SubnetIds" : { "Ref" : "Subnets" }
}
}
},
"Outputs" : {
"ClusterEndpoint" : {
"Description" : "Cluster endpoint",
"Value" : { "Fn::Join" : [ ":", [ { "Fn::GetAtt" : [ "RedshiftCluster", "Endpoint.Address" ] }, { "Fn::GetAtt" : [ "RedshiftCluster", "Endpoint.Port" ] } ] ] }
},
"ClusterName" : {
"Description" : "Name of cluster",
"Value" : { "Ref" : "RedshiftCluster" }
},
"ParameterGroupName" : {
"Description" : "Name of parameter group",
"Value" : { "Ref" : "RedshiftClusterParameterGroup" }
}
}
}
STACK

Terraformで作成されたvariableがそのまま埋め込めるのが素晴らしい。


機能実装の優先順位付け

ちなみに欲しい機能は以下のspreadsheetに自分のgithub idを付け足して投票する事によって、優先順位を決めているとのこと。

https://docs.google.com/spreadsheets/d/1yJKjLaTmkWcUS3T8TLwvXC6EBwNSpuQbIq0Y7OnMXhw/edit#gid=1149664272&vpid=A1