K3D Traefik

Wenn man mit K3D einen neuen Cluster anlegt, dann wird Treafik V1 per Default über Helm anstatt Nginx ausgerollt. Das ist oft nicht von Relevanz, aber einige Anwendung setzen für den Betrieb den NginX als Ingress Controler voraus.

K3D ohne Traefik

Man kann K3S –k3s-server-arg ‘–no-deploy=traefik’ nun K3S veranlassen Traefik nicht auszurollen, um NginX als Ingress Controller zu installieren.

k3d create cluster demo --k3s-server-arg '--no-deploy=traefik' 

Bug in K3D

Es befindet sich in Bug in K3D, sodass der Parameter –no-deploy=traefik an K3S nicht korrekt übergeben wird.

Fehler wurde behoben mit K3D >=4.1.1 siehe https://github.com/rancher/k3d/issues/482

Installation NginX Ingress Controller

K3S schaut beim Start in dem Verzeichnis /var/lib/rancher/k3s/server/manifests/ nach Manifesten. Man kann also hier das CRD für NginX ablegen und das führt. Mehr dazu unter https://rancher.com/docs/k3s/latest/en/helm/.

apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: ingress-controller-nginx
  namespace: kube-system
spec:
  repo: https://kubernetes.github.io/ingress-nginx
  chart: ingress-nginx
  version: 3.7.1
  targetNamespace: kube-system

Volume mappen

Jetzt muss man beim Start von dem K3D Cluster den Parameter volume übergeben, sodass die Datei helm-ingress-nginx.yaml in den Container in den Pfad gemappt wird.

volume "$(pwd)/helm-ingress-nginx.yaml:/var/lib/rancher/k3s/server/manifests/helm-ingress-nginx.yaml"

Damit wird beim Start des Clusters nun NginX als Ingress Controller automatisch deployt.

K3D

In der aktuellen Version von K3D wird in K3S CoreDNS für die Namesauflösung verwendet. Leider ist der Upstream Nameserver auf 8.8.8.8 voreingestellt, sodass es aus den Containern zu Problemen kommen kann, wenn man einen eigenen DNS hat und den für die Namensauflösung der Ingresses in dem Cluster sorgt.

So kann ein Ingress aus einem anderen POD heraus nicht über die Ingress URL aufgerufen werden.

Konfiguration des CoreDNS

Die Konfiguration erfogt über die Datei Corefile im Namespace kube-system.

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        hosts /etc/coredns/NodeHosts {
          ttl 60
          reload 15s
          fallthrough
        }
        prometheus :9153
        forward . 192.168.2.1
        cache 30
        loop
        reload
        loadbalance
    }

Hier ist die Zeile mit forward . 192.168.2.1 Interessant. Diese bestimmt den Upstream DNS Server für CoreDNS. Hier muss also der lokale DNS eingetragen werden, dann kann man das Manifest anwenden und der DNS ist umkonfiguriert. Dann sollte die Namensauflösung in den Containern funktionieren.

In einem K3D Cluster das Kubernetes Dashboard deployen

Hat man einen K3D Cluster aufgesetzt, dann liegt es gerade in den Anfängen nahe das Dashboard zu installieren. Für das Kubernetes Dashboard gibt es sogar ein Helm Chart.

Die Installation mit Helm ist ja an und für sich nicht schwierig, nur wird man nach der Installation eine Überraschung erleben. Folgt man der Anleitung:

# Add kubernetes-dashboard repository
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
# Deploy a Helm Release named "my-release" using the kubernetes-dashboard chart
helm install kubernetes-dashboard/kubernetes-dashboard --name my-release

Nach der Installation wird man anders als gedacht, von einem freundlichen internal server error empfangen.

Ingress

Der Ingress-Controler steuert das Routing anhand der vorhandenen Host Informationen im Header. Bei K3S/K3D wird implitziet Traefik v1.7 installiert.

Diese sorg für das genannte Problem und daher müssen wir ein paar Änderungen vornehmen, damit wir das Dashboard mit dem K3D Cluster zum laufen bringen.

Variante 1

Man übergibt direkt in den ingress.annotations die ingress.class=traefik und setzt den Host direkt.

