Ingress Nginx

Damit Kubernetes nicht nur Selbstzweck ist, müssen Services installiert werden. Bevor die Services sinnvoll nutzbar werden, ist eine Load-Balancing Lösung notwendig. Entsprechend den Sicherheitsanforderungen sollte jeder Webservice gleich mit TLS laufen, daher bauen wir gleich eine https Lösung.

Secrets

Ein private Key eines Zertifikates ist ein schützenswertes Objekt und findet daher seinen Platz in den Kubernetes Secrets. Die Dateien tls.crt und tls.key können z.B. mit Certbot erstellt werden, dann hat man gleich ein gültiges Serverzertifikat von Let's Encrypt. Zum Testen kann man sich mit

openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout tls.key -out tls.crt -subj "/CN=test.example.com/O=nginxsvc"

ein selbstsigniertes Zertifikat erstellen. Mit

kubectl create secret -n hello-zone tls test.example.com --key tls.key --cert tls.crt

kommt das Zertifikat in die Kubernetes Secrets. Man muss sich dann keine Gedanken mehr darum machen, wie die zuständigen Pods an das Zertifikat kommen, allerdings muss das Secret im richtigen Namespace erstellt werden, sonst findet Nginx das Zertifikat nicht. Für unser Hello World Beispiel wurde daher der dort angelegte Namespace hello-zone angegeben. Das Ergebnis kann man sich mit

kubectl get secret -n hello-zone test.example.com -o wide
NAME TYPE DATA AGE
test.example.com kubernetes.io/tls 2 84s

ansehen, damit liegen das Zertifikat und der private Key an einem sicheren Platz und können für Services verwendet werden.

Namespace

Bevor der Ingress-Loadbalancer installiert wird, sollte dafür aus Sicherheitsgründen ein eigener Namespace angelegt werden. Mit der Datei nginx-namespace.json wird der Namespace definiert:

{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"name": "nginx-ingress-zone",
"labels": {
"name": "nginx-ingress-zone"
}
}
}

Jetzt kann der Namespace mit kubectl create -f nginx-namespace.json aktiviert werden. Der Namespace sollte nun in der Liste erscheinen:

kubectl get namespaces
NAME STATUS AGE
default Active 137m
kube-node-lease Active 137m
kube-public Active 137m
kube-system Active 137m
nginx-ingress-zone Active 4s

Nun aber zum Load-Balancer.

Load Balancer

Unter https://kubernetes.github.io/ingress-nginx/deploy/ wird beschrieben, wie z.B. ein Nginx Ingress-Controller installiert wird. Aus Sicherheitsgründen wird dazu ein eigener Namespace verwendet.

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "minio" chart repository
Update Complete. ⎈Happy Helming!⎈
helm install --namespace nginx-ingress-zone my-nginx-release ingress-nginx/ingress-nginx | tee ingress-nginx.log
NAME: my-nginx-release
LAST DEPLOYED: Thu Dec 10 10:34:58 2020
NAMESPACE: nginx-ingress-zone
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace default get services -o wide -w my-release-ingress-nginx-controller'

An example Ingress that makes use of the controller:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls

If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:

apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls



In der Ausgabe sieht man direkt, dass der neu erstellte Namespace verwendet wurde. Die Ausgabe liefert auch gleich eine Anleitung für das weitere Vorgehen mit. Aus Redundanzgründen sollte der Ingress-Nginx mindestens mit zwei Replicas laufen. Das wird mit kubectl scale deployment -n nginx-ingress-zone my-nginx-release-ingress-nginx-controller --replicas=2 gemacht. Mit

kubectl get svc -n nginx-ingress-zone
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-release-ingress-nginx-controller LoadBalancer 10.103.79.91 172.17.1.0 80:31806/TCP,443:32718/TCP 65m
my-nginx-release-ingress-nginx-controller-admission ClusterIP 10.98.231.77 <none> 443/TCP 65m

kann man sehen, dass der Nginx im Namespace nginx-ingress-zone läuft. Die External-IP wurde von MetalLB erstellt und zugewiesen.

Debugging

Erste Anlaufstelle für Probleme mit dem Nginx ist das Lögfile. Zunächst muss der Pod des Nginx ermittelt werden mit kubectl get pods -n nginx-ingress-zone. Mit kubectl logs -n nginx-ingress-zone my-nginx-release-ingress-nginx-controller-<pod id> -f kann man sich das Logfile ansehen.