#import "../Helpers/code-snippets.typ": code

== Installation K3s
Der zweite Schritt der Umsetzung unseres Challenge Tasks war, einen K3s Cluster mithilfe der drei Nodes zu bauen. Wir haben uns für K3s entschieden, weil es sehr leichtgewichtig ist und trotzdem alle unsere Anforderungen erfüllt. Ausserdem ist es weit verbreitet und die Installation ist sehr einfach.
=== Vorbereitungen
Zuerst haben wir Ubuntu auf den neusten Stand gebracht:
#code(numbers: true)[```bash
apt update && apt upgrade -y && apt autoremove -y && reboot
```]
Dann haben wir die Uncomplicated Firewall aktiviert und konfiguriert:
#code(numbers: true)[```bash
ufw enable
ufw allow 6443/tcp                  # Kubernetes API Server
ufw allow from 10.42.0.0/16 to any  # Cilium Pod Netzwerk
ufw allow from 10.43.0.0/16 to any  # Cilium Service Netzwerk
ufw allow 2379:2380/tcp             # Etcd
ufw allow 10250/tcp                 # Kubelet
ufw allow 8472/udp                  # Cilium VXLAN
ufw allow 4240/tcp                  # Cilium Cluster Health Checks
ufw allow 4244/tcp                  # Cilium Hubble Server
ufw allow 4245/tcp                  # Cilium Hubble Relay
ufw allow 4250/tcp                  # Cilium Mutual Authentication port
ufw allow 9962/tcp                  # Cilium Agent Prometheus Metrics
ufw allow 9963/tcp                  # Cilium Operator Prometheus Metrics
```]

Als einheitlichen Hostname für die Kubernetes API haben wir `k3s` gewählt. Momentan löst er einfach lokal auf die IP vom ersten Node auf, später hätten wir aber die Möglichkeit, einen Load Balancer davor zu schalten, um die API hochverfügbar zu machen.
#code(numbers: true)[```bash
echo '10.0.10.11 k3s' >> /etc/hosts
```]

=== Konfiguration
Zwecks Nachvollziehbarkeit und Wartbarkeit haben wir die ganze K3s Konfiguration im File `/etc/rancher/k3s/config.yaml` auf den drei VMs vorgenommen:
#figure(
  code(
    numbers: true,
    caption: "config.yml",
  )[```yaml
# Neuen Cluster erstellen (nur auf k3s-01)
cluster-init: true
# Zu kontaktierende Kubernetes API für Cluster Join (nur auf k3s-02 und k3s-03)
server: https://k3s:6443
# Nur der User root kann auf die Kubeconfig zugreifen, Helm würde eine Fehlermeldung anzeigen, wenn die Kubeconfig group-readable oder world-readable ist.
write-kubeconfig-mode: "0600"
# Der API Hostname, den wir in der /etc/hosts Datei eingetragen haben, soll im API Zertifikat als Subject Alternative Name (SAN) eingetragen werden, damit die API auch über den Hostname ohne Zertifikatsfehler erreichbar ist.
tls-san:                        
  - "k3s"
# Der Token, den wir auf k3s-01 generiert haben und k3s-02/k3s-03 verwenden für den Cluster Join.
token: 'supersecret'
# Flannel wird standardmässig installiert, wir verwenden aber die modernere Alternative Cilium, daher wird Flannel deaktiviert.
flannel-backend: none
# ServiceLB wird standardmässig installiert, jedoch bringt Cilium diese Funktionalität schon mit, daher wird ServiceLB deaktiviert.
disable:
- servicelb
# Network Policies und der Kube Proxy können deaktiviert werden, weil Cilium diese Funktionalitäten übernimmt.
disable-network-policy: true
disable-kube-proxy: true
```]
)
=== Installation
Kubernetes benötigt eine ungerade Anzahl >=3 an Master Nodes ("server" in K3s), um ein hochverfügbares Control plane zu gewährleisten. Wir haben uns für 3 Nodes entschieden, um die minimalste Anzahl an Nodes zu verwenden, die ein hochverfügbares Control plane ermöglicht. In der Produktion würde man keinen Workload auf den Master Nodes laufen lassen, sondern nur auf den Worker Nodes. Da wir aber die Anzahl VMs möglichst niedrig halten wollten, haben wir uns für 3 Nodes entschieden, auf denen sowohl Master als auch Worker Rollen laufen. Mit diesem Command wird K3s mit Master und Worker Rolle auf den Nodes installiert:
#code(numbers: true)[```bash
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -
```]
Die Konfiguration aus dem File `/etc/rancher/k3s/config.yaml` wird automatisch miteinbezogen.