Selecting Array Elements with the Custom Columns Kubernetes CLI Output - kubernetes

How can I use the --output=custom-columns option for the the Kubernetes CLI (kubectl) to select array elements?
In other words, how can I turn this:
kubectl get services
#=>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kafka-manager NodePort 10.3.242.200 146.148.20.235 9000:32619/TCP 0d
spark-master NodePort 10.3.242.209 104.199.21.235 9000:32619/TCP 0d
into this?
kubectl get services \
--output=custom-columns=. . .
#=>
NAME EXTERNAL-ENDPOINT
kafka-manager 146.148.20.225:9000
spark-master 104.199.21.225:7077
What I have so far:
kubectl get services \
--output=custom-columns='NAME:.metadata.name,IP:.spec.clusterIP,PORT:.spec.ports'
#=>
NAME IP PORT
kafka-manager 10.3.242.200 [map[nodePort:32619 port:9000 protocol:TCP targetPort:9000]]
spark-master 10.3.242.209 [map[nodePort:30588 port:7077 protocol:TCP targetPort:7077]]

TLDR
For an element that is in a list use * in square brackets.
So your query should look like this:
kubectl get service \
-n kube-system \
-o=custom-columns='NAME:.metadata.name,IP:.spec.clusterIP,PORT:.spec.ports[*].targetPort'
#=>
NAME IP PORT
kube-dns 10.0.0.10 53,53
kubernetes-dashboard 10.0.0.250 9090
Notice the * in PORT:.spec.ports[*].targetPort.
Details:
So kubectl is expecting a json-path-expr after header. The error I got when playing with expressions was following:
expected <header>:<json-path-expr>
To iterate over all elements in a list instead of putting an index just use *.
Various other json-path expressions can be found here.

