今天給大家分享一個實戰例子,如何在EKS上創建容器化應用并通過ALB來發布。先介紹一下幾個基本概念:
-
IAM, OpenID Connect (OIDC)
2014 年,AWS Identity and Access Management 增加了使用 OpenID Connect (OIDC) 的聯合身份支持。此功能允許您使用支持的身份提供商對 AWS API 調用進行身份驗證,并接收有效的 OIDC JSON Web 令牌 (JWT)。您可以將此令牌傳遞給 AWS STS AssumeRoleWithWebIdentity API 操作并接收 IAM 臨時角色憑證。您可以使用這些憑證與任何 AWS 服務進行交互,包括 Amazon S3 和 DynamoDB。
每個 JWT 令牌都由簽名密鑰對簽名。密鑰由 Amazon EKS 管理的 OIDC 提供商提供,私鑰每 7 天輪換一次。Amazon EKS 會保留公鑰,直到它們過期。如果您連接外部 OIDC 客戶端,請注意,您需要在公鑰過期之前刷新簽名密鑰。了解如何獲取簽名密鑰以驗證 OIDC 令牌。
Kubernetes 長期以來一直使用服務賬戶作為自己的內部身份系統。Pod 可以使用自動掛載的令牌(非 OIDC JWT)向 Kubernetes API 服務器進行身份驗證,只有 Kubernetes API 服務器才能驗證該令牌。這些舊式服務賬戶令牌不會過期,并且輪換簽名密鑰是一個困難的過程。在 Kubernetes 1.12 版中,添加了對新 ProjectedServiceAccountToken 功能的支持。此功能是 OIDC JSON Web 令牌,還包含服務賬戶身份并支持可配置的受眾。
Amazon EKS 為每個集群托管一個公共 OIDC 發現終端節點,其中包含 ProjectedServiceAccountToken JSON Web 令牌的簽名密鑰,因此外部系統(例如 IAM)可以驗證和接受 Kubernetes 頒發的 OIDC 令牌。
通過下面的架構圖能清晰地說明它們之間的關系:
創建EKS cluster
TOKEN=`curl?-X?PUT?"http://169.254.169.254/latest/api/token"?-H?"X-aws-ec2-metadata-token-ttl-seconds:?21600"`
export?AWS_DEFAULT_REGION=$(curl?-H?"X-aws-ec2-metadata-token:?$TOKEN"?--silent?http://169.254.169.254/latest/meta-data/placement/region)
echo?$AWS_DEFAULT_REGIONeksctl?create?cluster?\
--name?eks-lab-cluster?\
--nodegroup-name?worknodes-1?\
--node-type?t3.medium?\
--nodes?2?\
--nodes-min?1?\
--nodes-max?4?\
--managed?\
--version?1.29?\
--region?${AWS_DEFAULT_REGION}
生成eks kubeconfig 文件
aws?eks?update-kubeconfig?--name?eks-lab-cluster?--region?${AWS_DEFAULT_REGION}
檢查EKS cluster 狀態
ec2-user:~/environment?$?kubectl?get?node
NAME????????????????????????????????????????????????STATUS???ROLES????AGE?????VERSION
ip-192-168-51-133.ap-southeast-2.compute.internal???Ready????<none>???5m26s???v1.29.3-eks-ae9a62a
ip-192-168-92-105.ap-southeast-2.compute.internal???Ready????<none>???5m25s???v1.29.3-eks-ae9a62a
ec2-user:~/environment?$?kubectl?get?pod?-A
NAMESPACE?????NAME???????????????????????READY???STATUS????RESTARTS???AGE
kube-system???aws-node-mm6xr?????????????2/2?????Running???0??????????6m
kube-system???aws-node-w6v9b?????????????2/2?????Running???0??????????6m1s
kube-system???coredns-57d946db4c-hjgb9???1/1?????Running???0??????????9m38s
kube-system???coredns-57d946db4c-x5t68???1/1?????Running???0??????????9m38s
kube-system???kube-proxy-6ffsn???????????1/1?????Running???0??????????6m1s
kube-system???kube-proxy-sj5k2???????????1/1?????Running???0??????????6m
創建docker 容器
創建website 的Dockerfile文件
FROM?public.ecr.aws/docker/library/httpd:2.4RUN?apt-get?update?&&?apt-get?-y?install?cron?&&?apt-get?install?vim?-yCOPY?cron?/etc/cron.d/COPY?index.html?/usr/local/apache2/htdocs/COPY?metadata.sh?/usr/local/apache2/htdocs/COPY?copy-metadata-file.sh?/COPY?font?/usr/local/apache2/htdocs/fontCOPY?images?/usr/local/apache2/htdocs/imagesRUN?mkdir?/var/metadataRUN?chmod?-R?0777?/var/metadata/RUN?chmod?+x?/usr/local/apache2/htdocs/metadata.shRUN?chmod?+x?/copy-metadata-file.shRUN?chmod?644?/etc/cron.d/cronRUN?crontab?/etc/cron.d/cronEXPOSE?80WORKDIR?/usr/local/apache2/htdocs/CMD?./metadata.sh?&&?crontab?&&?crontab?/etc/cron.d/cron?&&?service?cron?restart?&&?apachectl?-D?FOREGROUND
創建sidecar容器的Dockerfile
ROM?public.ecr.aws/docker/library/python:alpine3.16RUN?python3?--version
RUN?pip3?--version
RUN?apk?add?--no-cache?aws-cli
RUN?aws?--version
RUN?mkdir?/var/metadata/
COPY?metadata2.sh?/
COPY?metadata2.json?/
RUN?chmod?+x?/metadata2.sh
RUN?chmod?-R?0777?/var/metadata/
CMD?./metadata2.sh
創建鏡像文件
docker?build?-t?website?.
docker?build?-t?sidecar?.
創建ecr
$?aws?ecr?create-repository??--repository-name?website??--region?${AWS_DEFAULT_REGION}
{"repository":?{"repositoryArn":?"arn:aws:ecr:ap-southeast-2:654654314383:repository/website","registryId":?"654654314383","repositoryName":?"website","repositoryUri":?"654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/website","createdAt":?"2024-07-18T01:31:42.098000+00:00","imageTagMutability":?"MUTABLE","imageScanningConfiguration":?{"scanOnPush":?false},"encryptionConfiguration":?{"encryptionType":?"AES256"}}
}
ec2-user:~/environment/environment/eksLabRepo?(main)?$?aws?ecr?create-repository?\
>??--repository-name?sidecar?\
>??--region?${AWS_DEFAULT_REGION}
{"repository":?{"repositoryArn":?"arn:aws:ecr:ap-southeast-2:654654314383:repository/sidecar","registryId":?"654654314383","repositoryName":?"sidecar","repositoryUri":?"654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/sidecar","createdAt":?"2024-07-18T01:33:09.150000+00:00","imageTagMutability":?"MUTABLE","imageScanningConfiguration":?{"scanOnPush":?false},"encryptionConfiguration":?{"encryptionType":?"AES256"}}
}
給變量賦值
ec2-user:~/environment/environment/eksLabRepo?(main)?$?export?ECR_REPO_URI_WEBSITE=$(aws?ecr?describe-repositories?\>??--repository-names?website?\>??--region?${AWS_DEFAULT_REGION}?\>??--query?'repositories[*].repositoryUri'?\>??--output?text)ec2-user:~/environment/environment/eksLabRepo?(main)?$?export?ECR_REPO_URI_SIDECAR=$(aws?ecr?describe-repositories?\>??--repository-names?sidecar?\>??--region?${AWS_DEFAULT_REGION}?\>??--query?'repositories[*].repositoryUri'?\>??--output?text)ec2-user:~/environment/environment/eksLabRepo?(main)?$?echo?ECR_REPO_URI_WEBSITE=$ECR_REPO_URI_WEBSITE?&&?echo?ECR_REPO_URI_SIDECAR=$ECR_REPO_URI_SIDECARECR_REPO_URI_WEBSITE=654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/websiteECR_REPO_URI_SIDECAR=654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/sidecar
登錄ECR
ec2-user:~/environment/environment/eksLabRepo?(main)?$?aws?ecr?get-login-password?\>?--region?${AWS_DEFAULT_REGION}?\>??|?docker?login?\>??--username?AWS?\>??--password-stdin?$ACCOUNT_NUMBER.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.comWARNING!?Your?password?will?be?stored?unencrypted?in?/home/ec2-user/.docker/config.json.Configure?a?credential?helper?to?remove?this?warning.?Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-storeLogin?Succeeded
上傳鏡像到ECR
c2-user:~/environment/environment/eksLabRepo?(main)?$?docker?tag?website:latest?$ECR_REPO_URI_WEBSITE:latest
ec2-user:~/environment/environment/eksLabRepo?(main)?$?docker?push?$ECR_REPO_URI_WEBSITE:latest
The?push?refers?to?repository?[654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/website]
5f70bf18a086:?Pushed
latest:?digest:?sha256:35d429413b45d69f42da254cb875bc77774a0df50f1327888b071b6038b886da?size:?4480
ec2-user:~/environment/environment/eksLabRepo?(main)?$?docker?tag?sidecar:latest?$ECR_REPO_URI_SIDECAR:latest
ec2-user:~/environment/environment/eksLabRepo?(main)?$?docker?push?$ECR_REPO_URI_SIDECAR:latest
The?push?refers?to?repository?[654654314383.dkr.ecr.ap-southeast-2.amazonaws.com/sidecar]
254e6068aa48:?Pushed?
latest:?digest:?sha256:da1998c5b425dc986463ca94578c11f32ec10fcab0f9711f07f0c9185e4e8e86?size:?3242
檢查eks cluster 狀態
ec2-user:~/environment/environment/eksLabRepo?(main)?$?aws?eks?describe-cluster?\
>??--name?eks-lab-cluster?\
>??--query?'cluster.status'?\
>??--output?text
ACTIVE
在EKS上創建AWS Load Balancer Controller
export?ACCOUNT_NUMBER=$(aws?sts?get-caller-identity?--query?'Account'?--output?text)eksctl?utils?associate-iam-oidc-provider?--region?ap-southeast-2?--cluster?eks-lab-cluster?--approveeksctl?create?iamserviceaccount?--cluster=eks-lab-cluster?--namespace=kube-system?--name=aws-load-balancer-controller?--role-name?"AmazonEKSLoadBalancerControllerRole"?--attach-policy-arn=arn:aws:iam::$ACCOUNT_NUMBER:policy/AWSLoadBalancerControllerIAMPolicy?--approve
sleep?5helm?repo?add?eks?https://aws.github.io/eks-chartshelm?repo?updatehelm?install?aws-load-balancer-controller?eks/aws-load-balancer-controller?-n?kube-system?--set?clusterName=eks-lab-cluster?--set?serviceAccount.create=false?--set?serviceAccount.name=aws-load-balancer-controller
分析每條命令的作用
下面的命令將 oidc provider和 eks 關聯起來
eksctl?utils?associate-iam-oidc-provider?--region?ap-southeast-2?--cluster?eks-lab-cluster?--approve
下面的命令在eks中創建服務賬號并和aws role , policy 關聯起來。
eksctl?create?iamserviceaccount?--cluster=eks-lab-cluster?--namespace=kube-system?--name=aws-load-balancer-controller?--role-name?"AmazonEKSLoadBalancerControllerRole"?--attach-policy-arn=arn:aws:iam::$ACCOUNT_NUMBER:policy/AWSLoadBalancerControllerIAMPolicy?--approve
檢查aws load balancer創建成功
kubectl?get?pods?\?-n?kube-system?\?--selector=app.kubernetes.io/name=aws-load-balancer-controller
部署應用
-
創建命令空間
kubectl?create?namespace?containers-lab
-
準備yaml文件
apiVersion:?apps/v1
kind:?Deployment
metadata:namespace:?containers-labname:?eks-lab-deploylabels:app:?eks-app
spec:replicas:?3selector:matchLabels:app:?lab-apptemplate:metadata:labels:app:?lab-appspec:containers:-?name:?websiteimage:?$ECR_REPO_URI_WEBSITE:latest?##?<--?Placeholder?replaced?with?environment?variableports:-?containerPort:?80volumeMounts:-?mountPath:?/var/metadataname:?metadata-vol-?name:?sidecarimage:?$ECR_REPO_URI_SIDECAR:latest?##?<--?Placeholder?replaced?with?environment?variablevolumeMounts:-?mountPath:?/var/metadataname:?metadata-volvolumes:-?name:?metadata-volemptyDir:?{}
---
apiVersion:?v1
kind:?Service
metadata:name:?lab-servicenamespace:?containers-lab
spec:ports:-?port:?80targetPort:?80protocol:?TCPtype:?NodePortselector:app:?lab-app
---
apiVersion:?networking.k8s.io/v1
kind:?Ingress
metadata:namespace:?containers-labname:?lab-ingressannotations:alb.ingress.kubernetes.io/scheme:?internet-facingalb.ingress.kubernetes.io/target-type:?ipkubernetes.io/ingress.class:?alb
spec:rules:-?http:paths:-?path:?/pathType:?Prefixbackend:service:name:?lab-serviceport:number:?80
-
部署應用
kubectl?apply?-f?k8s-all.yamlkubectl?get?all?-n?containers-labkubectl?get?ingress?-n?containers-lab
通過瀏覽器訪問該地址
Amazon EKS 支持服務賬戶的 IAM 角色 (IRSA),允許集群操作員將 AWS IAM 角色映射到 Kubernetes 服務賬戶。
這為在 EKS 上運行并使用其他 AWS 服務的應用程序提供了細粒度的權限管理。這些應用程序可能是使用 S3、任何其他數據服務(RDS、MQ、STS、DynamoDB)或 Kubernetes 組件(如 AWS 負載均衡器控制器或 ExternalDNS)的應用程序。
您可以使用 eksctl 輕松創建 IAM 角色和服務賬戶對。
工作原理
它通過 EKS 公開的 IAM OpenID Connect 提供程序 (OIDC) 工作,并且必須參考 IAM OIDC 提供程序(特定于給定的 EKS 集群)以及對其將綁定到的 Kubernetes 服務帳戶的引用來構建 IAM 角色。創建 IAM 角色后,服務帳戶應將該角色的 ARN 作為注釋 (eks.amazonaws.com/role-arn)。默認情況下,將創建或更新服務帳戶以包含角色注釋,可以使用標志 --role-only 禁用此功能。
在 EKS 內部,有一個準入控制器,它根據 pod 使用的服務帳戶上的注釋將 AWS 會話憑據分別注入角色的 pod 中。憑據將由 AWS_ROLE_ARN 和 AWS_WEB_IDENTITY_TOKEN_FILE 環境變量公開。
在 eksctl 中,資源的名稱是 iamserviceaccount,它代表 IAM 角色和服務帳戶對。
在開始之前,我先介紹一下IAM 角色和策略:
角色
您可以在賬戶中創建具有特定權限的 IAM 身份。IAM 角色與 IAM 用戶有一些相似之處。角色和用戶都是具有權限策略的 AWS 身份,這些權限策略決定了身份在 AWS 中可以做什么和不能做什么。但是,角色并非唯一地與一個人相關聯,而是由任何需要它的人擔任。此外,角色沒有與之關聯的標準長期憑證(例如密碼或訪問密鑰)。相反,當您擔任角色時,它會為您的角色會話提供臨時安全憑證。
角色可供以下人員使用:
-
與角色位于同一 AWS 賬戶中的 IAM 用戶
-
與角色位于不同 AWS 賬戶中的 IAM 用戶
-
AWS 提供的 Web 服務,例如 Amazon Elastic Compute Cloud (Amazon EC2)
-
由與 SAML 2.0 或 OpenID Connect 兼容的外部身份提供商 (IdP) 服務或定制的身份代理進行身份驗證的外部用戶。
策略
您可以通過創建策略并將其附加到 IAM 身份(用戶、用戶組或角色)或 AWS 資源來管理 AWS 中的訪問權限。策略是 AWS 中的對象,當與身份或資源關聯時,它定義其權限。當 IAM 主體(用戶或角色)發出請求時,AWS 會評估這些策略。策略中的權限決定是允許還是拒絕請求。大多數策略都以 JSON 文檔的形式存儲在 AWS 中。AWS 支持六種類型的策略:基于身份的策略、基于資源的策略、權限邊界、組織 SCP、ACL 和會話策略。
IAM 策略定義操作的權限,無論您使用何種方法執行操作。例如,如果策略允許 GetUser 操作,則具有該策略的用戶可以從 AWS 管理控制臺、AWS CLI 或 AWS API 獲取用戶信息。創建 IAM 用戶時,您可以選擇允許控制臺或編程訪問。如果允許控制臺訪問,則 IAM 用戶可以使用其登錄憑證登錄控制臺。如果允許編程訪問,用戶可以使用訪問密鑰來使用 CLI 或 API。
默認情況下,當 Amazon EKS 集群具有 EC2 實例工作節點時,Pod 調用 AWS API 的權限有限。它們繼承了工作節點的 EC2 實例配置文件。實例配置文件附加了以下 AWS 托管策略:
-
AmazonEKSWorkerNodePolicy
-
AmazonEC2ContainerRegistryReadOnly
-
AmazonSSMManagedInstanceCore
-
AmazonEKS_CNI_Policy
在這種情況下,已部署的應用程序會調用 API 來檢索數據,但沒有所需的權限。最佳實踐是使用服務賬戶的 IAM 角色功能為在 Kubernetes pod 上運行的應用程序提供所需的權限。服務賬戶的 IAM 角色功能提供以下好處:
-
最小權限:通過使用服務賬戶的 IAM 角色功能,您無需為該節點上的 pod 提供節點 IAM 角色的擴展權限來調用 AWS API。您可以將 IAM 權限范圍限定到服務賬戶,只有使用該服務賬戶的 pod 才能訪問這些權限。此功能還意味著您不需要第三方解決方案,例如 kiam 或 kube2iam。
-
憑證隔離:容器只能檢索與其所屬服務賬戶關聯的 IAM 角色的憑證。容器永遠無法訪問屬于另一個 pod 的另一個容器的憑證。
-
可審計性:可通過 AWS CloudTrail 提供訪問和事件日志記錄,以幫助確保追溯審計。
需要為EKS pod創建IAM role.
提前創建一個policy eks-lab-read-policy,這里我用了默認的管理員權限,實際生產環境中不建議這樣做。
{"Version":?"2012-10-17","Statement":?[{"Effect":?"Allow","Action":?"*","Resource":?"*"}]
}
然后運行下面的命令來創建 iamserviceaccount
ec2-user:~/environment/environment/eksLabRepo/eks-lab-app?(main)?$?eksctl?create?iamserviceaccount?????--name?iampolicy-sa-3?????--namespace?containers-lab?????--cluster?eks-lab-cluster?????--role-name?"eksRole4serviceaccount3"?????--attach-policy-arn?arn:aws:iam::$ACCOUNT_NUMBER:policy/eks-lab-read-policy?????--approve?????--override-existing-serviceaccounts???????????????????????????????????????????????????????????????????????????????????????????????????????????
2024-07-19?04:51:43?[?]??2?existing?iamserviceaccount(s)?(default/s3-read-only,kube-system/aws-load-balancer-controller)?will?be?excluded
2024-07-19?04:51:43?[?]??1?iamserviceaccount?(containers-lab/iampolicy-sa-3)?was?included?(based?on?the?include/exclude?rules)
2024-07-19?04:51:43?[!]??metadata?of?serviceaccounts?that?exist?in?Kubernetes?will?be?updated,?as?--override-existing-serviceaccounts?was?set
2024-07-19?04:51:43?[?]??1?task:?{?2?sequential?sub-tasks:?{?create?IAM?role?for?serviceaccount?"containers-lab/iampolicy-sa-3",create?serviceaccount?"containers-lab/iampolicy-sa-3",}?}2024-07-19?04:51:43?[?]??building?iamserviceaccount?stack?"eksctl-eks-lab-cluster-addon-iamserviceaccount-containers-lab-iampolicy-sa-3"
2024-07-19?04:51:44?[?]??deploying?stack?"eksctl-eks-lab-cluster-addon-iamserviceaccount-containers-lab-iampolicy-sa-3"
2024-07-19?04:51:44?[?]??waiting?for?CloudFormation?stack?"eksctl-eks-lab-cluster-addon-iamserviceaccount-containers-lab-iampolicy-sa-3"
2024-07-19?04:52:14?[?]??waiting?for?CloudFormation?stack?"eksctl-eks-lab-cluster-addon-iamserviceaccount-containers-lab-iampolicy-sa-3"
2024-07-19?04:52:14?[?]??created?serviceaccount?"containers-lab/iampolicy-sa-3"
驗證服務賬號的狀態
ec2-user:~/environment/environment/eksLabRepo/eks-lab-app?(main)?$?kubectl?get?sa?iampolicy-sa-3?-n?containers-lab?-o?yaml??????????????????????????????????
apiVersion:?v1
kind:?ServiceAccount
metadata:annotations:eks.amazonaws.com/role-arn:?arn:aws:iam::654654314383:role/eksRole4serviceaccount3creationTimestamp:?"2024-07-19T04:52:14Z"labels:app.kubernetes.io/managed-by:?eksctlname:?iampolicy-sa-3namespace:?containers-labresourceVersion:?"316598"uid:?6d8b23ce-b9ca-4c67-be54-fb58eca29a82
更新deployment 的服務賬號
ec2-user:~/environment/environment/eksLabRepo/eks-lab-app?(main)?$?kubectl?set?serviceaccount?\
>??deployment?eks-lab-deploy?\
>??iampolicy-sa-3?-n?containers-lab
deployment.apps/eks-lab-deploy?serviceaccount?updated
驗證deployment服務賬號已經更新
ec2-user:~/environment/environment/eksLabRepo/eks-lab-app?(main)?$?kubectl?describe?deployment.apps/eks-lab-deploy?\
>??-n?containers-lab?|?grep?'Service?Account'Service?Account:??iampolicy-sa-3
獲得 ingress的ALB地址
ec2-user:~/environment/environment/eksLabRepo/eks-lab-app?(main)?$?kubectl?get?ingress?-n?containers-lab
NAME??????????CLASS????HOSTS???ADDRESS????????????????????????????????????????????????????????????????????????PORTS???AGE
lab-ingress???<none>???*???????k8s-containe-labingre-3207ffb4ea-1472706054.ap-southeast-2.elb.amazonaws.com???80??????17m
打開瀏覽器訪問該地址,可以看到 aws account, cluster name kubernetes version 信息已經可以正常顯示。