--set ingress.annotations."kubernetes\.io/ingress\.class"=traefik \
--set ingress.enabled=true \
--set ingress.hosts[0]=dashboard.k3d.duckdns.org

Variante 2

Bei der Variante 2 wird das Ingress in dem Helm Chart nicht genutzt und das Ingress klassisch als Kubernetes Manifest gesetzt.

Ingress in dem Helm Chart deaktivieren

Wie bereits angesprochen, müssen wir zunächst das Ingress in dem Helm Chart deaktivieren. Das geschied über den Parameter **–set ingress.enabled=false **

 --set ingress.enabled=false

Traefik Ingress per Kubernetes Manifest

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  labels:
    name: kubernetes-dashboard 
  name: kubernetes-dashboard-secure
  namespace: default
  annotations:
   kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: dashboard.k3d.duckdns.org
    http:
      paths:
      - backend:
          serviceName: dashboard-kubernetes-dashboard
          servicePort: 8080

Das Skript create_cluster_admin.sh

Das Skript create_cluster_admin.sh verwende ich, um einen Service Account mit der Rolle cluster-admin.

create_cluster_admin dashboard

Installation

Insgesamt ergeben sich nun daraus folgende Installationsschritte.

# add repo
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/

# add SA for Dashboard
create_cluster_admin.sh dashboard

# install chart
helm install dashboard kubernetes-dashboard/kubernetes-dashboard --set protocolHttp=true --set metricsScraper.enabled=true --set service.externalPort=8080 --set serviceAccount.name=dashboard --set serviceAccount.create=false

# set traefik ingress
kubectl apply -f ./ingress.yaml

KeyCloak mit WebAuthn

Ziel dieser Reihe soll es werden Anwendungen über WebAuthn zu schützen. Dazu wird ein K3S Cluster mit K3D aufgesetzt. Diese soll über .cluster.local erreichbar sein.

  • Im Ersten Teil beschäftige ich mich mit der Installation einer KeyCloak Instanz in einem K3S Cluster.

  • Im zweiten Teil wird die Demoanwendung (Gitea) deployt

  • Im dritte Teil geht es um die Konfiguration von KeyCloak, sodass die Anwendung von WebAuthn gescchützt wird

K3D Setup

Um den Cluster aufzusetzen werde ich K3D verwenden.

K3D installieren

Die Installation habe ich für Manjaro/Arch Linux bereits in dem Artikel K3D Cluster ausfsetzen beschrieben. Anmerkung: Die aktuelle Version kann nun mit yay bereits aus AUR gezogen werden.

K3D Cluster erstellen

Für diese Reihe erstelle ich einen kleinen Demo Cluster mit 2 Knoten und öffne den Port 8080 für den LoadBalancer. D.h. der NginX Reverse Proxy muss später auf den Host und Port 8080 verweisen, so dass die Anfragen vom KeyCloak dann beantwortet werden können.

k3d cluster create demo -a2 -p 8080:80@loadbalancer -p 8443:443@loadbalancer

Achtung: Die Syntax von K3D hat sich seit Version 3.0.0 geändert und folgt nun den anderen K8S Anwendungen, in dem es Nomen und Verb als Parameter verlangt. Bsp: aus k3d create cluster wurde nun k3d cluster create.

Namespace

Wie immer sollte mna einen eigenen Namespace für die Trennung der Anwendung verwenden. Diesen legen wir zuerst mit:

k create namespace keycloak

an.

Hinweis: K ist bei mir immer ein Alias für kubectl.

Self Signed Certificate ausstellen

Installation Cert-Manager

Die Installation von Cert-Manager wird hier beschrieben.

Selbst Signiertes Zertifikat ausstellen

Zunächst müssen wir ein Manifest erstellen, das einen Issuer und ein Certificate beschreibt. Die Domain wird hier auf *.clouster.local festgelegt.

apiVersion: cert-manager.io/v1alpha2 
kind: Issuer
metadata:
   name: selfsigned-issuer
spec:
   selfSigned: {}

---

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
   name: first-tls
spec:
   secretName: first-tls
   dnsNames:
   - "*.cluster.local"
   issuerRef:
     name: selfsigned-issuer

