k3s ist eine schlanke Variante zum vollen Kubernetes (k8s) Stack. Der k3s Cluster lässt sich daher mit wenigen Schritten installieren und einrichten. Dieses Tutorial beschreibt dir wie du den k3s Cluster installieren kannst.
Voraussetzungen
Für dieses Tutorial gibt es ein paar Voraussetzungen:
Mindestens zwei Linux Systeme (egal ob VM oder Raspberry Pi) mit mind. 2 Kernen und 1 GB RAM
Grundlegende Kenntnisse von Linux
Die Fähigkeit Tutorials komplett zu lesen (entschuldige den Sarkasmus)
Vorbereitungen
Solltest du eine VM verwenden, musst du nichts weiter vorbereiten als dein System auf den aktuellen Stand zu patchen. Zudem wäre es empfehlenswert, wenn du feste IP-Adressen verwenden würdest. Andernfalls kannst du natürlich auch die Kommunikation via DNS machen, dann benötigst du aber ein zuverlässiges DNS!
Solltest du allerdings einen Raspberry Pi verwenden müssen wir noch etwas am boot Prozess einstellen. Und zwar erweitern wir die cmdline.txt Datei. Diese liegt bei Rasbian und Ubuntu (ja auch das gibts für den RPi) unter verschiedenen Orten:
Rasbian
<pre class="wp-block-code">```
sudo vim /boot/cmdline.txt
Ubuntu
class="wp-block-code">``` sudo vim /boot/firmware/cmdline.txt ``` ``` Am Ende der Zeile fügen wir noch folgendes ein ```class="wp-block-code">``` cgroup_enable=1 cgroup_memory=1 cgroup_enable=memory ``` ``` Solltest du das bei den Raspberry Pis nicht tun, wird k3s nicht starten! ## k3s Cluster installieren ### Master installieren Fangen wir mir dem Master an. Dieser lässt sich quasi mit copy & paste von der k3s.io Webseite kopieren. Allerdings wollten wir ja die Installation ein wenig anpassen. Wir verwenden z. B. MetalLB als Cluster Load Balancer um IP Adressen aus dem normalen Netzbereich unseres Netzwerkes zu verwenden. Zudem bin ich ein Fan von Traefik. Zwar kommt der k3s Cluster im Standard schon mit Traefik daher, allerdings wollen wir die Funktion erweitern. Entsprechend müssen wir die Installation ein wenig abändern. ```class="wp-block-code">``` curl -sfL https://get.k3s.io | sh -s - --disable traefik --disable servicelb ``` ``` Nach ein paar Augenblicken sollte der Cluster soweit sein. Wir kontrollieren das mit ```class="wp-block-code">``` kubectl get nodes ``` ``` Und sollten eine Node sehen die den Status ready hat. ### Agenten hinzufügen Diesen Schritt wiederholst du entsprechend so oft wie viele Agenten du zu dem Cluster hinzufügen möchtest. Allerdings benötigen wir als erstes deinen Token um die verschlüsselte Kommunikation zu erlauben. Diesen lesen wir wie folgt aus ```class="wp-block-code">``` cat /var/lib/rancher/k3s/server/node-token ``` ``` Es erscheint eine lange Zeile aus Buchstaben und Zahlen z. B. ```class="wp-block-code">``` K10c8c26950c31536167a7a38f11979060f977cf33cfe10a5e7b130e057a8e1d4df::server:de0d941e347301d8ac112e4c2ef2826b ``` ``` Natürlich sieht das bei dir anders aus, daher ist ein einfaches kopieren aller Befehle in diesem Tutorial **nicht** möglich. Nun verbinden wir die Agenten mit dem Master ```class="wp-block-code">``` curl -sfL https://get.k3s.io | K3S_URL=https://{IP-Server}:6443 K3S_TOKEN={Token} sh - ``` ``` Passe bitte die zwei Variablen in dem Befehl an deine Gegebenheiten an. Auf dem Master führen wir nun den Befehl ```class="wp-block-code">``` kubectl get nodes --watch ``` ``` aus. Nach ein paar Augenblicken sollte der Agent dort erscheinen und nach ein paar weiteren in den Status Ready wechseln. Da jetzt der Cluster läuft, können wir uns um MetalLB kümmern. ## MetalLB installieren MetalLB ist wie gesagt ein LoadBalancer um Anfragen über den Cluster zu verteilen. Wir werden MetalLB als Layer2 LB verwenden. Alternativen für Menschen mit mehr Netzwerkkenntnissen wären z. B. noch BGP. Layer2 reicht aber für das Homelab und benötigt keine spezielle Konfiguration an Firewall und/oder Switchen. Die Version des Programmes ändert sich natürlich fortlaufend. Entsprechend ist zu beachten, dass du in den Befehlen die Version auf den neusten Stand bringst. Am besten ist, du wirfst immer vorher ein Blick in die offizielle [Dokumentation](https://metallb.universe.tf/installation/#installation-by-manifest). ```class="wp-block-code">``` kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/namespace.yaml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.5/manifests/metallb.yaml # On first install only kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" ``` ``` Ein paar Sekunden später ist die Grundarbeit erledigt. Jetzt legen wir noch den IP-Bereich fest, den MetalLB zur Verfügung hat. Dazu erstellen wir uns eine kleine Datei ```class="wp-block-code">``` vim ConfigMap.yaml ``` ``` und fügen folgenden Inhalt ein ```class="wp-block-code">``` --- apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: configdata: config: | address-pools: - name: default protocol: layer2 addresses: - 192.168.10.50-192.168.10.59 ``` ``` Den IP-Bereich unten passt du bitte so an, dass er bei dir passt! Last but not leased benötigen wir noch einen reverse proxy. Wie immer bei mir: Traefik. ## Traefik installieren Für Traefik verwenden wir zwei sogenannte Manifest Dateien. Erste Datei: ```class="wp-block-code">``` vim CustomRessourceDefinition.yaml ``` ``` Und da rein kommt folgender langer Inhalt ```class="wp-block-code">``` --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: ingressroutes.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: IngressRoute plural: ingressroutes singular: ingressroute scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: middlewares.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: Middleware plural: middlewares singular: middleware scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: ingressroutetcps.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: IngressRouteTCP plural: ingressroutetcps singular: ingressroutetcp scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: ingressrouteudps.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: IngressRouteUDP plural: ingressrouteudps singular: ingressrouteudp scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: tlsoptions.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: TLSOption plural: tlsoptions singular: tlsoption scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: tlsstores.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: TLSStore plural: tlsstores singular: tlsstore scope: Namespaced --- apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: name: traefikservices.traefik.containo.us spec: group: traefik.containo.us version: v1alpha1 names: kind: TraefikService plural: traefikservices singular: traefikservice scope: Namespaced --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress-controller rules: - api Groups: - "" resources: - services - endpoints - secrets verbs: - get - list - watch - apiGroups: - extensions resources: - ingresses verbs: - get - list - watch - apiGroups: - extensions resources: - ingresses/status verbs: - update - apiGroups: - traefik.containo.us resources: - middlewares - ingressroutes - traefikservices - ingressroutetcps - ingressrouteudps - tlsoptions - tlsstores verbs: - get - list - watch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik-ingress-controller subjects: - kind: ServiceAccount name: traefik-ingress-controller namespace: default ``` ``` Hiermit werden alle benötigen Clusterweiten Ressourcen und Abhängigkeiten eingerichtet. Anschließend brauchen wir natürlich noch den Container selbst. ```class="wp-block-code">``` vim Deployment.yaml ``` ``` mit folgendem Inhalt ```class="wp-block-code">``` --- apiVersion: v1 kind: Service metadata: name: traefik spec: ports: - protocol: TCP name: web port: 80 - protocol: TCP name: admin port: 8080 - protocol: TCP name: websecure port: 443 type: LoadBalancer selector: app: traefik --- apiVersion: v1 kind: ServiceAccount metadata: namespace: kube-system name: traefik-ingress-controller --- apiVersion: apps/v1 kind: Deployment metadata: namespace: kube-system name: traefik labels: app: traefik spec: replicas: 1 selector: matchLabels: app: traefik template: metadata: labels: app: traefik spec: serviceAccountName: traefik-ingress-controller containers: - name: traefik image: traefik:v2.3 args: - --api.insecure - --accesslog - --entrypoints.web.Address=:80 - --entrypoints.websecure.Address=:443 - --providers.kubernetescrd - --certificatesresolvers.myresolver.acme.tlschallenge - [email protected] - --certificatesresolvers.myresolver.acme.storage=acme.json ports: - name: web containerPort: 80 - name: websecure containerPort: 443 - name: admin containerPort: 8080 ``` ``` Nach kurzer Zeit sollte der Container auch erscheinen und den Status Ready bekommen ```class="wp-block-code">``` kubectl get pods --watch ``` ``` Als letztes kontrollieren wir noch ob Traefik auch eine IP-Adresse aus dem LoadBalancer Bereich erhalten hat ```class="wp-block-code">``` kubectl get svc ``` ``` Hier sollten wir eine Zeile ähnlich zu dieser haben ```
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEtraefik LoadBalancer 10.43.43.165 192.168.10.50 80:32049/TCP,8080:31750/TCP,443:31764/TCP 18h
```
```
Jetzt kannst du beginnen entsprechende Workload auf deinen Cluster zu bringen. Allerdings derzeit nur mit lokalem Storage. In weiteren Beiträgen werde ich noch Storagemöglichkeiten beschreiben.