TerraformのEKS published moduleを使ってEKSクラスターを作成する

2021.03.08

今回はTerraform Registryにある以下Published Moduleを使ってEKSクラスターを作成したいと思います。

Terraformとprovidersの設定

terraform {
  required_version = "= 0.14.7"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.30.0"
    }
  }
}
provider "aws" {
  region = "ap-northeast-1"
}

Terraform version 0.13以降の書き方ですね。

VPC作成

eksctlはクラスターを稼働させるVPCまで併せて作成してくれました。が、このeksモジュールはそこまではやってくれず、引数で既存VPCの情報を渡す必要があるようです。というわけで先にVPCを作成します。

以下のTerraform RegistryにあるVPCのPublished Moduleを利用します。

vpc.tf

data "aws_availability_zones" "available" {
  state = "available"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.77.0"

  name = "eks-module-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 state list
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]

Local Moduleを作る

後の検証で使いたいので、EKSクラスターを作成する部分はChild Module化します。そのModuleの中で前述のEKSのPublished Moduleを使いたいと思います。

$ tree
.
(略)
├── modules
│   └── k8s_cluster
│       ├── eks.tf
│       ├── providers.tf
│       ├── target_group.tf
│       └── variables.tf
(略)

providers

modules/k8s_cluster/providers.tf

provider "kubernetes" {
  host                   = data.aws_eks_cluster.cluster.endpoint
  cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
  exec {
    api_version = "client.authentication.k8s.io/v1alpha1"
    command     = "aws"
    args = [
      "eks",
      "get-token",
      "--cluster-name",
      data.aws_eks_cluster.cluster.name
    ]
  }
}
data "aws_eks_cluster" "cluster" {
  name = module.main.cluster_id
}

EKS published moduleが必要とするprividerには、kubernetes providerも含まれます。作成したEKSクラスター内にaws-auth ConfigMapリソースを作成する際に使われます。EKSクラスターへの接続情報が必要ですので、その情報をkuberetes providerのブロックに記述しています。記述内容は以下を参考にしました。

variables

modules/k8s_cluster/variables.tf

variable "cluster_name" {
  type = string
}
variable "k8s_version" {
  type = string
}
variable "vpc_id" {
  type = string
}
variable "subnet_ids" {
  type = list(string)
}

eks

modules/k8s_cluster/eks.tf

module "main" {
  source  = "terraform-aws-modules/eks/aws"
  version = "14.0.0"

  cluster_name    = var.cluster_name
  cluster_version = var.k8s_version
  subnets         = var.subnet_ids
  vpc_id          = var.vpc_id

  worker_groups = [{
    root_volume_type = "gp2"
    target_group_arns = [aws_alb_target_group.tg.arn]
  }]
}
  • workerのroot volume typeのデフォルト値はgp3です。以下エラーが出たためgp2に変更しています。 Worker Node GroupのAutoScaling Groupはこの書き方だと起動設定から作成されるのですが、どうやら起動設定だと現在root_volume_typeにgp3を指定することができないようです。

    Error: Error creating launch configuration: ValidationError: gp3 is invalid. Valid volume types are standard, io1, gp2, st1 and sc1.

  • Worker Node GroupのAutoScaling Groupに紐づくTarget Groupを指定しています。こちらは今後の検証で利用する予定です。

target group

前述のとおりWorker Node GroupのAutoScaling Groupに紐づく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します。 以下リソースが作成できました。

$ terraform state list
data.aws_availability_zones.available
module.blue.data.aws_eks_cluster.cluster
module.blue.aws_alb_target_group.tg
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]
module.blue.module.main.data.aws_ami.eks_worker
module.blue.module.main.data.aws_ami.eks_worker_windows
module.blue.module.main.data.aws_caller_identity.current
module.blue.module.main.data.aws_iam_policy_document.cluster_assume_role_policy
module.blue.module.main.data.aws_iam_policy_document.cluster_elb_sl_role_creation[0]
module.blue.module.main.data.aws_iam_policy_document.workers_assume_role_policy
module.blue.module.main.data.aws_partition.current
module.blue.module.main.data.template_file.userdata[0]
module.blue.module.main.aws_autoscaling_group.workers[0]
module.blue.module.main.aws_eks_cluster.this[0]
module.blue.module.main.aws_iam_instance_profile.workers[0]
module.blue.module.main.aws_iam_policy.cluster_elb_sl_role_creation[0]
module.blue.module.main.aws_iam_role.cluster[0]
module.blue.module.main.aws_iam_role.workers[0]
module.blue.module.main.aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy[0]
module.blue.module.main.aws_iam_role_policy_attachment.cluster_AmazonEKSServicePolicy[0]
module.blue.module.main.aws_iam_role_policy_attachment.cluster_AmazonEKSVPCResourceControllerPolicy[0]
module.blue.module.main.aws_iam_role_policy_attachment.cluster_elb_sl_role_creation[0]
module.blue.module.main.aws_iam_role_policy_attachment.workers_AmazonEC2ContainerRegistryReadOnly[0]
module.blue.module.main.aws_iam_role_policy_attachment.workers_AmazonEKSWorkerNodePolicy[0]
module.blue.module.main.aws_iam_role_policy_attachment.workers_AmazonEKS_CNI_Policy[0]
module.blue.module.main.aws_launch_configuration.workers[0]
module.blue.module.main.aws_security_group.cluster[0]
module.blue.module.main.aws_security_group.workers[0]
module.blue.module.main.aws_security_group_rule.cluster_egress_internet[0]
module.blue.module.main.aws_security_group_rule.cluster_https_worker_ingress[0]
module.blue.module.main.aws_security_group_rule.workers_egress_internet[0]
module.blue.module.main.aws_security_group_rule.workers_ingress_cluster[0]
module.blue.module.main.aws_security_group_rule.workers_ingress_cluster_https[0]
module.blue.module.main.aws_security_group_rule.workers_ingress_self[0]
module.blue.module.main.kubernetes_config_map.aws_auth[0]
module.blue.module.main.local_file.kubeconfig[0]
module.blue.module.main.null_resource.wait_for_cluster[0]
module.blue.module.main.random_pet.workers[0]

