為什麼 EKS worker node 可以自動加入 EKS cluster(一)
如果是一個自建的 Kubernetes cluster,我們會需要使用 Certificate Authority 憑證給予 Kubernetes Components [1] 所使用,如 Kubernetes The Hard Way [2] 或是以下 kubeadm join
[3] 命令則可以使 Kubernetes node 加入 cluster:
$ kubeadm join --discovery-token abcdef.1234567890abcdef --discovery-token-ca-cert-hash sha256:1234..cdef 1.2.3.4:6443
在 EKS 環境中,nodegroup 一詞代表了 Kubernetes nodes 集合,而我們也可以使用 eksctl scale
[4] 命令 scale up Nodes。
$ eksctl scale ng --nodes=3 --nodes-max=10 --name=ng1-public-ssh --cluster=ironman-2022
2022-09-18 14:14:18 [ℹ] scaling nodegroup "ng1-public-ssh" in cluster ironman-2022
2022-09-18 14:14:18 [ℹ] waiting for scaling of nodegroup "ng1-public-ssh" to complete
2022-09-18 14:14:48 [ℹ] nodegroup successfully scaled
而在短短幾分鐘內,我們並無需要手動設定 TLS 憑證,EKS node 則可以順利自動加入集群。
$ kubectl get node
NAME STATUS ROLES AGE VERSION
...
ip-192-168-40-16.eu-west-1.compute.internal Ready <none> 34s v1.22.12-eks-ba74326
...
故將探討「為什麼 EKS 節點可以自動加入集群」,希望理解 EKS node 預設了哪些設置允許 node 可以自動加入 cluster。本文將著重於:
- 何謂 EKS node group?
- EKS AMI bootstrap script 預設了哪些設定?
EKS node group
一個完整的 Kubernetes Components [1] 可以分成為 Control Plane 端及 Node 端。其中 在 EKS cluster 環境中,AWS 服務整合了 EC2、Auto Scaling groups 等服務的 worker node 資源稱之為 nodegroup(節點組)。根據 EKS Node 文件,又可以分成 Managed node groups(託管節點組) [6] 及 Self-managed nodes(自行管理節點組) [7]。
於 第一天 的 eksctl
ClusterConfig 文件定義使用了 Managed node groups ng1-public-ssh
。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: ironman-2022
region: eu-west-1
managedNodeGroups:
- name: "ng1-public-ssh"
desiredCapacity: 2
ssh:
# Enable ssh access (via the admin container)
allow: true
publicKeyName: "ironman-2022"
iam:
withAddonPolicies:
ebs: true
fsx: true
efs: true
awsLoadBalancerController: true
autoScaler: true
iam:
withOIDC: true
cloudWatch:
clusterLogging:
enableTypes: ["*"]
在建立完環境後,我們會有名為 ng1-public-ssh
的 Managed node groups:
$ eksctl get ng --cluster=ironman-2022
CLUSTER NODEGROUP STATUS CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID ASG NAME TYPE
ironman-2022 ng1-public-ssh ACTIVE 2022-09-14T09:54:36Z 0 10 3 m5.large AL2_x86_64 eks-ng1-public-ssh-62c19db5-f965-bdb7-373a-147e04d9f124 managed
因此我們也可以透過 aws eks describe-nodegroup
[8] 命令查看 nodegroup 資源資訊:
$ aws eks describe-nodegroup --cluster-name ironman-2022 --nodegroup-name ng1-public-ssh
{
"nodegroup": {
"nodegroupName": "ng1-public-ssh",
"nodegroupArn": "arn:aws:eks:eu-west-1:111111111111:nodegroup/ironman-2022/ng1-public-ssh/62c19db5-f965-bdb7-373a-147e04d9f124",
"clusterName": "ironman-2022",
"version": "1.22",
"releaseVersion": "1.22.12-20220824",
"createdAt": "2022-09-14T09:54:36.211000+00:00",
"modifiedAt": "2022-09-18T13:45:07.322000+00:00",
"status": "ACTIVE",
"capacityType": "ON_DEMAND",
"scalingConfig": {
"minSize": 0,
"maxSize": 2,
"desiredSize": 2
},
"instanceTypes": [
"m5.large"
],
"subnets": [
"subnet-0e863f9fbcda592a3",
"subnet-00ebeb2e8903fb3f9",
"subnet-02d98be342d8ab2a7"
],
"amiType": "AL2_x86_64",
"nodeRole": "arn:aws:iam::111111111111:role/eksctl-ironman-2022-nodegroup-ng1-publ-NodeInstanceRole-HN27OZ18JS6U",
"labels": {
"alpha.eksctl.io/cluster-name": "ironman-2022",
"alpha.eksctl.io/nodegroup-name": "ng1-public-ssh"
},
"resources": {
"autoScalingGroups": [
{
"name": "eks-ng1-public-ssh-62c19db5-f965-bdb7-373a-147e04d9f124"
}
]
},
"health": {
"issues": []
},
"updateConfig": {
"maxUnavailable": 1
},
"launchTemplate": {
"name": "eksctl-ironman-2022-nodegroup-ng1-public-ssh",
"version": "1",
"id": "lt-000b4417a7baebbf8"
},
"tags": {
"aws:cloudformation:stack-name": "eksctl-ironman-2022-nodegroup-ng1-public-ssh",
"alpha.eksctl.io/cluster-name": "ironman-2022",
"alpha.eksctl.io/nodegroup-name": "ng1-public-ssh",
"aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-1:111111111111:stack/eksctl-ironman-2022-nodegroup-ng1-public-ssh/2b5ad730-3413-11ed-9adb-0296792ac05b",
"auto-delete": "never",
"eksctl.cluster.k8s.io/v1alpha1/cluster-name": "ironman-2022",
"aws:cloudformation:logical-id": "ManagedNodeGroup",
"alpha.eksctl.io/nodegroup-type": "managed",
"alpha.eksctl.io/eksctl-version": "0.111.0"
}
}
}
由上述輸出內容 nodegroup 資源包含了此 Node 使用的 IAM role、Auto Scaling Group 名稱、Launch Template 及 CloudFormation 資訊。其中我們可以得知 EKS 預設使用 AMI 為: AL2_x86_64
,此為 AWS 基於 Amazon Linux 2 AMI 維護 Amazon EKS optimized Amazon Linux AMIs [9] 。
Amazon EKS AMI Build Specification
使用 aws ec2 describe-instance-attribute
命令查看 EC2 userdata [11] 並透過 base64 命令解析:
$ aws ec2 describe-instance-attribute --instance-id i-1234567890abcdef0 --attribute userData | jq -r .UserData.Value | base64 -d
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"
--//
Content-Type: text/x-shellscript; charset="us-ascii"
#!/bin/bash
set -ex
B64_CLUSTER_CA=LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvakNDQWVhZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHV... SKIP ...
... CA ...
... CONTENT ...
kZtcnI5V1lZRExMUDdLCm0xVUJQUWdzTzRQQlREUjlaLzhpbnZDV0FiT0szM2Z6OVZqU3dBbjlhQ0lXbU5FY2dVMkFUWm1FN0N4WEUrbFkKOFhjPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
API_SERVER_URL=https://1234567890ABCDEFGHIJKLMNOPQRSTUV.gr7.eu-west-1.eks.amazonaws.com
K8S_CLUSTER_DNS_IP=10.100.0.10
/etc/eks/bootstrap.sh ironman-2022 --kubelet-extra-args '--node-labels=eks.amazonaws.com/sourceLaunchTemplateVersion=1,alpha.eksctl.io/nodegroup-name=ng1-public-ssh,alpha.eksctl.io/cluster-name=ironman-2022,eks.amazonaws.com/nodegroup-image=ami-0ec9e1727a24fb788,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=ng1-public-ssh,eks.amazonaws.com/sourceLaunchTemplateId=lt-000b4417a7baebbf8 --max-pods=29' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP --use-max-pods false
--//--
我們可以得知 bash script 定義:
B64_CLUSTER_CA
、API_SERVER_URL
、K8S_CLUSTER_DNS_IP
環境變數。- 執行了於
/etc/eks/bootstrap.sh
路徑 script。
根據 Amazon EKS optimized Amazon Linux AMI build script [12] 提及了 GitHub Amazon EKS AMI Build Specification [13] 定義了 EKS node bootstrap script 包含 certificate data、control plane endpoint、cluster 名稱等資訊。
而預設的 userdata script 則定義了以下幾個參數:
- cluster 名稱。
--kubelet-extra-args
:定義額外 kubelet 參數,方便增加設定 labels 或 taints。--b64-cluster-ca
:EKS cluster based64 編碼後的內容。此部分透過 AWS CLIaws eks describe-cluster
命令取得後設定儲存於/etc/kubernetes/pki/ca.crt
。--apiserver-endpoint
: EKS cluster API Server endpoint。與--b64-cluster-ca
一樣皆是透過aws eks describe-cluster
命令,並設定 kubelet 所使用的 kubeconfig 文件(/var/lib/kubelet/kubeconfig
)。--dns-cluster-ip
:設定 EKS cluster 內部使用的 DNS IP 地址於 kubelet 設定文件/etc/kubernetes/kubelet/kubelet-config.json
,正是預設 CoreDNS(kube-dns
)Service Cluster IP。預設使用10.100.0.10
,若使用 CIDR 10. 為 prefix 則會使用172.20.0.10
[14]。
$ kubectl -n kube-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.100.0.10 <none> 53/UDP,53/TCP 4d5h
--use-max-pods
:設置 kubelet 參數--max-pods
於 kubelet 設定文件/etc/kubernetes/kubelet/kubelet-config.json
。
總結
以上是 EKS worker node 啟用前在預設 EKS optimized Amazon Linux AMI 內預設 script 及針對 kubelet 參數設定,在經過初步了解之後,下一篇我們將會探討 kubelet TLS bootstrapping 啟動過程,來了解實際自動加入 cluster 過程 kubelet 及 control plane 所需設置。
上述資訊透過 EKS 所提供 Logs 來驗證上游 Kubernetes 運作原理,倘若上述內文有所錯誤,隨時可以留言或是私訊我。
參考文件
- Kubernetes Components - https://kubernetes.io/docs/concepts/overview/components/#node-components
- Provisioning a CA and Generating TLS Certificates | Kubernetes The Hard Way - https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md
- kubeadm join - https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-join/
- Managing nodegroups | eksctl - https://eksctl.io/usage/managing-nodegroups/
- Amazon EKS nodes - https://docs.aws.amazon.com/eks/latest/userguide/eks-compute.html
- Managed node groups - https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html
- Self-managed nodes - https://docs.aws.amazon.com/eks/latest/userguide/worker.html
- aws eks describe-nodegroup - https://docs.aws.amazon.com/cli/latest/reference/eks/describe-nodegroup.html
- Amazon EKS optimized Amazon Linux AMIs - https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html
- aws ec2 describe-instance-attribute - https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instance-attribute.html
- Run commands on your Linux instance at launch - https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
- Amazon EKS optimized Amazon Linux AMI build script - https://docs.aws.amazon.com/eks/latest/userguide/eks-ami-build-scripts.html
- Amazon EKS AMI Build Specification - https://github.com/awslabs/amazon-eks-ami
- https://github.com/awslabs/amazon-eks-ami/blob/master/files/bootstrap.sh#L462-L485
- TLS bootstrapping - https://kubernetes.io/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/