# K8s on Amazon EKS
###### tags: `AWS`,`EKS`,`Kubernetes`
整理在 Amazon EKS 運行 k8s v1.28 的學習資料,以下範例內容需要先安裝下列指令工具
- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)
- [helm](https://helm.sh/docs/intro/install/)
- [aws cli](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)
## Kubernetes(K8s)
自動部署、擴充和管理「容器化應用程式」的開源系統。
### Deployment 演進

### K8s 架構
- K8s cluster 是由節點(node)所構成的,每個節點可運作多個 containers。
- 分成兩個 Components:Control Plane(Master) 及 worker node(s)。
- 最小部署單位是 pod,pod 可含多個 containers,同一個 pod 會共享 storage 及 network,one-container-per-Pod 是 k8s 常見使用方式。
- 支援符合 [Kubernetes CRI(Container Runtime Interface)](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md) 的 container runtime 應用軟體(EX: Docker(Dockershim 實作)、containerd、CRI-O)


### Control Plane(Master) Components
k8s 核心 pods,監聽事件、管理各節點等等工作
#### kube-apiserver
- 所有的 K8s 內部操作都是透過 Kubernetes API
- HTTP-based RESTful API,目前有支援 HTTPS,但不會進行驗證跟解密,須確保內部通訊是在安全非公開的網路環境,另有提供 TCP level proxy 的 [Konnectivity service](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-konnectivity/) 擴展取代現有的 HTTP-based 機制(v1.20 還是 beta)
#### etcd
儲存 cluster 資料,key–value database。
#### kube-scheduler
分配最適合的 node 來執行 pod。
#### kube-controller-manager
管理 nodes、tasks、endpoints、service account & token
#### 其他插件
- DNS: Kubernetes 内部域名的解析
- Web UI (Dashboard): web-based UI for Kubernetes clusters
### Node(Worker node) Components
#### kubelet
安裝於每一個 Node 上,負責與 API Server 溝通,也包含初始化並且將自己納入到整個 Cloud Cluster 的管理
##### Dockershim
- Docker 原生不支援 k8s CRI,為了讓 kubelet 可執行 docker 指令,出現 Dockershim 讓 kubelet 與 Docker 可透過 k8s CRI 溝通,kubelet 包含 Dockershim 程式碼
- k8s v1.20 之後將棄用 Dockershim,預計 [v1.23 會從 kubelet 移除](https://kubernetes.io/blog/2020/12/02/dockershim-faq/#when-will-dockershim-be-removed)

#### kube-proxy
安裝於每一個 Node 上,維護 Node 上的 network rules,負責內外部通訊
service 會在節點建立一組虛擬 clusterIP 和 port,並透過 kube-proxy 連線至多個 pods,下圖是 User space proxy mode 運作模式

### Kubernetes Objects
- Objects 內容會存在 k8s 系統裡頭,k8s 會確保 objects 內設定的東西正常運作,可透過 Kubernetes API 針對 objects 進行 CRUD 操作
- kubectl 指令可將 `.yaml` 設定檔轉成 JSON 並對 Kubernetes API 發出請求,目前常見是以這種方式操作 k8s 設定(`kubectl apply -f xxx.yml`)
- 每個 object 都會有一組 UUID
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
...
```
#### apiVersion and kind
k8s object kind 有分成很多種,例如 Pod、Deployment、Namespace、Role 等等,這些種類會對應到不同 api version,例如 `v1`、`apps/v1`、`v1`、`rbac.authorization.k8s.io/v1` 等等,要去官網確認
#### metadata
為 object 設定一些屬性
- name: 為 object 命名
- namespace: 在一個實體 cluster 下可用 namespace 區隔不同 virtual clusters,k8s 系統相關的服務會在 `kube-system` namespace 下運行
- labels: 可設定一組或多組標籤識別 object,EX: `app: my-nginx`
```yaml
apiVersion: v1
kind: Pod
metadata:
name: label-demo
namespace: my-test
labels:
app: my-nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
```
取得標籤 environment=production 的 pods
```
kubectl get pods -l environment=production
```
- selector: 指定 NodePort service 80 port 通往 label 為 `app: my-nginx` 的 pod
```yaml
apiVersion: v1
kind: Service
metadata:
name: label-demo-service
namespace: my-test
spec:
type: NodePort
selector:
app: my-nginx
ports:
- port: 80
targetPort: 80
protocol: TCP
```
### Kubernetes Object kinds
k8s object 有很多 kinds,以下列出常見的
#### Pod
- Kubernetes 最小運作單位
- 可包含一個或多個 contianers,彼此會共享 network 、namespaces & filesystem volumes,pod 內可透過 localhost 與其他 contianers 連線
- 每個 pod 都會分配到一個唯一的 ip
- 查看 pod state: `kubectl describe pod <name-of-pod>`
#### Deployment & ReplicaSet
- 可將 Pod 做橫向擴展,並監控 Pod,有問題時會重新啟動
- Rolling Update pod,可做到 Zero Downtime,Rolling Update 時會新建 ReplicaSet,新啟動的 pod 會綁定到新的 ReplicaSet,之後再關閉舊的 ReplicaSet,這是由 replication controller 負責
- 有 Rolling Back 機制

透過 Deployment 建立三個 nginx pod
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
```
#### ConfigMap
可設定 config 參數,然後 map 到 pod 環境變數
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-env
namespace: my-test
data:
APP_ENV: dev
DB_HOST: xxx
DB_DATABASE: ooo
DB_USERNAME: vvv
DB_PASSWORD: abc
```
#### HorizontalPodAutoscaler
[Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale) 是基於 Pod 某個指標(EX: CPU、Memery)使用率的水平擴充,Controller Manager 會進行監控

必須在每個 container 的 `resources.requests` 設定佔用資源請求數量,並且在 HPA 設定達到某個比例或上限值時要自動擴展,下面是設定 pod 佔用 100m(0.1 vCPU)
```yaml
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: nginx
resources:
requests:
cpu: 100m
```
HPA 的擴展門檻是依據 pod 佔用資源的平均值,假設 ReplicaSet 設定 2 個 pods,而 HPA 設定 CPU `averageUtilization` 為 80%,當一個 pod 使用率達 100%,另一個為 0 % 時,因平均起來是 50%,未達水平擴展門檻
實際應用中,往往需要基於其他指標進行擴展會比較準確,例如:response 時間或 request 佇列長度等等,Server 通常會提供一些指標,例如 PHP RoadRunner Server 有提供一些 [HTTP Metrics](https://docs.roadrunner.dev/docs/logging-and-observability/metrics#http-metrics),這些 Metrics 可以透過 Metrics Server 監控數據,並通過 adapter 去控制 HPA,如 [Prometheus Adapter](https://github.com/kubernetes-sigs/prometheus-adapter) 即為將 Prometheus 監控數據轉成 k8s 可是別的自定義指標,再通過這些自定義指標去控制 HPA
#### Service
Network service,執行 service discovery & load-balance,主要可分成無 `selectors` 跟有 `selectors`
#### 無 `selectors` service
無 `selectors`,無 `selectors` 不會產生 endpoints ,要自行指定 endpoints
- Service object
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
```
- Endpoints object
```yaml
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
```
#### 有 `selectors` service
service 會為 pods 分配 ip 及 DNS name,透過 selector 綁定這些 pod 的連線及存取,建立 pod 之間負載均衡
- Service object
```yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 80
```
- Deployment object
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: MyApp
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
```
以下介紹 service 的三種 type:
- ClusterIP:預設此種 type,僅能由 cluster 內部透過虛擬的 ClusterIP 存取
- NodePort:在節點(node)上開一個 port(30000-32767),cluster 外部可以透過這 node port 映射到設定的 pods(`<CLUSTER-IP>:<node port>`)

- LoadBalancer:要與外部的 load balancer 服務整合,EX: AWS ELB

#### Ingress
反向代理的概念,透過 HTTP and HTTPS routes (domain or path),從外連線到 cluster 內的 service,讓 service 保持在 private network,不暴露在外
k8s 內有多種服務可以可慮使用這方式,EX:不同的子網域對應到不同專案

- 使用 Ingress 需搭配 Ingress Controllers,不同服務商有自己的實現方式,可參考 [Additional controllers](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/#additional-controllers)
- Ingress 搭配的 Service type 為 NodePort,Ingress 會對應到某個 cluster 配發的 node port
## Helm
K8S 會有很多種 Object kind 的 yaml 設定檔,而 Helm 會將 K8S 的服務中的各種 yaml 檔案打包成一個叫做 chart 的集合,並且接受**帶入參數**的方式管理 K8S yaml 檔案,讓 K8S 在管理上更加彈性,不需要一個一個 yaml 部署。

當 chart 安装到 k8s 後會創建一個 release,每次更新時 release 的版本數就會加 1。同一個chart 可以部署多次。
### Values
透過 Values.yaml 可將參數傳遞給 k8s yaml
- Values.yaml:
```yaml
favoriteDrink: coffee
```
- k8s 設定 `{{ .Values.favoriteDrink }}` 即可取到 Values 參數
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favoriteDrink }}
```
- 也可透過 `--set` 去複寫參數
```
helm install --set favoriteDrink=beer <release name> <chart dir>
```
### 安裝
```
helm install <自訂的 release name> <chart 資料夾>
helm get manifest <自訂的 release name>
EX:
helm install --set laravel.app.env=dev --set laravel.db.password=xxxxx --set laravel.redis.password=ooooo burgess-backend ./burgess-backend
helm get manifest burgess-backend
```
### 更新
```
helm upgrade --set image.tag=0.0.1 burgess-backend ./burgess-backend
```
### 更新 or 沒有該 release 的話執行安裝
```
helm upgrade --instal --set laravel.app.env=dev --set laravel.db.password=xxxxx --set laravel.redis.password=ooooo burgess-backend ./burgess-backend
```
### 移除
```
helm uninstall <自訂的 release name>
helm uninstall burgess-backend
```
## Amazon EKS
### 架構
EKS Cluster 會建立 master(control plane),並整合了 Log(CloudWatch) 及 IAM認證,而我們可以針對應用得 pods 進行部署,部署可以選擇使用 EC2 or Fargate

### Cluster log
- API server
- Controller manager
- Scheduler
- Audit:記錄了由用戶、管理員或系統 security 相關的活動‘
- Authenticator:AWS 各服務間認證授權的紀錄
### Cluster authentication
若其他 client 端要操作 k8s cluster,一般來說會建立 [Service Account](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#service-account-tokens),取得 token 後可進行某個 namespaces 下的 cluster 操作。而 EKS 做法有些不同,是先經過 AWS identity 驗證後,再透過 k8s API 與 RBAC 做認證

必須為 client 準備一組 iam user,並且在 cluster aws-auth 中註冊該 user 的 ARN,細節可參考 [管理叢集的使用者或 IAM 角色](https://docs.aws.amazon.com/zh_tw/eks/latest/userguide/add-user-role.html) 和 [MAP AN IAM USER TO K8S](https://www.eksworkshop.com/beginner/090_rbac/map_iam_user_to_k8s_user/)
#### kubectl patch 方式修改 aws-auth ConfigMap
若要寫成指令方式,可以用 kubectl patch 去修改,準備一個 `aws-auth-user.yml`
```yml
data:
mapUsers: |
- userarn: <iam user 的 ARN>
username: burgess-backend-deployer
groups:
- system:masters
```
接著執行下列指令即完成註冊,該 iam user 就可操作 EKS cluster
```
kubectl patch configmap/aws-auth -n kube-system --patch "$(cat ./aws-auth-user.yml)"
```
### Nodes(Worker Nodes)
#### EKS managed node groups
- 可選擇 EC2 Instance Types、DiskSize,要注意每種可執行的 pods 數目上限,可參考 [eni-max-pods](https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt)。(每個 pod 都佔用一個私有 IP,不同 Instance Type 因 network interfaces 上限,可提供的私有 IP 數量不一樣)
- 每個 node 至少會佔用 2 個 kube-system 的 pods:aws-node & kube-proxy,其他基本的 pod 須依需求自行安裝,如果有使用 Horizontal Pod Autoscaler、Kubernetes Dashboard.,必須加裝 metrics-server pod 搜集數據;使用 Cluster Autoscaler 需安裝 cluster-autoscaler-autodiscover 監控 pod 使用狀況
- 可設定 node scaling 範圍,會自動擴展或減少
#### Self-managed nodes
自己維運 node,node 依附在 EKS cluster 介接,設定較複雜,請參考 [Self-managed nodes](https://docs.aws.amazon.com/eks/latest/userguide/worker.html)
#### Fargate
- 僅需設定 CPU 跟 memery
- 可設定 Scaling 範圍,會自動擴展或減少,擴展速度比 EC2 快
- 不需要管理 nodes

### 其他需自行安裝的 Add-ons(pod)
#### Cluster Autoscaler
當 Pod 出現故障或重新調度到其他節點時,Kubernetes Cluster Autoscaler 會自動調整 cluster 中的 nodes 數量,EKS managed node groups 是透過 Amazon EC2 Auto Scaling Groups 進行管理
安裝步驟可參考 [Cluster Autoscaler](https://docs.aws.amazon.com/eks/latest/userguide/cluster-autoscaler.html)
#### Horizontal Pod Autoscaler on EKS
HPA 是 Kubernetes 中的標準 API 資源,在 EKS 需額外安裝 metrics server,它監控 HPA 需要的 pod 指標
檢查有沒有安裝 metrics server
```
kubectl -n kube-system get deployment/metrics-server
```
安裝步驟可參考 [Horizontal Pod Autoscaler](https://docs.aws.amazon.com/zh_tw/eks/latest/userguide/horizontal-pod-autoscaler.html)
#### AWS Load Balancer Controller
如果我們想要透過 Load Balancer 連至我們部署的 pods,需要安裝 [aws-load-balancer-controller](https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html),EKS 支援 Network Load Balancer(NLB) 及 Application Load Balancer(ALB) 兩種 Load Balancer,差異可參考 [Elastic Load Balancing 功能](https://aws.amazon.com/tw/elasticloadbalancing/features/)
#### Network Load Balancer(NLB)
- 將 k8s `Service` type 設定為 `LoadBalancer` 會用此種 Load Balancer 處理 network traffic
- L4 of the OSI model,根據 IP + port 做負載均衡
- 安裝設定請參考 [Network load balancing on Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html)
#### Application Load Balancer(ALB)
- 建立 k8s Ingress 會用此種 Load Balancer 處理 network traffic,`Service` Type 可設定為 `NodePort` 或指定 pod ip
- L7 of the OSI model,可根據域名、內文做負載均衡,會做 TCP 交握,比較耗時
- listener 定義的規則,決定請求到目標的方法
- target group 使用指定的協議和 port,將請求導到一個或多個目標。可以針對每個 target group 運作狀態做檢查
- 安裝設定可參考 [Application load balancing on Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html)

注意:subnet tag 務必加入 `kubernetes.io/cluster/<cluster-name> = shared or owned`,ingress 不會自動加入,必須手動
#### Kubernetes Dashboard (web UI)
Kubernetes Dashboard 透過 web UI 介面查看 k8s 運作情形,參考 [Deploy the Kubernetes Dashboard](https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html) 安裝
### CloudFormation 部署 EKS Cluster 範例
AWS CloudFormation 是透過 yaml 檔建置 AWS 服務的工具,達到 Infrastructure as Code (IaC)的目的,類似的工具有 Terraform、Ansible、Puppet、AWS CDK、Azure Resource Manager、Google Cloud Deployment Manager 等等
#### EKS Cluster
- 建立一個 master(control plane)
- 會在 subnet 加必要的 tag
```yaml=
Type: AWS::EKS::Cluster
Properties:
Name: !Ref ClusterName
ResourcesVpcConfig:
SubnetIds:
- subnet-879a6bcf
- subnet-7502c313
RoleArn: !GetAtt [EKSClusterRole, Arn]
Version: !Ref K8SVersion
```
#### EKS Nodegroup
- 建立一個 EC2 Worker Node 以及 Amazon EC2 Auto Scaling Group
- AWS 會在每個 node(EC2) 運行基本必要的 pods(aws node、proxy)
- DesiredSize 兩台以上會自動跨 AZ
```yaml=
Type: AWS::EKS::Nodegroup
Properties:
ClusterName: !Ref EKSCluster
DiskSize: 4
InstanceTypes:
- t2.small
Labels:
app: burgess-laravel
NodeRole: !GetAtt [EKSNodeInstanceRole, Arn]
ScalingConfig:
DesiredSize: 1
MinSize: 1
MaxSize: 10
Subnets:
- subnet-879a6bcf
- subnet-7502c313
```
### 部署服務
#### 部署 EKS
```
aws --region ap-southeast-1 cloudformation deploy --template-file eks.yml --stack-name cf-eks-demo --parameter-overrides ClusterName=<cluster name> K8SVersion=<version>
```
#### 設定 kubectl 與 EKS cluster 連結
```
aws eks --region ap-southeast-1 update-kubeconfig --name <cluster name>
```
#### 設定 aws auth user
1. 建立 aws-auth-user.yml
以下可以建立某個 user or role 具有 master 權限
```yml
data:
mapUsers: |
- userarn: arn:aws:iam::xxxxxx:user/EKSDeployer
username: eks-deployer
groups:
- system:masters
- userarn: arn:aws:iam::xxxxx:user/burgess
username: burgess
groups:
- system:masters
```
2. 部署 aws-auth-user
下列指令將 aws-auth-user 設定至 EKS,就可以用該 user or role 進行 cluster 操作
```
kubectl apply -f aws-auth-user.yaml
kubectl get configmap -n kube-system aws-auth -o yaml
```
3. 透過 helm 部署自己的 pod
下列指令將 `./my-app` 資料夾下的 k8s yaml 設定檔案部署到 worker node
```
helm upgrade --install --set clusterName=<cluster name> my-app ./my-app
```
### 移除部署
```
aws --region ap-southeast-1 cloudformation delete-stack --stack-name cf-eks-demo
```
### 常用指令
- 查看所有 namespace 下的 pods
```
kubectl get pods --all-namespaces
```
- 查看 pod 設定細節
```
kubectl describe pod <pod name> -n=<namespace>
```
- 進入某個 pod
```
kubectl exec -it -n=<namespace> <pod name> –- /bin/sh
```
- 刪除 pod
```
kubectl delete pods <pod name>
```
- 刪除 Evicted pod
```
kubectl get pod -n <namespace> | grep Evicted | awk '{print $1}' | xargs kubectl delete pod -n <namespace>
```
- 查看所有 namespaces
```
kubectl get namespace
```
- 查看 namespace 下所有服務
```
kubectl get all -n <namespace>
```
- 查看某個 pod 的 log
```
kubectl logs <pod name> -n <namespace>
```
### 注意事項
#### helm 設定檔名問題
helm 使用的 Chart.yaml 跟 values.yaml 副檔名名稱必須為 `.yaml`,改成 `.yml` 將不會載入
#### configmap 只收字串
pod env 設定必須為字串,使用 configmap 時若為數字 or boolen 記得轉為字串(quote)
EX:
```
data:
APP_DEBUG: {{ .Values.laravel.app.debug | quote }}
DB_PORT: {{ .Values.laravel.db.port | quote }}
```
#### GET / 保持暢通
kube-proxy 會一直 call pods...請保持 `GET /` 暢通...
#### k8s namespace 綁定 helm release
同一 cluster 中,如果某個 k8s 服務的某個 namespace 給 helm release A 部署,helm release B 將無法部署那個 namespace
### k8s 升級
k8s 版本升級很快,常常會有相容性問題,[Amazon EKS Kubernetes versions](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html) 有說明各版本相容問題,最好的做法是升級 k8s 前先把相關 kinds 的 apiVersion 升級,否則可能遇到新版 k8s 不支援舊版 kinds 的 apiVersion
以下列出遇到的錯誤
#### 執行 eksctl 指令遇到 `error: exec plugin: invalid apiVersion "<出問題的版本>"`
eksctl 取 EKS 資料發生問題,試著升級 kubectl & aws-cli,kubectl 升級至對應的 k8s 版本,運行 aws eks update-kubeconfig --region <your region> --name <EKS cluster name> 重新取得認證資料
#### helm upgrade 時發生 `Error: UPGRADE FAILED: current release manifest contains removed kubernetes api(s) for this kubernetes version and it is therefore unable to build the kubernetes objects for performing the diff.`
Helm upgrade 時會比對前後 release 差異,helm 是以當前 k8s 版本支援的 apiVersion 為準,當進行 k8s 升級及 apiVersion 更新時,可能會發生舊版支援,但新版不支援,這時做 diff 會顯示舊版設定不支援的錯誤
EX: k8s v1.22 起不支援 `apiregistration.k8s.io/v1beta1`,要改成 `apiregistration.k8s.io/v1`,如果先把 k8s 升級,當執行 helm upgrade 時,會比對出當前 k8s 版本不支援舊 release 的 `v1beta1` 版本設定而發生 UPGRADE FAILED
這時要先去修改舊 release 設定,可參考 [Updating API Versions of a Release Manifest](https://helm.sh/docs/topics/kubernetes_apis/#updating-api-versions-of-a-release-manifest),安裝 helm mapkubeapis 調整或手動調整,調整原 release 中的無效版本後再執行 helm upgrade
#### Service EXTERNAL-IP 一直是 pending 狀態
執行 `kubectl get svc --all-namespaces`,如果要 public 的 service 的 EXTERNAL-IP 一直是 pending 狀態,代表 service 跟 load balancer 串接有異常,可以執行 `kubectl describe svc <service name> -n <namespace>` 查看異常原因,並參考 https://aws.amazon.com/tw/premiumsupport/knowledge-center/eks-load-balancer-webidentityerr/ 解決問題
## 參考資料
- [k8s 官方文件](https://kubernetes.io/docs/home/)
- [Getting Started with Kubernetes (K8s)](https://medium.com/@bhargavshah2011/getting-started-with-kubernetes-k8s-6e84ec4f76a4)
- [Kubernetes 只有淺出沒有深入 (K8s 架構介紹)](https://blog.toright.com/posts/6416/kubernetes-intro.html)
- [Kubernetes 基礎教學系列](https://medium.com/@C.W.Hu/kubernetes-basic-concept-tutorial-e033e3504ec0)
- [透過 Kubernetes Deployments 實現滾動升級](https://tachingchen.com/tw/blog/kubernetes-rolling-update-with-deployment/)
- [Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
- [Amazon EKS User Guide](https://docs.aws.amazon.com/eks/latest/userguide/what-is-eks.html)
- [Deploying a Kubernetes Cluster with Amazon EKS](https://logz.io/blog/amazon-eks-cluster/)
- [AWS Elastic Load Balancing 文件](https://docs.aws.amazon.com/elasticloadbalancing/index.html)
- [Elastic Load Balancing 功能](https://aws.amazon.com/tw/elasticloadbalancing/features/)
- [AWS CloudFormation EKS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_EKS.html)
- [如何利用 Managed Node Group 高效管理 Amazon EKS 集群](https://aws.amazon.com/cn/blogs/china/how-to-manage-amazon-eks-clusters-with-managed-node-group-preface/)
- [如何在 Amazon EKS 中的 Amazon EC2 节点上设置 ALB 入口控制器?](https://aws.amazon.com/cn/premiumsupport/knowledge-center/eks-alb-ingress-controller-setup/)
- [Kubernetes Ingress 与 AWS ALB Ingress 控制器的配合使用](https://aws.amazon.com/cn/blogs/china/kubernetes-ingress-aws-alb-ingress-controller/)
- [AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-alb-ingress-controller/)
- [troubleshoot pod status in Amazon EKS](https://aws.amazon.com/tw/premiumsupport/knowledge-center/eks-pod-status-troubleshooting/)
- [CoreDNS 系列](https://hansedong.github.io/2018/11/20/9/)
- [Kubernetes Rolling Update Configuration](https://www.bluematador.com/blog/kubernetes-deployments-rolling-update-configuration)
- [Helm 官方文件](https://helm.sh/docs/)
- [使用Helm管理kubernetes应用](https://jimmysong.io/kubernetes-handbook/practice/helm.html)
- [MAP AN IAM USER TO K8S](https://www.eksworkshop.com/beginner/090_rbac/map_iam_user_to_k8s_user/)