跳至主要内容

[06] 為什麼 EKS cluster 可以讓 Pod 部署至 Fargate

在開始主題之前,先簡單介紹一下 AWS Fargate。在 AWS EC2 服務,我們可以隨意啟用 EC2 instance 作為我們的主機來使用,而在 ECS 或是 EKS 服務上,則可以直接部署容器服務,如 ECS Service/Task 或是 EKS Deployment/Pod 到 AWS 託管的主機上。換言之,對於使用者可以更減少維護主機的成本,取而代之則是依照 vCPU、memory、作業系統、CPU 架構及儲存大小等五個維度計價1

在 EKS 服務,我們則可以透過建立 Fargate Profile 方式指定 namespace 及相應 label 後2,EKS 則可以整合 AWS Fargate 節點而無需手動管理節點。故本文將探討「為什麼 EKS cluster 可以部署至 Fargate 而非透過原生 Kubernetes 方式部署至 EKS worker node 」,希望理解 EKS 是如何更新 Pod 調度過程。

建立環境

  1. 建立 Fargate Profile 並指定 namespace 名稱為 fargate-ns
$ eksctl create fargateprofile \
--cluster ironman-2022 \
--name demo-profile \
--namespace fargate-ns
2022-09-20 20:08:51 [ℹ] deploying stack "eksctl-ironman-2022-fargate"
2022-09-20 20:08:51 [ℹ] waiting for CloudFormation stack "eksctl-ironman-2022-fargate"
2022-09-20 20:09:21 [ℹ] waiting for CloudFormation stack "eksctl-ironman-2022-fargate"
2022-09-20 20:09:21 [ℹ] creating Fargate profile "demo-profile" on EKS cluster "ironman-2022"
2022-09-20 20:11:31 [ℹ] created Fargate profile "demo-profile" on EKS cluster "ironman-2022"
  1. 建立 fargate-ns namepsace。
kubectl create ns fargate-ns
  1. 透過 kubectl 建立 Nginx Pod 於 fargate-ns 及 default namespace。
kubectl run nginx --image=nginx -n fargate-ns
kubectl run nginx --image=nginx -n default
  1. 將 Pod 資訊輸出成 YAML 文件。
kubectl -n default get po nginx -o yaml > default-nginx.yaml
kubectl -n fargate-ns get po nginx -o yaml > fargate-nginx.yaml

分析

透過 diff 命令比對,以下僅列舉較大差異部分,其他如 timestamp 或是 namespace 不同處則省略。

$ diff fargate-nginx.yaml default-nginx.yaml
5,6d4
< CapacityProvisioned: 0.25vCPU 0.5GB
< Logging: 'LoggingDisabled: LOGGING_CONFIGMAP_NOT_FOUND'
...
...
10d7
< eks.amazonaws.com/fargate-profile: demo-profile
...
...
...
30c27
< nodeName: fargate-ip-192-168-185-38.eu-west-1.compute.internal
---
> nodeName: ip-192-168-65-212.eu-west-1.compute.internal
32,33c29
< priority: 2000001000
< priorityClassName: system-node-critical
---
> priority: 0
35c31
< schedulerName: fargate-scheduler
---
> schedulerName: default-scheduler
...
...
...

可以發現到部署至 Fargate Pod 不同處有以下幾個

  • 多出以下 3 個 annotations :
    • CapacityProvisioned
    • Logging
    • eks.amazonaws.com/fargate-profile
  • node name 為 Fargate node
  • schedulerName 為 fargate-scheduler 而非 default kube-scheduler

接續,我們使用以下 CloudWatch Log Insights Syntax 查看 audit log 觀察 API server 是否有針對此 Pod 進行更新,整理如下時間軸及摘要重要資訊:

filter @logStream like /^kube-apiserver-audit/
| fields @timestamp, @message
| sort @timestamp asc
| filter objectRef.name == 'nginx' AND objectRef.resource == 'pods' AND verb != 'get'
| limit 10000

stageTimestamp 2022-09-20T20:17:17.328703Z

kubectl 建立此 Pod,其中經過 3 個 Mutating webhook,而被 Mutate webhook 0500-amazon-eks-fargate-mutation.amazonaws.com 更新 schedulerNamefargate-scheduler,以及上述 3 個 annotations:

  • annotations.mutation.webhook.admission.k8s.io/round_0_index_0: {"configuration":"0500-amazon-eks-fargate-mutation.amazonaws.com","webhook":"0500-amazon-eks-fargate-mutation.amazonaws.com","mutated":true}
  • annotations.mutation.webhook.admission.k8s.io/round_0_index_2: {"configuration":"pod-identity-webhook","webhook":"iam-for-pods.amazonaws.com","mutated":false}
  • annotations.mutation.webhook.admission.k8s.io/round_0_index_3: {"configuration":"vpc-resource-mutating-webhook","webhook":"mpod.vpc.k8s.aws","mutated":false}
  • annotations.patch.webhook.admission.k8s.io/round_0_index_0: {"configuration":"0500-amazon-eks-fargate-mutation.amazonaws.com","webhook":"0500-amazon-eks-fargate-mutation.amazonaws.com","patch":[{"op":"add","path":"/spec/schedulerName","value":"fargate-scheduler"},{"op":"add","path":"/spec/priorityClassName","value":"system-node-critical"},{"op":"add","path":"/spec/priority","value":2000001000},{"op":"add","path":"/metadata/labels","value":{"eks.amazonaws.com/fargate-profile":"demo-profile","run":"nginx"}}],"patchType":"JSONPatch"}
  • requestObject.spec.schedulerName: default-scheduler
  • responseObject.spec.schedulerName: fargate-scheduler

