Access NodePort service from another machine in the same network - kubernetes

I installed minikube on my mac and created deployment and a service for my nodejs app. I tested that everything is working by getting the URL of my service using the following command:
minikube service my-nodejs-app --url
and then I run this URL in the browser and got results. The problem is when i tried to access the same URL from another machine inside the same network it didn't worked.
my service.yml file is:
apiVersion: v1
kind: Service
metadata:
name: my-nodejs-app
spec:
type: NodePort
ports:
- port: 80
targetPort: 1337
protocol: TCP
name: app-server
selector:
app: my-nodejs-app
I tried to use port forwarding to forward my pod port to my localhost and it works only on the same machine who host the cluster and when I try to access from another machine on the same network (via the IP address of the machine where the cluster deployed) I still get page not found.

You can use "port forward a service". Assuming:
Your local machine IP: 166.6.6.6 (which hold minikube)
Your minikube IP: 192.168.99.100 (check the real IP with command $minikube ip)
The nodePort of your service 'my-nodejs-app': 31000 (check the real
nodePort with command: $kubectl get service)
In order to access your service from remote, you can forward a port (like 31000, recommend the same port with nodePort) to your service through the following command in your local machine:
ssh -i ~/.minikube/machines/minikube/id_rsa docker#$(minikube ip) -L \*:31000:0.0.0.0:31000
Then you can access your service through URL: http://166.6.6.6:31000, which will be forwarded to your service URL http://192.168.99.100:31000
Thx: https://github.com/kubernetes/minikube/issues/877

Probably a bit late, but if anyone still having this issue-
Check the list of services and the one you want to expose if it is present
kubectl get svc -n {namespace_name}
Change the type to NodePort if it is of cluster IP type.
kubectl patch svc {service_name} -n {namespace_name} --type='json' -p '[{"op":"replace","path":"/spec/type","value":"NodePort"}]'
Expose the above Node Port available to your local machine now for other machines on same network:
service_port=$(minikube service {service_name} -n {namespace_name} --url | cut -d':' -f3)
ssh -i ~/.minikube/machines/minikube/id_rsa docker#$(minikube ip) -NL \*:${service_port}:0.0.0.0:${service_port}
Now you can access the above service from other machines on same network by just hitting the link-
{your_hostname}:{node_port}

