Why Services Are Not the Best Fit for External Access?
In this lesson, we will discover why services are not the best fit for enabling external access to the applications.
Only services won’t suffice#
We cannot explore solutions before we know what the problems are. Therefore, we’ll re-create a few objects using the knowledge we already gained. That will let us see whether Kubernetes Services satisfy all the needs users of our applications might have. Or, to be more explicit, we’ll explore which features we’re missing when making our applications accessible to users.
We already discussed that it is a bad practice to publish fixed ports through Services. That method is likely to result in conflicts or, at the very least, create the additional burden of carefully keeping track of which port belongs to which Service. We already discarded that option before, and we won’t change our minds now.
The output of the get
command is as follows.
As you can see, these are the same Services and Deployments we previously created.
Before we move on, we should wait until all the Pods are up and running.
The output is as follows.
If, in your case, some of the Pods are not yet running, please wait a few moments and re-execute the kubectl get pods
command. We’ll continue once they’re ready.
Access through services#
One obvious way to access the applications is through Services. Since the service go-demo-2-api
in go-demo-2-deploy.yml
is listening on port 8080
while the platform is listening on port 3000 thus we are binding the port while calling the service. We used that information to send a request.
The output of the curl
command is as follows.
The application responded with the status code 200
thus confirming that the Service indeed forwards the requests.
While publishing a random, or even a hard-coded port of a single application might not be so bad, if we’d apply the same principle to more applications, the user experience would be horrible. To make the point a bit clearer, we’ll deploy another application.
This application follows similar logic to the first. From the latter command, we can see that it contains a Deployment and a Service. The details are of no importance since the YAML definition is very similar to those we used before. What matters is that now we have two applications running inside the cluster.
Understanding the process#
Let’s check whether the new application is indeed reachable.
We retrieved the port of the new Service and opened the application in a browser. If you get a page not found error, you might want to wait a bit longer until the containers are pulled, and try again
A simplified flow of requests is depicted in the below-given illustration.
A user sends a request to one of the nodes of the cluster. That request is received by a Service and load balanced to one of the associated Pods. It’s a bit more complicated than that, with iptables, kube DNS, kube proxy, and a few other things involved in the process. We explored them in more detail in the Using Services To Enable Communication Between Pods chapter, and there’s probably no need to go through them all again. For the sake of brevity, the simplified diagram should do.
We cannot expect our users to know specific ports behind each of those applications. Even with only two, that would not be very user-friendly. If that number would rise to tens or even hundreds of applications, our business would be very short-lived.
What we need is a way to make all services accessible through standard HTTP (80
) or HTTPS (443
) ports. Kubernetes Services alone cannot get us there. We need more.
The solution#
What we need is to grant access to our services on predefined paths and domains. Our go-demo-2
service could be distinguished from others through the base path /demo
. Similarly, the books application could be reachable through the devopstoolkitseries.com
domain. If we could accomplish that, we could access them with the commands as follows.
The request received the default backend - 404
response. There is no process listening on port 80
, so this outcome is not a surprise. We could have changed one of the Services to publish the fixed port 80
instead assigning a random one. Still, that would provide access only to one of the two applications.
We often want to associate each application with a different domain or sub-domain. Outside the examples we’re running, the books application is accessible through the devopstoolkitseries.com domain. Since access to the domain is not feasible, we’ll simulate it by adding the domain to the Host
header.
The command that should verify whether the application running inside our cluster is accessible through the devopstoolkitseries.com
domain is as follows.
As expected, the request is still refused.
SSL certificates#
Last, but not the least, we should be able to make some, if not all, applications (partly) secure by enabling HTTPS access. That means that we should have a place to store our SSL certificates. We could put them inside our applications, but that would only increase the operational complexity. Instead, we should aim towards SSL offloading somewhere between clients and the applications, and it should come as no surprise that Kubernetes has a solution for all these.
Try it yourself#
A list of all the commands used in the lesson is given below.
You can practice the commands in the following code playground by pressing the Run button and waiting for the cluster to set up.
/
- go-demo-2-deploy.yml
Troubleshooting with minikube
#
For deploying the services and running API on a local machine using minikube
, use the following code. Here IP
will retrieve the IP of the minikube
virtual machine while PORT
will get the nodePort
from the YAML file. The curl
command will send an HTTP request to the service.