この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
eksctlでのEKSクラスター作成は、デフォルトではクラスターが稼働するVPCも併せて作成してくれます。が、既存のVPC上にクラスターを作成することもできます。今回はこの構成をterraform-provider-eksctlでやってみます。
※ terraform-provider-eksctlについてご存じない方は、まずは以下ブログをどうぞ。
VPCの作成
VPC関連のリソースは色々あって一つずつプロビジョニングするのが煩雑なので、以下公式モジュールを利用してラクします。
main.tf
terraform {
required_version = "= 0.14.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.30.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
vpc.tf
data "aws_availability_zones" "available" {
state = "available"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "2.77.0"
name = "canary-test-vpc"
cidr = "10.0.0.0/16"
azs = data.aws_availability_zones.available.names
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
}
terraform init
してterraform apply
すると、以下リソースが作成されました。楽ちんですね。
$ terraform state list
data.aws_availability_zones.available
module.vpc.aws_eip.nat[0]
module.vpc.aws_eip.nat[1]
module.vpc.aws_eip.nat[2]
module.vpc.aws_internet_gateway.this[0]
module.vpc.aws_nat_gateway.this[0]
module.vpc.aws_nat_gateway.this[1]
module.vpc.aws_nat_gateway.this[2]
module.vpc.aws_route.private_nat_gateway[0]
module.vpc.aws_route.private_nat_gateway[1]
module.vpc.aws_route.private_nat_gateway[2]
module.vpc.aws_route.public_internet_gateway[0]
module.vpc.aws_route_table.private[0]
module.vpc.aws_route_table.private[1]
module.vpc.aws_route_table.private[2]
module.vpc.aws_route_table.public[0]
module.vpc.aws_route_table_association.private[0]
module.vpc.aws_route_table_association.private[1]
module.vpc.aws_route_table_association.private[2]
module.vpc.aws_route_table_association.public[0]
module.vpc.aws_route_table_association.public[1]
module.vpc.aws_route_table_association.public[2]
module.vpc.aws_subnet.private[0]
module.vpc.aws_subnet.private[1]
module.vpc.aws_subnet.private[2]
module.vpc.aws_subnet.public[0]
module.vpc.aws_subnet.public[1]
module.vpc.aws_subnet.public[2]
module.vpc.aws_vpc.this[0]
上記VPCを使ってEKSクラスターを作成
eksctlを使う部分は、今後(=次回以降のブログで)複数回使いたいのでmoduleにします。
blue.tf
data "aws_region" "current" {}
module "blue" {
source = "./modules/k8s_cluster"
cluster_name = "blue"
region = data.aws_region.current.name
k8s_version = "1.19"
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnets
public_subnet_ids = module.vpc.public_subnets
}
モジュール用のファイル群を用意します。
$ tree ./
./
├── blue.tf
├── main.tf
├── modules
│ └── k8s_cluster
│ ├── eksctl.tf
│ ├── providers.tf
│ ├── target_group.tf
│ ├── variables.tf
│ └── yaml
│ └── eksctl-config.yaml
└── vpc.tf
provider.tf
には、terraform-provider-eksctlを使うことだけ定義しています。
./modules/k8s_cluster/provider.tf
terraform {
required_providers {
eksctl = {
source = "mumoshu/eksctl"
version = "0.15.1"
}
}
}
provider "eksctl" {}
variables.tf
では変数を定義します。vpc_id
以降の3変数は先程のVPCモジュールから参照する想定です。この公式VPCモジュール、output値がものすごくたくさんあるので、こういった感じで他で参照するような要件もほとんど対応できるのではないかと思います。
./modules/k8s_cluster/variables.tf
variable "cluster_name" {
type = string
}
variable "region" {
type = string
}
variable "k8s_version" {
type = string
}
variable "vpc_id" {
type = string
}
variable "private_subnet_ids" {
type = list(string)
}
variable "public_subnet_ids" {
type = list(string)
}
eksctl.tf
のspec
に対しtemplatefile関数を使って動的に値を渡します。
./modules/k8s_cluster/eksctl.tf
data "aws_availability_zones" "available" {
state = "available"
}
resource "eksctl_cluster" "main" {
eksctl_version = "0.38.0"
name = var.cluster_name
region = var.region
version = var.k8s_version
spec = templatefile(
"./modules/k8s_cluster/yaml/eksctl-config.yaml"
, {
target_group_arn = aws_alb_target_group.tg.arn
az = data.aws_availability_zones.available.names
private = var.private_subnet_ids
public = var.public_subnet_ids
}
)
vpc_id = var.vpc_id
}
VPCのIDについては、素のeksctl(=terraform-provider-eksctlを介さず直接eksctlを使う、という意味です)ではYAMLファイル内(上記spec
引数部分に相当)に指定することができます。が、terraform-provider-eksctlでspec
内に記載したところ、
Error: validating eksctl_cluster's "spec": vpc.id must not be set within the spec yaml. use "vpc_id" attribute instead, becaues the provider uses it for generating the final eksctl cluster config yaml
と怒られましたので、 vpc_id
引数として spec
から外出しにする必要があるようです。
以下は前述のeksctl.tf
から呼ばれているYAMLファイルの部分です。
./modules/k8s_cluster/yaml/eksctl-config.yaml
nodeGroups:
- name: ng2
instanceType: m5.large
desiredCapacity: 1
targetGroupARNs:
- ${target_group_arn}
vpc:
subnets:
private:
${element(az,0)}:
id: ${element(private,0)}
${element(az,1)}:
id: ${element(private,1)}
${element(az,2)}:
id: ${element(private,2)}
public:
${element(az,0)}:
id: ${element(public,0)}
${element(az,1)}:
id: ${element(public,1)}
${element(az,2)}:
id: ${element(public,2)}
vpc.subnets
以降の実装はちょっとイマイチだなと自分でも思うのですが、ちょっと他の方法を思いつきませんでした。。nodeGroups.targetGroupARNs
はNodeGroupのAuto Scaling Groupと紐付けるTarget GroupのARNを指定します。今回の要件では不要ですが、次回以降のブログで必要になる予定なので指定しておきます。以下がそのTarget Groupの定義ファイルです。
./modules/k8s_cluster/target_group.tf
resource "aws_alb_target_group" "tg" {
name = "${var.cluster_name}-tg"
port = 30080
protocol = "HTTP"
vpc_id = var.vpc_id
}
再びterraform init
してterraform apply
します。
Target Groupとクラスターがプロビジョニングできました。
$ terraform state list
data.aws_availability_zones.available
data.aws_region.current
module.blue.data.aws_availability_zones.available
module.blue.aws_alb_target_group.tg
module.blue.eksctl_cluster.main
module.vpc.aws_eip.nat[0]
module.vpc.aws_eip.nat[1]
module.vpc.aws_eip.nat[2]
module.vpc.aws_internet_gateway.this[0]
module.vpc.aws_nat_gateway.this[0]
module.vpc.aws_nat_gateway.this[1]
module.vpc.aws_nat_gateway.this[2]
module.vpc.aws_route.private_nat_gateway[0]
module.vpc.aws_route.private_nat_gateway[1]
module.vpc.aws_route.private_nat_gateway[2]
module.vpc.aws_route.public_internet_gateway[0]
module.vpc.aws_route_table.private[0]
module.vpc.aws_route_table.private[1]
module.vpc.aws_route_table.private[2]
module.vpc.aws_route_table.public[0]
module.vpc.aws_route_table_association.private[0]
module.vpc.aws_route_table_association.private[1]
module.vpc.aws_route_table_association.private[2]
module.vpc.aws_route_table_association.public[0]
module.vpc.aws_route_table_association.public[1]
module.vpc.aws_route_table_association.public[2]
module.vpc.aws_subnet.private[0]
module.vpc.aws_subnet.private[1]
module.vpc.aws_subnet.private[2]
module.vpc.aws_subnet.public[0]
module.vpc.aws_subnet.public[1]
module.vpc.aws_subnet.public[2]
module.vpc.aws_vpc.this[0]
クラスター内のリソースも確認できました。
$ kubectl get all -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/aws-node-cj9bp 1/1 Running 0 94m
kube-system pod/coredns-59847d77c8-s47js 1/1 Running 0 113m
kube-system pod/coredns-59847d77c8-z2flq 1/1 Running 0 113m
kube-system pod/kube-proxy-rv9vs 1/1 Running 0 94m
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 114m
kube-system service/kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP 113m
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-system daemonset.apps/aws-node 1 1 1 1 1 <none> 113m
kube-system daemonset.apps/kube-proxy 1 1 1 1 1 <none> 113m
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 2/2 2 2 113m
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-59847d77c8 2 2 2 113m