【问题标题】:kubectl wait for Service on AWS EKS to expose Elastic Load Balancer (ELB) address reported in .status.loadBalancer.ingress fieldkubectl 等待 AWS EKS 上的服务公开 .status.loadBalancer.ingress 字段中报告的 Elastic Load Balancer (ELB) 地址
【发布时间】: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 docsthe 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 来实现这一点?

【问题讨论】:

    标签: amazon-web-services kubernetes kubectl amazon-eks aws-load-balancer


    【解决方案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 timeoutbrew 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 #80828kubectl 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如果你有兴趣。

    【讨论】:

      猜你喜欢
      • 2012-06-20
      • 2019-07-29
      • 1970-01-01
      • 2016-12-26
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 2017-05-10
      • 2015-10-24
      相关资源
      最近更新 更多