Amazon Elastic Kubernetes Service (EKS)
Table of contents
- Notice
- What is Kubernetes (K8s)?
- What is Amazon Elastic Kubernetes Service (EKS)?
- How to create a cluster
- How to create a node group
- How to configure a cluster autoscaler (CA)
- How to install the AWS load balancer controller
- How to install a metric server
- How to apply a namespace
- How to apply a deployment
- How to apply a service
- How to apply a horizontal pod autoscaler (HPA)
- How to apply an ingress
- Useful kubectl commands
- How to fix error
- Reference
1. Notice
- A guide for setting the Amazon Web Services (AWS) Cloud9
- The name of region is Asia Pacific (Seoul) and the corresponding code is ap-northeast-2 [1].
- I recommend that you should ignore the commented instructions with an octothorpe, #.
- I recommend that you should fill in the appropriate letters between the parentheses, <>.
2. What is Kubernetes (K8s)?
Kubernetes is a portable, extensible, open-source platform for managing containerized workloads and services, that facilitates both declarative configuration and automation. It has a large, rapidly growing ecosystem. Kubernetes services, support, and tools are widely available. The name Kubernetes originates from Greek, meaning helmsman or pilot. K8s as an abbreviation results from counting the eight letters between the “K” and the “s”. Google open-sourced the Kubernetes project in 2014. Kubernetes combines over 15 years of Google’s experience running production workloads at scale with best-of-breed ideas and practices from the community [2].
3. What is Amazon Elastic Kubernetes Service (EKS)?
Amazon Elastic Kubernetes Service (Amazon EKS) is a managed Kubernetes service that makes it easy for you to run Kubernetes on AWS and on-premises. Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. Amazon EKS is certified Kubernetes-conformant, so existing applications that run on upstream Kubernetes are compatible with Amazon EKS [3].
1. Amazon EKS cluster
An Amazon EKS cluster, which calls cluster for short, consists of two primary components:
- The Amazon EKS control plane
- Amazon EKS nodes that are registered with the control plane
The Amazon EKS control plane consists of control plane nodes that run the Kubernetes software, such as etcd and the Kubernetes API server. The control plane runs in an account managed by AWS, and the Kubernetes API is exposed via the Amazon EKS endpoint associated with your cluster. Each Amazon EKS cluster control plane is single-tenant and unique, and runs on its own set of Amazon EC2 instances [4].
The kinds of the Amazon EKS cluster are public (non-private) and private cluster.
- Public cluster (non-private cluster): All node groups in the cluster are in the public subnet.
- Private cluster: All node groups in the cluster are in the private subnet. Thus, it enables that all pods (in nodes) in the node groups are only internally accessed.
2. Amazon EKS managed node group
A node group means a set of worker nodes which calls just nodes for short. A cluster consists of a number of node groups. Please note that a cluster can be composed of various types of the node groups (e.g. g4dn.xlarge and t5.large). There are two types of the node groups [5].
- EKS managed node group
- Flag: managedNodeGroups
- When creating a worker node, it supports Amazon Linux based EKS optimized Amazon Linux 2 AMI.
- It automates the provisioning and lifecycle management of nodes (Amazon EC2 instances) for Amazon EKS Kubernetes clusters [6].
- Self managed nodes
- Flag: nodeGroups
- When creating a worker node, it supports other operating system (OS) which is not based on Amazon Linux (e.g. Windows).
3. Cluster Autosacler (CA)
The Kubernetes Cluster Autoscaler automatically adjusts the number of nodes in your cluster when pods fail or are rescheduled onto other nodes [7].
4. AWS Load Balancer Controller
The AWS Load Balancer Controller manages AWS Elastic Load Balancers for a Kubernetes cluster. Please note that The AWS Load Balancer Controller replaces the functionality of the AWS ALB Ingress Controller for Kubernetes [8].
5. Metrics Server
The Kubernetes Metrics Server is an aggregator of resource usage data in your cluster, and it is not deployed by default in Amazon EKS clusters. The Metrics Server is commonly used by other Kubernetes add ons, such as the Horizontal Pod Autoscaler (HPA) or the Kubernetes Dashboard [9].
6. Namespace
A namespace is a way to group services for an application. When you create a namespace, you specify how you want to discover service instances that you register with AWS Cloud Map: using API calls or using DNS queries. You also specify the name that you want your application to use to discover instances [10].
7. Deployment
A deployment provides declarative updates for pods and replicaset [11] In other words, the deployment manages a replicated application on the cluster. The pods are the smallest deployable units of computing that you can create and manage in Kubernetes [12]. The replicaset ensures that a specified number of pod replicas are running at any given time [13].
8. Service
An abstract way to expose an application running on a set of pods as a network service [14].
9. Horizontal Pod Autoscaling
In Kubernetes, a horizontal pod autoscaler (HPA) automatically updates a workload resource (such as a Deployment or StatefulSet), with the aim of automatically scaling the workload to match demand [15]. The statefulset is the workload API object used to manage stateful applications. it manages deployment and scaling of a set of pods, with durable storage and persistent identifier for each pod [16].
10. Ingress
Ingress is an Application Programming Interface (API) object that manages external access to the services in a cluster, typically Hypertext Transfer Protocol (HTTP) [17].
4. How to create a cluster
1. How to create a cluster
In about 40 minutes, you can create a cluster with a cluster.yaml. I recommend that you should check the field of the yaml file.
- metadata:name: vujade-cluster
- metadata:region: ap-northeast-2
- metadata:version: “1.21”
- vpc:subnets:private:
- ap-northeast-2a: { id: subnet-012a3456b78cde9f0 }
- ap-northeast-2c: { id: subnet-0123a4bc5d678e901 }
- secretsEncryption:keyARN: arn:aws:kms:ap-northeast-2:123456789123:key/a0b1234c-de5f-6789-g01h-2i3456j789k0
In this case, the vpc:subnets:private is required because of the private cluster. The values of the field which can be obtained on VPC Dashboard correspond to the subnets of the data plane which are created in the Amazon Virtual Private Cloud (VPC) - Section 5. How to set up subnets. Also, as far as I mentioned in Amazon Virtual Private Cloud (VPC) - Section 5. How to set up subnets, the considered EC2 instance type, g4dn.xlarge is only supported ap-northeast-2a and ap-northeast-2c. The value of the secretsEncryption:keyARN is the MASTER_ARN which is created in the Amazon Web Services (AWS) Cloud9 - Section 8. How to create an AWS KMS custom managed key (CMK). Please note that any tags for the VPC are not required because the cluster version is 1.19+ as far as I mentioned in Amazon Virtual Private Cloud (VPC) - Section 4. How to create a VPC.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: vujade-cluster
region: ap-northeast-2
version: "1.21"
vpc:
subnets:
private:
ap-northeast-2a: { id: subnet-012a3456b78cde9f0 }
ap-northeast-2c: { id: subnet-0123a4bc5d678e901 }
secretsEncryption:
keyARN: arn:aws:kms:ap-northeast-2:123456789123:key/a0b1234c-de5f-6789-g01h-2i3456j789k0
1 $ eksctl create cluster -f ./cluster.yaml
2022-01-27 06:49:03 [ℹ] eksctl version 0.80.0
2022-01-27 06:49:03 [ℹ] using region ap-northeast-2
2022-01-27 06:49:03 [✔] using existing VPC (vpc-012abcde34fg5678h) and subnets (private:map[ap-northeast-2a:{subnet-012a3456b78cde9f0 ap-northeast-2a 10.172.92.0/23} ap-northeast-2c:{subnet-0123a4bc5d678e901 ap-northeast-2c 10.172.94.0/23}] public:map[])
2022-01-27 06:49:03 [!] custom VPC/subnets will be used; if resulting cluster doesn't function as expected, make sure to review the configuration of VPC/subnets
2022-01-27 06:49:03 [ℹ] using Kubernetes version 1.21
2022-01-27 06:49:03 [ℹ] creating EKS cluster "vujade-cluster" in "ap-northeast-2" region with
2022-01-27 06:49:03 [ℹ] will create a CloudFormation stack for cluster itself and 0 nodegroup stack(s)
2022-01-27 06:49:03 [ℹ] will create a CloudFormation stack for cluster itself and 0 managed nodegroup stack(s)
2022-01-27 06:49:03 [ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=ap-northeast-2 --cluster=vujade-cluster'
2022-01-27 06:49:03 [ℹ] Kubernetes API endpoint access will use default of {publicAccess=true, privateAccess=false} for cluster "vujade-cluster" in "ap-northeast-2"
2022-01-27 06:49:03 [ℹ] CloudWatch logging will not be enabled for cluster "vujade-cluster" in "ap-northeast-2"
2022-01-27 06:49:03 [ℹ] you can enable it with 'eksctl utils update-cluster-logging --enable-types={SPECIFY-YOUR-LOG-TYPES-HERE (e.g. all)} --region=ap-northeast-2 --cluster=vujade-cluster'
2022-01-27 06:49:03 [ℹ]
2 sequential tasks: { create cluster control plane "vujade-cluster", wait for control plane to become ready
}
2022-01-27 06:49:03 [ℹ] building cluster stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:49:04 [ℹ] deploying stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:49:34 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:50:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:51:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:52:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:53:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:54:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:55:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:56:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:57:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:58:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 06:59:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 07:00:04 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-cluster"
2022-01-27 07:02:05 [ℹ] waiting for the control plane availability...
2022-01-27 07:02:05 [✔] saved kubeconfig as "/home/ubuntu/.kube/config"
2022-01-27 07:02:05 [ℹ] no tasks
2022-01-27 07:02:05 [✔] all EKS cluster resources for "vujade-cluster" have been created
2022-01-27 07:02:06 [ℹ] kubectl command should work with "/home/ubuntu/.kube/config", try 'kubectl get nodes'
2022-01-27 07:02:06 [✔] EKS cluster "vujade-cluster" in "ap-northeast-2" region is ready
2. How to check the created cluster
You can check the created cluster with three options.
- You can check the cluster on CloudFormation.
- You can check the cluster on Amazon Container Services - Clusters.
- You can check the cluster with an eksctl command.
1 $ eksctl get cluster
2022-01-27 14:27:46 [ℹ] eksctl version 0.80.0 2022-01-27 14:27:46 [ℹ] using region ap-northeast-2 NAME REGION EKSCTL CREATED vujade-cluster ap-northeast-2 True
3. How to connect a cluster
You can connect the created cluster as follows. Please note that the field, region and name are the AWS region and the cluster name, respectively.
1 $ aws eks --region ap-northeast-2 update-kubeconfig --name vujade-cluster
Added new context arn:aws:eks:ap-northeast-2:123456789123:cluster/vujade-cluster to /home/ubuntu/.kube/config
4. How to delete a cluster
You can delete the created cluster as follows. Please note that the field, name is the cluster name.
1 $ eksctl delete cluster --name vujade-cluster
2022-01-27 14:27:46 [ℹ] eksctl version 0.79.0
2022-01-27 14:27:46 [ℹ] using region ap-northeast-2
2022-01-27 14:27:46 [ℹ] deleting EKS cluster "vujade-cluster"
2022-01-27 14:27:46 [ℹ] deleted 0 Fargate profile(s)
2022-01-27 14:27:46 [✔] kubeconfig has been updated
2022-01-18 07:43:29 [ℹ] cleaning up AWS load balancers created by Kubernetes objects of Kind Service or Ingress
2022-01-27 14:27:30 [ℹ] 1 task: { delete cluster control plane "vujade-cluster" [async] }
2022-01-27 14:27:30 [ℹ] will delete stack "eksctl-vujade-cluster-cluster"
2022-01-27 14:27:30 [✔] all cluster resources were deleted
5. How to create a node group
1. How to create a node group
In about 20 minutes, you can create a node group with a nodegroup.yaml. Please note that the node group is based on the EKS managed node group in this case. I recommend that you should check the field of the yaml file.
- metadata:name: vujade-cluster
- metadata:region: ap-northeast-2
- managedNodeGroups:name: ng-dl
- managedNodeGroups:instanceType: g4dn.xlarge
- managedNodeGroups:minSize: 1
- managedNodeGroups:maxSize: 5
- managedNodeGroups:desiredCapacity: 1
- managedNodeGroups:volumeSize: 80
- managedNodeGroups:privateNetworking: true
- managedNodeGroups:ssh:allow: true
- managedNodeGroups:ssh:publicKeyName: vujade-eks
The fields, managedNodeGroups:minSize, managedNodeGroups:maxSize and managedNodeGroups:desiredCapacity are parameters for the Cluster Autoscaler (CA) which scales up and down EC2 instances in node groups. the managedNodeGroups:volumeSize means the size of the Elastic Block Storage (EBS). The default value is 80. In this case, the managedNodeGroups:privateNetworking is true because the cluster is private cluster. The value of the field, managedNodeGroups:ssh:publicKeyName is the name of the SSH key obtained from the Amazon Web Services (AWS) Cloud9 - Section 7. How to create and import a SSH key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: vujade-cluster
region: ap-northeast-2
managedNodeGroups:
- name: ng-dl
instanceType: g4dn.xlarge
minSize: 1
maxSize: 5
desiredCapacity: 1
volumeSize: 80
privateNetworking: true
ssh:
allow: true
publicKeyName: vujade-eks
1 $ eksctl create nodegroup -f ./eks_yaml/dev/nodegroup/nodegroup.yaml
2022-01-27 07:11:22 [ℹ] eksctl version 0.80.0
2022-01-27 07:11:22 [ℹ] using region ap-northeast-2
2022-01-27 07:11:22 [ℹ] will use version 1.21 for new nodegroup(s) based on control plane version
2022-01-27 07:11:22 [ℹ] nodegroup "ng-dl" will use "" [AmazonLinux2/1.21]
2022-01-27 07:11:22 [ℹ] using EC2 key pair "vujade-eks"
2022-01-27 07:11:22 [ℹ] 1 nodegroup (ng-dl) was included (based on the include/exclude rules)
2022-01-27 07:11:22 [ℹ] will create a CloudFormation stack for each of 1 managed nodegroups in cluster "vuajde-cluster"
2022-01-27 07:11:23 [ℹ]
2 sequential tasks: { fix cluster compatibility, 1 task: { 1 task: { create managed nodegroup "ng-dl" } }
}
2022-01-27 07:11:23 [ℹ] checking cluster stack for missing resources
2022-01-27 07:11:23 [ℹ] cluster stack has all required resources
2022-01-27 07:11:23 [ℹ] building managed nodegroup stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:11:23 [ℹ] deploying stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:11:23 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:11:39 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:11:56 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:12:14 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:12:31 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:12:47 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:13:03 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:13:19 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:13:39 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:13:55 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:14:13 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:14:32 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:14:50 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:15:09 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:15:27 [ℹ] waiting for CloudFormation stack "eksctl-vuajde-cluster-nodegroup-ng-dl"
2022-01-27 07:15:27 [ℹ] 1 task: { install Nvidia device plugin }
2022-01-27 07:15:27 [ℹ] created "kube-system:DaemonSet.apps/nvidia-device-plugin-daemonset"
2022-01-27 07:15:27 [ℹ] as you are using the EKS-Optimized Accelerated AMI with a GPU-enabled instance type, the Nvidia Kubernetes device plugin was automatically installed.
to skip installing it, use --install-nvidia-plugin=false.
2022-01-27 07:15:27 [✔] created 0 nodegroup(s) in cluster "vuajde-cluster"
2022-01-27 07:15:27 [ℹ] nodegroup "ng-dl" has 1 node(s)
2022-01-27 07:15:27 [ℹ] node "ip-10-172-95-87.ap-northeast-2.compute.internal" is ready
2022-01-27 07:15:27 [ℹ] waiting for at least 1 node(s) to become ready in "ng-dl"
2022-01-27 07:15:27 [ℹ] nodegroup "ng-dl" has 1 node(s)
2022-01-27 07:15:27 [ℹ] node "ip-10-172-95-87.ap-northeast-2.compute.internal" is ready
2022-01-27 07:15:27 [✔] created 1 managed nodegroup(s) in cluster "vuajde-cluster"
2022-01-27 07:15:27 [ℹ] checking security group configuration for all nodegroups
2022-01-27 07:15:27 [ℹ] all nodegroups have up-to-date cloudformation templates
2. How to check the created node group
- Check node groups.
You can check node groups as follows.1 $ eksctl get nodegroup --cluster vujade-cluster
2022-01-28 00:47:46 [ℹ] eksctl version 0.80.0 2022-01-28 00:47:46 [ℹ] using region ap-northeast-2 CLUSTER NODEGROUP STATUS CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID ASG NAME vujade-cluster ng-dl ACTIVE 2022-01-27T07:12:18Z 1 5 1 g4dn.xlarge AL2_x86_64_GPU eks-ng-dl-0abc1d23-01a2-0a12-012a-a0bc1234d5e6
- Check nodes.
You can also check nodes in the node groups. Please note that you should connect the created cluster as described in Section 5. How to create a cluster before listing nodes below.1 $ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS ip-10-172-95-87.ap-northeast-2.compute.internal Ready <none> 17h v1.21.5-eks-9017834 alpha.eksctl.io/cluster-name=vujade-cluster,alpha.eksctl.io/nodegroup-name=ng-dl,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=g4dn.xlarge,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup-image=ami-04a860d4e53598406,eks.amazonaws.com/nodegroup=ng-dl,eks.amazonaws.com/sourceLaunchTemplateId=lt-0fbc06a2d297490d2,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=ap-northeast-2,failure-domain.beta.kubernetes.io/zone=ap-northeast-2c,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-10-172-95-87.ap-northeast-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=g4dn.xlarge,topology.kubernetes.io/region=ap-northeast-2,topology.kubernetes.io/zone=ap-northeast-2c
3. How to delete a node group
You can delete a node group as follows.
1 $ eksctl delete nodegroup --region=ap-northeast-2 --cluster=vujade-cluster --name=ng-dl
2022-01-18 07:41:36 [ℹ] eksctl version 0.79.0
2022-01-18 07:41:36 [ℹ] using region ap-northeast-2
2022-01-18 07:41:36 [ℹ] 1 nodegroup (ng-dl) was included (based on the include/exclude rules)
2022-01-18 07:41:36 [ℹ] will drain 1 nodegroup(s) in cluster "vujade-cluster"
2022-01-18 07:41:36 [!] no nodes found in nodegroup "ng-dl" (label selector: "alpha.eksctl.io/nodegroup-name=ng-dl")
2022-01-18 07:41:36 [ℹ] will delete 1 nodegroups from cluster "vujade-cluster"
2022-01-18 07:41:36 [ℹ] 1 task: { 1 task: { delete nodegroup "ng-dl" [async] } }
2022-01-18 07:41:36 [ℹ] will delete stack "eksctl-vujade-cluster-nodegroup-ng-dl"
2022-01-18 07:41:36 [ℹ] will delete 0 nodegroups from auth ConfigMap in cluster "vujade-cluster"
2022-01-18 07:41:36 [✔] deleted 1 nodegroup(s) from cluster "vujade-cluster"
6. How to configure a cluster autoscaler (CA)
You can configure a cluster autoscaler (CA) by executing following commands. You can get more information in the AWS EKS workshop guide, Configure Cluster Autoscaler (CA). Please note the CA only works when there is a node group at least.
I provide a bash script, bash_install_ca.sh to install the CA easily. Please note that you can get the ACCOUNT_ID in the Amazon Web Services (AWS) Cloud9 - Section 8. How to create an AWS KMS custom managed key (CMK).
1 $ bash ./bash_install_ca.sh NAME_CLUSTER ACCOUNT_ID
1. IAM roles for service accounts
- Enabling IAM roles for service accounts on your cluster (i.e. Creating IAM OIDC provider).
1 $ eksctl utils associate-iam-oidc-provider --cluster vujade-cluster --approve
2022-01-28 08:41:31 [ℹ] eksctl version 0.80.0 2022-01-28 08:41:31 [ℹ] using region ap-northeast-2 2022-01-28 08:41:32 [ℹ] will create IAM Open ID Connect provider for cluster "vujade-cluster" in "ap-northeast-2" 2022-01-28 08:41:32 [✔] created IAM Open ID Connect provider for cluster "vujade-cluster" in "ap-northeast-2"
- Creating an IAM policy for your service account that will allow your CA pod to interact with the autoscaling groups.
You can create the IAM policy with k8s-asg-policy.json as below. Please note that you don’t need to create the customer managed IAM policy if it already exists as below.1 $ aws iam create-policy --policy-name k8s-asg-policy --policy-document file://./k8s-asg-policy.json
An error occurred (EntityAlreadyExists) when calling the CreatePolicy operation: A policy called k8s-asg-policy already exists. Duplicate names are not allowed.
- Finally, create an IAM role for the cluster-autoscaler Service Account in the kube-system namespace.
You can obtain the policy ARN in IAM - Policies with k8s-asg-policy.1 $ eksctl create iamserviceaccount \ 2 --name cluster-autoscaler \ 3 --namespace kube-system \ 4 --cluster vujade-cluster \ 5 --attach-policy-arn "arn:aws:iam::123456789123:policy/k8s-asg-policy" \ 6 --approve \ 7 --override-existing-serviceaccounts
2022-01-28 09:15:51 [ℹ] eksctl version 0.80.0 2022-01-28 09:15:51 [ℹ] using region ap-northeast-2 2022-01-28 09:15:52 [ℹ] 1 iamserviceaccount (kube-system/cluster-autoscaler) was included (based on the include/exclude rules) 2022-01-28 09:15:52 [!] metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set 2022-01-28 09:15:52 [ℹ] 1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/cluster-autoscaler", create serviceaccount "kube-system/cluster-autoscaler", } }2022-01-28 09:15:52 [ℹ] building iamserviceaccount stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-cluster-autoscaler" 2022-01-28 09:15:52 [ℹ] deploying stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-cluster-autoscaler" 2022-01-28 09:15:52 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-cluster-autoscaler" 2022-01-28 09:16:12 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-cluster-autoscaler" 2022-01-28 09:16:27 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-cluster-autoscaler" 2022-01-28 09:16:27 [ℹ] created serviceaccount "kube-system/cluster-autoscaler"
- Make sure your service account with the ARN of the IAM role is annotated.
1 $ kubectl -n kube-system describe sa cluster-autoscaler
Name: cluster-autoscaler Namespace: kube-system Labels: app.kubernetes.io/managed-by=eksctl Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::123456789123:role/eksctl-vujade-cluster-addon-iamserviceaccount-Role1-1DOGJCHJ8OE45 Image pull secrets: <none> Mountable secrets: cluster-autoscaler-token-29s2h Tokens: cluster-autoscaler-token-29s2h Events: <none>
2. Deploy the Cluster Autoscaler (CA)
- Deploy the Cluster Autoscaler to your cluster with the following command.
You can get a yaml file for deploying a cluster from official EKS workshop site or my GitHub. Please note that you should modify the cluster name to yours.1 $ kubectl apply -f ./cluster-autoscaler-autodiscover.yaml
clusterrole.rbac.authorization.k8s.io/cluster-autoscaler created role.rbac.authorization.k8s.io/cluster-autoscaler created clusterrolebinding.rbac.authorization.k8s.io/cluster-autoscaler created rolebinding.rbac.authorization.k8s.io/cluster-autoscaler created deployment.apps/cluster-autoscaler created
- To prevent CA from removing nodes where its own pod is running, we will add the
cluster-autoscaler.kubernetes.io/safe-to-evict annotation to its deployment with the following command.
1 $ kubectl -n kube-system annotate deployment.apps/cluster-autoscaler cluster-autoscaler.kubernetes.io/safe-to-evict="false"
deployment.apps/cluster-autoscaler annotated
- Finally let’s update the autoscaler image.
1 $ export K8S_VERSION=$(kubectl version --short | grep 'Server Version:' | sed 's/[^0-9.]*\([0-9.]*\).*/\1/' | cut -d. -f1,2) 2 $ export AUTOSCALER_VERSION=$(curl -s "https://api.github.com/repos/kubernetes/autoscaler/releases" | grep '"tag_name":' | sed -s 's/.*-\([0-9][0-9\.]*\).*/\1/' | grep -m1 ${K8S_VERSION}) 3 $ kubectl -n kube-system set image deployment.apps/cluster-autoscaler cluster-autoscaler=us.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:v${AUTOSCALER_VERSION}
deployment.apps/cluster-autoscaler image updated
- You can watch logs.
1 $ kubectl -n kube-system logs -f deployment/cluster-autoscaler
- Check the created cluster autoscaler.
1 $ kubectl get deploy -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE kube-system cluster-autoscaler 1/1 1 1 7m39s kube-system coredns 2/2 2 2 28h
7. How to install the AWS load balancer controller
You can install the AWS load balanacer controller by executing following commands. You can get more information in the AWS Load Balancer Controller, Ingress Controller and Install Kubernetes Tools.
I provide a bash script, bash_install_lbc.sh to install the AWS load balancer controller easily. Please note that you can get the ACCOUNT_ID and NAME_ROLE_AWS_LBC in the Amazon Web Services (AWS) Cloud9 - Section 8. How to create an AWS KMS custom managed key (CMK) and Step 7. Attach the IAM policy to the IAM role, respectively.
1 $ bash ./bash_install_lbc.sh NAME_CLUSTER ACCOUNT_ID NAME_ROLE_AWS_LBC
1. Deploy the AWS Load Balancer Controller
- We will verify if the AWS Load Balancer Controller version has been set.
1 $ echo 'export LBC_VERSION="v2.3.1"' >> ~/.bash_profile 2 $ . ~/.bash_profile 3 $ if [ ! -x ${LBC_VERSION} ] 4 then 5 tput setaf 2; echo '${LBC_VERSION} has been set.' 6 else 7 tput setaf 1; echo '${LBC_VERSION} has NOT been set.' 8 fi
${LBC_VERSION} has been set.
- Create IAM OIDC provider.
You can skip this step if you already execute the command in 7. How to configure a cluster autoscaler (CA)1 $ eksctl utils associate-iam-oidc-provider --cluster vujade-cluster --approve
- Create an IAM policy, AWSLoadBalancerControllerIAMPolicy.
Please note that you don’t need to create the customer managed IAM policy if it already exists as below. You can also download the iam_policy.json.1 $ curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.3.1/docs/install/iam_policy.json 2 $ aws iam create-policy \ 3 --policy-name AWSLoadBalancerControllerIAMPolicy \ 4 --policy-document file://iam_policy.json
An error occurred (EntityAlreadyExists) when calling the CreatePolicy operation: A policy called AWSLoadBalancerControllerIAMPolicy already exists. Duplicate names are not allowed.
- Create a IAM role and ServiceAccount.
You can obtain the policy ARN in IAM - Policies with AWSLoadBalancerControllerIAMPolicy.1 $ eksctl create iamserviceaccount \ 2 --cluster vujade-cluster \ 3 --namespace kube-system \ 4 --name aws-load-balancer-controller \ 5 --attach-policy-arn arn:aws:iam::123456789123:policy/AWSLoadBalancerControllerIAMPolicy \ 6 --override-existing-serviceaccounts \ 7 --approve
2022-01-28 13:32:15 [ℹ] eksctl version 0.80.0 2022-01-28 13:32:15 [ℹ] using region ap-northeast-2 2022-01-28 13:32:16 [ℹ] 1 existing iamserviceaccount(s) (kube-system/cluster-autoscaler) will be excluded 2022-01-28 13:32:16 [ℹ] 1 iamserviceaccount (kube-system/aws-load-balancer-controller) was included (based on the include/exclude rules) 2022-01-28 13:32:16 [!] metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set 2022-01-28 13:32:16 [ℹ] 1 task: { 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/aws-load-balancer-controller", create serviceaccount "kube-system/aws-load-balancer-controller", } }2022-01-28 13:32:16 [ℹ] building iamserviceaccount stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-aws-load-balancer-controller" 2022-01-28 13:32:16 [ℹ] deploying stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-aws-load-balancer-controller" 2022-01-28 13:32:16 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-aws-load-balancer-controller" 2022-01-28 13:32:34 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-aws-load-balancer-controller" 2022-01-28 13:32:53 [ℹ] waiting for CloudFormation stack "eksctl-vujade-cluster-addon-iamserviceaccount-kube-system-aws-load-balancer-controller" 2022-01-28 13:32:54 [ℹ] created serviceaccount "kube-system/aws-load-balancer-controller"
- Download the IAM policy.
You can also download the iam_policy_v1_to_v2_additional.json.1 $ curl -o iam_policy_v1_to_v2_additional.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.3.1/docs/install/iam_policy_v1_to_v2_additional.json
- Create the IAM policy and note the ARN that is returned.
Please note that you don’t need to create the customer managed IAM policy if it already exists as below.1 $ aws iam create-policy \ 2 --policy-name AWSLoadBalancerControllerAdditionalIAMPolicy \ 3 --policy-document file://iam_policy_v1_to_v2_additional.json
An error occurred (EntityAlreadyExists) when calling the CreatePolicy operation: A policy called AWSLoadBalancerControllerAdditionalIAMPolicy already exists. Duplicate names are not allowed.
- Attach the IAM policy to the IAM role.
You can find the role name as follows:- Open the AWS CloudFormation console
- Select the eksctl-your-cluster-name-addon-iamserviceaccount-kube-system-aws-load-balancer-controller stack.
- Click the Resources tab.
- The role name is in the Physical ID column. bag
1 $ aws iam attach-role-policy \ 2 --role-name eksctl-vujade-cluster-addon-iamserviceaccount-Role1-1ABC2D3E4FGHI \ 3 --policy-arn arn:aws:iam::123456789123:policy/AWSLoadBalancerControllerAdditionalIAMPolicy
- Add the eks-charts repository.
1 $ helm repo add eks https://aws.github.io/eks-charts
"eks" has been added to your repositories
- Update your local repo to make sure that you have the most recent charts.
1 $ helm repo update
Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "eks" chart repository ...Successfully got an update from the "stable" chart repository Update Complete. ⎈Happy Helming!⎈
- Install the TargetGroupBinding CRDs.
1 $ kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller/crds?ref=master" 2 $ kubectl get crd
customresourcedefinition.apiextensions.k8s.io/ingressclassparams.elbv2.k8s.aws created customresourcedefinition.apiextensions.k8s.io/targetgroupbindings.elbv2.k8s.aws created NAME CREATED AT eniconfigs.crd.k8s.amazonaws.com 2022-01-27T06:57:16Z ingressclassparams.elbv2.k8s.aws 2022-01-28T13:59:28Z securitygrouppolicies.vpcresources.k8s.aws 2022-01-27T06:57:19Z targetgroupbindings.elbv2.k8s.aws 2022-01-28T13:59:28Z
- Install the AWS Load Balancer Controller.
1 $ helm install aws-load-balancer-controller eks/aws-load-balancer-controller \ 2 -n kube-system \ 3 --set clusterName=vujade-cluster \ 4 --set serviceAccount.create=false \ 5 --set serviceAccount.name=aws-load-balancer-controller
NAME: aws-load-balancer-controller LAST DEPLOYED: Fri Jan 28 14:02:37 2022 NAMESPACE: kube-system STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: AWS Load Balancer controller installed!
- Verify that the controller is installed.
1 $ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME READY UP-TO-DATE AVAILABLE AGE aws-load-balancer-controller 2/2 2 2 38s
8. How to install a metric server
You can install a metric server which is a scalable, efficient source of container resource metrics for Kubernetes built-in autoscaling pipelines by executing following commands. You can get more information in the Configure Horizontal Pod Autoscaler (HPA).
1 $ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.5.0/components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
1 $ kubectl get apiservice v1beta1.metrics.k8s.io -o json | jq '.status'
{
"conditions": [
{
"lastTransitionTime": "2022-01-28T14:15:04Z",
"message": "all checks passed",
"reason": "Passed",
"status": "True",
"type": "Available"
}
]
}
1 $ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-load-balancer-controller-cb56f956d-cmvh7 1/1 Running 0 13m
kube-system aws-load-balancer-controller-cb56f956d-d76rf 1/1 Running 0 13m
kube-system aws-node-frdxk 1/1 Running 0 31h
kube-system cluster-autoscaler-77d7c6c9b8-8bzck 1/1 Running 0 155m
kube-system coredns-6dbb778559-2dhqq 1/1 Running 0 31h
kube-system coredns-6dbb778559-t4twm 1/1 Running 0 31h
kube-system kube-proxy-glbbl 1/1 Running 0 31h
kube-system metrics-server-6dfddc5fb8-zq97v 1/1 Running 0 111s
kube-system nvidia-device-plugin-daemonset-q2fbv 1/1 Running 0 31h
9. How to apply a namespace
1. Preparations
You can check the namespace.yaml.
2. How to apply a namespace
1 $ kubectl apply -f namespace.yaml
namespace/ns-vujade created
3. How to check the applied namespace
1 $ kubectl get namespace
NAME STATUS AGE
default Active 2d4h
kube-node-lease Active 2d4h
kube-public Active 2d4h
kube-system Active 2d4h
ns-vujade Active 50s
4. How to delete the applied namespace
1 $ kubectl delete -f namespace.yaml
namespace "ns-vujade" deleted
10. How to apply a deployment
1. Preparations
You can check the dep_dl.yaml.
2. How to apply a deployment
1 $ kubectl apply -f deployment.yaml
deployment.apps/dep-dl created
3. How to check the applied deployment
1 $ kubectl get deployment -A
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system aws-load-balancer-controller 2/2 2 2 21h
kube-system cluster-autoscaler 1/1 1 1 23h
kube-system coredns 2/2 2 2 2d4h
kube-system metrics-server 1/1 1 1 21h
ns-vujade dep-dl 3/3 3 3 32s
4. How to delete the applied deployment
1 $ kubectl delete -f deployment.yaml
deployment.apps "dep-dl" deleted
11. How to apply a service
1. Preparations
You can check the svc_dl.yaml.
2. How to apply a service
1 $ kubectl apply -f service.yaml
service/svc-dl created
3. How to check the applied service
1 $ kubectl get service -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 2d4h
kube-system aws-load-balancer-webhook-service ClusterIP 172.20.122.144 <none> 443/TCP 21h
kube-system kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP 2d4h
kube-system metrics-server ClusterIP 172.20.46.230 <none> 443/TCP 21h
ns-vujade svc-dl NodePort 172.20.205.201 <none> 11001:31803/TCP 15s
4. How to delete the applied service
1 $ kubectl delete -f service.yaml
service "svc-dl" deleted
12. How to apply a horizontal pod autoscaler (HPA)
1. Preparations
You can check the hpa_dl.yaml.
2. How to apply a HPA
1 $ kubectl apply -f hpa.yaml
horizontalpodautoscaler.autoscaling/hpa-dl created
3. How to check the applied HPA
1 $ kubectl get hpa -A
NAMESPACE NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
ns-vujade hpa-dl Deployment/dep-dl 0%/65% 3 12 3 20s
4. How to delete the applied HPA
1 $ kubectl delete -f hpa.yaml
horizontalpodautoscaler.autoscaling "hpa-dl" deleted
5. How does the HPA work?
The HPA is based on how many resources are being used compared to the requests allocated to the pod. In other words, the condition for scale-out of pods by the HPA as follows:
\begin{equation} \label{eq:cauchy-schwarz} averageUtilization \le 100 * \frac{CPU_{Total}}{N_{Pod} \times CPU_{Request}} \end{equation}
- CPUTotal is the total central processing unit (CPU) usage in a worker node.
- NPod is the number of pod in a worker node.
- CPURequest is assigned in the deployment. It means minimum resources that the CPU must be guaranteed. Please note that the CPU usage is controlled in units of milli-cores (i.e m) by the Kubernetes. A single CPU is equivalent to 1m.
13. How to apply an ingress
1. Preparations
You can check the ingress.yaml.
2. How to apply an ingress
1 $ kubectl apply -f ingress.yaml
ingress.extensions/alb-ing-eks-vujade created
3. How to check the applied ingress
1 $ kubectl get ingress -A
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
ns-vujade alb-ing-eks-vujade <none> * internal-k8s-nsvujade-albingea-1716e099f7-114012471.ap-northeast-2.elb.amazonaws.com 80 54s
4. How to delete the applied ingress
1 $ kubectl delete -f ingress.yaml
ingress.extensions "alb-ing-eks-vujade" deleted
14. Useful kubectl commands
1. How to list nodes in details
1 $ kubectl get nodes -A -o wide
2. How to list pods in details
1 $ kubectl get pods -A -o wide
3. How to watch logs for a pod
1 $ kubectl logs -f --namespace ${NAMESPACE} ${NAME_POD}
4. How to execute a command for a pod
1 $ kubectl exec --namespace ${NAMESPACE} ${NAME_POD} ${COMMAND}
15. How to fix error
1. Cannot create a node group
When the node is deployed in a private subnet, the subnet must have a route to a NAT gateway where a public IP address is assigned. Amazon Virtual Private Cloud (VPC) - Section 10. How to set up a route table for the NAT gateway. The error messages are as follows.
2022-01-18 08:32:14 [✖] unexpected status "ROLLBACK_IN_PROGRESS" while waiting for CloudFormation stack "eksctl-vujade-cluster-nodegroup-ng-dl"
2022-01-18 08:32:14 [ℹ] fetching stack events in attempt to troubleshoot the root cause of the failure
2022-01-18 08:32:14 [✖] AWS::EKS::Nodegroup/ManagedNodeGroup: CREATE_FAILED – "Nodegroup ng-dl failed to stabilize: [{Code: NodeCreationFailure,Message: Instances failed to join the kubernetes cluster,ResourceIds: [i-0a12bc3d45e67fg8h]}]"
2022-01-18 08:32:14 [ℹ] 1 error(s) occurred and nodegroups haven't been created properly, you may wish to check CloudFormation console
16. Reference
- Regions and Zones
- What is Kubernetes?
- Amazon EKS features
- Amazon EKS clusters
- Amazon EKS nodes
- Managed node groups
- Autoscaling
- AWS Load Balancer Controller
- Installing the Kubernetes Metrics Server
- Working with Namespaces
- Deployments
- Pods
- ReplicaSet
- Service
- Horizontal Pod Autoscaling
- StatefulSets
- Ingress