あすたぴのブログ

astap(あすたぴ)のブログ

terraformで aws のいい感じの構成を作る (subnet編)

対象読者

terraformが何かを知っていて、 terraformを使おうと考えている人。

terraform version 0.9.1

subnet とは何なのか。

VPCのネットワーク内で更に細かくネットワークを分割したもの。 http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Subnets.html http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Scenario2.html ここらへんの話しになります。

今回は、イカ3つのsubnet構成を作ります。

  • public
  • nat-private
  • private

public サブネット

public サブネットには、public ip アドレスを付与し、VPCの外からも見えるネットワークを作ります。 ELBを配置します。 また、nat-privateへの踏み台サーバーを建てたりします。

nat-private サブネット

外部ネットワークからアクセスは行えず、外のネットワークへ出る際に、nat を通るネットワーク おもに、自分で作ったアプリケーション(Railsアプリとか)を配置します。

private サブネット

外部ネットワークからアクセスは行えず、外のネットワークに出る必要のないネットワーク Database等のdatastoreを配置します。

multi-az

awsにはAvailabilityZoneと呼ばれる区分けがあります。 これは、物理的なインスタンスの位置の違いを示しており、片方のAZ(データセンター)が(天災とか)で壊れても、もう片方のAZにも配置しておくことでサービスが死なないようにするという手法に使います。

subnetはそれぞれAZごとに作ります。 東京リージョンでは a, c とAZがあるので2つ作ることになります。

subenet 作成のコード

resource "aws_subnet" "public1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 0)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-public1a"
  }
}

resource "aws_subnet" "public1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 1)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-public1c"
  }
}

resource "aws_subnet" "nat-private1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 4)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-nat-private1a"
  }
}

resource "aws_subnet" "nat-private1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 5)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-nat-private1c"
  }
}

resource "aws_subnet" "private1a" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 2)}"
  availability_zone = "ap-northeast-1a"

  tags {
    Name    = "${var.service}-${var.envname}-private1a"
  }
}

resource "aws_subnet" "private1c" {
  vpc_id = "${aws_vpc.vpc.id}"

  cidr_block        = "${cidrsubnet(aws_vpc.vpc.cidr_block, 8, 3)}"
  availability_zone = "ap-northeast-1c"

  tags {
    Name    = "${var.service}-${var.envname}-private1c"
  }
}

cidr_blockは、192.168.0.0/24 192.168.1.0/24 みたいになってます。 1つのsubnetで 256 アドレス使えます。ただ、AWSがいろいろ使うので実際にはこれよりちょっと少ないです。

subnet のネットワーク

subnet内でのネットワークの流れを定義する必要があります。 どうやって外と通信するか。という感じです。

public subnetでは、internet gateway を用意します。 これはVPCとしてのネットワークの出入り口でもあります。

nat-private subnetでは nat_gateway というものを用意します。 これは実態としてはEC2インスタンス(だとおもう)で、public ipアドレスを付与する必要があります。 以前は、AWSが用意したnat用のAMIを自身で起動して用意していましたが、nat_gatewayというマネージドなnatが利用できるようになりました。

イカ、コード

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.vpc.id}"

  tags {
    Name    = "${var.service}_${var.envname}_gateway"
  }
}

resource "aws_eip" "nat_gateway" {
  vpc = true
}

resource "aws_nat_gateway" "nat_gw" {
  allocation_id = "${aws_eip.nat_gateway.id}"
  subnet_id     = "${aws_subnet.public1a.id}"
  depends_on    = ["aws_internet_gateway.gw"]
}

ルートテーブル

実際の、subnetのルーティングを設定します。 0.0.0.0/0 、つまりすべてのネットワークをgatewayに流しています。

resource "aws_route_table" "public" {
  vpc_id = "${aws_vpc.vpc.id}"

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags {
    Name    = "${var.service}_${var.envname}_public"
  }
}

resource "aws_route_table" "nat-private" {
  vpc_id = "${aws_vpc.vpc.id}"

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat_gw.id}"
  }

  tags {
    Name    = "${var.service}_${var.envname}_nat-private"
  }
}

ルートテーブルを作っただけではダメで、それをどのsubnetで使うかを設定します。

resource "aws_route_table_association" "public1a" {
  route_table_id = "${aws_route_table.public.id}"
  subnet_id      = "${aws_subnet.public1a.id}"
}

resource "aws_route_table_association" "public1c" {
  route_table_id = "${aws_route_table.public.id}"
  subnet_id      = "${aws_subnet.public1c.id}"
}

resource "aws_route_table_association" "nat-private1a" {
  route_table_id = "${aws_route_table.nat-private.id}"
  subnet_id      = "${aws_subnet.nat-private1a.id}"
}

resource "aws_route_table_association" "nat-private1c" {
  route_table_id = "${aws_route_table.nat-private.id}"
  subnet_id      = "${aws_subnet.nat-private1c.id}"
}

まとめ

正直、かなりハマりました。 というものの、terraformで作らないでAWSコンソールで作ると、最初からいい感じに設定されているんですよね。 自分で、terraformで細かく作って初めて知ったものは多かったです。 nat-privateのネットワークがハマりどころだと思います。