[[improve]] Kubernetes ist ein OpenSource System zur Automatisierung der Bereitstellung, Skalierung und Verwaltung von [[Container]]-Anwendungen wie [[Docker]] oder [[Containerd]]. Docker hat ein integriertes Tool (Docker Swarm) zum selben Zweck, Kubernetes kann jedoch das selbe und noch viel mehr und wird ab Werk von Docker unterstützt. Kubernetes ist deklarativ, das bedeutet man beschreibt den gewünschten Endzustand. Ein Pod ist eine Resource eines Replicaset was eine Resourse eines Deployment ist. * Du definierst einen Service (z. B. vom Typ LoadBalancer, ClusterIP oder NodePort). * Der Service hat ein Label-Selector, z. B. app:my-app, der sagt: "Ich leite Traffic an alle Pods mit diesem Label weiter." * Kubernetes erstellt eine virtuelle IP-Adresse (ClusterIP) für den Service. * Der Load Balancer (z. B. AWS ELB, MetalLB, Traefik, NginX, Apache) leitet Traffic an diese IP. * Kubernetes nutzt kube-proxy oder IPVS auf den Nodes, um den Traffic an die richtigen Pods weiterzuleiten, basierend auf den Labels und dem internen Routing. kubectl get pods -n kube-system -o wide # Zusätzlichen Control-Plane joinen # Das gibt dir entweder: einen kubeadm join ...-Befehl (für Worker), oder zwei Zeilen, eine davon mit --control-plane. kubeadm token create --print-join-command kubeadm init phase upload-certs --upload-certs kubeadm join :6443 --token --discovery-token-ca-cert-hash sha256: --control-plane --certificate-key =====Installation===== ====Cluster Reset==== sudo kubeadm reset -f sudo systemctl restart containerd sudo systemctl restart kubelet sudo rm -rf ~/.kube /var/lib/kubelet /var/lib/etcd sudo rm -rf /etc/cni/net.d /var/lib/cni ====Ubuntu 18==== At least 2 cpu's and 2048 MB RAM per node are required. On all nodes * Edit hostname * Edit ''/etc/hosts'' file and add all nodes. * Edit ''/etc/fstab'' and uncomment SWAP partition * Edit ''/etc/initramfs-tools/conf.d/resume'' and uncomment swap uuid * Find swap unit using ''systemctl --type swap'' and mask it using ''systemctl mask xxx.swap''. SWAP must be deactivated! todo: what about fw, selinux? apt update && apt install apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" apt update && apt install -y kubelet kubeadm kubectl docker.io systemctl enable docker Only on master node kubeadm init --apiserver-advertise-address 192.168.0.100 --pod-network-cidr=172.16.0.0/16 # REMEMBER JOIN TOKEN output from last command !!!!!!!!!!!!!!!!! # when done execute as regular user mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # enable network addon sudo kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Only on nodes except master kubeadm join 192.168.0.100:6443 --token zbdvek.v8fnw7hw8xcdxk03 --discovery-token-ca-cert-hash sha256:724601e4cd00fd78312f1fbf3726b688e894fc88f2c25962f478e546a59929c7 API Token vergessen/abgelaufen? kubeadm token create --print-join-command Test on master node kubectl run my-httpd --image=httpd --port=80 kubectl get pods -l app=demo kubectl scale deployment [deployment] --replicas 3 kubectl exec -it my-httpd -- /bin/bash kubectl set image deployment demo nginx=1.9.1 kubectl patch pod my-httpd --patch '{}' kubectl delete pod myhttpd Finally autostart systemctl start kubelet systemctl enable kubelet systemctl start docker systemctl start kubelet ====Ubuntu 24==== # SWAP deaktivieren sudo swapoff -a # aus fstab auskommentieren sudo sed -ri 's/^\s*([^#].*\s+swap\s+)/# \1/' /etc/fstab # Kernel-Module & sysctl richtig setzen echo -e "overlay\nbr_netfilter" | sudo tee /etc/modules-load.d/k8s.conf sudo modprobe overlay sudo modprobe br_netfilter # sysctl cat <<'EOF' | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sudo sysctl --system # Basis-Tools sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gpg # Keyring anlegen und Key importieren sudo mkdir -p -m 755 /etc/apt/keyrings curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg # Repo eintragen (überschreibt ggf. vorhandene kubernetes.list) echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /' \ | sudo tee /etc/apt/sources.list.d/kubernetes.list # Pakete installieren und auf Version pinnen sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl [[Containerd]] als Runtime # containerd installieren sudo apt-get install -y containerd # Standardkonfiguration erzeugen sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml >/dev/null # systemd-cgroups aktivieren (wichtig, damit kubelet + containerd zusammenpassen) sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml # Dienst aktivieren sudo systemctl enable --now containerd Alternativ [[Docker]] als Runtime # Docker-Repo einbinden (offiziell) sudo apt-get remove -y docker.io docker-doc docker-compose podman-docker || true sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ https://download.docker.com/linux/ubuntu noble stable" \ | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl enable --now docker # cri-dockerd (erforderlich, da Docker kein CRI spricht) # (Variante: .deb von GitHub Releases installieren – kurz gefasst) sudo apt-get install -y curl wget VER=$(curl -s https://api.github.com/repos/Mirantis/cri-dockerd/releases/latest | grep -Po '"tag_name": "\K.*?(?=")') wget https://github.com/Mirantis/cri-dockerd/releases/download/${VER}/cri-dockerd_${VER#v}.ubuntu-24.04_amd64.deb sudo apt-get install -y ./cri-dockerd_${VER#v}.ubuntu-24.04_amd64.deb sudo systemctl enable --now cri-docker sudo systemctl enable --now kubelet # Cluster initialisieren sudo kubeadm init --apiserver-advertise-address=10.0.0.1 --pod-network-cidr=10.244.0.0/16 # Config für akt user mkdir -p $HOME/.kube sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc # Netzwerk installieren sudo kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml # Taints checken! # kubectl describe node ubuntu | grep -i Taints -A5 Taints: node-role.kubernetes.io/control-plane:NoSchedule node.kubernetes.io/not-ready:NoSchedule Unschedulable: false Lease: HolderIdentity: ubuntu AcquireTime: # kubectl taint nodes ubuntu node.kubernetes.io/not-ready:NoSchedule- node/ubuntu untainted # Worker Nodes joinen kubeadm join 1.2.3.4:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxx # Netzwerk nochmal f. neue Nodes installieren? kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml # Fortschritt beobachten kubectl -n kube-system get pods -w | egrep -i 'calico|cni' # Defekten Pod entfernen kubectl delete pod -n kube-system calico-node-68mw4 # error: error loading config file "/etc/kubernetes/admin.conf": open /etc/kubernetes/admin.conf: permission denied sudo kubectl get nodes --kubeconfig /etc/kubernetes/admin.conf # Falls "kubectl cluster-info dump" hängt export KUBECONFIG=/etc/kubernetes/admin.conf # 1) Is the API healthy? kubectl get --raw=/healthz ; echo # 2) See overall control-plane endpoints kubectl cluster-info # 3) Nodes status kubectl get nodes -o wide # 4) System pods (this tells you ~everything) kubectl -n kube-system get pods -o wide manuel@ubuntu1:~$ sudo mkdir -p $HOME/.kube manuel@ubuntu1:~$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config manuel@ubuntu1:~$ sudo chown $(id -u):$(id -g) $HOME/.kube/config manuel@ubuntu1:~$ kubectl get nodes error: error loading config file "/etc/kubernetes/admin.conf": open /etc/kubernetes/admin.conf: permission denied manuel@ubuntu1:~$ echo $KUBECONFIG /etc/kubernetes/admin.conf manuel@ubuntu1:~$ unset KUBECONFIG manuel@ubuntu1:~$ kubectl get nodes NAME STATUS ROLES AGE VERSION ubuntu1 Ready control-plane 95m v1.34.2 ubuntu2 Ready 83m v1.34.2 ubuntu3 Ready 42m v1.34.2 manuel@ubuntu1:~$ # Falls du root bist export KUBECONFIG=/etc/kubernetes/admin.conf # optional dauerhaft machen: echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc kubectl cluster-info kubectl cluster-info dump kubectl get nodes kubectl get nodes -o wide kubectl get pods -A kubectl get services -A kubectl get events --sort-by=.metadata.creationTimestamp kubectl get all --all-namespaces kubeadm config print init-defaults kubeadm config print join-defaults kubectl -n kube-system get configmap kubeadm-config -o yaml kubectl -n kube-system get configmap kubeadm-config -o yaml | grep -A5 networking kubeadm token list kubeadm token create --print-join-command --v=5 # Deployment 1 (Node Port) kubectl create deployment demo-nginx --image=nginx:stable kubectl rollout status deploy/demo-nginx # Expose it as NodePort kubectl expose deployment demo-nginx --port=80 --type=NodePort kubectl get svc demo-nginx -o wide # Get the node port and test from the node itself NODEPORT=$(kubectl get svc demo-nginx -o jsonpath='{.spec.ports[0].nodePort}') curl -I http://127.0.0.1:$NODEPORT/ # Quick in-cluster DNS check kubectl run -it --rm dns-test --image=busybox:1.36 --restart=Never -- sh # inside the pod: curl http://demo-nginx.default.svc.cluster.local ## Deployment 2 (Cluster IP) kubectl create deployment hello-k8s --image=nginx:latest # skalieren kubectl scale deployment hello-k8s --replicas=3 # Expose it as Cluster IP kubectl expose deployment hello-k8s --port=80 --target-port=80 --name=hello-k8s-service --type=ClusterIP # Test DNS im Cluster kubectl run test-pod --image=nginx:latest --restart=Never --rm -it -- bash # im Pod curl http://hello-k8s-service # Konfig anzeigen kubectl describe node kubectl describe pod -n # Web Dashboard installieren kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml ====AlmaLinux8==== #!/usr/bin/env bash sudo dnf install -y curl yum-utils sudo tee /etc/yum.repos.d/kubernetes.repo < # containerd installieren sudo dnf install -y containerd # Standardkonfiguration erzeugen sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml >/dev/null # systemd-cgroups aktivieren (wichtig, damit kubelet + containerd zusammenpassen) sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml # Dienst aktivieren sudo systemctl enable --now containerd =====Node entfernen===== # Node als "nicht verfügbar" markieren, Pods werden nicht woanders hin verschoben aber keine neuen mehr auf dem Node platziert kubectl cordon ubuntu3 # Drain markiert den Node als "nicht verfügbar" und verschiebt zusätzlich alle Pods auf andere Nodes. kubectl drain ubuntu3 --ignore-daemonsets --delete-emptydir-data # Re-Activate kubectl uncordon ubuntu3 =====Labels===== Labels sind frei definierbare Key/Value-Paare, die Ressourcen beschreiben. Sie sind essenziell für Selektoren und Gruppierungen. * app=frontend * role=database * env=prod * version=v1 Labels setzen Beim Erstellen eines Pods/Deployments metadata: labels: app: demo tier: backend Für existierende Ressourcen kubectl label pod demo app=demo kubectl get pods --show-labels =====Namespaces===== Namespaces sind logische Bereiche innerhalb eines Kubernetes-Clusters. Sie dienen zur Trennung, Organisation und Rechteverwaltung von Ressourcen. * Ressourcen mit gleichem Namen können in unterschiedlichen Namespaces existieren. * NetworkPolicies, ResourceQuotas und RBAC-Regeln werden oft pro Namespace definiert. * Pods innerhalb desselben Namespaces können sich standardmäßig gegenseitig erreichen. * Der Namespace "default" wird automatisch verwendet, wenn kein anderer angegeben ist. kubectl get namespaces kubectl create namespace frontend kubectl label namespace frontend app=demo =====Selektoren===== Selektoren nutzen Labels, um Ressourcen zu finden. Die häufigsten sind: * podSelector * namespaceSelector * labelSelector (z. B. bei Services oder Deployments) ====Pod Selektor==== Der podSelector wird u. a. in NetworkPolicies oder Services verwendet und wählt Pods anhand ihrer Labels aus. # Wählt alle Pods mit app=backend im gleichen Namespace. podSelector: matchLabels: app: backend # Wählt alle Pods im Namespace podSelector: {} ====Namespace selektor==== Ein namespaceSelector filtert Namespaces, nicht Pods. namespaceSelector: matchLabels: app: demo Wählt alle Namespaces mit dem Label app=demo. ====Label Selektor (generell)==== Viele Kubernetes-Objekte (Deployments, ReplicaSets, Services) verwenden LabelSelector. Der Selektor verbindet z. B. ein Deployment mit den Pods, die es verwaltet. selector: matchLabels: app: demo =====Yaml===== ====Pod==== apiVersion: v1 kind: Pod metadata: name: demo spec: containers: - image: nginx name: nginx imagePullPolicy: Always kubectl create -f mypod.yml kubectl delete pod demo ====ReplicaSet==== **Wird selten genutzt**, eher für Tests/Labs. Update muss manuell vorgenommen werden (downtime). apiVersion: apps/v1 kind: ReplicaSet metadata: name: demo spec: replicas: 2 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: nginx image: nginx imagePullPolicy: Always kubectl create -f myreplica.yml kubectl delete replicaset demo # NodePort Service apiVersion: v1 kind: Service metadata: name: demo-service spec: type: NodePort selector: app: demo ports: - protocol: TCP port: 80 targetPort: 80 nodePort: 30080 # optional, ansonsten automatisch vergeben ====Deployment==== Deployments nutzen intern replicaset und managen das rolling update von selbst. Ein Deployment ist **sozusagen ein Controller für Replikasets**. apiVersion: apps/v1 kind: Deployment metadata: name: demo spec: replicas: 2 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: nginx image: nginx imagePullPolicy: Always env: - name: VERSION value: "v1" kubectl create -f mydeployment.yml kubectl delete deployment demo Deployment: 3 Replikas, je Node max. 1 Pod (inkl. Control-Plane) apiVersion: apps/v1 kind: Deployment metadata: name: nginx-3 spec: replicas: 3 selector: matchLabels: app: nginx-3 template: metadata: labels: app: nginx-3 spec: # Control-Plane zulassen (entfernen, wenn nicht gewünscht) tolerations: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" # verhindert, dass zwei Pods auf demselben Node landen affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: nginx-3 topologyKey: "kubernetes.io/hostname" # optionale zusätzliche Streuung (seit K8s 1.19+) topologySpreadConstraints: - maxSkew: 1 topologyKey: "kubernetes.io/hostname" whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: nginx-3 containers: - name: nginx image: nginx:1.27-alpine ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-3 spec: type: NodePort # Default = ClusterIP selector: app: nginx-3 ports: - port: 80 targetPort: 80 kubectl apply -f nginx-deploy-3.yaml kubectl get pods -o wide -l app=nginx-3 ====DaemonSet==== Bei einem Daemonset sorgt Kubernetes dafür das ein Pod per (möglichem Node) Node läuft. apiVersion: apps/v1 kind: DaemonSet metadata: name: ds-demo namespace: default spec: selector: matchLabels: app: ds-demo template: metadata: labels: app: ds-demo spec: containers: - name: pause-and-log image: busybox:1.36 command: ["sh","-c","echo 'Hello from node:' $(cat /etc/hostname); sleep 360000"] ----------- Container bauen Nginx Config # nginx-3/nginx.conf user nginx; worker_processes auto; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # Logging optional minimal access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; server { listen 80 default_server; server_name _; root /usr/share/nginx/html; index index.html; location /healthz { return 200 'ok'; add_header Content-Type text/plain; } # Beispiel: statischer SPA-Fallback # location / { # try_files $uri /index.html; # } } } index.html nginx-3 custom

