In Part 3 of the “Migrating a Django app to Kubernetes” I’ve written a Helm chart to run a Django application and a few corollary services on Kubernetes, but aside from port-forwarding, it’s still stuck “inside” the box.
Time to let it out.
Kubernetes keeps applications inside of itself by default, there are a few different ways to expose them.
LoadBalancer
Load Balancers expose applications with their own IP.
Unfortunately most loadbalancers are external services that run in the cloud, and it seems like “on-prem” Kubernetes clusters are kinda B-class citizens.
Luckily, we have MetalLb
When installed as a microk8s addon, it prompts to give it one or more address ranges to assign IPs from.
I gave it the range of 192.168.1.50-192.168.1.70, and the install script did the rest.
Let’s start by exposing the dashboard on its own address.
apiVersion: v1 metadata: name: kube-dash-lb namespace: kube-system kind: Service spec: ports: - port: 443 protocol: TCP targetPort: 8443 selector: k8s-app: kubernetes-dashboard type: LoadBalancer
Apply with kubectl apply -f <file>
, then check the service status with kubectl -n kube-system get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dash-lb LoadBalancer 10.152.183.63 192.168.1.52 443:30114/TCP 10s
Now our dashboard is exposed on https://192.168.1.52
This is nice and everything, but what if we don’t have as many addresses as the services we want to expose? Afterall, virtual hosts have been a thing since at least 1999
Ingress
An API object that manages external access to the services in a cluster, typically HTTP.
Kubernetes documentation
Ingress may provide load balancing, SSL termination and name-based virtual hosting.
Unfortunately Kubernetes does not have a native, standard Ingress, so we’re going to need an:
Ingress controller
In this case we’re going to use Træfik Proxy, because I have previous experience with it on Docker. There’s a number of other controllers that you can use instead of the one I’m going with.
Installation is just another Helm chart, for a simple matter of keeping things organised we’ll deploy it in its own namespace
microk8s kubectl create namespace traefik
microk8s helm repo add traefik https://traefik.github.io/charts
microk8s helm install -n traefik traefik traefik/traefik
Check that it’s assigned an IP address from the LoadBalancer
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
traefik LoadBalancer 10.152.183.53 192.168.1.53 443:32020/TCP 13m
And then let’s re-deploy our Helm chart after setting
ingress: enabled: true hosts: - host: metamonitor.k8s paths: - path: / pathType: ImplementationSpecific
Moments later, Kubernetes is happy
And so is Traefik, on the dashboard
After adding “metamonitor.k8s” to our DNS server (or adding it to localhost file) we can finally visit the page
To recap:
- a Container runs a process
- a Pod is a set of Containers
- managed by a ReplicaSet
- spawned by a Deployment
- a Service matches a certain subset of Pods and creates a hostname inside the cluster
- while an Ingress is an external-facing service-equivalent served by an Ingress Controller
- an Ingress Controller is comprised of one or more Pods interacting with the Kubernetes API to discover Ingresses
- they each expose one or more Services
- which are assigned an IP by a Load Balancer
Makes total sense, right?
…right?