繁体   English   中英

如何等到 Kubernetes 将外部 IP 分配给 LoadBalancer 服务?

[英]How to wait until Kubernetes assigned an external IP to a LoadBalancer service?

创建Kubernetes LoadBalancer 会立即返回(例如: kubectl create -f ...kubectl expose svc NAME --name=load-balancer --port=80 --type=LoadBalancer )。

我知道在 shell 中等待的手动方法:

external_ip=""
while [ -z $external_ip ]; do
    sleep 10
    external_ip=$(kubectl get svc load-balancer --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")
done

然而,这并不理想:

  • 至少需要 5 行 Bash 脚本。
  • 即使出现错误也无限等待(否则需要超时,这会增加很多行数)。
  • 可能效率不高; 可以使用--wait--wait-once但使用这些命令永远不会返回。

有没有更好的方法来等待服务外部 IP (又名LoadBalancer Ingress IP )设置或设置失败?

只是在这里添加答案,现在最好的选择是使用 bash 脚本。 为方便起见,我将其放在一行中,其中包括导出环境变量。

等待并查找 Kubernetes 服务端点的命令

bash -c 'external_ip=""; while [ -z $external_ip ]; do echo "Waiting for end point..."; external_ip=$(kubectl get svc NAME_OF_YOUR_SERVICE --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}"); [ -z "$external_ip" ] && sleep 10; done; echo "End point ready-" && echo $external_ip; export endpoint=$external_ip'

我还修改了您的脚本,因此它仅在 ip 不可用时才执行等待。 最后一位将导出一个名为“端点”的环境变量

用于检查给定服务的 Bash 脚本

将其保存为check-endpoint.sh ,然后您可以执行$sh check-endpoint.sh SERVICE_NAME

#!/bin/bash
# Pass the name of a service to check ie: sh check-endpoint.sh staging-voting-app-vote
# Will run forever...
external_ip=""
while [ -z $external_ip ]; do
  echo "Waiting for end point..."
  external_ip=$(kubectl get svc $1 --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")
  [ -z "$external_ip" ] && sleep 10
done
echo 'End point ready:' && echo $external_ip

在 Codefresh 步骤中使用它

我将它用于 Codefresh 管道,它在完成后传递一个变量 $endpoint。

  GrabEndPoint:
    title: Waiting for endpoint to be ready
    image: codefresh/plugin-helm:2.8.0
    commands:
      - bash -c 'external_ip=""; while [ -z $external_ip ]; do echo "Waiting for end point..."; external_ip=$(kubectl get svc staging-voting-app-vote --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}"); [ -z "$external_ip" ] && sleep 10; done; echo "End point ready-" && echo $external_ip; cf_export endpoint=$external_ip'

通过工作解决方案,这有点棘手:

kubectl get service -w load-balancer -o 'go-template={{with .status.loadBalancer.ingress}}{{range .}}{{.ip}}{{"\n"}}{{end}}{{.err}}{{end}}' 2>/dev/null | head -n1

也许这不是您正在寻找的解决方案,但至少它的代码行更少:

until [ -n "$(kubectl get svc load-balancer -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" ]; do
    sleep 10
done

没有真正的“设置失败”条件,因为我们将永远重试它。 失败可能是云提供商中的暂时性错误或在数小时或数天或任何数量的事情中得到解决的配额问题。 唯一的失败来自“你愿意等多久?” ——这只有你自己知道。

我们没有通用的“等待表达式”命令,因为它最终变得非常复杂,您最好只用真正的语言对其进行编码。 因此,上面的 bash 循环。 我们可以更好地使用“监视”命令,但最终仍然是超时。

真的只是对@Dan Garfield 工作示例的清理; 我的强迫症不会让这个幻灯片。 在这种情况下:

  • 在 GCP 上
  • 请求内部
  • 在服务定义中带有注释

apiVersion: v1
kind: Service
metadata:
  name: yo
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
    # external-dns.alpha.kubernetes.io/hostname: vault.stage.domain.tld.
...

注意:我只能让 external-dns 将名称与公共 IP 地址相关联。


这已被编写为接受一些参数,现在它是一个库; 例子:

myServiceLB=$1
while true; do                                                                     
    successCond="$(kubectl get svc "$myServiceLB" \                                
        --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")"        
    if [[ -z "$successCond" ]]; then                                               
        echo "Waiting for endpoint readiness..."                                   
        sleep 10                                                                   
    else                                                                           
        sleep 2                                                                    
        export lbIngAdd="$successCond"                                             
        pMsg """
            The Internal LoadBalancer is up!
        """                                                                        
        break                                                                      
    fi                                                                             
done

稍后,可以使用$lbIngAdd设置记录。 似乎-o jsonpath="{.status.loadBalancer.ingress[*].ip}"也可以工作; 无论什么工作。

感谢您让我们开始 Dan :-)

对于给定命令的输出中的任何正则表达式,这是一个使用 timeout 监视的通用 bash 函数:

function watch_for() {
  CMD="$1" # Command to watch. Variables should be escaped \$
  REGEX="$2" # Pattern to search
  ATTEMPTS=${3:-10} # Timeout. Default is 10 attempts (interval of second)
  COUNT=0;

  echo -e "# Watching for /$REGEX/ during $ATTEMPTS seconds, on the output of command:\n# $CMD"
  until eval "$CMD" | grep -m 1 "$REGEX" || [[ $COUNT -eq $ATTEMPTS ]]; do
    echo -e "$(( COUNT++ ))... \c"
    sleep 1
  done
  if [[ $COUNT -eq $ATTEMPTS ]]; then
    echo "# Limit of $ATTEMPTS attempts has exceeded."
    return 1
  fi
  return 0
}

下面是我如何使用它来等待工作节点获得外部 IP (花费了超过一分钟):

$ watch_for "kubectl get nodes -l node-role.kubernetes.io/worker -o wide | awk '{print \$7}'" \
"[0-9]" 100

0... 1... 2... 3... .... 63... 64... 3.22.37.41

我们在 AWS EKS 上遇到了类似的问题,并希望有一个单线用于我们的 CI 管道。 kubectl wait是理想的,但在 v1.23之前将无法等待任意v1.23 (请参阅此 PR )。

在那之前,我们只是“观察”命令的输出,直到观察到特定的字符串,然后使用until循环退出

until kubectl get service/<service-name> --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; do : ; done

为了避免无限循环,您可以使用超时来增强它(在 Mac 上使用brew install coreutils ):

timeout 10s bash -c 'until kubectl get service/<service-name> --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; do : ; done'

之后获取 ip 很容易使用:

kubectl get service/<service-name> --output=jsonpath='{.status.loadBalancer.ingress[0].ip}' 

或者在使用像 AWS EKS 这样的服务时,您很可能填充了hostname而不是ip

kubectl get service/<service-name> --output=jsonpath='{.status.loadBalancer.ingress[0].hostname}' 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM