Kubernetes auf Proxmox mit Ansible und Terraform (Teil 2)
Table of Contents
Dieser Post wurde aus dem Original (https://datastrophic.io/kubernetes-homelab-with-proxmox-kubeadm-calico-openebs-and-metallb/)auf Deutsch übersetzt und leicht angepasst.
Einleitung
Nachdem wir im ersten Teil mit Terraform die VMs für unseren K8s Cluster deployed haben, werden wir nun mit Ansible die folgenden K8s Komponenten in den worker Nodes und dem Controller installieren:
kubeadm
für das Kubernetes Cluster bootstrappingcontainerd
als container runtimeCalico
für das Pod networkingMetalLB
verwenden wir alsLoadBalancer
service typeOpenEBS
für das Volume provisioningIstio
für ingress und traffic management
Die Kubernetes-Distribution der Wahl ist in diesem Fall Vanilla Open Source Kubernetes, das mit dem kubeadm-Tool für Cluster-Bootstrapping geliefert wird. Vanilla Kubernetes hat einen grösseren Fussabdruck im Vergleich zu k3s und eignet sich deshalb nicht gut für Umgebungen mit eingeschränkten Ressourcen. Es ist jedoch herstellerunabhängig und vollständig Open-Source, hat keine Modifikationen und sowohl die API-Änderungen als auch die Tools haben die gleiche Release-Kadenz, sodass das Risiko von Inkompatibilitäten oder Verzögerungen geringer ist.
Voraussetzungen
- Cluster VMs sollten bereits provisioniert und erreichbar sein via SSH
- empfohlen ist Ubuntu 20.04 als Cluster OS zu verwenden
- der Benutzer (in unserem Fall ubuntu) sollte Superuser Berechtigungen haben auf den Cluster Nodes
- Ansible ist lokal bei dir installiert
Vorbereitungen
Lade dir die Terraform und Ansible Files von diesem Git Repo herunter.
Die Variablen in ansible/group_vars/all
sollten noch überprüft werden:
pod_subnet
service_subnet
dns
metallb_address_range
Weiter musst du die IPs deiner VMs in dieser Datei nachtragen: ansible/inventory.yaml
Vor der Bereitstellung von Kubernetes selbst müssen die Cluster-Knoten zusätzlich konfiguriert und Software installiert werden:
- Knoten müssen Swap deaktiviert, iptables aktiviert haben und Weiterleitung und überbrückten Datenverkehr gemäss Bootstrapping-Clustern mit kubeadm zulassen.
- Auf den Knoten muss die Containerlaufzeit installiert sein. Die gängigste Containerlaufzeit, die in verschiedenen Cloud- und Anbieter-Kubernetes-Distributionen verwendet wird, ist containerd, also werden wir sie verwenden.
- Weitere Informationen darüber, warum wir Docker nicht verwenden werden, findest du in Don’t Panic: Kubernetes and Docker.
- Auf Knoten müssen die folgenden Pakete installiert sein: kubelet, kubectl und kubeadm. Diese können über den Standard-Paketmanager wie apt installiert werden.
Es gibt ein dediziertes Playbook zum Bootstrapping der Knoten mit allen erforderlichen Konfigurationen und Abhängigkeiten, die unter ansible/bootstrap.yaml verfügbar sind. Überprüfe die Standardeinstellungen und führe das Playbook wie folgt aus:
#~$ ansible-playbook -i ansible/inventory.yaml ansible/bootstrap.yaml -u ubuntu
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
PLAY [Bootstrapping hosts] ************************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [control-plane-0.k8s.cluster]
ok: [worker-1.k8s.cluster]
ok: [worker-0.k8s.cluster]
ok: [worker-2.k8s.cluster]
TASK [commons : install common packages] **********************************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [worker-0.k8s.cluster]
TASK [commons : disable swap] *********************************************************************************************************
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
TASK [commons : disable swap in fstab] ************************************************************************************************
ok: [worker-2.k8s.cluster]
ok: [control-plane-0.k8s.cluster]
ok: [worker-0.k8s.cluster]
ok: [worker-1.k8s.cluster]
TASK [commons : enable br_netfilter] **************************************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
TASK [commons : ensure iptables enabled] **********************************************************************************************
changed: [worker-1.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
TASK [commons : enable port forward] **************************************************************************************************
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
TASK [container-runtime : create config and data dirs] ********************************************************************************
changed: [worker-2.k8s.cluster] => (item=/etc/containerd)
changed: [control-plane-0.k8s.cluster] => (item=/etc/containerd)
changed: [worker-1.k8s.cluster] => (item=/etc/containerd)
changed: [worker-0.k8s.cluster] => (item=/etc/containerd)
changed: [control-plane-0.k8s.cluster] => (item=/tmp/containerd)
changed: [worker-2.k8s.cluster] => (item=/tmp/containerd)
changed: [worker-1.k8s.cluster] => (item=/tmp/containerd)
changed: [worker-0.k8s.cluster] => (item=/tmp/containerd)
TASK [container-runtime : download and install runc] **********************************************************************************
changed: [worker-1.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
TASK [container-runtime : download and install crictl] ********************************************************************************
changed: [worker-1.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-0.k8s.cluster]
TASK [container-runtime : download containerd] ****************************************************************************************
changed: [worker-0.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
TASK [container-runtime : copy containerd binaries] ***********************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
TASK [container-runtime : copy containerd config] *************************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
TASK [container-runtime : create containerd systemd service] **************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [worker-2.k8s.cluster]
TASK [container-runtime : reload systemd] *********************************************************************************************
ok: [worker-1.k8s.cluster]
ok: [worker-0.k8s.cluster]
ok: [worker-2.k8s.cluster]
ok: [control-plane-0.k8s.cluster]
TASK [container-runtime : enable containerd systemd service] **************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
TASK [container-runtime : start containerd service] ***********************************************************************************
changed: [worker-0.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
TASK [kubernetes-packages : adding Kubernetes repository apt key] *********************************************************************
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
TASK [kubernetes-packages : adding Kubernetes deb repository] *************************************************************************
changed: [worker-1.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [control-plane-0.k8s.cluster]
TASK [kubernetes-packages : installing Kubernetes packages] ***************************************************************************
changed: [control-plane-0.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-0.k8s.cluster]
changed: [worker-1.k8s.cluster]
TASK [kubernetes-packages : hold kubeadm, kubectl, kubelet] ***************************************************************************
changed: [worker-0.k8s.cluster] => (item=kubeadm)
changed: [worker-1.k8s.cluster] => (item=kubeadm)
changed: [control-plane-0.k8s.cluster] => (item=kubeadm)
changed: [worker-2.k8s.cluster] => (item=kubeadm)
changed: [worker-0.k8s.cluster] => (item=kubectl)
changed: [worker-1.k8s.cluster] => (item=kubectl)
changed: [worker-2.k8s.cluster] => (item=kubectl)
changed: [control-plane-0.k8s.cluster] => (item=kubectl)
changed: [worker-0.k8s.cluster] => (item=kubelet)
changed: [worker-1.k8s.cluster] => (item=kubelet)
changed: [worker-2.k8s.cluster] => (item=kubelet)
changed: [control-plane-0.k8s.cluster] => (item=kubelet)
PLAY RECAP ****************************************************************************************************************************
control-plane-0.k8s.cluster : ok=21 changed=18 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-0.k8s.cluster : ok=21 changed=18 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-1.k8s.cluster : ok=21 changed=18 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-2.k8s.cluster : ok=21 changed=18 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Sobald alle Voraussetzungen erfüllt sind, können wir kubeadm für das Cluster-Bootstrapping verwenden. Die Installation des Kubernetes-Clusters besteht aus zwei Hauptschritten: Bootstrapping der Steuerungsebene und Joining zu den Worker-Knoten. Wir können dies tun, indem wir das Playbook ansible/kubernetes-install.yaml ausführen:
#~$ ansible-playbook -i ansible/inventory.yaml ansible/kubernetes-install.yaml -u ubuntu
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
PLAY [Bootstrap Kubernetes Control Plane] *********************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [control-plane-0.k8s.cluster]
TASK [kubeadm-init : copy kubeadm init config] ****************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [kubeadm-init : running kubeadm init] ********************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [calico : copy Calico manifests] *************************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [calico : install Calico] ********************************************************************************************************
changed: [control-plane-0.k8s.cluster]
PLAY [Retrieve join token and certificate hash] ***************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [control-plane-0.k8s.cluster]
TASK [kubeadm-join-config : create local dir for token and cert hash] *****************************************************************
changed: [control-plane-0.k8s.cluster -> localhost]
TASK [kubeadm-join-config : kubeadm token generate] ***********************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [kubeadm-join-config : generate cert hash] ***************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [kubeadm-join-config : persist token locally] ************************************************************************************
changed: [control-plane-0.k8s.cluster -> localhost]
TASK [kubeadm-join-config : persist cert hash locally] ********************************************************************************
changed: [control-plane-0.k8s.cluster -> localhost]
PLAY [Join Kubernetes worker nodes] ***************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [worker-1.k8s.cluster]
ok: [worker-2.k8s.cluster]
ok: [worker-0.k8s.cluster]
TASK [kubeadm-join : copy kubeadm join config] ****************************************************************************************
changed: [worker-0.k8s.cluster]
changed: [worker-1.k8s.cluster]
changed: [worker-2.k8s.cluster]
TASK [kubeadm-join : running kubeadm join] ********************************************************************************************
changed: [worker-1.k8s.cluster]
changed: [worker-2.k8s.cluster]
changed: [worker-0.k8s.cluster]
PLAY [Copy kubeconfig from remote] ****************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [control-plane-0.k8s.cluster]
TASK [fetching] ***********************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
PLAY RECAP ****************************************************************************************************************************
control-plane-0.k8s.cluster : ok=13 changed=10 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-0.k8s.cluster : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-1.k8s.cluster : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
worker-2.k8s.cluster : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Das Playbook führt kubeadm init auf den Knoten der Steuerungsebene aus und verwendet eine deklarative Clusterkonfiguration, die die bevorzugte Methode zum Konfigurieren von kubeadm ist. Die Konfigurationsvorlage ist unter ansible/roles/kubeadm-init/templates/kubeadm.yaml verfügbar. Sobald der Bootstrap der Steuerungsebene abgeschlossen ist, ruft Ansible ein Token und einen Zertifikat-Hash ab, die für die Authentifizierung der Worker-Knoten beim API-Server erforderlich sind, und führt kubeadm join auf den Worker-Knoten aus.
Das Playbook stellt Calico für die Clusternetzwerke bereit. Die Wahl von Calico ist motiviert, weil es die am weitesten verbreitete Netzwerk- und Sicherheitslösung für Kubernetes ist (zum Zeitpunkt des Schreibens).
Sobald die Playbook-Ausführung abgeschlossen ist, wird eine kubeconfig-Datei admin.conf in das aktuelle Verzeichnis geholt. Um zu überprüfen, ob der Cluster gebootet und verbunden ist, führe Folgendes aus:
#~$ kubectl --kubeconfig=admin.conf get nodes
NAME STATUS ROLES AGE VERSION
control-plane-0.k8s.cluster Ready control-plane,master 3m30s v1.21.6
worker-0 Ready <none> 2m54s v1.21.6
worker-1 Ready <none> 2m55s v1.21.6
worker-2 Ready <none> 2m55s v1.21.6
es ist empfohlen die Location der admin.conf Datei als env. Variabel zu exportieren, damit man die Datei nicht jedesmal mit --kubeconfig mitgeben muss:
export KUBECONFIG=$(pwd)/admin.conf
Notwendige Software
Wenn der Kubernetes-Cluster eingerichtet und ausgeführt wird, können wir jetzt Container darauf bereitstellen und ausführen. Ein paar wesentliche Teile des voll funktionsfähigen Clusters fehlen jedoch noch: die dynamische Volume-Bereitstellung und die Unterstützung für Dienste welche einen LoadBalancer benötigen.
Volume Provisioning mit OpenEBS
Die Volume Provisioner-Lösung ist sowohl in Situationen nützlich, in denen Anwendungen von Drittanbietern eine Standard-StorageClass zum Bereitstellen von PersistentVolumes benötigen, als auch in Situationen, in denen eine Datenreplikation für Hochverfügbarkeitsgarantien erforderlich ist.
Die Verwendung von OpenEBS für das Home-Lab-Setup erscheint vernünftig, da es lokale Engines für die Bereitstellung von PersistentVolumes bereitstellt, die direkt von den lokalen Festplatten auf Hosts unterstützt werden. Wenn eine Datenreplikation erforderlich ist, verfügt OpenEBS über mehrere Replicated Engines, deren Leistung jedoch unterschiedlich ist.
Um eine minimale Installation mit hostlokalen PersistentVolumes bereitzustellen, bietet OpenEBS eine „Lite“-Version:
#~$ kubectl apply -f https://openebs.github.io/charts/openebs-operator-lite.yaml
namespace/openebs created
serviceaccount/openebs-maya-operator created
clusterrole.rbac.authorization.k8s.io/openebs-maya-operator created
clusterrolebinding.rbac.authorization.k8s.io/openebs-maya-operator created
customresourcedefinition.apiextensions.k8s.io/blockdevices.openebs.io created
customresourcedefinition.apiextensions.k8s.io/blockdeviceclaims.openebs.io created
configmap/openebs-ndm-config created
daemonset.apps/openebs-ndm created
deployment.apps/openebs-ndm-operator created
deployment.apps/openebs-ndm-cluster-exporter created
service/openebs-ndm-cluster-exporter-service created
daemonset.apps/openebs-ndm-node-exporter created
service/openebs-ndm-node-exporter-service created
deployment.apps/openebs-localpv-provisioner created
Sobald der Operator installiert ist, erstellen wir eine StorageClass und setzen diese als Standard. Das ermöglicht die Verwendung von OpenEBS für die Volume-Bereitstellung, ohne dass jedes Mal die StorageClass für PersistentVolumes angegeben werden muss:
#~$ kubectl apply -f https://openebs.github.io/charts/openebs-operator-lite.yaml
namespace/openebs created
serviceaccount/openebs-maya-operator created
clusterrole.rbac.authorization.k8s.io/openebs-maya-operator created
clusterrolebinding.rbac.authorization.k8s.io/openebs-maya-operator created
customresourcedefinition.apiextensions.k8s.io/blockdevices.openebs.io created
customresourcedefinition.apiextensions.k8s.io/blockdeviceclaims.openebs.io created
configmap/openebs-ndm-config created
daemonset.apps/openebs-ndm created
deployment.apps/openebs-ndm-operator created
deployment.apps/openebs-ndm-cluster-exporter created
service/openebs-ndm-cluster-exporter-service created
daemonset.apps/openebs-ndm-node-exporter created
service/openebs-ndm-node-exporter-service created
deployment.apps/openebs-localpv-provisioner created
Dave@ChuckNorris[08:37:02]~/github/homelab$ kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: openebs-hostpath
annotations:
storageclass.kubernetes.io/is-default-class: "true"
openebs.io/cas-type: local
cas.openebs.io/config: |
- name: StorageType
value: "hostpath"
- name: BasePath
value: "/var/openebs/local/"
provisioner: openebs.io/local
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
EOF
storageclass.storage.k8s.io/openebs-hostpath created
LoadBalancer mit MetalLB
Eine letzte fehlende Funktionalität im bereitgestellten Cluster ist die Möglichkeit, Dienste vom Typ LoadBalancer für das lokale Netzwerk verfügbar zu machen. Bei der Ausführung in der Cloud wird diese Funktionalität von den Kubernetes-Integrationen mit Cloud-Anbietern bereitgestellt, und entsprechende netzwerkseitige Load Balancer werden über den Infrastrukturanbieter bereitgestellt. Bei der Ausführung auf Bare Metal ist eine solche Integration in Kubernetes standardmässig nicht verfügbar.
MetalLB ist die am weitesten verbreitete Lösung für den NetzwerkLB.
Die MetalLB-Installation wird über eine ConfigMap konfiguriert und kann mehrere Adresspools enthalten:
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- "{{ lab.metallb_address_range }}"
Die obere Vorlage ist Teil des Ansible-Playbooks ansible/metallb.yaml
, das die MetalLB installiert und konfiguriert, um Adressen aus der in group_vars
angegebenen Variable lab.metallb_address_range
zuzuweisen. Der Adressbereich muss für die Zielumgebung relevant sein (Teil des reservierten statischen Adressbereichs, der im Abschnitt zum Bereitstellungslayout beschrieben ist, damit die Adressen zugewiesen werden können. Um MetalLB zu installieren, führe Folgendes aus:
#~$ ansible-playbook -i ansible/inventory.yaml ansible/metallb.yaml -u ubuntu
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
PLAY [Install MetalLB] ******************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************
ok: [control-plane-0.k8s.cluster]
TASK [metallb : copy MetalLB manifests] *************************************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [metallb : copy MetalLB config] ****************************************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [metallb : create namespace] *******************************************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [metallb : install MetalLB config] *************************************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
TASK [metallb : install MetalLB] ********************************************************************************************************************************************
changed: [control-plane-0.k8s.cluster]
PLAY RECAP ******************************************************************************************************************************************************************
control-plane-0.k8s.cluster : ok=6 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Installation überprüfen
Um die Installation zu überprüfen, erstellen wir eine MinIO-Bereitstellung mit einem PersistentVolume für die Speicherung und stellen die Bereitstellung dem lokalen Netzwerk über den LoadBalancer-Diensttyp zur Verfügung. Das Beispiel basiert auf den Kubernetes-Speicherbeispielen.
- Erstellen ein PersistentVolumeClaim:
#~$ kubectl apply -f - <<EOF apiVersion: v1 kind: PersistentVolumeClaim metadata: name: minio-pv-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi EOF persistentvolumeclaim/minio-pv-claim created
- Erstelle ein Deployment:
#~$ kubectl apply -f - <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: minio-deployment spec: selector: matchLabels: app: minio strategy: type: Recreate template: metadata: labels: app: minio spec: volumes: - name: storage EOF mountPath: "/storage"Ytim deployment.apps/minio-deployment created
- Überprüfe ob der PersistentVolumeClaim an das PersistentVolume gebunden ist und dies erstellt wurde:
#~$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE minio-pv-claim Bound pvc-8cb55047-43b6-4ab8-a8cb-20dc1ecf1979 1Gi RWO openebs-hostpath 3m4s
#~$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-8cb55047-43b6-4ab8-a8cb-20dc1ecf1979 1Gi RWO Delete Bound default/minio-pv-claim openebs-hostpath 28s
- Überprüfe, ob das Deployment erfolgreich war:
#~$ kubectl describe deployment minio-deployment Name: minio-deployment Namespace: default CreationTimestamp: Sat, 02 Jul 2022 08:54:36 +0200 Labels: <none> Annotations: deployment.kubernetes.io/revision: 1 Selector: app=minio Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: Recreate MinReadySeconds: 0 Pod Template: Labels: app=minio Containers: minio: Image: minio/minio:latest Ports: 9000/TCP, 9001/TCP Host Ports: 9000/TCP, 9001/TCP Args: server /storage --console-address :9001 Environment: MINIO_ACCESS_KEY: minio MINIO_SECRET_KEY: minio123 Mounts: /storage from storage (rw) Volumes: storage: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: minio-pv-claim ReadOnly: false Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: minio-deployment-59659f9655 (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 56s deployment-controller Scaled up replica set minio-deployment-59659f9655 to 1
- Stelle das Deployment via Service vom Typ LoadBalancer zur Verfügung:
#~$ kubectl apply -f - <<EOF apiVersion: v1 kind: Service metadata: name: minio spec: ports: - name: http port: 9000 protocol: TCP targetPort: 9000 - name: http-ui port: 9001 protocol: TCP targetPort: 9001 selector: app: minio type: LoadBalancer EOF
- Überprüfe, ob der Service erstellt wurde und eine Externe IP erhalten hat:
#~$ kubectl get service minio NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE minio LoadBalancer 10.97.129.247 192.168.30.150 9000:31713/TCP,9001:32327/TCP 10s
Die externe IP Adresse sollte in dem Anfangs definierten lokalen Subnetz Range sein. Du kannst nun via Browser die MinIO Konsole öffnen (in meinem Fall war die URL: http://192.168.30.150:9001/login) und dich mit Benutzer minio und Passwort minio123 einloggen. Erstelle anschliessend ein Test Bucket, damit wir später auch überprüfen können ob die Daten persistent im Volume gespeichert werden:
Nun können wir direkt überprüfen, ob das Test-Bucket (testsetsetsgsdgfsdgagbadfg) im PersistentVolume gespeichert wurde:
#~$ kubectl exec deploy/minio-deployment -- bash -c "ls -la /storage"
drwxrwxrwx 4 root root 4096 Jul 2 06:59 .
drwxr-xr-x 1 root root 4096 Jul 2 06:54 ..
drwxr-xr-x 8 root root 4096 Jul 2 06:54 .minio.sys
drwxr-xr-x 5 root root 4096 Jul 2 15:06 testsetsetsgsdgfsdgagbadfg
Damit können wir sicher sein, dass die Daten im Testbucket im PersistentVolume landen.
Als letzter Schritt werden wir das Kubernetes Dashboard deployen, damit kann man den Gesamten K8s Cluster als WebUI bedienen.
Kubernetes Dashboard
Das Kubernetes-Dashboard ist die unverzichtbare Mindestlösung für die Beobachtbarkeit. Das Kubernetes-Dashboard verfügt über eine entsprechende Installationsanleitung, und hier konzentrieren wir uns auf die entsprechenden RBAC-Berechtigungen für den verwendeten ServiceAccount.
Zuerst installieren wir das Kubernetes Dashboard:
#~$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.4.0/aio/deploy/recommended.yaml
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
Während das Kubernetes-Dashboard das Erstellen neuer Ressourcen und das Bearbeiten vorhandener Ressourcen ermöglicht, ist die Verwendung im schreibgeschützten Modus sicherer und würde keine Sicherheitsrisiken mit sich bringen, falls jemand Zugriff auf die Benutzeroberfläche erhält. Der Sichtbarkeitsbereich des Dashboards wird über RBAC der darauf zugreifenden Benutzer gesteuert.
Der konservativste Ansatz wäre, eine Aggregated ClusterRole basierend auf der Standard-Viewer-Rolle zu verwenden und sie bei Bedarf mit zusätzlichen Regeln zu erweitern:
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dashboard-viewer
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
- matchLabels:
rbac.homelab.k8s.io/aggregate-to-view: "true"
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: dashboard-extended-view
labels:
rbac.homelab.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups:
- ""
resources:
- nodes
- extensions
- apps
- batch
- storage
- networking
verbs:
- get
- list
- watch
EOF
Die ClusterRole bietet erweiterte Anzeigeberechtigungen, erlaubt aber immer noch nicht das Anzeigen von Secrets und Ressourcen aus der API-Gruppe rbac.authorization.k8s.io. Wir erstellen uns nun ein dedizierter ServiceAccount und binden den Account an die erstellte ClusterRole:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: dashboard-viewer
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dashboard-viewer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: dashboard-viewer
subjects:
- kind: ServiceAccount
name: dashboard-viewer
namespace: kubernetes-dashboard
EOF
Auf das Dashboard kann entweder über den kubectl-Proxy oder über die Portweiterleitung zugegriffen werden:
kubectl -n kubernetes-dashboard port-forward service/kubernetes-dashboard 8443:443
Das Dashboard kann nun unter dieser URL erreicht werden: https://localhost:8443/ :
Um das ServiceAccount-Token für den Zugriff auf das Dashboard zu ermitteln, führen wir Folgendes aus:
kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/dashboard-viewer -o jsonpath="{.secrets[0].name}") -o go-template="{{.data.token | base64decode}}"