Jetzt muss das Manifest angewendet werden und der Cert-Manager erstellt für uns das selbst signierte Zertifikat, welches wir in dem Ingress später referenzieren werden.

k apply -n keycloak -f keycloak-cert.yaml

Überprüfung der Ausstellung

Ein paar Schnelltests geben auskunft über die erfolgreiche Erstellung der Zertifikate:

# Zertifikat überprüfen
k -n keycloak get certificate
# Secret überprüfen
k -n keycloak get secret first-tls

Nun zum Abschluss noch mit OpenSSL überprüfen…

openssl x509 -in <(kubectl -n keycloak get secret first-tls -o jsonpath='{.data.tls\.crt}' | base64 -d) -text -noout

…in der Ausgabe erhält man dann die Informationen…

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2e:df:ae:86:5c:27:f9:25:bf:77:ca:d1:7a:3a:48:c6
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: 
        Validity
            Not Before: Sep  2 08:14:52 2020 GMT
            Not After : Dec  1 08:14:52 2020 GMT
        Subject: 
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c5:e0:f9:be:a6:b9:41:cb:38:e9:11:57:0a:1b:
                    b5:2b:c2:7e:78:87:5f:43:dc:22:c3:7d:8b:a7:f3:
                    c0:d4:f9:bc:75:4e:96:93:66:17:67:f7:e2:02:96:
                    37:19:90:64:6f:fa:c3:1f:c5:21:80:de:e0:aa:76:
                    12:d6:24:a0:f2:7b:37:14:34:a8:eb:9c:1a:17:b0:
                    4f:d8:a4:9b:3a:51:fe:18:30:3e:81:f5:20:01:85:
                    c1:af:61:cf:2e:30:fd:42:3c:00:c0:28:f9:60:37:
                    84:80:84:85:54:33:6c:0f:cb:c2:7e:5f:50:ee:82:
                    a1:4a:35:c3:5b:fe:8a:47:21:75:c5:0e:03:08:f2:
                    2d:fa:98:e8:d6:16:d6:fb:af:97:d8:86:3a:c6:84:
                    63:5d:bd:f1:1b:72:0f:73:f5:09:33:26:aa:bc:8f:
                    8c:9b:fa:a6:11:53:19:69:33:bc:68:47:c3:74:6a:
                    70:86:c5:19:93:83:cc:9e:07:11:0d:6e:9f:f8:5b:
                    67:d7:d8:ef:ca:37:4e:7c:1b:a2:f5:ee:70:eb:55:
                    2f:86:45:02:b4:4d:6d:9a:1b:20:3b:c4:d5:db:f3:
                    66:8c:22:e1:da:94:c4:e6:20:9f:c4:ff:79:b9:26:
                    b6:ae:d0:8f:f2:45:d5:7d:eb:88:7f:39:36:7d:ef:
                    f6:85
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Alternative Name: critical
                DNS:*.cluster.local
    Signature Algorithm: sha256WithRSAEncryption
         39:b5:cf:d7:08:b1:9d:07:44:ef:79:f3:13:46:11:f9:07:96:
         f3:db:cb:8d:5e:df:14:5f:2f:74:ff:4a:c8:58:af:57:fa:35:
         fb:19:1e:73:af:f5:d2:eb:ec:b9:d1:60:f5:28:c1:39:ba:a1:
         0c:4e:0d:3c:10:83:ba:0f:ef:4f:7a:1c:68:25:3a:3c:bf:de:
         04:24:f0:ca:15:34:6d:66:8f:3b:69:96:fe:b8:03:54:98:a6:
         fe:b8:0f:d4:6f:1b:7a:87:6a:5a:c6:57:ff:62:ee:0f:24:ff:
         e9:e8:e9:b5:4d:ca:ec:27:7c:03:7b:63:2e:ff:4d:3a:c8:5e:
         d8:b4:f5:8a:e8:0c:2c:62:f1:00:c6:4d:fe:cf:45:e2:5b:74:
         55:0a:fe:f7:5a:b4:c0:5a:2c:04:4c:ae:b2:5a:d3:d7:26:ca:
         63:2c:69:2b:81:cd:6e:39:c4:66:5f:67:47:2d:f4:ea:eb:9b:
         31:17:5d:4c:5b:77:26:d4:a4:4c:f1:52:ae:92:84:e9:f4:01:
         7e:f1:f5:cf:1d:54:a5:8c:6b:58:b2:35:b3:44:0d:81:b6:da:
         4e:0b:02:fe:21:21:75:59:53:15:17:67:7e:37:00:59:00:11:
         67:47:4e:5f:0b:1d:c4:1e:4b:5c:d2:80:57:7f:2b:58:01:ba:
         83:fc:c9:ce   