Sounds like reaching it from another machine compares to exposing a ssevice to the web.
In that case you need to look into spec/type:LoadBalancer (http://kubernetes.io/docs/user-guide/load-balancer/)
That said, with minikube i'd stick to a single machine and development only tests

If I understand your problem correctly:
Your machine's IP: 192.168.1.4
Your minikube IP: 192.168.99.100
Accessing your service from a browser on your machine: http://192.168.99.100:30080
Now, let's say you're on another machine, say192.168.1.5, and you want to access this service.
The problem is that you need to map your machine's port to minikube's 30080 because minikube is a VM running on your machine (which cannot be accessed from outside your machine).
So you can try: Virtualbox "port forward" from Guest to Host.
Another alternative is to forward a port from your localhost to a pod directly (not the k8s svc unfortunately) by using kubectl port-forward.

You have not specified nodePort in ports.
Add below configuration in port
nodePort: 30000
You can access your service at http://[IP address]:30000

Related

How to connect kubernetes pod server on guest os from host os

I am testing k8s on ubuntu using virtual box.
I have two nodes, one is master, another is worker node.
I deployed a pod containing nginx server container for test.
I can access the webpage deployed by the pod on master node with commands below
kubectl port-forward nginx-server 8080:80
curl localhost:8080
but I want to open this page on my host os(windows10) using chrome web browser
This is how I set port-forwading on virtual-box...
simply answer your question, use address args for the kubectl command:
kubectl port-forward --address 0.0.0.0 nginx-server 8080:80
here is the explanation:
kubectl port-forward bind to localhost by default
the port forward for your virtual box is bind to 10.100.0.104
0.0.0.0 will bind the port to both localhost and 10.100.0.104
change 0.0.0.0 to 10.100.0.104 will also work for 10.100.0.104 access, but not the localhost
and also, when exposing a port, you could use a NodePort service: https://kubernetes.io/docs/concepts/services-networking/service/#nodeport

How to find the url of a service in kubernetes?

I have a local kubernetes cluster on my local docker desktop.
This is how my kubernetes service looks like when I do a kubectl describe service
Name: helloworldsvc
Namespace: test
Labels: app=helloworldsvc
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"helloworldsvc"},"name":"helloworldsvc","namespace":"test...
Selector: app=helloworldapp
Type: ClusterIP
IP: 10.108.182.240
Port: http 9111/TCP
TargetPort: 80/TCP
Endpoints: 10.1.0.28:80
Session Affinity: None
Events: <none>
This service is pointing to a deployment with a web app.
My question how to I find the url for this service?
I already tried http://localhost:9111/ and that did not work.
I verified that the pod that this service points to is up and running.
URL of service is in the below format:
<service-name>.<namespace>.svc.cluster.local:<service-port>
In your case it is:
helloworldsvc.test.svc.cluster.local:9111
Get the service name: kubectl get service -n test
URL to a kubernetes service is service-name.namespace.svc.cluster.local:service-port where cluster.local is the kubernetes cluster name.
To get the cluster name: kubectl config get-contexts | awk {'print $2'}
URL to service in your case will be helloworldsvc.test.svc.cluster.local:9111
The way you are trying to do won't work as to make it available on your localhost you need to make the service available at nodeport or using port-forward or using kubectl proxy.
However, if you want dont want a node port and to check if inside the container everything works fine then follow these steps to get inside the container if it has a shell.
kubectl exec -it container-name -n its-namespace-name sh
then do a
curl localhost:80 or curl helloworldsvc.test.svc.cluster.local:9111 or curl 10.1.0.28:80
but both curl commands will work only inside Kubernetes pod and not on your localhost machine.
To access on your host machine kubectl port-forward svc/helloworldsvc 80:9111 -n test
The service you have created is of type ClusterIP which is only accessible from inside the cluster. You have two ways to access it from your desktop:
Create a nodeport type service and then access it via nodeip:nodeport
Use Kubectl port forward and then access it via localhost:forwardedport
The following url variations worked for me when in the same cluster and on the same namespace (namespace: default; though all but first should still work when services are on different namespaces):
http://helloworldsvc
http://helloworldsvc.default
http://helloworldsvc.default.svc
http://helloworldsvc.default.svc.cluster.local
http://helloworldsvc.default.svc.cluster.local:80
//
using HttpClient client = new();
string result = await client.GetStringAsync(url);
Notes:
I happen to be calling to and from an ASP.NET 6 application using HttpClient
That client I think just sets port to 80 by default, so no 80 port needs to be explicitly set to work. But I did verify for all of these it can be added or removed from the url
http only (not https, unless you configured it specially)
namespace can only be omitted in the first case (i.e. when domain / 'authority' is just the service name alone). So helloworldsvc.svc.cluster.local:80 fails with exception "Name or service not known (helloworldsvc.svc.cluster.local:80)"
If you are working with minikube , you can run the code below
minikube service --all
for specific service
minikube service service-name --url
Here is another way to get the URL of service
Enter one pod through kubectl exec
kubectl exec -it podName -n namespace -- /bin/sh
Then execute nslookup IP of service such as 172.20.2.213 in the pod
/ # nslookup 172.20.2.213
nslookup: can't resolve '(null)': Name does not resolve
Name: 172.20.2.213
Address 1: 172.20.2.213 172-20-2-213.servicename.namespace.svc.cluster.local
Or execute nslookup IP of serviceName in the pod
/ # nslookup servicename
nslookup: can't resolve '(null)': Name does not resolve
Name: 172.20.2.213
Address 1: 172.20.2.213 172-20-2-213.servicename.namespace.svc.cluster.local
Now the service URL is servicename.namespace.svc.cluster.local attached with the service port after removing IP for the output of nslookup.

How to map nodePort to my own defined port

