Access an application running on kubernetes from the internet - kubernetes

I'm pretty sure that this is a basic use case when running apps on kubernetes, but till now I wasn't able to find a tutorial, nor understand from the documentation, how to make it work.
I have an application, which is listening on a port 9000. So when run on my localhost, I can access it through a web browser on a localhost:9000. When run in a docker container, which is running on my VPS, it's also accessible on myVPSAddress:9000. Now the question is, how to deploy it on kubernetes running on the very same Virtual Private Server and expose the application to be visible as well, as when deployed on docker. I can access the application from within the VPS on the address of the cluster, but not on the IP address of the server itself. Can somebody show me some basic dockerfile with a description what is it doing or show me some idiot-proof way, how to make it work? Thanks

While one would think that this is a very basic use-case, that is not the case for people running their own kubernetes clusters on bare metal servers. (The way you are on your VPS).
The recommended way of exposing an application to "the world" is to use kubernetes services, see this piece of documentation about exposing services. You define a kubernetes service, either of the type NodePort or of type Loadbalancer *.
Here is what a dead simple service looks like (hint: it's of the default type NodePort):
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 9000
targetPort: 9376
This will expose your service with label name: my-service (interally running on port 9000) on all nodes in your VPS cluster at port 9376.
Assuming your nodes have a public IP (which from your question I assume they do), you can safely do curl localhost:9376.
Because this is usually not ideal UX/UI to expose to users, people use services of type Loadbalancer. This service type provides a unique IP to each of your services instead of a port.
These services are first class citizens on cloud managed clusters, such as Google's GKE, but if you run your own Kubernetes cluster (setup using say kubeadm), then you need to deploy your Loadbalancer service provider. I've used the excellent MetalLB and it works flawlessly once it's been setup, but you need to set it up yourself. If you want dns names for you services as well, you should also look at ExternalDNS.
* Caveat here is that you can also use a service of type ExternalIP if you can somehow make that IP routable, but unless the network is in your control, this is usually not a feasible approach, and I'd recommend looking at an LB provider instead.

Related

Access the Kubernetes cluster/node from outside

I am new to kubernetes. I have created a cluster of db of kubernetes with 2 nodes. I can access those kubernetes pods from thin client like dbeaver to check the data. But I can not access those kubernetes nodes externally. I am currently trying to run a thick client which will load the data into cluster on kubernetes.
kubectl describe svc <svc>
I can see cluster-Ip assigned to the service. Type of my service is loadbalancer. I tried to use that but still not connecting. I read about using nodeport but without any IP address how to access that
So what is the best way to connect any node or cluster from outside.
Thank you in advance
Regards
#KrishnaChaurasia is right but I would like to explain it in more detail with the help of the official docs.
I strongly recommend going through the following sources:
NodePort Type Service: Exposes the Service on each Node's IP at a static port (the NodePort). A ClusterIP Service, to which the NodePort Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>:<NodePort>. Here is an example of the NodePort Service:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
# By default and for convenience, the `targetPort` is set to the same value as the `port` field.
- port: 80
targetPort: 80
# Optional field
# By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
nodePort: 30007
Accessing services running on the cluster: You have several options for connecting to nodes, pods and services from outside the cluster:
Access services through public IPs.
Use a service with type NodePort or LoadBalancer to make the service reachable outside the cluster. See the services and kubectl expose documentation.
Depending on your cluster environment, this may just expose the service to your corporate network, or it may expose it to the internet. Think about whether the service being exposed is secure. Does it do its own authentication?
Place pods behind services. To access one specific pod from a set of replicas, such as for debugging, place a unique label on the pod and create a new service which selects this label.
In most cases, it should not be necessary for application developer to directly access nodes via their nodeIPs.
A supplement example: Use a Service to Access an Application in a Cluster: This page shows how to create a Kubernetes Service object that external clients can use to access an application running in a cluster.
These will help you to better understand the concepts of different Service Types, how to expose and access them from outside the cluster.

Kubernetes nginx ingress accesses outside of cluster without using service

Apologies if this has been answered before, but I am a little confused on Ingress Nginx is working together with services.
I am trying to implement an nginx ingress in my Kubernetes environment.
So far I have an ingress-nginx-controller-deployment setup, as well as a deployment and service for the default backend. I still need to create my actual Ingress resources, the ingress-nginx-controller-service and also my backend.
curl <NodeIP>
returns "default backend 404" on port 80 for the Node which the ingress-nginx-controller-deployment is deployed on.
However, my understanding is that exposing anything out of the cluster requires a service (Nodeport/Loadbalancer), which is the duty of the ingress-nginx-controller-service.
My question is how is this possible, that I can access port 80 for my Node on my browser, which is outside the cluster?
Could I then deploy my backend app on port 80 the same way the above is done?
I feel like I am misunderstanding a key concept here.
default backend image: gcr.io/google_containers/defaultbackend:1.0
nginx-controller image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.3
I think you missed a really good article about how nginx-ingress expose to the world!
I short:
If you're using hostNetwork: true then you bypass the kubernetes network (kube-proxy). in a simple word, you bypass the container and orchestration network and just using the host network then the node with nginx-ingress container will expose port 80 to the world.
There are other ways that you can use to expose nginx port to outside of the cluster (node-port, network load balancer like MetalLB).

How can I expose a StatefulSet service with ClusterIP None on Google Cloud Platform?

How can I expose a StatefulSet service (cassandra, mysql, etc...) with ClusterIP=None on Kubernetes in Google Cloud Platform?
I need to change the ClusterIP config? Or I need to configure Google Cloud NAT? Or I need to change other things?
Thanks
EDIT: I want to connect to cassandra from an external IP, from anyplace on the internet
EDIT2: I guess that the solution is to use LoadBalance instead of ClusterIP, but when I use LoadBalance, the Cassandra nodes can't find the seed node. Then I sill using ClusterIP=None to Cassandra cluster, and I created another POD with type=LoadBalance to connect to Cassandra and to have connections to exterior. And now it's working :)
If by "expose" you mean ability to reach your service endpoints without cluster IP , then just use selector in your headless service, i.e.
apiVersion: v1
kind: Service
metadata:
name: cassandra
spec:
clusterIP: None
selector:
app: cassandra
ports:
- port: 80
targetPort: 80
For more details refer to documentation
Otherwise, if you want to expose your deployments outside of the cluster, you won't be able to do it with headless service.
ClusterIP services are not exposed outside of the Kubernetes cluster. Perhaps you mean to use a NodePort or LoadBalancer service instead?
If you want to expose the service externally, you will need a service that is ClusterIP backed whether that be a NodePort or LoadBalancer; even if you use ingress, you will need to back it up with a ClusterIP service at the very least.
The ClusterIP is only internal and provides the Kubebernetes cluster a fixed endpoint to reference your deployment/pod internally. The simplest method to expose your services is to use a NodePort, in which case your service will take on the IP of the node externally with a high port number (30000+). On GCP, if you define a load-balancer, you will be given an external IP, and the traffic will be forwarded in order to your pods in the stateful sets. If you use an ingress, your external IP will be that of your ingress, and the packet forwarding to your services will be done based on the request URL (ie. you can have multiple FQDNs mapped to a single external IP in your DNS).
"Headless" services are mainly used to decouple your design from Kubernetes. The assumption is that you will be doing your own service discovery, and I don't believe that is a good use case for your application.
Hope this helps!