Download Kubernetes Manifest

Wir laden das Manifest keycloak.yaml mit wget runter und modifizieren die Defaultwerte für den Namespace und setzen ein neues Passwort. Der Namespace wird auf den zuvor erstellten Namespace keycloak gesetzt. Das Passwort wird auf 123 gesetzt.

wget -q -O - https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/latest/kubernetes-examples/keycloak.yaml | sed "s/namespace: default/namespace: keycloak/" > keycloak.yaml

Achtung: Username und Passwort sind hier admin. Wer es sicherer mag, der sollte das YAML bearbeiten und die Werte ersetzen.

k apply -n keycloak -f keycloak.yaml   

Das hochfahre der Pods kan mit

watch kubectl -n keycloak get pods

überwacht werden.

Ingress

Da K3S in der Defaulteinstellung Traefik als Ingress Controller verwendet, nutze ich hier nicht die von KeyCloak Team bereitgestelltes Kubernetes Manifest für Ingress.

HTTPS Anfragen für die FQDN keycloak.cluster.local an den Cluster werden werden so an den Service keycloak an Port 8443 weitergeleitet.

apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

---

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: first-tls
spec:
  secretName: first-tls
  dnsNames:
  - "*.cluster.local"
#  - "*.keyclaok"
  issuerRef:
    name: selfsigned-issuer

Hosts Datei Vorbereiten

Damit das Ganze funtkioniert, muss der FQDN keycloak.cluster.local in die /etc/hosts Datei eingetragen werden:

192.168.2.XXX keycloak.cluster.local

Erster Test mit CURL

curl -k https://keycloak.cluster.local:8443
<!--
  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
  ~ and other contributors as indicated by the @author tags.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
    <meta http-equiv="refresh" content="0; url=/auth/" />
    <meta name="robots" content="noindex, nofollow">
    <script type="text/javascript">
        window.location.href = "/auth/"
    </script>
</head>
<body>
    If you are not redirected automatically, follow this <a href='/auth'>link</a>.
</body>
</html>

Aufruf mit dem Browser

Nun kann nach dem ersten erfolgreichen Test der KeyCloak über https://keycloak.cluster.local:8443/auth/ bzw. die Admin-Console über https://keycloak.cluster.local:8443/auth/admin/master/console/ aufgerufen werden. Die Credentials für die Admin-Console sind im Kubernetes Manifest (siehe oben) festgelegt worden.

Standard ist hier Username admin und Passwort admin.

Kubernetes mit Manjaro

Diese Liste wird ständig von mir erweitert und unterliegt daher der Änderung.

Lokale Kubernetes Cluster

Name Beschreibung Homepage
minikube Der Standard um Kubernetes lokal zu testen https://minikube.sigs.k8s.io/docs/
k3s Minimale Kubernetes Cluster basierend auf einem einzigen Executable https://k3s.io/
k3d Mit K3D kann man lokal ein Kubernetes Cluster aus mehreren Nodes innerhalb von Sekunden erzeugen. Intern werden Docker Container mit K3S, um die Nodes zu erzeugen. Es ist zu empfehlen hier auf das Beta der Version 3 zu wechseln. https://github.com/rancher/k3d
k3sup K3sup ist ein Tool um K3S lokal oder per SSH auf einem entfernten Rechner zu installieren. Da k3sup in GO geschrieben ist, besteht es auch nur aus einem Binary und besitzt keien weiteren Abhängigkeiten https://github.com/alexellis/k3sup
k3c https://github.com/rancher/k3c
yay --noconfirm -S minikube k3s-bin rancher-k3d-beta-bin

Kubernetes Tools

Introspektion