クラスター内リソースも確認します。 このモジュールは引数write_kubeconfigをtrue(デフォルト値)にすればコンテキストファイルを作成してくれますが、ちょっと扱いづらいので、別途AWS CLIを使って書きます。

$ aws eks update-kubeconfig --name blue-with-module
Updated context arn:aws:eks:ap-northeast-1:123456789012:cluster/blue-with-module in /Users/kazue.masaki/.kube/config
$ kubectl config use-context arn:aws:eks:ap-northeast-1:123456789012:cluster/blue-with-module
Switched to context "arn:aws:eks:ap-northeast-1:123456789012:cluster/blue-with-module".

クラスター内リソースも確認できました。

$ kubectl get all -A
NAMESPACE     NAME                           READY   STATUS    RESTARTS   AGE
kube-system   pod/aws-node-54h7s             1/1     Running   0          30h
kube-system   pod/coredns-59847d77c8-n9gb6   1/1     Running   0          30h
kube-system   pod/coredns-59847d77c8-p6dzd   1/1     Running   0          30h
kube-system   pod/kube-proxy-xdrmg           1/1     Running   0          30h

NAMESPACE     NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)         AGE
default       service/kubernetes   ClusterIP   172.20.0.1    <none>        443/TCP         30h
kube-system   service/kube-dns     ClusterIP   172.20.0.10   <none>        53/UDP,53/TCP   30h

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
kube-system   daemonset.apps/aws-node     1         1         1       1            1           <none>          30h
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           <none>          30h

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   2/2     2            2           30h

NAMESPACE     NAME                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-59847d77c8   2         2         2       30h

起動設定→起動テンプレート

前述のとおり、Worker Node GroupのAutoScaling Groupは起動設定から作成されました。これを起動テンプレートからに変えたいと思います。やり方は簡単で、worker_groupsworker_groups_launch_templateに変えるだけです。

 module "main" {
   source  = "terraform-aws-modules/eks/aws"
   version = "14.0.0"
 
   cluster_name    = var.cluster_name
   cluster_version = var.k8s_version
   subnets         = var.subnet_ids
   vpc_id          = var.vpc_id
 
-  worker_groups = [{
+  worker_groups_launch_template = [{
     root_volume_type = "gp2"
     target_group_arns = [aws_alb_target_group.tg.arn]
   }]
 }

起動テンプレートだとroot_volume_typeにgp3を使うこともできます。

 module "main" {
   source  = "terraform-aws-modules/eks/aws"
   version = "14.0.0"
 
   cluster_name    = var.cluster_name
   cluster_version = var.k8s_version
   subnets         = var.subnet_ids
   vpc_id          = var.vpc_id
 
   worker_groups_launch_template = [{
-    root_volume_type = "gp2" # デフォルトのgp3を使う
     target_group_arns = [aws_alb_target_group.tg.arn]
   }]
 }

セルフマネージド型ノード → マネージド型ノードグループ

worker_groups及びworker_groups_launch_templateセルフマネージド型ノードのプロビジョニングに使われるものでした。今回は特にセルフマネージド型ノードにする必要性がなかったので、マネージド型ノードグループに変更します。

node_groups引数を使います。使い方詳細は以下ページにあります。

modules/k8s_cluster/eks.tf

 module "main" {
   source  = "terraform-aws-modules/eks/aws"
   version = "14.0.0"
 
   cluster_name    = var.cluster_name
   cluster_version = var.k8s_version
   subnets         = var.subnet_ids
   vpc_id          = var.vpc_id
 
-  worker_groups_launch_template = [{
-    target_group_arns = [aws_alb_target_group.tg.arn]
-  }]
+  node_groups = {
+    example = {
+      target_group_arns = [aws_alb_target_group.tg.arn]
+      subnets = var.private_subnet_ids
+    }
+  }
 }

modules/k8s_cluster/variables.tf

 variable "cluster_name" {
   type = string
 }
 variable "k8s_version" {
   type = string
 }
 variable "vpc_id" {
   type = string
 }
 variable "subnet_ids" {
   type = list(string)
 }
+variable "private_subnet_ids" {
+  type = list(string)
+}

vpc.tf

 module "blue" {
   source = "./modules/k8s_cluster"
 
   cluster_name = "blue-with-module"
   k8s_version  = "1.19"
 
   subnet_ids         = concat(module.vpc.private_subnets, module.vpc.public_subnets)
+  private_subnet_ids = module.vpc.private_subnets
   vpc_id             = module.vpc.vpc_id
 }

参考情報