Hallo von deinem eigenen Nginx-Image 🎉

Version 1.0.0

# nginx-3/Dockerfile FROM docker.io/library/nginx:1.27-alpine # Eigene Nginx-Konfiguration (siehe nginx.conf) COPY nginx.conf /etc/nginx/nginx.conf # Statischer Content / App-Assets COPY index.html /usr/share/nginx/html # Alternativ podman docker create -t nginx-3 . DaemonSet: 1 Pod auf jedem Node (inkl. Control-Plane) apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx-per-node spec: selector: matchLabels: app: nginx-per-node template: metadata: labels: app: nginx-per-node spec: # Control-Plane erlauben (sonst nur Worker) tolerations: - key: "node-role.kubernetes.io/control-plane" operator: "Exists" effect: "NoSchedule" containers: - name: nginx image: nginx:1.27-alpine ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-per-node spec: type: NodePort # Default = ClusterIP selector: app: nginx-per-node ports: - port: 80 targetPort: 80 protocol: TCP type: ClusterIP kubectl apply -f daemonset.yaml kubectl get pods -o wide -l app=nginx-per-node ====Persistent Volumes==== ===NFS=== apiVersion: v1 kind: PersistentVolume metadata: name: pv0003 spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: slow mountOptions: - hard - nfsvers=4.1 nfs: path: /tmp server: 172.17.0.2 Das Volume bindet man nicht direkt in Deployments ein. Dazu legt man einen PVC (Persistent volume claim) an. apiVersion: v1 kind: PersistentVolumeClaim metadata: name: demo-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi storageClassName: slow PVC in einem Deployment nutzen. apiVersion: apps/v1 kind: Deployment metadata: name: demo spec: replicas: 1 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: nginx image: nginx:stable volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data persistentVolumeClaim: claimName: demo-pvc ===SMB=== [[https://github.com/kubernetes-csi/csi-driver-smb|Treiber]] Secret apiVersion: v1 kind: Secret metadata: name: smbcreds type: Opaque stringData: username: k8suser password: "DEIN_PASSWORT" # domain: "DEINDOMAIN" # nur wenn Domain-User PV apiVersion: v1 kind: PersistentVolume metadata: name: pv-smb-demo annotations: pv.kubernetes.io/provisioned-by: smb.csi.k8s.io spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: smb mountOptions: - dir_mode=0777 - file_mode=0777 - noperm - mfsymlinks - cache=strict - noserverino csi: driver: smb.csi.k8s.io # volumeHandle muss im Cluster eindeutig sein volumeHandle: WIN-SERVER.local/k8s-demo## volumeAttributes: source: //WIN-SERVER.local/k8s-demo nodeStageSecretRef: name: smbcreds namespace: default PVC apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-smb-demo spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi storageClassName: smb volumeName: pv-smb-demo ====StatefulSet==== todo =====Volume types===== * Host based * EmptyDir * HostPath * Block Storage * Amazon EBS * GCE Persistent Disk * Azure Disk * vSphere Volume * ... * Distributed file system * NFS * Ceph * Gluster * Amazon EFS * Azure File System * ... * Other * Flocker * iSCSI * Git Repo * Quobyte * ... =====Service Types===== In Kubernetes gibt es vier Haupttypen von Services: ClusterIP, NodePort, LoadBalancer und ExternalName. Zusätzlich gibt es den Sonderfall Headless Service. Siehe [[https://spacelift.io/blog/kubernetes-service|Kubernetes Service – What It is, Types & Examples]] ^Service^Beschreibung^Erreichbarkeit^Einsatzbereich^ |Cluster IP|Standardtyp. Stellt den Service nur intern im Cluster bereit.|Nur intern (Cluster)|Kommunikation zwischen Pods| |NodePort|Öffnet einen Port auf jedem Node, erreichbar über :.|Extern über Node-IP|Einfacher externer Zugriff, z. B. für Tests| |Load Balancer|Erstellt einen externen Load Balancer (Cloud-abhängig).|Extern über öffentliche IP|Produktivbetrieb mit automatischer Skalierung| |External Name|eitet den Service auf einen externen DNS-Namen um.|Extern (DNS)|Integration externer Dienste| |Headless Service|Kein Cluster-IP, direkter Zugriff auf einzelne Pods via DNS.|Intern (DNS)|z. B. für StatefulSets, Datenbanken| ====Cluster IP==== ClusterIP-Dienste weisen jedem Dienst eine IP-Adresse zu, über die der Dienst innerhalb Ihres Clusters erreichbar ist. Dieser Diensttyp stellt den Dienst **nicht extern** bereit. ClusterIP ist der Standarddiensttyp, der verwendet wird, wenn keine alternative Option angegeben wird. Er ist der am häufigsten verwendete Diensttyp, da er eine einfache interne Netzwerkverbindung für Ihre Workloads ermöglicht. Zwei ClusterIP-Services **können problemlos denselben Port verwenden** – da kollidiert nichts. Wichtig ist: * Jeder Service hat seine eigene Cluster-IP (z.B. 10.96.0.1, 10.102.10.4). * Das Routing macht kube-proxy über die Kombination (Ziel-IP, Port, Protokoll). ====Node Port==== NodePort Dienste sind **extern über eine festgelegte statische Portbindung auf jedem Node** (auch Control Plane) erreichbar. Man kann auf den Dienst zugreifen, indem man sich mit dem Port auf einem beliebigen Node verbindet. **NodePort Diensten wird außerdem eine Cluster-IP Adresse zugewiesen**, über die sie innerhalb des Clusters erreichbar sind, genau wie ClusterIP-Dienste. Die Verwendung von NodePort Diensten wird generell nicht empfohlen. Sie weisen funktionale Einschränkungen auf und können zu Sicherheitsproblemen führen. * Jeder, der sich mit dem Port Ihrer Knoten verbinden kann, kann auf den Dienst zugreifen. * Um Konflikte zu vermeiden, kann jede Portnummer jeweils nur von einem NodePort-Dienst verwendet werden. * Jeder Knoten in Ihrem Cluster muss standardmäßig auf dem Port lauschen, auch wenn er keinen Pod ausführt, der zum Dienst gehört. * Es findet kein automatischer Lastausgleich statt: Clients werden von dem Knoten bedient, mit dem sie sich verbinden. Ein NodePort-Dienst wird üblicherweise verwendet, um die Nutzung einer eigenen Load-Balancing-Lösung zu ermöglichen, die den Datenverkehr von außerhalb des Clusters umleitet. NodePorts eignen sich auch für temporäre Debugging-, Entwicklungs- und Fehlerbehebungsszenarien, in denen verschiedene Konfigurationen schnell getestet werden müssen. ====Load Balancer==== LoadBalancer-Dienste werden außerhalb Ihres Clusters über eine externe Load-Balancer-Ressource bereitgestellt. Dies erfordert eine Verbindung zu einem Load-Balancer-Anbieter, die typischerweise durch die Integration Ihres Clusters in Ihre Cloud-Umgebung hergestellt wird. Durch das Erstellen eines LoadBalancer-Dienstes wird automatisch eine neue Load-Balancer-Infrastrukturkomponente in Ihrem Cloud-Konto bereitgestellt. Diese Funktionalität wird automatisch konfiguriert, wenn Sie einen verwalteten Kubernetes-Dienst wie Amazon EKS oder Google GKE verwenden. Sobald Sie einen LoadBalancer-Dienst erstellt haben, können Sie Ihre öffentlichen DNS-Einträge auf die IP-Adresse des bereitgestellten Load Balancers verweisen. Dadurch wird der Datenverkehr an Ihren Kubernetes-Dienst weitergeleitet. LoadBalancer sind daher der Diensttyp, den Sie normalerweise verwenden sollten, wenn eine Anwendung außerhalb von Kubernetes erreichbar sein muss. ====External Name==== ExternalName-Dienste ermöglichen den komfortablen Zugriff auf externe Ressourcen innerhalb Ihres Kubernetes-Clusters. Im Gegensatz zu anderen Diensttypen leiten sie den Datenverkehr nicht an Ihre Pods weiter. Beim Erstellen eines ExternalName-Dienstes müssen Sie das Manifestfeld spec.externalName auf die gewünschte externe Adresse (z. B. example.com) setzen. Kubernetes fügt dann einen CNAME-DNS-Eintrag zu Ihrem Cluster hinzu, der die interne Adresse des Dienstes (z. B. my-external-service.app-namespace.svc.cluster.local) in die externe Adresse (example.com) auflöst. Dadurch können Sie die externe Adresse später problemlos ändern, ohne die darauf zugreifenden Workloads neu konfigurieren zu müssen. ====Headless Service==== Headless-Services sind ein spezieller Service-Typ, der weder Load Balancing noch eine Cluster-IP-Adresse bereitstellt. Sie sind "headless", da Kubernetes keinen Traffic automatisch über sie leitet. Dadurch können Sie DNS-Abfragen verwenden, um die einzelnen IP-Adressen der vom Service ausgewählten Pods zu ermitteln. Ein Headless-Service ist nützlich, wenn Sie mit anderen Service-Discovery-Systemen interagieren möchten, ohne dass kube-proxy stört. Sie können einen solchen Service erstellen, indem Sie das Feld spec.clusterIP eines Services explizit auf den Wert None setzen. =====Networking===== ====CNI (Common networking interface)==== Kubernetes selbst macht kein Networking, sondern ruft über CNI-Plugins andere Programme auf, die die Netzwerke zwischen Pods herstellen (IP-Zuweisung, Routing, DNS usw.). * Flannel: sehr einfach, gut für Lernumgebungen * Calico: leistungsstärker, Policies, für Produktivsysteme * Weave Net: leichtgewichtig, self-managing * Cilium: frei wählbar, modern, eBPF-basiert, High-Performance =====Lokale Registry===== Falls die Registry mal wieder kaputt ist, auf den Node verbinden wo sie läuft und das Image löschen. Damit wird sie gezwungen das Image neu zu pullen. # Auf Node sudo crictl images | grep registry sudo crictl rmi registry:2 # Auf dem Control Plane kubectl delete pod -l app=registry Für eine kleine Testumgebung ist hostPath oft am einfachsten. Beispiel: Daten liegen dauerhaft auf dem Node unter /opt/registry/data. Vorsicht: Wenn man den ganzen Cluster neu startet und die Registry auf einen anderen Node verteilt wird, hostPath ist immer nur auf dem aktuellen Node, nicht clusterweit. Für Demo reichts. Registry (hostPath) apiVersion: apps/v1 kind: Deployment metadata: name: registry spec: replicas: 1 selector: matchLabels: app: registry template: metadata: labels: app: registry spec: containers: - name: registry image: registry:2 ports: - containerPort: 5000 volumeMounts: - name: registry-data mountPath: /var/lib/registry volumes: - name: registry-data hostPath: path: /opt/registry/data type: DirectoryOrCreate --- apiVersion: v1 kind: Service metadata: name: registry spec: selector: app: registry ports: - name: http port: 5000 targetPort: 5000 --- apiVersion: v1 kind: Service metadata: name: registry-nodeport spec: type: NodePort selector: app: registry ports: - name: http port: 5000 nodePort: 30050 targetPort: 5000 Auf allen Nodes in /etc/containerd/config.toml suche nach [plugins."io.containerd.grpc.v1.cri".registry] So soll es aussehen [plugins."io.containerd.grpc.v1.cri".registry] config_path = "" [plugins."io.containerd.grpc.v1.cri".registry.auths] [plugins."io.containerd.grpc.v1.cri".registry.configs] [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.1.2:30050".tls] insecure_skip_verify = true [plugins."io.containerd.grpc.v1.cri".registry.headers] [plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.1.2:30050"] endpoint = ["http://192.168.1.2:30050"] Danach sudo systemctl restart containerd # Test ctr -n k8s.io images pull --plain-http 192.168.1.2:30050/demo-php:v1 Dockerfile FROM php:8.2-cli # Arbeitsverzeichnis anlegen WORKDIR /app # index.php ins Image kopieren COPY index.php /app/index.php # PHP Built-in Webserver starten CMD ["php", "-S", "0.0.0.0:80", "-t", "/app"] index.php Deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: demo spec: replicas: 2 selector: matchLabels: app: demo template: metadata: labels: app: demo spec: containers: - name: demo image: 192.168.1.2:30050/demo-php:v1 imagePullPolicy: Always ports: - containerPort: 80 Service.yaml apiVersion: v1 kind: Service metadata: name: demo-service spec: type: NodePort selector: app: demo ports: - port: 80 nodePort: 30080 [[buildah]] ist bereits installiert (mit kube...) # Image erstellen buildah bud -t 192.168.1.2:30050/demo-php:v1 . # In die Registry pushen buildah push --tls-verify=false 192.168.1.2:30050/demo-php:v1 # Registry API curl -k http://192.168.1.2:30050/v2/_catalog {"repositories":["demo-php"]} curl -k http://192.168.1.2:30050/v2/demo-php/tags/list {"name":"demo-php","tags":["v1"]} ====Registry (PVC)==== PVC anlegen apiVersion: v1 kind: PersistentVolumeClaim metadata: name: registry-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi Registry (PVC) apiVersion: apps/v1 kind: Deployment metadata: name: registry spec: replicas: 1 selector: matchLabels: app: registry template: metadata: labels: app: registry spec: containers: - name: registry image: registry:2 ports: - containerPort: 5000 volumeMounts: - name: registry-storage mountPath: /var/lib/registry volumes: - name: registry-storage persistentVolumeClaim: claimName: registry-pvc --- apiVersion: v1 kind: Service metadata: name: registry spec: selector: app: registry ports: - name: http port: 5000 targetPort: 5000 --- apiVersion: v1 kind: Service metadata: name: registry-nodeport spec: type: NodePort selector: app: registry ports: - name: http port: 5000 nodePort: 30050 targetPort: 5000 =====Network Policies===== NetworkPolicies steuern den Netzwerkverkehr zwischen Pods und Namespaces. * podSelector: Welche Pods werden geschützt? * ingress / egress: Verkehr erlauben * from/to: Quellen oder Ziele * podSelector * namespaceSelector * ipBlock Beispiel: Traffic nur von Namespace "frontend" auf Port 80 zulassen apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend namespace: backend spec: podSelector: {} ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: frontend ports: - protocol: TCP port: 80 =====Links===== * [[https://www.youtube.com/watch?v=Fr9GqFwl6NM|Kubernetes Course – Certified Kubernetes Administrator Exam Preparation - FreeCodeCamp]] * [[https://www.youtube.com/watch?v=MTHGoGUFpvE|Kubernetes Zero to Hero]] * [[https://youtu.be/NFApeJRXos4|Service types explained]] * [[https://www.youtube.com/watch?v=d6WC5n9G_sM|Full beginner course]] * [[https://www.youtube.com/watch?v=S6CVIqQeJww|First steps after install]] * [[https://www.youtube.com/watch?v=ZxC6FwEc9WQ|Persistent volumes]] * [[https://www.youtube.com/watch?v=tZEKGNnvBzg|Kubectl secrets]] * [[https://www.youtube.com/watch?v=u948CURLDJA|Ingress NginX]] * [[https://www.youtube.com/watch?v=1SaPfm96lY4|The native web]] * [[https://www.youtube.com/watch?v=tq9ng_Nz9j8|Networking]] * [[https://www.youtube.com/watch?v=EQNO_kM96Mo|Application deployment tutorial video]] todo * [[https://stackoverflow.com/questions/69448131/kubernetes-whats-the-difference-between-deployment-and-replica-set|Difference between deployment and replicaset]] * [[https://github.com/derailed/k9s|K9s - Manage your Kubernetes Cluster with Style]] * [[https://kruschecompany.com/de/helm-kubernetes/|Die Rolle von HELM in Kubernetes]]