1. Description
In diesem Tutorial werden wir eine Postgresql Datenbank, Quarkus Backend und ein Angular Client deployen
2. Requirements
-
kubectl muss installiert und konfiguriert sein
-
Kind oder Minikube
-
Linux oder WSL2 Terminal
-
Docker muss installiert sein
3. Allgemeine Regeln
3.1. Wichtige Begriffe
3.1.2. Deployment
Mit einem Deployment kann man ein Pod erstellen und dabei festlegen, welche und wie viele Secrets, Volumes, CPUs, RAM und Replikationen für diesen benötigt werden.
3.1.4. Service
Um einen Zugriff auf die Pods mittels REST, TCP oder andere Protokolle zu erhalten, werden sogenannte Services verwendet
3.1.5. ConfigMaps
Damit ein Pod einen Zugriff auf Umgebungsvariablen erhält, wird dafür eine ConfigMap verwendet
3.1.6. Secrets
Ähnlich wie bei einer ConfigMap. Allerdings werden Secrets für sensible Daten wie zum Beispiel Credentials (Login Daten) verwendet.
3.1.7. Persistence Volume
Damit die Daten im Falle eines Ausfalls eines Servers nicht verloren gehen, werden sogenannte Volumes erstellt. Diese sind vergleichbar mit docker volumes.
3.1.8. Persistence Volume Claim (PVC)
Damit ein Pod auf einer Persistence Volume zugreifen kann, werden Persistence Volume Claim (PVC) verwendet.
Schüler haben keinen Zugriff auf die Persistence Volumes von der Leocloud. |
Grundsätzlich braucht man für jede Komponente in unserem System ein Deployment und eine Service
4. Deployment von einer Postresql Datenbank
kubectl create deployment postgres-demo --image=postgres:12.16-bullseye --port=5432
Folgender Befehl wurde verwendet, um ein Deployment für unsere Datenbank zu erstellen.
4.1. Warum rennt die Datenbank nicht
Wenn man jetzt kubectl get pods
oder kubectl get deployments
im Terminal eingibt, dann könnte man sehen, dass bei der Spalten Ready
0/1 dabei steht.
Um das Problem zu finden, können wir folgendes machen.
Wir kopieren uns den Namen des Pods in der Zwischenablage und geben dann folgendes im Terminal ein
kubectl log <Name des Pods> -c <Name des Images, welches von dem Pod verwendet wird>
In meinem Fall habe ich folgendes eingeben müssen
kubectl logs postgres-demo-7cd674d4b5-9msfr -c postgres
Die Fehlermeldung schaut wie folgends aus:
Error: Database is uninitialized and superuser password is not specified. You must specify POSTGRES_PASSWORD to a non-empty value for the superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run". You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all connections without a password. This is *not* recommended. See PostgreSQL documentation about "trust": https://www.postgresql.org/docs/current/auth-trust.html
Für das Lösen dieses Problems müssen wir jetzt eine ConfigMap oder ein Secret erstellen, wo wir die benötigten Umgebungsvariablen definieren können.
kubectl get deployments/postgres-demo -o yaml > deployment.yaml im Terminal eingeben, damit man die ganze Konfiguration von dem Deployment in einem YAML File speichert.
(Das könnte man auch bei Services, Secrets usw. auch machen ).
Es lohnt sich auch, diesen Befehl nach jeder Änderung zu machen und dann die Files STÄNDIG zu kontrollieren.
|
4.2. Erstellung von des Secrets
Für die Erstellung des Secrets kann man diesen Befehl verwenden
kubectl create secret generic postgres-secret \ --from-literal=POSTGRES_USER=<Name des Users> \ --from-literal=POSTGRES_PASSWORD=<Password> \ --from-literal=POSTGRES_DB=<Name der DBs>
Die Argumente,welche nach --from-literal kommen, sollen mit den Namen der benötigten Umgebenungsvariablen übereinstimmen.
Das zweite Argument ist einfach der Wert dieser Umgebungsvariable.
|
Jetzt kann man die Konfigurationen von unserem Secret mit der Verwendung von diesem Befehl in einem YAML File speichern
kubectl get secrets postgres-secret -o yaml > secret.yaml
Wir sind aber noch immer nicht fertig mit dem Secret. Das Deployment soll sich die Werte von diesem Secret für seine Umgebungsvariablen holen. Dafür muss man folgendes im Terminal eingeben:
kubectl set env deployment/postgres-demo --from=secret/postgres-secret
Unser Deployment soll jetzt problemlos funktionieren. Wenn das nicht der Fall ist, könnte man folgendes machen (Nicht vergessen, YAML Files mit Hilfe der kubectl CLI zu generieren):
kubectl delete deployments/postgres-demo kubectl apply -f postgres.yaml
4.3. Erstellung einer Service
Wir haben die Datenbank jetzt zum Laufen gebracht. Damit wir auf diese zugreifen können, müssen wir ein Service erstellen:
kubectl expose deployments/postgres-demo --type=LoadBalancer --port=5432 kubectl get services
Connection String von postgres schaut dann wie folgendes aus:
jdbc:postgresql://<Minikube IP>:<NodePort>/db
die Minikube IP kann man mit dem Befehl minikube ip
anzeigen lassen. beim NodePort muss mann kubectl get services/postgres-demo
eingeben und dann den Port, welcher nach dem Doppelpunkt steht nehmen
5. Persistence Volume/Persistence Volume Claim
Bei der Leocloud sind diese schon vordefiniert. Auf dem lokalen Minikube könnte man folgende Konfiguration verwenden
apiVersion: v1
kind: PersistentVolume
metadata:
finalizers:
- kubernetes.io/pv-protection
labels:
type: local
name: task-pv-volume
resourceVersion: "33077"
uid: ae6d772a-0090-4074-b3ac-1edb929daf29
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi
hostPath:
path: /mnt/data
type: ""
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
volumeMode: Filesystem
status:
phase: Available
Wir brauchen noch ein PVC, damit unsere Anwendung auf die Datenbank zugreifen kann.
Folgende Konfiguration kann dafür verwendet werden
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
finalizers:
- kubernetes.io/pvc-protection
name: franklyn-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Mi
storageClassName: standard
Jetzt müssen wir unser Deployment umkonfigurieren, sodass es dieses Volume verwendet. Leider können wir diese Konfigurationen nicht mit der Verwendung von der kubectl CLI hinzufügen. Deshalb habe ich sie in diesem Code-Snippet markiert. (Ich rate Ihnen, den Code nicht zu kopieren, sondern nur die Zeilen, die einen Plus enthalten, in ihrem Config Files händisch hinzufügen. Ohne die Plus-Symbole natürlich)
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "2"
generation: 2
labels:
app: postgres-demo
name: postgres-demo
namespace: default
resourceVersion: "40443"
uid: 5e97ba55-98ff-454d-9247-946157c8a5ec
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: postgres-demo
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: postgres-demo
spec:
containers:
- env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
key: POSTGRES_PASSWORD
name: postgres-secret
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
key: POSTGRES_USER
name: postgres-secret
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
key: POSTGRES_DB
name: postgres-secret
image: postgres:12.16-bullseye
imagePullPolicy: IfNotPresent
name: postgres
+ volumeMounts:
+ - name: postgres-data
+ mountPath: /var/lib/postgresql/data
ports:
- containerPort: 5432
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
+ volumes:
+ - name: postgres-data
+ persistentVolumeClaim:
+ claimName: my-pvc
Es ist jetzt völlig egal, ob die Pods aus irgendeinem Grund gestoppt oder gekillt werden. Die Daten existieren noch immer.
Gratuliere! Sie haben jetzt die Datenbank erfolgreich deployed :)
Wenn Sie das Program auf ihren Namespace deployen wollen, dann müssen Sie bei jedem YAML File das Attribut namespace
ändern
6. Deployment einer Java Applikation
Vorgehensweise:
-
Hochladen des Image auf ghcr.io oder andere Conatiner Registries
-
Erstellung eines Deployments
-
Erstellung eines Services
-
Zugriffsroute in der Ingress.yml Datei definieren
6.2. Erstellung eines Deployments
Für die Erstellung des Services kann man diesen Befehl verwenden
kubectl create deployment <beliebiger Namen> --image=<Name des Images, was sie bereits auf ghcr hochgeladen haben> --port=<beliebiger Port>
6.3. Erstellung eines Services
Gleich wie Erstellung einer Service allerdings müssen sie das richtige Deployment auswählen
7. Deployment einer Angular Applikation
Vorgehensweise: gleich wie Deployment einer Java Applikation
8. Erstellung von Ingress
Damit man auf die deployten Komponenten mittels http und https von außen zugreifen kann, wird ein Ingress gebraucht.
Wir müssen zuerst ein Reverse Proxy mittels nginx erstellen und dann die Routen für unsere Komopnenten definieiren.
8.1. Erstellung von nginx Reverse Proxy
Es gibt 100 unterschiedliche Lösungen und Konfigurationen dafür, aber wir können uns an der Lösung von Prof. Christian Aberger orientieren.
server {
listen 80;
root /usr/share/nginx/html;
rewrite_log on;
error_log /dev/stdout debug;
location /api/ {
proxy_pass <Name von dem Service>:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host:$server_port;
}
}
Danach sollen wir ein Dockerfile erstellen, in dem wir diese Konfigurationen kopieren
FROM nginx:stable
# COPY frontend/* /usr/share/nginx/html/
COPY ./default.conf /etc/nginx/conf.d/default.conf
Letztendlich sollen wir dieses Image auf ghcr.io publishen how to upload an image to ghcr - 2023/24
9. Erstellung von Deployment und Service für unser Reverse Proxy
Sie sollen mittlerweile wissen, wie man ein Deployment und eine Service erstellt.
# nginx Web Server
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: <Name von dem nginx Package, den Sie bereits auf einem Container Registery hochladen haben>
# remove imagePullPolicy when stable. Currently we do not take care of version numbers
ports:
- containerPort: 80
# livenessProbe:
# httpGet:
# path: /index.html
# port: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx
9.1. Konfiguration von Routen
Dafür muss man auch eine fertige Konfiguration nehmen und diese umändern
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
name: nginx-ingress
namespace: <Namespace von Ihnen>
spec:
rules:
- host: student.cloud.htl-leonding.ac.at
http:
paths:
- path: <Ihr Namen in diesem Format m.mustermann >
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
- path: <Name von Ihnen in diesem Format m.mustermann>/<belieger Namen für die Route ihrer Anwendung>
pathType: Prefix
backend:
service:
name: <Name von dem Service, was sie deployen möchten>
port:
number: <Port von dem Service, was sie deployen möchten>