I have a service which is accessible on 8081. If I do via docker-compose or swarm without any specific changing on port it's work.
http://$(minikube ip):8081
but when i run my app via Kubernetes(minikube) is assign a nodePort in range of 30000-32767.
Then i have to call as follow:
http://$(minikube ip):30546
which is not acceptable from my service. Is there any way to map randomly given port to my own defined port?
When call second url then i am getting connection refused
I also used
kubectl port forward my-service 8081
but still no success.
kubectl port-forward command is incorrect. try below one
kubectl port-forward svc/my-service 8081:8081
then you should be able to access the service at http//:127.0.0.1:8081
This answer is not specific to Minikube but applicable to any Kubernetes cluster running inside a docker container.
In order to send a request from the host machine to the Kubernetes pod running in a container, you have to map ports from host machine to all the way to the pod.
Here is how you do it:
Publish the NodePort you want to use inside container to the host machine using --publish or -p.
# Map port 8080 on host machine to 31080 inside the container
docker run -p 8080:31080 ...
Use a custom NodePort when creating the service:
# You need to specify the exposed port as the nodePort value
# Otherwise Kubernetes will generate a random nodePort for you
kubectl create service nodeport myservice --node-port=31080 --tcp=3000:80
The application inside the pod listens to port 80 which is exposed as a service at port 3000. The traffic received at port 31080 on Kubernetes node will be directed at this service.
The query you send to 8080 on your host machine will follow this path:
Request -> Host Machine -> Docker Container -> Kubernetes Node -> Service -> Pod
↑ ↑ ↑ ↑ ↑
localhost:8080 :31080 :31080 :3000 :80
References:
https://docs.docker.com/engine/reference/commandline/run/
https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-em-service-nodeport-em-

Where do I find the host IP address for an app deployed in minikube

I'm deploying a spring boot app in minikube that connects to a database running on the host. Where do I find the IP address that the app can use to get back to the host? For docker I can use ifconfig and get the IP address from the docker0 entry. ifconfig shows another device with IP address 172.18.0.1. Would that be how my app would get back to the host?
I think I understood you correctly and this is what you are asking for.
Minikube is started as a VM on your machine. You need to know the IP which Minikube starts with. This can be done with minikube status or minikube ip, output might look like:
$ minikube status
minikube: Running
cluster: Running
kubectl: Correctly Configured: pointing to minikube-vm at 192.168.99.1
This will only provide you the IP address of Minikube not your application.
In order to connect to your app from outside the Minikube you need to expose it as a Service.
Example of a Service might look like this:
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
- nodePort: 31317
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: webapp
You can see results:
$ kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
postgres ClusterIP 10.0.0.140 <none> 5432/TCP 32m app=postgres
webapp NodePort 10.0.0.235 <none> 8080:31317/TCP 2s app=webapp
You will be able to connect to the webapp from inside the Cluster using 10.0.0.235:8080 of from outside the Cluster using Minikube IP and port 31317.
I also recommend going through Hello Minikube tutorial.
It was the 172.18.0.1 IP address. I passed it to the Spring app running in minikube with a configmap like this:
kubectl create configmap springdatasourceurl --from-literal=SPRING_DATASOURCE_URL=jdbc:postgresql://172.18.0.1:5432/bookservice
The app also needed SPRING_DATASOURCE_DRIVER_CLASS_NAME to be set in a configmap and that credentials SPRING_DATASOURCE_PASSWORD and SPRING_DATASOURCE_USERNAME be set as secrets.
More information on configmap and secret are here.

How kubectl port-forward works?

