13

I am trying to get the first pod from within a deployment (filtered by labels) with status running - currently I could only achieve the following, which will just give me the first pod within a deployment (filtered by labels) - and not for sure a running pod, e.g. it might also be a terminating one:

kubectl get pod -l "app=myapp" -l "tier=webserver" -l "namespace=test" 
                -o jsonpath="{.items[0].metadata.name}"

How is it possible to

a) get only a pod list of "RUNNING" pods and (couldn't find anything here or on google)

b) select the first one from that list. (thats what I'm currently doing)

Regards

Update: I already tried the link posted in the comments earlier with the following:

kubectl get pod -l "app=ms-bp" -l "tier=webserver" -l "namespace=test"  
-o json | jq -r '.items[] | select(.status.phase = "Running") | .items[0].metadata.name'

the result is 4x "null" - there are 4 running pods.

Edit2: Resolved - see comments

user3746259
  • 1,491
  • 2
  • 23
  • 46
  • Check out the example in https://github.com/kubernetes/kubernetes/issues/49387 – kichik Sep 28 '17 at 17:39
  • @kichik: thanks for your reply, I already know this issue - could not integrate the "current workaround". Do you know how to? – user3746259 Sep 28 '17 at 20:16
  • How/why is the current solution failing for you? – kichik Sep 28 '17 at 20:26
  • @kichik: updated the question -maybe the problem is that I am mixing "json" and "jsonpath" as "o"? – user3746259 Sep 28 '17 at 20:51
  • I don't have a setup to try it out now, but it sounds like `.items[0].metadata.name` is `null` for some reason. Try printing `.items[0]` instead and see what's in it and where you can find the data you actually need. – kichik Sep 28 '17 at 20:53
  • So i debugged it - and the problem lays within the ".items[0].metadata.name". I don't know how to access "item[0]" within the json object, already tried ".items.0", "items.first"... when I only have ".metadata.name", I get the 4 names of the 4 running pots, but I only need the first one – user3746259 Sep 28 '17 at 21:07
  • 2
    To get the first one simply append `| head -n 1` – kichik Sep 28 '17 at 21:11
  • Thanks, its working. According to http://www.compciv.org/recipes/cli/jq-for-parsing-json/ I should have been able to access the first object in the list by using "[0]" - but this didn't work. Nevermind :) – user3746259 Sep 28 '17 at 21:16
  • 1
    Update: Ok it also works according to the link by wrapping the jq result in an array, then you can access [0]. ~closed – user3746259 Sep 28 '17 at 21:21
  • Note that for many usecases it's unnecessary to get the first running pod, since commands like `exec` which excpect a pod can also take a service or deployment as argument and a random running pod will be selected automatically. (I.e. `kubectl exec deploy/mydeployment -- date` or `kubectl exec svc/myservice -- date` to quote `kubectl exec --help`.) – David Ongaro Jun 23 '22 at 17:33

1 Answers1

24

Since kubectl 1.9 you have the option to pass a --field-selector argument (see https://github.com/kubernetes/kubernetes/pull/50140). E.g.

kubectl get pod -l app=yourapp --field-selector=status.phase==Running -o jsonpath="{.items[0].metadata.name}"

Note however that for not too old kubectl versions, many reasons to find a running pod are moot, because a lot of commands which expect a pod also accept a deployment or service and automatically select a corresponding pod. To quote from the documentation:

$ echo exec logs port-forward | xargs -n1 kubectl help | grep -C1 'service\|deploy\|job'

  # Get output from running 'date' command from the first pod of the deployment mydeployment, using the first container by default
  kubectl exec deploy/mydeployment -- date

  # Get output from running 'date' command from the first pod of the service myservice, using the first container by default
  kubectl exec svc/myservice -- date

--

  # Return snapshot logs from first container of a job named hello
  kubectl logs job/hello

  # Return snapshot logs from container nginx-1 of a deployment named nginx
  kubectl logs deployment/nginx -c nginx-1

--

 Use resource type/name such as deployment/mydeployment to select a pod. Resource type defaults to 'pod' if omitted.

--

  # Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in a pod selected by the deployment
  kubectl port-forward deployment/mydeployment 5000 6000

  # Listen on port 8443 locally, forwarding to the targetPort of the service's port named "https" in a pod selected by the service
  kubectl port-forward service/myservice 8443:https

(Note logs also accepts a service, even though an example is omitted in the help.)

The selection algorithm favors "active pods" for which a main criterion is having a status of "Running" (see source).

David Ongaro
  • 3,568
  • 1
  • 24
  • 36
  • What about kubectl 1.5 – Gauraang Khurana Jan 18 '21 at 23:39
  • @GauraangKhurana You can fallback to `-o json` and filtering via `jq`. A working example adapted from the question should be `kubectl get pod -l "app=ms-bp" -l "tier=webserver" -l "namespace=test" -o json | jq -r '.items[] | select(.status.phase == "Running") | .metadata.name, halt'`. Notice that we need to use `==` instead of `=` for the `select` condition and that filtering by `.items[0]` would yield `null` after we filtered by `.items[]` already, which is why the second example in the question fails. – David Ongaro Jan 20 '21 at 21:22
  • Thanks David! I used grep and 'awk' to fetch my results. Since I was using bash it was easier – Gauraang Khurana Jan 25 '21 at 03:08
  • Ok, but if you're already invoking `awk`, there is seldom a reason to also use `grep`. – David Ongaro Jan 25 '21 at 07:00
  • 1
    The command ```.status.phase == "Running"``` also returns CrashbackLoopOff pods, I think it is a kubectl bug. Therefore, I had to go for ```kubectl get pods -l "app=xyz" | grep Running``` Since this was returning multiple pods which many fields and I only needed the name of any one, I used awk to fetch the first of the list. how could I have run this command better, any suggestions? ```kubectl get pods -l app=xyz | grep "Running" | awk 'NR==1{print \$1}'``` – Gauraang Khurana Jan 26 '21 at 16:59
  • That's fine if that works for you. I'm only getting grumpy because so many people seem to think `awk` is merely a column selection tool. If you want to do it "better" I suggest `kubectl get pods -l app=xyz | awk '/Running/{print $1; exit}'`. – David Ongaro Jan 28 '21 at 01:05
  • phase is "running" even for stuck/terminating pods. also ither suggestions are not working when the pod has scaling more than 1 – Azee77 Jul 24 '23 at 10:27
  • @Azee77 did you try my suggestion of auto-selecting a pod via the `svc/...` syntax? As mentioned, this takes many more factors into account than just the running status (see https://github.com/kubernetes/kubectl/blob/master/pkg/util/podutils/podutils.go#L133-L173) – David Ongaro Jul 24 '23 at 22:34