EKS 學習筆記 - 基礎安裝篇


上一篇 整理了使用 kubeadm 安裝 K8s Cluster / Worker Nodes / CNI … 等,同樣的,本文整理使用 AWS EKS 安裝 K8s v1.14 的筆記,安裝過程則以 AWS CLI 為主,同樣方式也可以使用 eksctl、AWS Console、CloudFormation 執行。

如同之前提及,雖然 EKS 是 Managed Service,但是實際上只有針對 Master Nodes,而 Worker Nodes 還是需要自行管理以及維護的,另外針對 Ingress、使用者權限、Log 蒐集、資源監控、網路 (CNI 相關) … 等,還是需要額外規劃。

筆記內容:

  1. 準備: IAM User, IAM Role, VPC Subnets
  2. 建置: EKS Master Nodes, ConfigMap, CNI, Worker Nodes
  3. Q and A

準備 (Preparation)

使用 EKS 有幾件事情要先準備、規劃的,主要是 VPC 還有權限部分。

準備工具

先準備以下工具:

  1. awscli: 本文以 awscli 為主,版本至少要 1.16.232 以上才可以。
  2. kubectl: 安裝 1.14 以上版本
  3. aws-iam-authenticator (optional): 非必要, 如果 awscli 版本在 1.16.232 以下,那就需要

底下筆記安裝過程,建議開一台乾淨的 Linux 安裝,避免本機環境不乾淨,造成後續安裝問題:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
## 1. 安裝 awscli
pip install awscli

~$ aws --version
aws-cli/1.16.253 Python/3.5.2 Linux/4.4.0-1095-aws botocore/1.12.243

## 2. 安裝 kubectl: for linux
~$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
~$ chmod +x ./kubectl
~$ mv ./kubectl /usr/local/bin/kubectl
~$ kubectl version --short --client
Client Version: v1.16.1

## 安裝 kubectl: for macOS
#curl -o kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.14.6/2019-08-22/bin/darwin/amd64/kubectl
#~$ kubectl version --short --client

## 3. 安裝 aws-iam-authenticator
## see: https://github.com/kubernetes-sigs/aws-iam-authenticator
~$ curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/1.14.6/2019-08-22/bin/linux/amd64/aws-iam-authenticator
~$ chmod +x ./aws-iam-authenticator
~$ sudo mv aws-iam-authenticator /usr/local/bin
~$ aws-iam-authenticator version --short
Version: v0.4.0
Commit: c141eda34ad1b6b4d71056810951801348f8c367

VPC Consideration

相關 VPC 規劃的考量,參閱:EKS 學習筆記 - 網路規劃與管理篇

建置 EKS Cluster 準備以下資訊:

  • Subnet IDs: subnet-1234567,subnet-1234568
  • Security Groups: sg-1234567890123456

規劃權限

準備以下身份給 K8s Cluster 使用:

  • IAM User au-eks-admin: 用來建立 EKS Cluster 的 IAM 身份
  • IAM Roles:
    • K8s-Master-Node-Role: Master Node 的身份,提供以下的 Policies:
      • AmazonEKSClusterPolicy
      • AmazonEKSServicePolicy
    • K8S-Worker-Node-Role: Worker Node 的身份,提供以下的 Policies:
      • AmazonEKSWorkerNodePolicy
      • AmazonEC2ContainerRegistryReadOnly
      • AmazonEKS_CNI_Policy

config.sh

前述的資訊,整理成以下的 Scripts 當作,底下的資訊都是範例,記得改成自己需要的,後續的動作都會假設這些變數已經初始化。

config.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## IAM Profile
AWS_DEFAULT_PROFILE="au-eks-admin"
AWS_DEFAULT_REGION="us-west-2"

## K8S info
K8S_CLUSTER_NAME="eks-v114-20191013"
K8S_VERSION="1.14"

## IAM ROLES
K8S_MASTER_NODE_ROLE_ARN="arn:aws:iam:::role/K8S-Master-Node-Role"
K8S_WORKER_NODE_ROLE_ARN="arn:aws:iam:::role/K8S-Worker-Node-Role"

# VPC: Subnet, Security Groups
K8S_WORKER_SUBNETS="subnet-12345678,subnet-12345679"
K8S_WORKER_SECURITY_GROUPS="sg-1234567890123456"

