Anket は EKS を使ってます。
こんな感じ↓
今回やったこと
AWS 内の各サービスは基本は Terraform を使って作成しているのですがEKS周りの必要なものはeksctlを使ってました。
Anket における Terraform と eksctl の役割をざっと書くとこんな感じ
Terraform
eksctl
今回はこの中の eksctl で作成していた VPC を eksctl ではなく Terraform 側で作成するようにしました。
なぜ eksctl で VPC を作成するのをやめたのか
eksctl は本当に便利でコマンド1つたたけば クラスター作ってEC2たててそれをノードとして扱えるようになる。
つまりコマンド実行して待つだけで kubectl
が使えるようになる!!
便利!!
AWS の各リソースを1つ1つ eksctl が AWS API をたたいて作っているのではなく AWS CloudFormation を使って作成していて、eksctl create cluster
をした時は クラスターの作成、ノードグループの作成の2つのスタックが作成される。
ここで問題になるのが例えば eksctl 側で作成されるスタックの仕様?変更が生じた時を考える。
ノードグループ側の仕様変更が起きた場合は新しいノードグループを eksctl create nodegroup
で作って古いほうを削除すれば良いはず。
ただクラスター側に変更があった時に少し厄介だと思っている。
それが↓のissueのようなケース。今回僕も同じようなケースにあたってしまった。
古い eksctl で作成していたクラスターから 新しい eksctl で nodegroup を追加しようとしたらできなかったやつで、僕のケースの場合は クラスター側のスタックに修正が入っていて eksctl utils update-cluster-stack
でもダメだった。
この issue に書いてあるようにクラスターを作りなおすという選択肢をとって単純に新しいクラスターを作りなおした場合に問題になるのが VPC がかわってしまうこと。
EKS だけで構築しているサービスなら問題ないけど Anket のように RDS や ElasticCache のような VPC 内にサービスをおくようなものを使っているとVPCまたぐことになるので不都合が生じてしまう。
一応 eksctl には 既存の VPC を指定できるようなパラメータがあるので↓のような感じで作成はできる。
$ eksctl create cluster \ --name anket \ --region ap-northeast-1 \ --nodes 2 \ --nodes-min 1 \ --nodes-max 2 \ --version=1.11 \ --vpc-private-subnets=subnet-1111,subnet-2222,subnet-3333 \ --vpc-public-subnets=subnet-4444,subnet-5555,subnet-6666
とはいえ古いスタックを残しつつ VPC を使い回すのも嫌だったので良い機会だと思って Terraform で VPC を作成してしまおうと思ったわけです。
VPC を Terraform で作成する。
まずは Terraform で VPC を作成します。
locals { prefix = "anket" } resource "aws_vpc" "main" { cidr_block = "192.168.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "${var.vpc_name}" Product = "Anket" } lifecycle { ignore_changes = [ "tags" ] } } # subnet resource "aws_subnet" "public-subnet" { vpc_id = "${aws_vpc.main.id}" count = "${length(var.public_subnets_availability_zones)}" availability_zone = "${element(var.public_subnets_availability_zones, count.index)}" cidr_block = "${element(var.public_subnets_cidr_blocks, count.index)}" tags { Name = "${local.prefix}-public-${element(var.public_subnets_availability_zones, count.index)}" Product = "Anket" } lifecycle { ignore_changes = [ "tags" ] } } resource "aws_subnet" "private-subnet" { vpc_id = "${aws_vpc.main.id}" count = "${length(var.private_subnets_availability_zones)}" availability_zone = "${element(var.private_subnets_availability_zones, count.index)}" cidr_block = "${element(var.private_subnets_cidr_blocks, count.index)}" tags { Name = "${local.prefix}-private-${element(var.private_subnets_availability_zones, count.index)}" Product = "Anket" } lifecycle { ignore_changes = [ "tags" ] } } # gateway resource "aws_internet_gateway" "gw" { vpc_id = "${aws_vpc.main.id}" tags = { Name = "${local.prefix}-gw" Product = "Anket" } } resource "aws_eip" "nat" { vpc = true } resource "aws_nat_gateway" "nat" { allocation_id = "${aws_eip.nat.id}" subnet_id = "${aws_subnet.public-subnet.0.id}" depends_on = ["aws_internet_gateway.gw"] tags = { Name = "${local.prefix}-nat-gw" Product = "Anket" } } # Private Route Table resource "aws_route_table" "private" { vpc_id = "${aws_vpc.main.id}" tags = { Name = "${local.prefix}-private-rtb" } } resource "aws_route" "private" { route_table_id = "${aws_route_table.private.id}" destination_cidr_block = "0.0.0.0/0" nat_gateway_id = "${aws_nat_gateway.nat.id}" } resource "aws_route_table_association" "private" { count = "${length(aws_subnet.private-subnet.*.id)}" route_table_id = "${aws_route_table.private.id}" subnet_id = "${element(aws_subnet.private-subnet.*.id, count.index)}" } # Public Route Table resource "aws_route_table" "public" { vpc_id = "${aws_vpc.main.id}" tags = { Name = "${local.prefix}-public-rtb" } } resource "aws_route" "public" { route_table_id = "${aws_route_table.public.id}" destination_cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.gw.id}" } resource "aws_route_table_association" "public" { count = "${length(aws_subnet.public-subnet.*.id)}" route_table_id = "${aws_route_table.public.id}" subnet_id = "${element(aws_subnet.public-subnet.*.id, count.index)}" }
基本的に eksctl で作成していたものをトレースしただけですがポイントがあるとしたら vpc や subnet リソースの作成で ignore_changes
でタグを指定しているところですかね。
lifecycle { ignore_changes = [ "tags" ] }
eksctl でクラスターを作成した時に vpc や サブネットに自動でタグを付与していきます。
ignore_changes を指定しないと apply した時に差分が出るので eksctl が付与するタグを消してしまうからです。
VPC が作られたら後は subnetを指定して eksctl を作成するだけです。
$ eksctl create cluster \ --name anket \ --region ap-northeast-1 \ --nodes 2 \ --nodes-min 1 \ --nodes-max 2 \ --version=1.11 \ --vpc-private-subnets=subnet-1111,subnet-2222,subnet-3333 \ --vpc-public-subnets=subnet-4444,subnet-5555,subnet-6666
最後に
今回 EKS のクラスター 何回も壊して作りなおしたので今後クラスター から作り直すとなってしまった場合でも落ち着いて対応ができそう。(できればやりたくない)