k8s create service with port, targetPort and nodePort identical - kubernetes

I need to create Kubernetes services that their nodePort are auto-allocated by K8S, and port/targetPort must equal to nodePort. (The requirement comes from the spec of a spark YARN node as the backend of the services).
Maybe I can first create the service with a fixed dummy port/targetPort and an auto-allocated nodePort, then update the service to set port/targetPort to the same value as the nodePort.
But is there any better way of doing this?

There are two main ways to expose a resource on k8s
First one using kubectl expose command: using this one you can choose the pod/deploy to expose but not the nodePort value. Then as you already know you must set the nodeport value on the created yaml
Another way to expose is using kubectl create service nodeport command: using this one you can set the port, target port and nodeport.
If you know the label of the pod to expose (for example app: superPod ) you can create a file, then replace a label (for example TOREPLACE)
with the value of your choosen port (for example 30456):
On linux:
portValue=30456 && k create service nodeport TOREPLACE \
--node-port=$portValue --tcp=$portValue --dry-run=client -oyaml > file.yaml \
&& sed -i 's/app: TOREPLACE/app: yourselector/g' file.yaml \
&& sed -i 's/name: TOREPLACE/name: yourselector-name/g' file.yaml
This will creates the file with preferred values.
After that, you can apply the file using kubectl -f file.yaml apply
However, depending on your needs, and if you want a reliable customizations of your resources, you could try to use:
https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
or
https://helm.sh/docs/
Hope it helps.

Related

What are the best solutions to replace kubernetes port-forward

I am working on rancher server, k3s to improve my knowledge on these solutions.
I want to expose container services on LAN network, this is why I used kubectl port-forward.
kubectl port-forward --namespace=ns-name --address LAN-IP service/hello 30104:8080
But I can see in several web resources that is not a reliable solution, just for local testing purpose.
I tried to replace them by ingress but I am a bit lost between ingress, DNS and nginx-ingress in addition to rancher component.
I understood than load balancer need a cloud provider, to have a public IP for instance, and handle the <pending> state of load balancer.
Can you highlight me on how replace port-forward in LAN without a cloud provider?
[edit #Rajesh Dutta]
I already use NodePort, but, without port-forward the service is exposed as NODE_IP:PORT, not LAN_IP:PORT. My need is to join it from outside of the cluster.
So this is what i did :
1 - create deployment
kubectl create deployment hello --image=gcr.io/google-samples/node-hello:1.0 --port=8080 --replicas=2
2 - expose deployment(create service)
kubectl expose deployment hello --type=NodePort
3 - forward service
kubectl port-forward --namespace=ns-name --address local-ip service/hello 30104:8080
IP schema
Now, considering that i will have several service, i would find the best ways to replace port-forward.
To start with I would recommend to use NodePort service. This will expose your application to a NodePort(30000-32767). Later if you want you can choose to switch to ingress.
Assuming that you are trying with a deployment type object
command:
kubectl expose deployment deployment-name --type=NodePort --port=8080 --target-port=<rancher server port>

How to get kubernetes service as spec yaml after has been `exposed`?

I'm very new to kubernetes and I find it a bit confusing and to understand I'd like to know what exactly kubectl expose deployment xxx--type=LoadBalancer --name=xxx does. So I was wondering if is possible to extract this service to yaml spec definition somehow.
I understand that Im creating a service, but not sure how he figures out all the ports automatically. I'd like to have the same thing in a file to run it like kubectl apply -f ./service.yaml.
kubectl expose doesnot assign ports automatically. If any port defination mentioned in deploymwnt yaml then only it uses the port. otherwise it will give error like :
error: couldn't find port via --port flag or introspection
to assign port on run use:
kubectl expose deployment xxx --type=NodePort --name=xxx --port=80 --target-port=8080
you can get the yaml by running this:
kubectl get service xxx -o yaml

How to deploy keycloak as a pod in kubernetes dashboard which is set up up in AWS EC2?

Added from a form which is quay.io/keycloak/keycloak
Changed from Loadbalancer to a Nodeport
Can visit that but ip:port
Showing error to add a user from localhost:8080 or use add-user-keycloak script
Please follow the docs Keycloak on Kubernetes.
You can find instructions there, how deploy keycloak inside minikube.
However you can download this deployment files and modify the settings according to your needs.
F.E. you can change service type from Loadbalancer to NodePort.
In addition please consider making a changes in other settings like: KEYCLOAK_USER, KEYCLOAK_PASSWORD:
wget -q -O - https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/kubernetes-examples/keycloak.yaml | \
sed "s/LoadBalancer/NodePort/" | \
kubectl create -f -
In order to access your keycloak instance you should change:
minikube ip ( to your externalIp address associated with your vm or use nodeIP from inside the vm)
verify your service NodePort by running.
kubectl get services/keycloak -o go-template='{{(index .spec.ports 0).nodePort}}'
kubectl get svc -o wide
By default NodePort should be in the range (30000-32767)

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 externally access a service with kubernetes NodePort?

I've setup a NodePort service using the following config:
wordpress-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: wordpress
name: wordpress
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: wordpress
Is this sufficient to access the service externally, if so how can I now access the service? What details do I need - and how do I determine them - for example node IP.
For Kubernetes on GCE:
We had the same question regarding services of type NodePort: How do we access node port services from our own host?
#ivan.sim 's answer (nodeIp:nodePort) is on mark however, you still wouldn't be able to access your service unless you add a firewall ingress (inbound to google cloud) traffic rule on the VPC network console to allow your host to be able to access your compute node
the above rule is dangerous and should be used only during development
You can find the node port using either the Google Cloud console or by running subsequent kubectl commands to find out the node running your pod which has your container. i.e kubectl get pods , kubectl describe pod your-pod-name, kubectl describe node node-that-runs-you-pod .status.addresses has your ExternalIP
It would be great if we could extract the node ip running our container in the pod using only a label/selector and a few line of commands, so here is what we did, in this case our selector is app: your-label:
$ nodename=$(kubectl get pods -o jsonpath='{.items[?(#.metadata.labels.app=="your-label")].spec.nodeName}')
$ nodeIp=$(kubectl get nodes -o jsonpath='{.items[?(#.metadata.name=="'$(echo $nodename)'")].status.addresses[?(#.type=="ExternalIP")].address}')
$ echo nodeIp
notice: we used json path to extract the information we desired, for more on json path see: json path
You could certainly turn this into a script that takes a label/selector as input and outputs an external ip of the node running your container !!!
To get the nodeport just type:
$ kubectl get services
under the PORT(S) columns you will see something like tagetPort:nodePort. this nodeport is what you want .
nodeIp:nodePort
When you define a service as type NodePort, every node in your cluster will proxy that port to your service. If you nodes are reachable from outside the Kubernetes cluster, you should be able to access the service at nodeIP:nodePort.
To determine nodeIP of a particular node, you can use either kubectl get no <node> -o yaml or kubectl describe no <node>. The status.Addresses field will be of interest. Generally, you will see fields like HostName, ExternalIP and InternalIP there.
To determine nodePort of your service, you can use either kubectl get svc wordpress -o yaml or kubectl describe svc wordpress. The spec.ports.nodePort is the port you need.
Service defined like this got assgned a high port number and is exposed on all your cluster nodes on that port (probably something like 3xxxx). Hard to tell the rest without proper knowledge of how your cluster is provisioned. kubectl get nodes should give you some knowledge about your nodes.
Although I assume you want to expose the service to the outside world. In the long run I suggest getting familiar with LoadBalancer type services and Ingress / IngressController