建置 (Provisioning)

建置過程的執行身份要特別注意,否則問題會很多。底下的範例都是使用 au-eks-admin 這個身份執行。

建置 Master Nodes

直接建立一個 EKS Cluster,底下的配置包含指定 Cluster Name, IAM Role, VPC, Region, Profile 等資訊。

1
2
3
4
5
6
7
8
## 1. 建立 EKS Cluster
aws eks create-cluster \
--name ${K8S_CLUSTER_NAME} \
--role-arn ${K8S_MASTER_NODE_ROLE_ARN} \
--resources-vpc-config subnetIds=${K8S_WORKER_SUBNETS},securityGroupIds=${K8S_WORKER_SECURITY_GROUPS},endpointPublicAccess=true,endpointPrivateAccess=true \
--kubernetes-version ${K8S_VERSION} \
--region ${AWS_DEFAULT_REGION} \
--profile ${AWS_DEFAULT_PROFILE}

執行下去會看到以下的輸出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"cluster": {
"name": "eks-v114-20191006",
"version": "1.14",
"roleArn": "arn:aws:iam::123456789012:role/K8S_MASTER_NODE_ROLE_ARN",
"certificateAuthority": {},
"createdAt": 1570342594.516,
"status": "CREATING",
"arn": "arn:aws:eks:us-west-2:123456789012:cluster/eks-v114-20191013",
"platformVersion": "eks.1",
"resourcesVpcConfig": {
"endpointPublicAccess": true,
"subnetIds": [
"subnet-12345678",
"subnet-12345679"
],
"vpcId": "vpc-1234567",
"securityGroupIds": [
"sg-1234567890123456"
],
"endpointPrivateAccess": true
}
}
}

接下來要等待大約十分鐘的時間,可以透過以下 CLI 取得 Cluster 狀態:

1
2
3
4
5
6
7
8
9
10
11
## Status
aws eks describe-cluster \
--region ${AWS_DEFAULT_REGION} \
--name ${K8S_CLUSTER_NAME} \
--query cluster.status

"CREATING"

# 大約等十到十五分鐘

"ACTIVE"

配置 kubeconfig

使用以下 cli 產生 kubeconfig:

1
2
3
4
5
6
7
8
9
aws eks update-kubeconfig \
--role-arn ${K8S_MASTER_NODE_ROLE_ARN} \
--name ${K8S_CLUSTER_NAME} \
--region ${AWS_DEFAULT_REGION} \
--profile ${AWS_DEFAULT_PROFILE} \
--kubeconfig "${HOME}/.kube/config_${K8S_CLUSTER_NAME}"

echo "copy and paste following to export KUBECONFIG:"
echo " export KUBECONFIG=${HOME}/.kube/config_${K8S_CLUSTER_NAME}"

請把 ${HOME}/.kube/config_${K8S_CLUSTER_NAME} 檔案裡的 envrole 部份都註解掉,如下:

新版的 awscli 產生如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
users:
- name: arn:aws:eks:us-west-2:123456789012:cluster/eks-v114-20191013
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
args:
- --region
- us-west-2
- eks
- get-token
- --cluster-name
- eks-v114-20191013
# - --role
# - arn:aws:iam::123456789012:role/K8S-Master-Node-Role
command: aws
# env:
# - name: AWS_PROFILE
# value: gtcafe-dev.au-eks-admin

舊版的 awscli

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
users:
- name: arn:aws:eks:us-west-2:123456789012:cluster/eks-v114-20191013
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
args:
- token
- -i
- eks-v114-20191013
# - -r
# - arn:aws:iam::123456789012:role/K8S-Master-Node-Role
command: aws-iam-authenticator
# env:
# - name: AWS_PROFILE
# value: gtcafe-dev.au-eks-admin

確認 Cluster Status

取得現在的 nodes 狀態:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
## 看不到任何 Nodes
~$ kubectl get nodes -o wide
No resources found.

## 取得所有的 ComponentStatuses
~$ kubectl get cs --all-namespaces
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health":"true"}

## 取得 Services, Pods
~$ kubectl get svc,po --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 17m
kube-system service/kube-dns ClusterIP 10.100.0.10 <none> 53/UDP,53/TCP 17m

NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-6f647f5754-5zdwb 0/1 Pending 0 17m
kube-system pod/coredns-6f647f5754-9xcl2 0/1 Pending 0 17m

配置 ConfigMap for EKS Auth

主要是提供一個 IAM Role 的身份讓 Master Cluster 去管理。修改以下 aws-auth-cm.yaml 黨,把其中的 <ARN of instance role (not instance profile)> 置換成 Worker Nodes 的 ARN,其他不要動。

aws-auth-cm.template.yaml
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: <ARN of instance role (not instance profile)>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes

直接執行 kubectl apply -f aws-auth-cm.yaml,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
~$ kubectl apply -f aws-auth-cm.yaml
configmap/aws-auth created

~$ kubectl describe configmap -n kube-system aws-auth
Name: aws-auth
Namespace: kube-system
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","data":{"mapRoles":"- rolearn: arn:aws:iam::123456789012:role/EKS-Worker-Node-Role\n username: system:node:{{EC2Privat...

Data
====
mapRoles:
----
- rolearn: arn:aws:iam::123456789012:role/EKS-Worker-Node-Role
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes

Events: <none>

到此 Master Node 已經完成準備。

CNI

EKS 不用特別配置 CNI,建置起來就會準備好 DaemonSet,可以透過了解 aws-node 的配置,可以知道相關資訊以及 VPC CNI 的配置,如下:

1
2
3
4
5
6
7
8
~$ kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
amazon-k8s-cni:v1.5.4

~$ kubectl describe daemonset aws-node --namespace kube-system | grep Image
Image: 602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.5.4

## Find CNI Config Variable, see: https://github.com/aws/amazon-vpc-cni-k8s
~$ kubectl edit daemonset -n kube-system aws-node

建置 Worker Nodes

這邊使用手動建立 Worker Nodes,步驟大概如下:

  1. 找到 AWS 提供的 Woker Node AMI-ID,參考 Amazon EKS-Optimized Linux AMI, 也可以透過 SSM 取得
  2. 建立 Launch Configuration
  3. 建立 EC2 Auto Scaling Group

也可以使用 CloudFormation,下載這份 template 即可。

建立 Launch Configuration

建立一個 LC,如下圖:

其中 User Data 填入以下,注意 EKS-CLUSTER-NAME 記得修改。

1
2
3
4
5
#!/bin/bash
set -o xtrace

# /etc/eks/bootstrap.sh {EKS-CLUSTER-NAME}
/etc/eks/bootstrap.sh eks-v114-20191013

建立 EC2 ASG

建立一個 EC2 ASG,使用前面建立的 LC,如下圖。特別注意的是 Tag 必續指定如下:

  • Key: kubernetes.io/cluster/<CLUSTER_NAME>, Value: owned

如果沒有指定,Worker Node 就無法加入 Cluster。

順利的話,執行以下就可以看到 Nodes 的狀態了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## 取得 Nodes
~$ kubectl get no
NAME STATUS ROLES AGE VERSION
ip-172-31-0-198.us-west-2.compute.internal Ready <none> 3m51s v1.14.7-eks-1861c5
ip-172-31-5-6.us-west-2.compute.internal Ready <none> 3m58s v1.14.7-eks-1861c5

## 取得所有的 Pod
~$ kubectl get svc,po --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 65m
kube-system service/kube-dns ClusterIP 10.100.0.10 <none> 53/UDP,53/TCP 65m

NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/aws-node-jmt6l 1/1 Running 0 8m3s
kube-system pod/aws-node-w94hd 1/1 Running 0 8m10s
kube-system pod/coredns-6f647f5754-5zdwb 1/1 Running 0 65m
kube-system pod/coredns-6f647f5754-9xcl2 1/1 Running 0 65m
kube-system pod/kube-proxy-ms9pl 1/1 Running 0 8m3s
kube-system pod/kube-proxy-vggsq 1/1 Running 0 8m10s

完成

到此整個 EKS Cluster 算是完成建置了。可以接續 上一篇 提到的各種 Addons 的安裝,都可以正常的使用。


刪除 EKS Cluster

刪除 Worker Nodes: 把 ASG Desired, Min, Max 調成 0

刪除 EKS Master Nodes:

1
2
3
4
~$ aws eks delete-cluster \
--name ${K8S_CLUSTER_NAME} \
--region ${AWS_DEFAULT_REGION} \
--profile ${AWS_DEFAULT_PROFILE}

輸出:

1
2
3
4
5
6
7
8
9
10
11
{
"cluster": {
"status": "DELETING",
"endpoint": "https://DEB7D38018734725F9E5420DB103A5EB.gr7.us-west-2.eks.amazonaws.com",
"roleArn": "arn:aws:iam::123456789012:role/K8S-Master-Node-Role",

... 略 ...

"createdAt": 1570970988.023
}
}

Q and A

Q: 本文使用的身份是 au-eks-admin,如何讓其他 IAM 身份可以使用此 Cluster?

參考文件的整理: Managing Users or IAM Roles for your Cluster,修改 configMap - aws-auth: k edit cm aws-auth -n kube-system,如下的範例,修改 mapUsers 部分,增加需要的 IAM User ARN 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
data:
mapRoles: |
- rolearn: arn:aws:iam::555555555555:role/devel-worker-nodes-NodeInstanceRole-74RF4UBDUKL6
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
mapUsers: |
- userarn: arn:aws:iam::555555555555:user/rickhwang
username: admin
groups:
- system:masters
- userarn: arn:aws:iam::111122223333:user/ops-user
username: ops-user
groups:
- system:masters

要注意的是,實際上這例子的角色只是抽象定義,他們實際上的權限都是 system:masters

注意:這不是最佳的帳號管理策略,因為這樣的用法比哨:使用者都需要有 AWS IAM 權限才行,實務上每個使用者不見得都有 IAM User 帳號。

Q: Worker Node 一定要等 Master Node 建好才能建?

實測過,不用等 Master Node 建好,只要 ASG 的 Tag / User Data 指定的資料正確,可以先建置沒關係。

Q: Worker Node 沒有加入 Cluster?

步驟如下:

  1. 確認 config map aws-auth.yaml 裡的 WorkerNode ARN 是正確的
  2. 確認 LC 裡的:
    • User Data 裡面指定的是對的
    • WorkerNode ARN 是對的
  3. 確認 ASG 的 Tag Key 是否正確,格式為 Key: kubernetes.io/cluster/<CLUSTER_NAME>, Value: owned

Q: 出現這樣的 Error 該怎麼處理: error: You must be logged in to the server (Unauthorized)

通常是執行 aws cli 的身份錯誤,使用 aws sts get-caller-identity 確認現在的身份:

1
2
3
4
5
6
~$ aws sts get-caller-identity
{
"Account": "12345678",
"UserId": "ABCDEFGHIJKLMNOPRRSTUVWXYZ",
"Arn": "arn:aws:iam::123456789012:user/au-eks-admin"
}

重新執行:export AWS_DEFAULT_PROFILE=<profile_name>,當然要確認這個 profile 是否已經在 $HOME/.aws/config, $HOME/.aws/credentials 配置好。

Q: 過程為什麼要自己手動建立 Worker Nodes 而不使用 CloudFormation?

主要原因是要了解其運作原理,另外 CloudFormation 會把很多 VPC 的設定打亂,像是 Security Groups、IAM Roles,實務上這些都是有 Infra Team 在管理,不會希望產生一堆亂七八糟的名稱,打亂管理規則。更多關於 VPC 的規劃與管理,參閱以下文章:

  • [Plan and Design Multiple VPCs in Different Regions][ct3]
  • [Study Notes - Virtual Private Cloud (VPC)][ct2]
  • [Building a VPN Between GCP and AWS][ct5]

Q: Pod 的 Log 要如何有效地蒐集以及管理?

選項:

重點在於:

  • 能夠區分 namespaces 與各個 pod 的 logs.

Q: EKS 要支援 HPA (Horizontal Pod Autoscaler) 要先準備好什麼?

先準備好 Metric Server,依照文件步驟安裝即可。


結論

本文與上一篇 kubeadm 都只是最基本部分,如同一開始提到,建置 Cluster 之後,還有很多事要規劃,完整目錄整理在 EKS 學習筆記 - 目錄


延伸閱讀

K8s 相關


Comments