kubectl exposes commands that can be used to create a Service for an application and assigns an IP address to access it from internet.
As far as I understand, to access any application within Kubernetes cluster there should be a Service resource created and that should have an IP address which is accessible from an external network.
But in case of port-forward how does kubectl create a connection to the application without an IP address which is accessible externally?
To start, it's useful to note and remember that in Kubernetes, every pod gets its own ip address from 10.*, that is usable only within the cluster. Now, the port-forward feature of kubectl simply tunnels the traffic from a specified port at your local host machine to the specified port on the specified pod. API server then becomes, in a sense, a temporary gateway between your local port and the Kubernetes cluster.
kubectl port-forward forwards connections to a local port to a port on a pod. Compared to kubectl proxy, kubectl port-forward is more generic as it can forward TCP traffic while kubectl proxy can only forward HTTP traffic.
kubectl port-forward is useful for testing/debugging purposes so you can access your service locally without exposing it.
Below is the name of the pod and it will forward it's port 6379 to localhost:6379.
kubectl port-forward redis-master-765d459796-258hz 6379:6379
which is the same as
kubectl port-forward pods/redis-master-765d459796-258hz 6379:6379
or
kubectl port-forward deployment/redis-master 6379:6379
or
kubectl port-forward rs/redis-master 6379:6379
or
kubectl port-forward svc/redis-master 6379:6379
kubectl port-forward makes a specific Kubernetes API request. That means the system running it needs access to the API server, and any traffic will get tunneled over a single HTTP connection.
Having this is really useful for debugging (if one specific pod is acting up you can connect to it directly; in a microservice environment you can talk to a back-end service you wouldn't otherwise expose) but it's not an alternative to setting up service objects. When I've worked with kubectl port-forward it's been visibly slower than connecting to a pod via a service, and I've found seen the command just stop after a couple of minutes. Again these aren't big problems for debugging, but they're not what I'd want for a production system.
If you want to forward to a different port in localhost. Try this
kubectl port-forward <pod-name> <locahost-port>:<pod-port>
kubectl port-forward sample-pod-sadasds-sxawdd 8090:6379
The above command forwards to localhost 8090 from pod 6379
The port-forward command, Forwards one (or more) local ports to a pod.
This command is very useful for example in blue/green deployments where you would want to troubleshoot a misbehaving pod.
To take things even further, you could even execute some preliminary tests to the pods you feel could be more error-prone right inside your CI/CD pipeline in Jenkins by using multiple conditions, declarative pipeline.
Usage examples:
Listen on port 8888 locally, forwarding to 5000 in the pod
kubectl port-forward pod/mypod 8888:5000
Listen on port 8888 on all addresses, forwarding to 5000 in the pod
kubectl port-forward --address 0.0.0.0 pod/mypod 8888:5000
Listen on a random port locally, forwarding to 5000 in the pod
kubectl port-forward pod/mypod :5000
Listen on port 8888 on localhost and selected IP, forwarding to 5000 in the pod
kubectl port-forward --address localhost,10.19.21.23 pod/mypod 8888:5000
Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in the pod
kubectl port-forward pod/mypod 5000 6000
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 ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in a pod selected by the service
kubectl port-forward service/myservice 5000 6000
To access something inside the cluster, there ae a couple of different options available to,
Cluster IP service with Ingress-Nginx
NodePort Service to expose the pod directly to the outside world.
Above both approach will require to write config file, In case if you want to access a pod without writing a config file then it comes to third option.
Port Forward: We can run a command at our terminal that tells our kubernets cluster to port-forward a port off a very specific pod inside of our cluster when we use this port forwarding thing that's going to cause our cluster to essentially behaves as though it has a node port service running inside it. It's going to expose this pod or a very specific port on it to the outside world and allow us to connect to it directly from our local machine.
Let's go by an example:
const stan = nats.connect('ticketing', 'abc', {
url: 'http://localhost:5000',
});
Our goal is to establish a connection between stan and a pod inside a kubernets cluster.
first we will need the pod name, you can get the name by command kubectl get pods
kubectl get pods
I am assuming my pod name is nats-depl-855d477f4d-xgbd7, and it is accessiable via a cluster IP service
apiVersion: v1
kind: Service
metadata:
name: nats-srv
spec:
selector:
app: nats
ports:
- name: client
protocol: TCP
port: 4222
targetPort: 4222
now to establish the connection run the below command:
kubectl port-forward nats-depl-855d477f4d-xgbd7 5000:4222
5000: is the port of my local machine
4222 : is the port of the pod I want to get access
kubectl port-forward is the easiest communication method with the Pod, but under the hood, this method is much more complicated. The communication goes through several Kubernetes components, so if anything is broken in the communication path, you will not be able to talk to the pod, even if the pod itself is accessible via regular communication channels.
The server proxy runs via kubectl port-forward command forwards the connection to the Kubernetes API Server living in Master node, then the API Server delivers the connection to the Kubelet on the node hosting your Pod, and then the Kubelet forwards the connection to the application running in the pod's container.
NOTE
The application in the container must be bound to a port on the
loopback device for the Kubelet to reach it. If it listens only on the
pod’s eth0 network interface, you won’t be able to reach it with the
kubectl port-forward command.
Marko Lukša "Kubernetes in Action, Second Edition"
TIP
kubectl port-forward allows you to forward communication also to Services and has several other useful features. Run kubectl port-forward --help to learn more.