Accessing a webpage hosting on a pod

I have deployment that hosts a website on port 9001 and a service attached to it. I want to allow anyone (from outside cluster) to be able to connect to that site.
Any help would be appreciated.
I want to allow anyone (from outside cluster) to be able to connect to that site
There are many ways to do this using kubernetes services to expose port 9001 of the website to the outside world:
Service type LoadBalancer if you have an external, cloud-provider's load-balancer.
ExternalIPs. The website can be hit at ExternalIP:Port.
Service type NodePort if the cluster's nodes are reachable from the users. The website can be hit at NodeIP:NodePort.
Ingress controller and ingress resource.
As you wrote that this is not a cloud deployment, you need to consider how to correctly expose this to the world in a decent fashion. First and formost, create a NodePort type service for your deployment. With this, your nodes will expose that service on a high port.
Depending on your network, at this point you either need to configure a loadbalancer in your network to forward traffic for some IP:80 to your node(s) high NodePort, or for example deploy HAProxy in a DeamonSet with hostNetwork: true that will proxy 80 to your NodePort.
A bit more complexity can be added by deployment of Nginx IngressController (exposed as above) and use of Ingress to make the Ingress Controller expose all your services without the need to fiddle with NodePort/LB/HAProxy for each of them individualy any more.

I just want to run a simple app in Kubernetes

I have a docker image that serves a simple static web page.
I have a working Kubernetes cluster of 4 nodes (physical servers not in the cloud anywhere).
I want to run that docker image on 2 of the 4 Kubernetes nodes and have it be accessible to the world outside the cluster and load balanced and have it move it to another node if one dies.
Do I need to make a pod then a replication controller then a kube proxy something?
Or do I need to just make a replication controller and expose it somehow?
Do I need to make service?
I don't need help with how to make any of those things, that seems well documented, but what I can't tell what I need to make.
What you need is to expose your service (that consists of pods which are run/scaled/restarted by your replication controller). Using deployment instead of replication controller has additional benefits (mainly for updating the app).
If you are on bare metal then you probably wish to expose your service via type: NodePort - so every node in your cluster will open a static port that routes traffic to pods.
You can then either point your load balancer to that nodes on that port, or make a DNS entry with all Kubernetes nodes.
Docs: http://kubernetes.io/docs/user-guide/quick-start/
You'll need:
1) A load balancer on one of your nodes in your cluster, that is a reverse proxy Pod like nginx to proxy the traffic to an upstream.
This Pod will need to be exposed to the outside using hostPort like
ports:
- containerPort: 80
hostPort: 80
name: http
- containerPort: 443
hostPort: 443
name: https
2) A Service that will use the web server selector as target.
3) Set the Service name (which will resolve to the Service IP) as the upstream in nginx config
4) Deploy your web server Pods, which will have the selector to be targeted by the Service.
You might also want to look at External IP for the Service
http://kubernetes.io/docs/user-guide/services/#external-ips
but I personally never managed to get that working on my bare metal cluster.