Search code examples
kubectlgo-templates

Get first element of a map when using kubectl get ... -o template


I have a service and I would like to get an IP from its spec, using -o go-template I can do it that way:

kubectl get service webapp1-loadbalancer-svc -o go-template='{{(index .status.loadBalancer.ingress 0).ip}}'

This returns the IP of the first ingress in the load balancer which is what I want.

However, instead of using -o go-template, I would like to use -o template. I have tried multiple commands but I am unable to do so. The closest thing I have working is:

kubectl get service webapp1-loadbalancer-svc -o template={{.status.loadBalancer.ingress}}

But this returns the map [map[ip:172.17.0.28]], not just the IP. Everything I have tried to get the IP in the same command is returning errors while executing the template.

Is there a way to obtain the IP from the map using one kubectl command using -o template instead of -o go-template?


Solution

  • Kubectl supports JSONPath template.

    Using JsonPath you can retrieve service cluster IP or other details as below.

    ubuntu@k8s-master:~$ kubectl get all -o wide
    NAME        READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
    pod/nginx   1/1     Running   0          129m   192.168.85.226   k8s-node01   <none>           <none>
    
    NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE    SELECTOR
    service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d2h   <none>
    service/nginx        ClusterIP   10.96.184.196   <none>        80/TCP    11m    run=nginx
    
    
    ubuntu@k8s-master:~$ kubectl get service nginx -o jsonpath='{.spec.clusterIP}'
    10.96.184.196
    

    Using JsonPath Works well with LoadBlancer type as well .. hope this is what you want to work with.

    $ kubectl get all -o wide
    NAME        READY   STATUS    RESTARTS   AGE    IP               NODE         NOMINATED NODE   READINESS GATES
    pod/nginx   1/1     Running   0          133m   192.168.85.226   k8s-node01   <none>           <none>
    
    NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE    SELECTOR
    service/kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP        2d2h   <none>
    service/nginx        LoadBalancer   10.100.165.17   <pending>     80:30852/TCP   5s     run=nginx
    ubuntu@k8s-master:~$
    
    
    
    10.100.165.17ubuntu@k8s-master:~$ kubectl get service nginx -o jsonpath='{.spec.type}'
    LoadBalancer
    
    ubuntu@k8s-master:~$ kubectl get service nginx -o jsonpath='{.spec.clusterIP}'
    10.100.165.17
    

    So when you extract PORTs it also return a map as below

    $ kubectl get service nginx -o jsonpath='{.spec.ports}'
    
    [map[nodePort:30852 port:80 protocol:TCP targetPort:80]]
    

    you can extract the nodePort, port and targetPort each as as below

    $ kubectl get service nginx -o jsonpath='{.spec.ports[].targetPort}'
    80
    
    ubuntu@k8s-master:~$ kubectl get service nginx -o jsonpath='{.spec.ports[].nodePort}'
    30852
    
    ubuntu@k8s-master:~$ kubectl get service nginx -o jsonpath='{.spec.ports[].port}'
    80
    

    Hope above examples will help you fix your query

    I think you should be able to do by this command when using jsonpath.

    kubectl get service webapp1-loadbalancer-svc -o jsonpath={{.status.loadBalancer.ingress[].ip}}