How to get the cluster IP of a kubernetes service - kubernetes

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

Related

How to list really all objects of a nonexistant namespace?

Okay, the title is quite mouthful. But it's actually describing the situation.
I deployed a service on GKE in namespace argo-events. Something was wrong with it so I tore it down:
kubectl delete namespace argo-events
Actually, that's already where the problems started (I suspect a connection to the problem described below) and I had to resort to a hack because argo-events got stuck in a Terminating state forever. But the result was as desired - namespace seemed to be gone together with all objects in it.
Because of problems with redeployment I inspected the GKE Object Browser (just looking around - cannot filter for argo-events namespace anymore as it is officially gone) where I stumbled upon two lingering objects in ns argo-events:
argo-events is not listed by kubectl get namespaces. Just confirming that.
And I can find those two objects if I look them up specifically:
$ kubectl get eventbus -n argo-events
NAME AGE
default 17h
$ kubectl get eventsource -n argo-events
NAME AGE
pubsub-event-source 14h
But - I cannot find anything by asking for all objects:
$ kubectl get all -n argo-events
No resources found in argo-events namespace.
So my question is. How can I generically list all lingering objects in argo-events?
I'm asking because otherwise I'd have to inspect the entire Object Browser Tree to maybe find more objects (as I cannot select the namespace anymore).
By using command $ kubectl get all you will only print a few resources like:
pod
service
daemonset
deployment
replicaset
statefulset
job
cronjobs
It won't print all resources which can be found when you will use $ kubectl api-resources.
Example
When create PV from PersistentVolume documentation it won't be listed in $ kubectl get all output, but it will be listed if you will specify this resource.
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/pods/storage/pv-volume.yaml
persistentvolume/task-pv-volume created
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Available manual 3m12s
$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.3.240.1 <none> 443/TCP 86m
$
If you would like to list all resources from specific namespace you should use command below:
kubectl -n argo-events api-resources --namespaced=true -o name | xargs --verbose -I {} kubectl -n argo-events get {} --show-kind --ignore-not-found
Above solution was presented in Github thread kubectl get all does not list all resources in a namespace. In this thread you might find some additional variations of above command.
In addition, you can also check How to List all Resources in a Kubernetes Namespace article. You can find there method to list resources using function.

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.

Selecting Array Elements with the Custom Columns Kubernetes CLI Output

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

Do Kubernetes service IPs change?

I'm very new to kubernetes/docker, so apologies if this is a silly question.
I have a pod that is accessing a few services. In my container I'm running a python script and need to access the service. Currently I'm doing this using the services' IP addresses.
Is the service IP address stable or is it better to use environment variables? If so, some tips on doing that would be great.
The opening paragraph of the Services Documentation gives a motivation for services which implies stable IP addresses, but I never see it explicitly stated:
While each Pod gets its own IP address, even those IP addresses cannot be relied upon to be stable over time. This leads to a problem: if some set of Pods (let’s call them backends) provides functionality to other Pods (let’s call them frontends) inside the Kubernetes cluster, how do those frontends find out and keep track of which backends are in that set?
Enter Services.
My pod spec for reference:
kind: Pod
apiVersion: v1
metadata:
name: fetchdataiso
labels:
name: fetchdataiso
spec:
containers:
- name: fetchdataiso
image: 192.111.1.11:5000/ncllc/fetch_data
command: ["python"]
args: ["feed/fetch_data.py", "-hf", "10.222.222.51", "-pf", "8880", "-hi", "10.223.222.173", "-pi","9101"]
The short answer is "Yes, the service IP can change"
$ kubectl apply -f test.svc.yml
service "test" created
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.12.0.1 <none> 443/TCP 10d
test 10.12.172.156 <none> 80/TCP 6s
$ kubectl delete svc test
service "test" deleted
$ kubectl apply -f test.svc.yml
service "test" created
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.12.0.1 <none> 443/TCP 10d
test 10.12.254.241 <none> 80/TCP 3s
The long answer is that if you use it right, you will have no problem with it. What is even more important in scope of your question is that ENV variables are way worse then DNS/IP coupling.
You should refer to your service by service or service.namespace or even full path like something along the lines of test.default.svc.cluster.local. This will get resolved to service ClusterIP, and in opposite to your ENVs it can get re-resolved to a new IP (which will probably never happen unless you explicitly delete and recreate service) while ENV of a running process will not be changed
The service IP address is stable. You should only need to use environment variables if you don't have a better way of discovering the IP address (e.g. DNS).
If you use the DNS cluster addon within your cluster to access your services, and your service is called foo in namespace bar, you can also access it as bar.foo, which is likely more meaningful than a plain IP address.
See http://kubernetes.io/docs/user-guide/services/#dns