Name Beschreibung Homepage
k9s Kommandoszeilentool mit dem man sehr einfach und schnell einen bestehenden Cluster untersuchen kann. Universelles Tool das man mit dem Kubernetes Dashboard für die Konsole vergleichen kann. https://github.com/derailed/k9s
kubespy
kubectx
kubefwd Findet alle Services in einem Namespace und erstellt ein Portforwarding für den Dienst ein und erstellt einen Eintrag in der /etc/hosts Datei, sodass sehr einfach auf die laufenden Dienste zugegriffen werden kann https://github.com/txn2/kubefwd
yay --noconfirm -S kubespy kubectx kubefwd-bin

Logging

Name Beschreibung Homepage
stern Mit Stern kann man die Logausgaben meherer Container in mehreren Pods ausgeben lassen. Für eine gute Unterscheidbarkeit werden die Ausgaben der verschiedenen Container in unterschiedlichen Farben eingefärbt. Dieses erlaubt ein schnelleres Debugging in komplexen Setups https://github.com/wercker/stern
yay --noconfirm -S stern-bin

Development

Name Beschreibung Homepage
tilt Mit Hilfe von einem Autodeployment in ein Kubernetes Cluster, werden Codeänderungen sofort wirksam und es werden Fehler überrsichtlich in einer Web UI dargestellt. https://tilt.dev/
yay -S --noconfirm  tilt-bin

K3D

Ist ein Hilfsmittel um einen K3S Cluster mit Docker innerhalb weniger Sekunden aufzusetzen. Hierbei wird eine Installation von K3S auf dem Host nicht benötigt, da K3S in Docker Containern gestartet wird. Wenn einmal die Docker Images geladen sind und lokal vorliegen, dann lässt sich sogar auf einem älteren Laptop ein Cluster mit mehreren Nodes innerhalb weniger Sekunden starten.

Installation

Die Installation erfolg über ein PKGBUILD, da

pkgname="rancher-k3d-bin"
pkgver=3.0.0b2
_pkgver=3.0.0-beta.2
pkgrel=1
pkgdesc='Little helper to run Rancher Labs k3s in Docker'
arch=('x86_64')
url='https://github.com/rancher/k3d'
license=('MIT')
provides=("k3d")
source=("${pkgname}-${_pkgver}::https://github.com/rancher/k3d/releases/download/v$_pkgver/k3d-linux-amd64")
md5sums=('563d008cf92dbe42afe280b0930a0d79')

package() {
  install -Dm 0755 ${pkgname}-${_pkgver} "$pkgdir/usr/bin/k3d"
}

Die Version 3.0.0 befindet sich aktuell noch in der Entwicklung, aber da sie einige wichtige Änderungen beinhaltet, werde ich hier auf die Beta setzen. Diese scheint aber bereits ausgereift, so dass sie getestet werden kann. Bislang gab es keine Probleme.

Einen Cluster erstellen

Wie bereits beschrieben, lässt sich ein Cluster sehr einfach und schnell starten. K3D benötigt hierzu nur wenige Parameter. Der Cluster soll den Namen Demo erhalten und insgesamt 3 Worker (Nodes) bereitstellen. Zusätzlich wird ein Portmapping eingerichtet, sodass auf die Anwendung von außen zugegriffen werden kann.

k3d create cluster Demo -w 3 -p 8081:80@loadbalancer

Das Portmapping -p auf dem Host Port 8081 wird auf den Container gematched der auf den Nodefilter loadbalancer hört.

Liste der Cluster ausgeben

k3d get cluster

Cluster löschen

k3d delete cluster Demo

Cluster starten und stoppen

$k3d stop cluster Demo
INFO[0000] Stopping cluster 'demo'  

$k3d start cluster Demo
INFO[0000] Starting cluster 'demo'                      
INFO[0000] Starting Node 'k3d-demo-worker-3'            
INFO[0000] Starting Node 'k3d-demo-worker-2'            
INFO[0001] Starting Node 'k3d-demo-worker-1'            
INFO[0001] Starting Node 'k3d-demo-worker-0'            
INFO[0002] Starting Node 'k3d-demo-master-0'            
INFO[0002] Starting Node 'k3d-demo-masterlb'

Die Nodes anzeigen

Eine Liste der Nodes auf dem Cluster kann man sich mit get node anzeigen lassen.

k3d get node