All the code for this chapter (and other chapters) is available at https://github.com/param108/kubernetes101 check the directory 018
In an earlier post we saw how we could connect a port on a node to a port on a pod using the containers.ports.hostPort
.
While this will always work, its not a good way of doing this. The reason is that the pod maybe rescheduled on some other node later and then it wont be accessible on the old node’s ip address any more.
Enter Ingress
One of the ways you can get a stable ip address to external world is to use an Ingress.
An ingress is always complemented by an IngressController which does the actual work of load balancing and terminating https/https protocols.
Controller Pattern
The Controller Pattern describes a component that watches the state of the system and pushes it into the direction you want.
A good example of a controller would be a thermostat. It measures the temperature of the ambient air and if it is below a configured value, it starts a heating process and stops it when the temperature crosses the specified value.
Ingress Controller
This controller watches for any resources of type Ingress and when one is created, it creates the necessary load balancer pods with necessary configurations to support that ingress.
In the real world, these controllers are usually already created along with the control-plane. You usually just create Ingress objects and leave the IngressController to the service provider.
This is unfortunately not the case for Minikube and Kind. We need to set it up on our own.
Kind IngressController setup
Instead of repeating this, the instuctions for Kind are available on the website directly. For now just install the nginx IngressController.
Notes:
- Make sure nothing else is already listening on 80/443. Stop httpd/apache if there is one.
- Dont apply the section
Using Ingress
Create Web components
Do the following commands from the repository directory 018
$ cd 018
$ make docker
...
...
$ docker tag web:latest localhost:5000/web:latest
$ docker push localhost:5000/web:latest
# create the ingress
$ kubectl apply -f ingress.yaml
# enter the kind directory for kind specific configuration.
$ cd kind
# create the web pods
$ kubectl apply -f webpod1.yaml
$ kubectl apply -f webpod2.yaml
# create the services
$ kubectl apply -f service1.yaml
$ kubectl apply -f service2.yaml
Lets look at the ingress config a bit
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /ping
spec:
rules:
- http:
paths:
- path: /foo
backend:
serviceName: web-pod1
servicePort: 80
- path: /bar
backend:
serviceName: web-pod2
servicePort: 80
There is one optional parameter we have missed that is hostname
. If you specify hostname, only requests to <hostname>/
will be accepted.
Also note that this is a list, you can have multiple hostnames or multiple http blocks and route to different services appropriately.
The annotation here nginx.ingress.kubernetes.io/rewrite-target: /ping
tells the IngressController that whatever url you get, rewrite it as /ping
which is what the pods listen for.
When all this is setup, you should be able to see
$ curl localhost/foo
<html>ok</html>
Minikube IngressController setup
(we will only deal with nginx controller for now, which is the default for Minikube as well.)
minikube addons enable ingress
This should create the ingress-controller. The rest of the commands should be similar. Try it out and let me know the issues you encounter.
Learnings
Use an ingress to provide a stable path into the cluster.
To create ingress you need to have an IngressController ready for you. Most service providers provide you a default IngressController. If you want anything special you need to create it yourself.
Ingress allows you to route different URLs to different backend services.
Annotations help you configure the LoadBalancer created by the Controller (Nginx and Contour are the common ones).
Conclusion
Now we have covered the basic components of a web-service in kubernetes – i.e. Ingress, Services, Pods.
The final piece of the puzzle then is persistence of some sort. As pods are ephemeral, we need to be sure that data stored (if any) is persisted. To do this we look at persistent volumes.