You can use * for understanding the data in the JSON. For example:
kubectl get svc gdpr -o custom-columns='svc:*'
As for me, the get command was perfect (due external IP info.) and looks like:
kubectl get svc -o custom-columns='SVC:.metadata.name,IP:.metadata.annotations.domainName,PORT:.spec.ports[*].targetPort'
#=>
SVC IP PORT
event site1.com 9000
gdpr site2.com 3333,8080
svcInt none 80
ui site6.com 80,6123,6124,6125,8081
P.S. About list external IP and hosts:
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name} {.status.addresses[?(#.type=="ExternalIP")].address}{"\n"}'
#=>
ip-10-10-40-13.xxxxx.internal xx.xx.xx.175
ip-10-10-40-15.xxxxx.internal xx.xx.xx.236
ip-10-10-40-18.xxxxx.internal xx.xx.xx.207
kubectl get nodes -o jsonpath='{range .items[*]}{.status.addresses[?(#.type=="ExternalIP")].address}{"\n"}'
#=>
xx.xx.xx.175
xx.xx.xx.236
xx.xx.xx.207

If you want to search in a map using custom columns, you can use
[?(#.Key=="Value"]
An important thing if you want to use it, is that the query in the custom-columns must be insider ['] character.
For example, the following query fails:
kubectl get nodes -o=custom-columns=NAME:.metadata.name,CPU:.status.capacity.cpu,MEM:.status.capacity.memory,IP:.status.addresses[?(#.type=="InternalIP")].address
bash: syntax error near unexpected token `('
But if we execute the same query using ['] character it works:
kubectl get nodes -o=custom-columns='NAME:.metadata.name,ROLE:TOBEDEFINED,CPU:.status.capacity.cpu,MEM:.status.capacity.memory,IP:.status.addresses[?(#.type=="InternalIP")].address'
NAME CPU MEM IP
name-node 8 8 10.10.10.10

Would that work for you?
kubectl get service -o=custom-columns=NAME:.metadata.name,IP:.spec.clusterIP,PORT:.spec.ports[0].targetPort

Related

How to find cluster node ip address

Minikube has the specific node ip address (192.168.99.100) for single cluster, if I using kubeadm to create many nodes cluster, what should I do to find this ip address?
This should be fairly straightforward: kubectl get nodes -o wide
To get informations about Kubernetes objects you should use kubectl get <resource> or kubectl describe <resource>.
In docs
Display one or many resources
Prints a table of the most important information about the specified resources. You can filter the list using a label selector and the --selector flag. If the desired resource type is namespaced you will only see results in your current namespace unless you pass --all-namespaces.
If you will check manual for kubectl get you will get information about -o flag.
-o, --output='': Output format. One of:
json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...
See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template
[http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template
[http://kubernetes.io/docs/user-guide/jsonpath].
Thats mean you can get output in YAMLs or JSON format. Detailed information can be found in this doc.
As #Bernard Halas mentioned, you can just use kubectl get nodes -o wide.
Another option is use describe with grep. -A will print number lines of trailing context. Its helpful if you need to get list about information per node.
$ kubectl describe node | grep Addresses: -A 4
Addresses:
InternalIP: 10.164.0.63
ExternalIP: 35.204.67.223
InternalDNS: gke-test-default-pool-d11b1330-g44z.c.composite-rune-239911.internal
Hostname: gke-test-default-pool-d11b1330-g44z.c.composite-rune-239911.internal
--
Addresses:
InternalIP: 10.164.0.61
ExternalIP: 35.204.63.113
InternalDNS: gke-test-default-pool-d11b1330-gtpj.c.composite-rune-239911.internal
Hostname: gke-test-default-pool-d11b1330-gtpj.c.composite-rune-239911.internal
--
Addresses:
InternalIP: 10.164.0.62
ExternalIP: 35.204.202.107
InternalDNS: gke-test-default-pool-d11b1330-r4dw.c.composite-rune-239911.internal
Hostname: gke-test-default-pool-d11b1330-r4dw.c.composite-rune-239911.internal
You can also use YAML or JSON format. Output will be similar to previous one.
$ kubectl get nodes -o yaml | grep addresses: -A 8
addresses:
- address: 10.164.0.63
type: InternalIP
- address: 35.204.67.223
type: ExternalIP
- address: gke-test-default-pool-d11b1330-g44z.c.composite-rune-239911.internal
type: InternalDNS
- address: gke-test-default-pool-d11b1330-g44z.c.composite-rune-239911.internal
type: Hostname
...
In addition if you will need some specific output (only information you need and ar not print as default) you can use custom columns. It's based on YAML format.
$ kubectl get pods -o custom-columns=Name:.metadata.name,NS:.metadata.namespace,HostIP:.status.hostIP,PodIP:status.podIP,REQ_CPU:.spec.containers[].resources.requests.cpu
Name NS HostIP PodIP REQ_CPU
httpd-5d8cbbcd67-gtzcx default 10.164.0.63 10.32.2.7 100m
nginx-7cdbd8cdc9-54dds default 10.164.0.62 10.32.1.5 100m
nginx-7cdbd8cdc9-54ggt default 10.164.0.62 10.32.1.3 100m
nginx-7cdbd8cdc9-bz86v default 10.164.0.62 10.32.1.4 100m
nginx-7cdbd8cdc9-zcvrf default 10.164.0.62 10.32.1.2 100m
nginx-test-59df8dcb7f-hlrcr default 10.164.0.63 10.32.2.4 100m
generally, there is no such thing as a single IP of a kubernetes cluster. Minikube has it, because it's a special 1 node case. Most production clusters will be one way or another operating with many network-internal, cluster-internal and external IP addresses. For example each node is usually deployed on a separate (virtual) machine that has it's own IP address, either external or network-internal (like 10.x.y.z or 192.168.x.y) depending on your network setup. Moreover, many kubernetes objects, like pods or services have their IPs also (cluster-internal or external).
Now the question is what do you need the IP for:
if you are looking for the address of your kubernetes API endpoint server (the endpoint to which kubectl talks) then in case of clusters created manually with kubeadm, this will be the IP of the master node that you created with kubeadm init command (assuming single master case). See this official doc for details. To talk to your cluster using kubectl you will need some authorization data except its IP: see subsequent sections of the mentioned document how to obtain it.
if you are looking for the IP of a LoadBalancer type service, then it will be reported among lots of other stuff in the output of kubectl get service name-of-your-service -o yaml or kubectl describe service name-of-your-service. Note however that clusters created with kubeadm don't provide external load-balancers on their own (that's why they are called external) and if you intend to setup a fully functional production cluster manually, you will need to use something like MetalLB in addition.
if you are looking for IPs of NodePort type services then these will be all the IPs of worker node (virtual) machines that you assimilated into you cluster by running kubeadm join command on them. if you don't remember them then you can use kubectl get nodes -o wide as suggested in the other answer.
This command display the nodes name, private and public IP addresses.
kubectl get nodes -o wide | awk -v OFS='\t\t' '{print $1, $6, $7}'
Here's a command that should show the internal IP addresses of each node in the cluser:
ubuntu#astrocyte:~$ kubectl get nodes -o yaml | grep -- "- address:"
- address: 192.168.1.6
- address: astrocyte
- address: 192.168.1.20
- address: axon2.local
- address: 192.168.1.7
- address: axon3.local
It also shows hostnames, if you have them configured

How to get the cluster IP of a kubernetes service

I've created a service which wraps an nfs, and I need to get the cluster IP for it so that I can set it to persistent volumne using it.
I know I can use the following to get this:
$ kubectl get svc nfs-server
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nfs-server ClusterIP 10.59.243.58 <none> 2049/TCP,20048/TCP,111/TCP 2m
What I want to know is, how do I extract that cluster IP in a bash script? It's generated as part of a deployment process, so I can't just type it in to my persistent volume manifest.
You can parse the of kubectl get svc command something like below to get the inner details of the deployment.
export CLUSTER_IP=$(kubectl get services/nfs-server -o go-template='{{(index.spec.clusterIP)}}');echo CLUSTER_IP=$CLUSTER_IP
Alternatively, you can try any combination of shell hacks involving cut and awk. One such example is;
kubectl describe svc/nfs-server | grep IP: | awk '{print $2;}'
The previous answer using go-template output was failing. Using jsonpath worked for me:
#!/bin/bash
cluster_ip=$(kubectl get svc nfs-server -ojsonpath='{.spec.clusterIP}')
echo $cluster_ip

Kubernetes - Get value of a specific metadata when using describe command

When ruining kubectl describe service MyService command and can get the details of my kubernetes service as per below sample:
I am only interested to get the value of LoadBalancer Ingress metadata. Is there a way to retrieve this specific metadata using kubectl describe command?
I think it's better to use the get method and the go-template output :
kubectl get svc MyService -o go-template --template='{{range .status.loadBalancer.ingress}}{{.ip}}{{end}}'
Otherwise (but I don't recommend it), use bash tools like grep and cut
kubectl describe svc MyService | grep "LoadBalancer Ingress" | cut -d ':' -f2
How do you define "LoadBalancer Ingress metadata"? The IP address? If so, that information should appear under "IP:", right on top of LoadBalancer Ingress. But the LoadBalancer type service is cloud provider specific.
Do you actually have an IP address assigned to that specific load balancer?

How do I get the External IP of a Kubernetes service as a raw value?

I am running an application with GKE. It works fine but I can not figure out how to get the external IP of the service in a machine readable format.
So i am searching a gcloud or kubectl command that gives me only the external IP or a url of the format http://192.168.0.2:80 so that I can cut out the IP.
You can use the jsonpath output type to get the data directly without needing the additional jq to process the json:
kubectl get services \
--namespace ingress-nginx \
nginx-ingress-controller \
--output jsonpath='{.status.loadBalancer.ingress[0].ip}'
NOTE
Be sure to replace the namespace and service name, respectively, with yours.
Maybe not GKE as my clusters are on AWS, but I assume logic will be similar. When you kubectl get svc you can select output format and it will show more then just the "normal" get. For me, with ELB based services to het LB hostname it's enough to run ie. kubectl -n kube-system get svc cluster-nginx-ingress-controller -o json | jq .status.loadBalancer.ingress.hostname
In my case 'kubectl get services' returns array of items, but not just one service.
So then such jsonpath works fine to me:
kubectl get services -l component=controller,app=nginx-ingress -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}"
...and yet another way... This will list all the "load-balancer" services
kubectl get services --all-namespaces -o json | jq -r '.items[] | { name: .metadata.name, ns: .metadata.namespace, ip: .status.loadBalancer?|.ingress[]?|.ip }'
Depending on the networkPlugin used by your cluster services/pods may be exposed directly on external-ip. But this will also find an Ingress controllers run in the cluster.
To get the external-ip on GCP i can use:
kubectl get services --namespace=<your-namespace> -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}"
The answers above do not provide the output the user asked. The correct command would be:
kubectl -n $namespace get svc $ingressServiceName -o json | jq -r .status.loadBalancer.ingress[].hostname
All previous solutions don't work any more for me (on GCP).
To get the IP:
kubectl get ingress <YOUR_INGRESS_NAME> -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
To get the host-name:
kubectl get ingress <YOUR_INGRESS_NAME> -o jsonpath="{.spec.rules[0].host}"
Type
minikube tunnel
or
kubectl cluster-info
You can get the public exposed IP of your relevant service.

Is there anyway to get the external ports of the kubernetes cluster

I have exposed a service on an external port on all nodes in a kubernetes
cluster from:
kubectl create -f nginx-service.yaml
You have exposed your service on an external port on all nodes in your
cluster. If you want to expose this service to the external internet, you may
need to set up firewall rules for the service port(s) (tcp:30002) to serve traffic.
See http://releases.k8s.io/release-1.2/docs/user-guide/services-firewalls.md for more details.
service "nginx-service" created.`
Is there anyway to get the external ports of the kubernetes cluster?
kubectl get svc --all-namespaces -o go-template='{{range .items}}{{range.spec.ports}}{{if .nodePort}}{{.nodePort}}{{"\n"}}{{end}}{{end}}{{end}}'
This gets all services in all namespaces, and does basically: "for each service, for each port, if nodePort is defined, print nodePort".
I hope this answer is short and simple:
kubectl describe service --all-namespaces | grep -i nodeport
But, using go template is the ideal option and can be used to extract more details.
If you view your service using kubectl describe service NAME it should show you what port was assigned (in the NodePort field).
To get extended information about service ports:
kubectl describe service -A
To get only service endpoints:
kubectl get endpoints -A
To limit the output by node IP, you can grep by a network mask or use a more sophisticated script.
kubectl get svc --all-namespaces -o go-template='{{range .items}}{{ $save := . }}{{range.spec.ports}}{{if .nodePort}}{{$save.metadata.namespace}}{{"/"}}{{$save.metadata.name}}{{" - "}}{{.name}}{{": "}}{{.nodePort}}{{"\n"}}{{end}}{{end}}{{end}}'
This gets not just the used nodeports but the name of the nodeport, the service name and namespace of the service in this format:
<namespace>/<service name> - <nodeport name>: <nodeport>
...and you can perform the same solution alternatively with a JsonPath...
get the external Port (the "nodePort") of myservice corresponding to the internal port 1234
kubectl get svc myservice -o=jsonpath='{.spec.ports[?(#.port==1234)].nodePort}'
get a list of all IPs of the Nodes underlying your cluster, in one line
kubectl get node -o=jsonpath='{.items[*].status.addresses[?(#.type=="InternalIP")].address}'
Obviously this information can easily be combined into a convenient bash script to suit any specific needs...
#!/bin/bash
#
# discoverService - extract the externally visible Node-IP and port for a specific Service in Kubernetes
#
KUBECTL=kubectl
#
if [[ $# < 2 || "$1" == "-h" ]]
then
echo discoverService SERVICENAME INTERNALPORT
exit -1
fi
SERVICENAME=$1
INTERNALPORT=$2
EXTPORT=`${KUBECTL} get svc $SERVICENAME -o=jsonpath="{.spec.ports[?(#.port==${INTERNALPORT})].nodePort}"`
EXTIP=`${KUBECTL} get node -o=jsonpath='{.items[0].status.addresses[?(#.type=="InternalIP")].address}'`
if [[ -z $EXTPORT ]]
then
echo -e "ERROR: service=$SERVICENAME internal-port=$INTERNALPORT not found.\n"
exit -2
elif [[ -z $EXTIP ]]
then
echo -e "ERROR: could not retrieve underlying node IPs.\n"
exit -2
fi
# Success...
echo $EXTIP:$EXTPORT
Missing part for me was actual IP address of minikube
---->$:kubectl describe service --all-namespaces | grep -i nodeport
Name: my-nodeport-service
Type: NodePort
NodePort: <unset> 30007/TCP
---->$:curl $(minikube ip):30007
For the ones who want to get the hostIP as well, here is a command who:
Use a specific NAMESPACE (default to the current-context one)
Get the HostIP
Get the NodePort
# if want to explicit choose a NAMESPACE uncomment the line bellow and change the value
# NAMESPACE=default && \
if [[ -z $NAMESPACE ]]; then NAMESPACE="$(kubectl config view --minify -o jsonpath='{..namespace}')"; fi && \
kubectl get pod -o=custom-columns=POD_NAME:.metadata.name,IP:.status.hostIP --namespace=${NAMESPACE} && \
kubectl get svc -o=custom-columns=SVC_NAME:.metadata.name,PORT:.spec.ports[0].nodePort --namespace=${NAMESPACE}