terraformとeksctlで作成するManaged Node GroupとFargate

仕事でEKS on Fargateの環境に対してManaged Node Groupを追加で作成する必要があってその一環でVPCから作ってみようとなったのでその備忘録でTerraformとeksctlを使用してEKS環境を作成していきます。

筆者のバージョン環境は以下の通りです

MacOS 10.15.4

$ terraform version

Terraform v0.12.25

$ eksctl version
0.22.0

事前にAWSアカウントの作成とIAMの作成を実施しておいてください。

自身のプロファイル情報を先に設定しておいて切り替えておいてください

export AWS_PROFILE=<your profile>

VPCの作成

最初にTerraformを使用してVPCを作成していくのですが作成が必要なリソースとしてVPCとNode Groupに割り当てるIAM Roleの作成。 本来はEC2Nodeに対してsshするなどの必要性もありキーペアの管理をなどをする必要が出てくるのですが今回は作成のみなので割愛させていただきます。 今回は test-vpcという名前でVPCの作成をします

terraformのディレクトリ構造はこのようになっています

terraform
    └── workspaces
        ├── accounts
        │   ├── iam.tf
        │   ├── providers.tf
        │   ├── terraform.tfstate
        │   └── yaml_files
        │       └── managed_node_group_assume_role_policy.yaml
        └── networks
            ├── providers.tf
            ├── terraform.tfstate
            ├── variable.tf
            └── vpc.tf

vpcの作成に必要なリソースはnetworksの配下にあるのでディレクトリをnetworksまで移動しましょう

 cd terraform/workspaces/network

VPCの作成ですがTerraform registoryのVPCを使用して作成していきます

dev.classmethod.jp

コードはこのようにしています

vpc.tf

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

  name = "test-vpc"
  cidr = var.vpc_cidr
  azs  = var.azs

  vpc_tags = {
    "kubernetes.io/cluster/${var.cluster}" = "shared"
  }

  #public_subnets
  public_subnets = var.public_subnet
  public_subnet_tags = {
    "kubernetes.io/role/elb"                       = 1
    "kubernetes.io/cluster/${var.cluster}" = "shared"
  }

  #pirvate_subent
  private_subnets = var.private_subnet
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb"              = 1
    "kubernetes.io/cluster/${var.cluster}" = "shared"
  }

  enable_nat_gateway     = true
  single_nat_gateway     = false
  one_nat_gateway_per_az = false
  enable_vpn_gateway     = true
  enable_dns_hostnames   = true
}

所々 var を使用していますがこれはvariable.tfを作成して設定します cidr設計は適当なので実際に実行する際は設計をしっかりおこないましょう。

variable.tf

variable "vpc_cidr" {
  default = "10.10.0.0/16"
}

variable "azs" {
  default = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}

variable "public_subnet" {
  default = ["10.10.1.0/24", "10.10.2.0/24", "10.10.3.0/24"]
}

variable "private_subnet" {
  default = ["10.10.4.0/24", "10.10.5.0/24", "10.10.6.0/24"]
}

variable "cluster" {
  default = "test-cluster"
}

terraformを実行していきます

terraform init

terraform plan

問題なければapplyをしましょう

このリソースの作成は少し時間がかかります

 terraform apply

Apply complete! Resources: 29 added, 0 changed, 0 destroyed.

AWSのコンソールを確認して作成されているか確認しましょう。

IAM Roleの作成

次にIAM Roleの作成になります

accountsのディレクトリ配下に移動して説明していきます

 cd terraform/workspaces/accounts

IAM Roleの作成を行なっていきますManaged Node Groupを作成する際にはワーカーノードのロール以下のポリシーがアタッチされている必要があります

AmazonEKSWorkerNodePolicy

AmazonEKS_CNI_Policy

AmazonEC2ContainerRegistryReadOnly

docs.aws.amazon.com

iam.tf

resource "aws_iam_role" "eks_managed_node_group" {
  name               = "eks-managed-node-group-role"
  description        = "managed node group iam role"
  assume_role_policy = jsonencode(yamldecode(file("${path.module}/yaml_files/managed_node_group_assume_role_policy.yaml")))
}

resource "aws_iam_role_policy_attachment" "eks_worker_node_policy" {
  role       = aws_iam_role.eks_managed_node_group.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
}

resource "aws_iam_role_policy_attachment" "eks_cni_policy" {
  role       = aws_iam_role.eks_managed_node_group.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
}

