こんにちは、SREの岩立です。
re:Invent2019の少し前にEKSのManaged Node Groupsが発表されました。
https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html
従来のEKSでは、Nodeを追加するためには、EC2インスタンスの起動時にUserDataなどを用いてVMの設定、VMをEKSのクラスタにNodeとして登録させたりしなければいけませんでした。しかし、このManaged Node Groupsが登場したことにより、それらの作業を行わずにEKSクラスタにNodeを追加することが出来るのでとても楽になれます。
今回はそのManaged Node Groupsを用いてEKSのクラスタをTerraformでシュッと構築してみます。
構築の作業内容
今回の記事では、以下の作業を順番に行っていきます。
- EKSクラスタの作成
- VPC・Subnetの作成
- EKSクラスタ用のIAM Roleの作成
- EKSクラスタ自体の作成
- kubeconfigの設定・EKSクラスタへの疎通確認
- Managed Node Groupsの作成
- Managed Node Groups用のIAM Roleの作成
- Managed Node Groupsを作成
- Nodeが追加されたことの確認
EKSクラスタの作成
クラスタの作成にはVPCとSubnetとIAM Roleが必要なので、先にそちらを作成します。以下のコードではap-northeast-1内のavailableなzoneにそれぞれsubnetを作成します。
provider "aws" {
region = "ap-northeast-1"
}
data "aws_availability_zones" "available-zone" {
state = "available"
}
resource "aws_vpc" "eks-test-clueter-vpc" {
cidr_block = "10.25.0.0/16"
}
resource "aws_subnet" "eks-test-cluster-subnet" {
count = "${length(data.aws_availability_zones.available-zone.zone_ids)}"
availability_zone = "${data.aws_availability_zones.available-zone.names[count.index]}"
cidr_block = "${cidrsubnet(aws_vpc.eks-test-clueter-vpc.cidr_block, 8, count.index)}"
vpc_id = "${aws_vpc.eks-test-clueter-vpc.id}"
}
VPCとSubnetを作成したら、EKSクラスタ用のIAM Roleの作成を行います。
resource "aws_iam_role" "eks-test-cluster-role" {
name = "eks-test-cluster-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-role-AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = "${aws_iam_role.eks-test-cluster-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-role-AmazonEKSServicePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
role = "${aws_iam_role.eks-test-cluster-role.name}"
}
VPC、Subnet、IAM Roleを作成したら、aws_eks_clusterリソースを用いてEKSクラスタを作成します。
https://www.terraform.io/docs/providers/aws/r/eks_cluster.html
resource "aws_eks_cluster" "test-cluster" {
name = "test-cluster"
role_arn = "${aws_iam_role.eks-test-cluster-role.arn}"
version = "1.14"
vpc_config {
subnet_ids = ["${aws_subnet.eks-test-cluster-subnet.*.id}"]
endpoint_public_access = true
}
}
output "api endpoint" {
value = "${aws_eks_cluster.test-cluster.endpoint}"
}
output "kubeconfig-certificate-authority-data" {
value = "${aws_eks_cluster.test-cluster.certificate_authority.0.data}"
}
10分程度でクラスタ自体の作成は完了します。outputで吐き出されたAPIエンドポイントと認証情報を用いてkubeconfigを設定します。kubeconfig上のクラスタ名は任意なので、今回はEKSのクラスタ名と同じtest-clusterとします。
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: outputで出力された認証情報(base64)
server: outputで出力されたAPIエンドポイント
name: 適当なクラスタ名
users:
- name: test-cluster
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
args:
- --region
- ap-northeast-1
- eks
- get-token
- --cluster-name
- test-cluster
command: aws
env: null
contexts:
- context:
cluster: test-cluster
user: test-cluster
name: test-cluster
current-context: test-cluster
上記の内容を~/.kube/configに記述します。その後kubectl get svcコマンドでクラスタへ接続できることを確認します。
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 14m
$ kubectl get nodes
No resources found.
現段階ではクラスタ自体しか作成していないためkubectl get nodesを叩いてもNo resources foundとなってしまいます。
そのため、これから本題のManaged Worker Groupsを使ってNodeを追加したいと思います。
Managed Node Groupsの作成
Managed Node Groupsを作成する前に、EKSクラスタからAWSのAPIを触るためにIAM Roleを作成する必要があります。そのため、以下のコードでロールの作成、作成したロールに対してポリシーのアタッチを行います。
resource "aws_iam_role" "eks-test-cluster-node-role" {
name = "eks-test-cluster-node-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
そして、本題のManaged Node Groupsを作成するにはaws_eks_node_groupリソースを使用します。
https://www.terraform.io/docs/providers/aws/r/eks_node_group.html
下記のコードでManaged Node Groupsを作成します。
resource "aws_eks_node_group" "test-cluster-node-group" {
cluster_name = "${aws_eks_cluster.test-cluster.name}"
node_group_name = "test-cluster-node-group"
node_role_arn = "${aws_iam_role.eks-test-cluster-node-role.arn}"
subnet_ids = ["${aws_subnet.eks-test-cluster-subnet.*.id}"]
scaling_config {
desired_size = 3
max_size = 3
min_size = 3
}
}
terraform applyした後、大体2分弱でNode GroupとNodeが作成され、kubectl get nodeから追加されたNodeを確認できるようになります。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
ip-***-***-***-***.ap-northeast-1.compute.internal Ready <none> 45s v1.14.7-eks-*****
ip-***-***-***-***.ap-northeast-1.compute.internal Ready <none> 43s v1.14.7-eks-*****
ip-***-***-***-***.ap-northeast-1.compute.internal Ready <none> 51s v1.14.7-eks-*****
今回は3台のノードを作成しましたが、台数の調整はscaling_configのパラメータを変更することで行えます。以上でManaged Node Groupsを用いたEKSクラスタの構築は完了です。
最終的なコードの全体
https://github.com/jagaNikuman/eks-managed-node-groups
provider "aws" {
region = "ap-northeast-1"
}
data "aws_availability_zones" "available-zone" {
state = "available"
}
resource "aws_vpc" "eks-test-clueter-vpc" {
cidr_block = "10.25.0.0/16"
}
resource "aws_subnet" "eks-test-cluster-subnet" {
count = "${length(data.aws_availability_zones.available-zone.zone_ids)}"
availability_zone = "${data.aws_availability_zones.available-zone.names[count.index]}"
cidr_block = "${cidrsubnet(aws_vpc.eks-test-clueter-vpc.cidr_block, 8, count.index)}"
vpc_id = "${aws_vpc.eks-test-clueter-vpc.id}"
}
resource "aws_iam_role" "eks-test-cluster-role" {
name = "eks-test-cluster-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "eks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-role-AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = "${aws_iam_role.eks-test-cluster-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-role-AmazonEKSServicePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy"
role = "${aws_iam_role.eks-test-cluster-role.name}"
}
resource "aws_eks_cluster" "test-cluster" {
name = "test-cluster"
role_arn = "${aws_iam_role.eks-test-cluster-role.arn}"
version = "1.14"
vpc_config {
subnet_ids = ["${aws_subnet.eks-test-cluster-subnet.*.id}"]
endpoint_public_access = true
}
}
output "api endpoint" {
value = "${aws_eks_cluster.test-cluster.endpoint}"
}
output "kubeconfig-certificate-authority-data" {
value = "${aws_eks_cluster.test-cluster.certificate_authority.0.data}"
}
resource "aws_iam_role" "eks-test-cluster-node-role" {
name = "eks-test-cluster-node-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
resource "aws_iam_role_policy_attachment" "eks-test-cluster-node-role-AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = "${aws_iam_role.eks-test-cluster-node-role.name}"
}
resource "aws_eks_node_group" "test-cluster-node-group" {
cluster_name = "${aws_eks_cluster.test-cluster.name}"
node_group_name = "test-cluster-node-group"
node_role_arn = "${aws_iam_role.eks-test-cluster-node-role.arn}"
subnet_ids = ["${aws_subnet.eks-test-cluster-subnet.*.id}"]
scaling_config {
desired_size = 3
max_size = 3
min_size = 3
}
}
まとめ
今回はManaged Node Groupsを使ってEKSのクラスタ構築をTerraformでシュッとやってみました。Managed Node Groupsを用いることで従来の手法より圧倒的に楽に構築できるようになったかと思います。これからも更なるEKSの新機能に注目したいと思います。