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,但可以像这样使用untilgrep

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 密钥?

使用 Nginx-Ingress-Controller 在 AWS 上的 EKS 中使用 gRPC

EKS 上的网络负载均衡器与 AWS 负载均衡器控制器

EKS 上的 AWS NLB 粘性会话

EKS:在特定 AWS 自动缩放组上运行特定服务(pod)