6

I'm trying to use kubectl to wait for a service to get an external ip assigned. I've been trying to use the below just to get started

kubectl wait --for='jsonpath={.spec.externalTrafficPolicy==Cluster}' --timeout=30s --namespace cloud-endpoints svc/esp-echo

But I keep getting the below error message

error: unrecognized condition: "jsonpath={.spec.externalTrafficPolicy==Cluster}"
user672009
  • 4,379
  • 8
  • 44
  • 77

4 Answers4

8

It is not possible to pass arbitrary jsonpath and there is already a request for the feature.

However, you can use a bash script with some sleep and monitor the service using other kubectl commands:

kubectl get --namespace cloud-endpoints svc/esp-echo --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}"

The above command will return the external IP for the LoadBalancer service for example.

You can write a simple bash file using the above as:

#!/bin/bash
ip=""
while [ -z $ip ]; do
  echo "Waiting for external IP"
  ip=$(kubectl get svc $1 --namespace cloud-endpoints --template="{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}")
  [ -z "$ip" ] && sleep 10
done
echo 'Found external IP: '$ip
user672009
  • 4,379
  • 8
  • 44
  • 77
Krishna Chaurasia
  • 8,924
  • 6
  • 22
  • 35
2

Updated from Krishna Chaurasia's answer, kubectl have implemented the feature to be able to wait on arbitrary jsonpath value now.

However, the catch is the value will only be primitive value, excluding nested primitive value (map[string]interface{} or []interface{})

1

Right now kubectl wait doesn't seem to work for in this case (see also this PR's comment). Meanwhile you can do this:

until kubectl get svc/esp-echo --namespace cloud-endpoints --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; do : ; done

or even enhance the command using timeout (brew install coreutils on a Mac) to prevent the command from running infinitely:

timeout 10s bash -c 'until kubectl get service/tekton-dashboard-external-svc-manual -n tekton-pipelines --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; do : ; done'

We the same problem on AWS EKS, where a AWS Elastic Load Balancer (ELB) gets provisioned when one creates a Service with the type LoadBalancer. That's most likely comparable to other cloud providers behaviour since it's part of the official kubernetes.io docs:

On cloud providers which support external load balancers, setting the type field to LoadBalancer provisions a load balancer for your Service. The actual creation of the load balancer happens asynchronously, and information about the provisioned balancer is published in the Service's .status.loadBalancer field.

Krishna Chaurasia's answer also used this field, but we wanted to have a one-liner which could be used without extra bash script just like a kubectl wait. So our solution incorporates the solution stated on serverfault about "watching" the output of a command until a particular string is observed and then exit with using the until loop.

jonashackt
  • 12,022
  • 5
  • 67
  • 124
0

You need to provide a condition. Like:

kubectl -n foobar wait --for=condition=complete --timeout=32s foo/bar

Here is a good article that explains that: https://mrkaran.dev/posts/kubectl-wait/

In your case, you might use one of the k8s probes.

Roman Klimenko
  • 1,297
  • 1
  • 12
  • 24
  • Right now in current Kubernetes versions `kubectl wait` isn't usable for this problem (as stated in the issues [kubectl wait unable to not wait for service ready #80828](https://github.com/kubernetes/kubernetes/issues/80828#issuecomment-517555879) & [kubectl wait on arbitrary jsonpath #83094](https://github.com/kubernetes/kubernetes/issues/80828). Only from Kubernetes `v1.23` on (see [this merged PR](https://github.com/kubernetes/kubernetes/pull/105776)) using jsonpath together with `kubectl wait` will be possible. – jonashackt Nov 25 '21 at 09:55
  • 2
    The main reason is, that `kubectl wait` assumes that the `status` field of a Kubernetes resource queried with `kubectl get service/xyz --output=yaml` contains a `conditions` list. [Which a `Service` doesn't have](https://github.com/kubernetes/kubernetes/issues/80828#issuecomment-517555879). So in your `kubectl wait` command the `condition=complete` will never be reached, since there are no conditions in Services. – jonashackt Nov 25 '21 at 09:58