kubectl 等待 AWS EKS 上的服务公开 .status.loadBalancer.ingress 字段中报告的 Elastic Load Balancer (ELB) 地址
Posted
技术标签:
【中文标题】kubectl 等待 AWS EKS 上的服务公开 .status.loadBalancer.ingress 字段中报告的 Elastic Load Balancer (ELB) 地址【英文标题】:kubectl wait for Service on AWS EKS to expose Elastic Load Balancer (ELB) address reported in .status.loadBalancer.ingress field 【发布时间】:2022-01-03 13:49:13 【问题描述】:作为the kubernetes.io docs state about a Service
of type LoadBalancer
:
在支持外部负载平衡器的云提供商上,设置 LoadBalancer 的 type 字段为您的 服务。负载均衡器的实际创建发生 异步的,关于预配平衡器的信息是 发布在服务的
.status.loadBalancer
字段中。
在 AWS Elastic Kubernetes Service (EKS) 上,预置了一个 AWS 负载均衡器,用于对网络流量进行负载均衡(see AWS docs 和 the example project on GitHub provisioning a EKS cluster with Pulumi)。假设我们有一个 Deployment
与选择器 app=tekton-dashboard
(它是 default Tekton dashboard you can deploy as stated in the docs)一起准备好,tekton-dashboard-service.yml
中定义的 LoadBalancer
类型的 Service
可能如下所示:
apiVersion: v1
kind: Service
metadata:
name: tekton-dashboard-external-svc-manual
spec:
selector:
app: tekton-dashboard
ports:
- protocol: TCP
port: 80
targetPort: 9097
type: LoadBalancer
如果我们使用kubectl apply -f tekton-dashboard-service.yml -n tekton-pipelines
在集群中创建服务,AWS ELB 会自动创建:
只有一个问题:.status.loadBalancer
字段异步填充了ingress[0].hostname
字段,因此无法立即使用。如果我们一起运行以下命令,我们可以检查这一点:
kubectl apply -f tekton-dashboard-service.yml -n tekton-pipelines && \
kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer'
输出将是一个空字段:
%
因此,例如,如果我们想在 CI 管道中运行此设置(例如 GitHub Actions, see the example project's workflow provision.yml
),我们需要以某种方式等到 .status.loadBalancer
字段填充 AWS ELB 的主机名。我们如何使用kubectl wait
来实现这一点?
【问题讨论】:
【参考方案1】:TLDR;
Prior to Kubernetes v1.23
不能使用kubectl wait
,但可以像这样使用until
和grep
:
until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer' | grep "ingress"; do : ; done
甚至增强命令using timeout(brew install coreutils
on a Mac),防止命令无限运行:
timeout 10s bash -c 'until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer' | grep "ingress"; do : ; done'
kubectl wait的问题及解决方案详细解释
正如this so Q&A 中所述,kubernetes 使用kubectl wait
发出kubectl wait unable to not wait for service ready #80828 和kubectl wait on arbitrary jsonpath #83094,因为目前在当前的 Kubernetes 版本中这是不可能的。
主要原因是,kubectl wait
假定使用kubectl get service/xyz --output=yaml
查询的 Kubernetes 资源的status
字段包含conditions
列表。 Service
没有。在此处使用 jsonpath 将是一种解决方案,并且可以从 Kubernetes v1.23
开始(请参阅 this merged PR)。但在此版本在 EKS 等托管 Kubernetes 集群中广泛使用之前,我们需要另一种解决方案。它也应该像 kubectl wait
一样作为“单行”提供。
一个好的起点可能是这个关于"watching" the output of a command until a particular string is observed and then exit 的超级用户回答:
until my_cmd | grep "String Im Looking For"; do : ; done
如果我们将此方法与kubectl get
一起使用,我们可以制作一个命令,该命令将等到ingress
字段被填充到Service
中的status.loadBalancer
字段中:
until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer' | grep "ingress"; do : ; done
这将等到 ingress
字段被填充,然后打印出 AWS ELB 地址(例如,此后通过使用 kubectl get service tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer.ingress[0].hostname'
):
$ until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer' | grep "ingress"; do : ; done
"ingress":["hostname":"a74b078064c7d4ba1b89bf4e92586af0-18561896.eu-central-1.elb.amazonaws.com"]
现在我们有了一个单行命令,其行为类似于 kubectl wait
,让我们的 Service
可以通过 AWS 负载均衡器使用。我们可以仔细检查这是否与以下命令组合使用(请确保在执行之前使用kubectl delete service/tekton-dashboard-external-svc-manual -n tekton-pipelines
删除服务,否则服务包括 AWS LoadBalancer 已经存在):
kubectl apply -f tekton-dashboard-service.yml -n tekton-pipelines && \
until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer' | grep "ingress"; do : ; done && \
kubectl get service tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='.status.loadBalancer.ingress[0].hostname'
Here's also a full GitHub Actions pipeline run如果你有兴趣。
【讨论】:
以上是关于kubectl 等待 AWS EKS 上的服务公开 .status.loadBalancer.ingress 字段中报告的 Elastic Load Balancer (ELB) 地址的主要内容,如果未能解决你的问题,请参考以下文章
EKS 无法使用 Kubectl 向 Kubernetes 进行身份验证 - “用户:无权执行:sts:AssumeRole”
如何使用 aws-cdk 从 AWS Secrets Manager 导入 EKS 密钥?