resource "aws_iam_role_policy_attachment" "ec2_container_registry_read_only" {
  role       = aws_iam_role.eks_managed_node_group.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

IAM Roleのassume roleですがyamlファイルを作成して参照します

Version: "2012-10-17"
Statement:
  - Action: "sts:AssumeRole"
    Effect: "Allow"
    Principal: 
      Service: "ec2.amazonaws.com"

これでVPC同様実行していきます

terraform init

terraform plan

terraform apply

マネジメントコンソール上に eks-managed-node-group-role というロールができていると思います。 このロールを確認してポリシーがアタッチされているか確認しておきましょう。

これでリソースの準備ができたのでEKSを作成していきましょう。

EKS Clusterの作成

eksctl側のディレクトリ構成はこのようになっています

.
├── eksctl
│   ├── cluster.yaml
│   ├── fargateprofile.yaml
│   └── managed-node-group.yaml

EKSのClusterを作成していきます

cluster.yaml

---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: test-cluster
  region: ap-northeast-1
  version: "1.15"
  tags:
    env: test

iam:
  withOIDC: true

vpc:
  subnets:
    public:
      ap-northeast-1a: { id: 作成されたsubnetのid }
      ap-northeast-1c: { id: 作成されたsubnetのid  }
      ap-northeast-1d: { id: 作成されたsubnetのid }
    private:
      ap-northeast-1a: { id: 作成されたsubnetのid  }
      ap-northeast-1c: { id: 作成されたsubnetのid  }
      ap-northeast-1d: { id: 作成されたsubnetのid  }

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

これでeksctlコマンドを使用していきます

eksctl create cluster -f eksctl/cluster.yaml

EKS Clusterの作成はめちゃくちゃ重いです。。。 コーヒーでも飲んでtwitterでもして時間を潰してください

作成されたらManaged Node Groupを作成していきます

managed-node-group.yaml

---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: test-cluster
  region: ap-northeast-1
  version: "1.15"
  tags:
    env: test

managedNodeGroups:
  - name: test-managed-ng
    desiredCapacity: 2
    minSize: 2
    maxSize: 4
    instanceType: t3.large
    volumeSize: 20
    ssh:
      allow: true
    privateNetworking: true
    iam:
      instanceRoleARN: 作成したIAM Roleを付与
eksctl create nodegroup -f eksctl/managed-node-group.yaml

無事作成されたらFargateも作成しましょう

fargateprofile.yaml

---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: test-cluster
  region: ap-northeast-1
  version: "1.15"
  tags:
    env: test

fargateProfiles:
  - name: fp-default
    selectors:
      - namespace: default
      - namespace: kube-system
    subnets:
      - プライベートサブネット1aの値
      -  プライベートサブネット1cの値
      -  プライベートサブネット1dの値

適用します

eksctl create fargateprofile -f eksctl/fargateprofile.yaml

これでFargateも作成されたと思います。

kubectl get nodeでnodeが作成されているか確認してみましょう。

$ kubectl get nodes

NAME                                                    STATUS   ROLES    AGE     VERSION
fargate-ip-10-10-5-19.ap-northeast-1.compute.internal   Ready    <none>   40s     v1.15.10-eks-094994
fargate-ip-10-10-5-83.ap-northeast-1.compute.internal   Ready    <none>   51s     v1.15.10-eks-094994
ip-10-10-4-18.ap-northeast-1.compute.internal           Ready    <none>   8m42s   v1.15.11-eks-af3caf
ip-10-10-5-230.ap-northeast-1.compute.internal          Ready    <none>   8m45s   v1.15.11-eks-af3caf
ip-10-10-6-25.ap-northeast-1.compute.internal           Ready    <none>   8m46s   v1.15.11-eks-af3caf

これでFargateとManaged Node Groupの作成ができました。

今回は構築するだけですので用がなければ最後は作成したリソースの削除をしましょう

eksctl delete cluster -f eksctl/cluster.yaml
terraform destroy

これで以上です。 思ったよりも作るだけなら簡単に作成することができました。 実際にはalbのリソースのIRSAの作成なども対象になるのですが今回は割愛します。

実際これらのことはeksctlコマンドで全部作成自体は可能なのですがIaCで管理することによって明示的に確認できるのでメリットはでかいなと思いました。 eksctlでリソースの作成をする際にupdateがリソースの更新ではなくてクラスタ自体のアップデートになってしまうので注意が必要です。

なのでクラスタの設定とNode GroupやFargateを別で管理しておくことによって管理のしやすさが高まるかなあと個人的には思っています。 長くなりましたが見ていただきありがとうございました。

他にこのような方法がいいというものがありましたらご指摘・意見をいただけると嬉しいです。