stageTimestamp 2022-09-20T20:17:18.503220Z

由 username eks:fargate-scheduler 更新 request 先前所提及的 Mutate webhook 0500-amazon-eks-fargate-mutation.amazonaws.com 內容。

  • user.username: eks:fargate-scheduler
  • verb: update
  • requestObject.spec.schedulerName: fargate-scheduler
  • requestObject.metadata.labels.eks.amazonaws.com/fargate-profile: demo-profile
  • requestObject.metadata.annotations.CapacityProvisioned: 0.25vCPU 0.5GB
  • requestObject.metadata.annotations.Logging: LoggingDisabled: LOGGING_CONFIGMAP_NOT_FOUND

stageTimestamp 2022-09-20T20:18:16.033300Z

由 username eks:fargate-scheduler 建立 Nginx Pod 及 Fargate Node fargate-ip-192-168-185-38.eu-west-1.compute.internal 綁定。

  • user.username: eks:fargate-scheduler
  • verb: create
  • requestObject.kind: Binding
  • requestObject.target.name: fargate-ip-192-168-185-38.eu-west-1.compute.internal

stageTimestamp 2022-09-20T20:18:16.054810Z 及 2022-09-20T20:18:23.041304Z

此兩個 patch 皆是由 kubelet 更新 Pod condition 狀態最終至 Ready

  • user.username: system:node:fargate-ip-192-168-185-38.eu-west-1.compute.internal
  • userAgent: kubelet/v1.22.6 (linux/amd64) kubernetes/35f06c9
  • verb: patch

什麼是 Mutate webhook

根據 Kubernetes blog A Guide to Kubernetes Admission Controllers3,Kubernetes Admission Controllers 功能提供一種方式讓經驗證後的 API 請求修改 API 請求內的 object 或是拒絕請求的一道防衛門。Admission control 過程上可以分成兩階段,其細節流程讀如下所示:

  • mutating:其最終目的是修改 API object 確保一些預設數值或是增加功能。如:修改 Pod spec 中的 CPU 或是 Memory 預設值,或 Service Mesh inject sidecar container 至每一個 Pod。
  • validating:其目的為確保每一個 object 都是被維護的,換言之,類似於某種 Policy。如:Gatekeeper4 可自定義 policy 確保至少 replica 數量為 3,或是可以定義annotation 中需要有 email 欄位作為 resource owner。

0500-amazon-eks-fargate-mutation.amazonaws.com 是否為 Mutating webhook

答案:是

依照上述 audit log,其實我們就已經知道答案。在 annotations.mutation.webhook.admission.k8s.io 代表了 mutating webhook,而 round_0_index_0 代表了第一輪 mutation 中第一個 mutating webhook 並且成功 mutation[5]。而其他 mutating webhook 分別為:

  • pod-identity-webhook
  • vpc-resource-mutating-webhook

我們可以透過 kubectl 命令查看對應 mutating webhook 資源,其中我並未手動建立 0500-amazon-eks-fargate-mutation.amazonaws.com mutating webhook configurations:

$ kubectl get mutatingwebhookconfigurations
NAME WEBHOOKS AGE
0500-amazon-eks-fargate-mutation.amazonaws.com 2 3h47m
pod-identity-webhook 1 6d14h
vpc-resource-mutating-webhook 1 6d14h

再次使用 CloudWatch Logs insight syntax,查看是誰幫忙建立部署此 mutating webhook 。

filter @logStream like /^kube-apiserver-audit/
| fields @timestamp, @message
| sort @timestamp asc
| filter objectRef.name == '0500-amazon-eks-fargate-mutation.amazonaws.com' AND objectRef.resource verb == 'create'
| limit 10000

由以下資訊,可以得知是由 EKS username eks:cluster-bootstrap 透過 kubectl 方式部署,比對時間與 Fargate Profile 建立時間相符。

  • userAgent: kubectl/v1.22.12 (linux/amd64) kubernetes/dade57b
  • user.username: eks:cluster-bootstrap
  • stageTimestamp2022-09-20T20:09:59.446214Z

總結

https://ithelp.ithome.com.tw/upload/images/20220921/20151040Qiew5SKWrK.png

此流程圖出自於 AWS re:Invent 2020: Amazon EKS on AWS Fargate deep dive5

由上述 log 比對,我們可以知道流程為:

  1. 於 Pod spec 定義相應 namespace 及 label。
  2. 在建置 Fargate Profile 同時,EKS 部署 0500-amazon-eks-fargate-mutation.amazonaws.com mutating webhook。
  3. 基於 Fargate Profile 所指定 namespace 及 label 更新 Pod spec annotation 及 scheduler。
  4. Fargate scheduler 調度 Fargate 節點,Pod 部署至 Fargate node 。

參考文件

Footnotes

  1. AWS Fargate Pricing - https://aws.amazon.com/fargate/pricing/

  2. Getting started with AWS Fargate using Amazon EKS - https://docs.aws.amazon.com/eks/latest/userguide/fargate-getting-started.html

  3. A Guide to Kubernetes Admission Controllers - https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/

  4. How to use Gatekeeper - https://open-policy-agent.github.io/gatekeeper/website/docs/howto/

  5. AWS re:Invent 2020: Amazon EKS on AWS Fargate deep dive - https://www.youtube.com/watch?v=9tQFXEhHdn0