Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a service in a kubernetes cluster using the service name .

Tags:

kubernetes

I am pretty new to kubernetes and I have successfully setup a cluster on google container engine . In my cluster I have a backend api developed with dropwizard, front end developed with node js and a mysql database. All have been deployed to the cluster and are working .However my challenge is this after setting up an external ip for my node containers and backend I can access them remotely but I can't access my backed from my front end using the service name e.g my backend is called backendapi within the cluster. I can't do this http://backendapi:8080 to call my rest services when deployed to the cluster . The catch for me is when I deploy to the cluster I don't want my front end to hit my back end using the external ip, I want them to connect within the cluster without going via the external ip address. When I connect to a pod and ping backendapi it returns a result but when I deploy my front end and use the label name it doesn't work .What could I be doing wrong ?.

like image 717
I.Tyger Avatar asked Oct 31 '17 02:10

I.Tyger


People also ask

How do I check my services in Kubernetes?

Using kubectl describe pods to check kube-system If the output from a specific pod is desired, run the command kubectl describe pod pod_name --namespace kube-system . The Status field should be "Running" - any other status will indicate issues with the environment.

How do I access Kubernetes service with cluster IP?

The default Kubernetes ServiceType is ClusterIp , which exposes the Service on a cluster-internal IP. To reach the ClusterIp from an external computer, you can open a Kubernetes proxy between the external computer and the cluster. You can use kubectl to create such a proxy.


2 Answers

As long as kube-dns is running (which I believe is "always unless you disable it"), all Service objects have an in cluster DNS name of service_name +"."+ service_namespace + ".svc.cluster.local" so all other things would address your backendapi in the default namespace as (to use your port numbered example) http://backendapi.default.svc.cluster.local:8080. That fact is the very reason Kubernetes forces all identifiers to be a "dns compatible" name (no underscores or other goofy characters).

Even if you are not running kube-dns, all Service names and ports are also injected into the environment of Pods just like docker would do, so the environment variables ${BACKENDAPI_SERVICE_HOST}:${BACKENDAPI_SERVICE_PORT} would contain the Service's in-cluster IP (even though the env-var is named "host") and the "default" Service port (8080 in your example) if there is only one.

Whether you choose to use the DNS name or the environment-variable-ip is a matter of whether you like having the "readable" names for things in log output or error messages, versus whether you prefer to skip the DNS lookup and use the Service IP address for speed but less legibility. They behave the same.

The whole story lives in the services-networking concept documentation

like image 108
mdaniel Avatar answered Oct 06 '22 14:10

mdaniel


But the problem still persists when I change to this backendapi.default.svc.cluster.local:8080. I even tried using the other port that it is mapped to internally and my front end web page keeps saying backendapi.default.svc.cluster.local:32208/api/v1/auth/login net::ERR_NAME_NOT_RESOLVED. The funny thing is when I curl from my front end pod it works . But when I'm accessing it using my web browser it doesnt

Because it is resolvable only within the cluster. (Because only the K8s cluster with kube-dns add-on can translate the domain name backendapi.default.svc.cluster.local:8080 to it's corresponding IP address)

Could this be because i exposed an external ip for the service as well . The external ip works though

No, It is because domain name backendapi.default.svc.cluster.local is resolvable only within the cluster, not from a random browser in a random machine.

Solution

What you did is one of the solutions, exposing an external ip for the service. If you don't want the IP to be used, you can Create an ingress (and use an ingress controller in your cluster) and expose your Microservice. Since you are on GCP, you can make use of their API gateway rather than exposing a cryptic IP address.

Note: Remember to add the authentication/Authorization to lock down your microservice as it's getting exposed to the user.

Another Solution

Proxy all the backend calls through the server which serves your web app (nginx/nodejs etc)

Advantage of this approach is, you will avoid all the Same Origin Policy/CORS headaches, your microservice (express) authentication details will be abstracted out from user's browser. (This is not necessarily an advantage).

Disadvantage of this approach is, your backend microservice will have a tight coupling with front end (or vice-versa depending on how you look at it), This will make the scaling of backend dependent on front end. Your Backend is not exposed. So, if you have another consumer (let's just say an android app) it will not be able to access your service.

Hybrid Solution

Proxy all the backend calls through the server which serves your web app (nginx/nodejs etc) so that your APIs will inherit your webapps domain. And still expose the backend service (as and when required) so that other consumers (if any, in future) can make use of it.

Kind of similar question: https://stackoverflow.com/a/47043871/6785908

like image 29
so-random-dude Avatar answered Oct 06 '22 15:10

so-random-dude