WordPress ist das meistgenutzte Content-Management-System im Internet. Warum du es benutzen und - nach Möglichkeit - selbst hosten solltest, kannst du hier nachlesen.
In diesem Tutorial lernst du, wie du WordPress auf deinem Azure Kubernetes Service Cluster manuell zum Laufen bringst. Alternativ zu dieser manuellen Methode kannst du natürlich auch das Helm Chart von Bitnami verwenden um WordPress automatisch zu deployen.
Viel Spaß!
Schritt #1 vorbereiten des Cluster
Den Kubernetes Cluster sowie das Tool kubectl solltest du schon eingerichtet haben. Schau dir dazu am besten den Beitrag über das Anlegen eines AKS Clusters an.
Ferner gehe ich in diesem Beitrag davon aus, dass du bereits einen Ingress Controller mit Certificate Issuer einsetzt. Was das ist, kannst du hier nachlesen.
Um deinen Cluster gut zu strukturieren, solltest du für dieses Projekt einen Namespace anlegen. In diesem Fall bietet sich der Name “wordpress-ns” an. Dazu legst du eine neue Datei “namespace.yaml” an.
apiVersion: v1
kind: Namespace
metadata:
name: wordpress-ns
Schritt #2 Bereitstellen eines persistenten Volumes
Um ein persistentes Volume im Deployment verwenden zu können musst du es zunächst anlegen. Das Erstellen von persistenten Volumes ist auf Kubernetes Clustern nicht ganz einfach da hierfür mehreren Komponenten angelegt werden müssen.
Für dieses Projekt reicht es, wenn du zwei Ansprüche auf persistente Volumes auf einer managed Disk erzeugst. Das eine für den WordPress Container und das andere für den MySQL Container.
Lege eine neue Datei “persistentVolumeclaims.yaml” an und kopiere folgenden Inhalt hinein.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpress-pv-cm
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: default
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pv-cm
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: default
Ich habe die Speicherklasse default mit 20 Gigabyte verwendet. Dies ist eine spezielle Speicherklasse für AKS.
Damit du besser verstehst, was das bedeutet und um einen kurzen Überblick zu geben, gehe ich noch auf die einzelnen Komponenten von persistenten Volumes bei Kubernetes ein. Dieses Hintergrundwissen kann sinnvoll sein, wenn du darüber nachdenkst auf einen anderen Cloudanbieter zu wechseln.
Wenn dich das nicht interessiert dann mach einfach bei Schritt #3 weiter.
Was ist eine Speicherklasse (storage class)
In der Speicherklasse wird die Art des Volumes definiert. Kubernetes weiß anhand der Speicherklasse wie es das jeweilige Volume Claim handhaben soll. Typische Speicherklassen sind der lokale Speicher, ISCI, Cloudproviderspezifische Storages oder einfache Netzwerkfreigaben über NFS.
Glücklicherweise bietet Microsoft auf dem AKS Cluster vordefinierte Speicherklassen an mit denen Kubernetes das Anlegen der jeweiligen Azure Ressourcen übernimmt. Diese umfassen aktuell die managed Disks (default / managed-premium) sowie Azure Storage per SMB Schnittstelle (azurefile / azurefile-premium).
Dabei ist anzumerken, dass bei diesen 4 vordefinierten Speicherklassen die Storages von Kubernetes zwar angelegt, aber nicht wieder gelöscht werden. Da dies Fluch und Segen zugleich sein kann, solltest du es auf jeden Fall im Hinterkopf behalten.
Mehr zu dem Thema Speicherklassen auf Azure findest du in den Microsoft Docs. Informationen über Speicherklassen im Allgemeinen findest du in der offiziellen Kubernetes Dokumentation.
Was ist ein persistentes Volume (persistent volume)
Persistente Volumes sind dazu da, um Daten zwischen Pods auszutauschen. Sie bleiben bestehen auch, wenn der dazugehörige Pod gelöscht wird. Ähnlich wie Nodes sind sie Clusterressourcen.
Du kannst ein persistentes Volume manuell erzeugen oder - wie oben - über eine Storage Klasse dynamisch erzeugen lassen. Beim dynamischen Erzeugen übernimmt Kubernetes die Details der Implementation direkt von der Storage Class.
Was ist ein Anspruch auf ein persistentes Volume (persistent volume claim)
Mit Ansprüchen auf persistenten Volumes grenzt Kubernetes in abstrakter Form Storage Ressourcen ab. Du kannst dir das so vorstellen, dass sich der Anspruch zu einem persistenten Volume so verhält wie ein Ordner zu einem Dateisystem.
Dieser Aufbau hat den Hintergrund, dass Appentwickler nicht unbedingt wissen müssen wie ein Volume im Hintergrund implementiert ist. Es reicht, wenn sie einen Anspruch auf ein persistentes Volume stellen und sich darauf verlassen können, dass es funktioniert.
Schritt #3 Anlegen der Deployments
In diesem Projekt brauchst du nur zwei Container. Einen WordPress Container für das Frontend und einen MySQL Container für das Backend.
Erstellen des MySQL Deployments
Ich verwende hier MySQL 5.7. Du kannst natürlich die jeweils aktuellste Version benutzen. Achte aber darauf, dass nicht alle WordPress Versionen mit allen MySQL Versionen funktionieren. Genauere Informationen hierzu findest du bei WordPress.com.
Für das MySQL Deployment legst du eine neue Datei “mysqldeployment.yaml” an.
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- image: mysql:5.7
name: mysql
args:
- "--ignore-db-dir"
- "lost+found"
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: wordpresssecret
key: MYSQL_ROOT_PASSWORD
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-store
mountPath: "/var/lib/mysql"
volumes:
- name: mysql-persistent-store
persistentVolumeClaim:
claimName: mysql-pv-cm
Dieses Deployment verwendet das eben erstellte Persistent Volume Claim mysql-pv-cm sowie ein Secret das du in Schritt #6 erstellen wirst.
Erstellen des WordPress Deployments
Der WordPress Container greift ebenfalls auf das Secret zu und bekommt das andere Persistente Volume Claim zugewiesen. Falls du noch weitere Veränderungen am Container vornimmst, solltest du darauf achten, dass in diesem Beispiel nur der Ordner “/var/www/html” persistent gespeichert wird.
Erstelle eine Datei mit dem Namen “wordpressdeployment.yaml”.
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:5.7
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: mysqlservice:3306
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: wordpresssecret
key: MYSQL_ROOT_PASSWORD
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: "/var/www/html"
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wordpress-pv-cm
Schritt #4 Anlegen der Kubernetes Services
In diesem Projekt benötigst du zwei Services. Der Erste für MySQL auf Port 3306. Dieser braucht keine ClusterIP da du ihn mit dem Label ansprichst. Der Zweite für WordPress mit Port 443 und Port 80. Diesen Service benötigst du im nächsten Schritt beim Ingress Regelsatz.
Um die Services anzulegen, erstellst du eine Datei mit dem Namen “services.yaml”.
apiVersion: v1
kind: Service
metadata:
name: mysqlservice
labels:
app: wordpress
tier: mysql
spec:
ports:
- port: 3306
selector:
app: wordpress
clusterIP: None
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
name: http
protocol: TCP
- port: 443
targetPort: 443
name: https
protocol: TCP
selector:
app: wordpress
tier: frontend
Schritt #5 Anlegen von Ingressregeln
Der Ingress Controller benutzt Ingressregeln, um einkommende Datenströme weiterzuleiten.
Folgende Regeln leiten alle Anfragen die auf diese URL gehen zum Service wordpress den du im vorherigen Schritt konfiguriert hast. Vor dem Weiterleiten wird das SSL Handling vom Ingress Controller übernommen, sodass der WordPress Container nur auf Port 80 lauschen muss.
Anstelle von ENTERURLHERE musst du natürlich deine eigene URL eingeben.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: wordpress-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
cert-manager.io/cluster-issuer: letsencrypt
spec:
tls:
- hosts:
- ENTERURLHERE
- www.ENTERURLHERE
secretName: tls-secret
rules:
- host: ENTERURLHERE
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
path: /(.*)
- host: www.ENTERURLHERE
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
path: /(.*)
Weil ich die Adresse sowohl mit als auch ohne “www” benutzen möchte verwende ich hier 2 Regeln. Eine mit www und eine ohne. WordPress leitet in beiden Fällen auf die gewünschte Variante selbstständig um.
Schritt #6 Deployen der ganzen App
Jetzt fehlt nur noch eine Passwortdatei für den MySQL Container. Erstelle dazu die Datei “.password.txt”.
MYSQL_ROOT_PASSWORD=HIERPASSWORTEINGEBEN
Hast du die ganzen Dateien erstellt müssen sie nur noch in den Cluster Deployt werden. Dazu kannst du folgendes Windows Bat Script verwenden.
kubectl apply -f .\namespace.yaml
for /f "delims=" %%a in (.password.txt) do set %%a
kubectl delete secret wordpresssecret --ignore-not-found -n wordpress-ns
kubectl create secret generic wordpresssecret --from-literal=MYSQL_ROOT_PASSWORD=%MYSQL_ROOT_PASSWORD% -n wordpress-ns
kubectl apply -f .\storageclass.yaml -n wordpress-ns
kubectl apply -f .\persistentvolumeclaims.yaml -n wordpress-ns
kubectl apply -f .\services.yaml -n wordpress-ns
kubectl apply -f .\mysqldeployment.yaml -n wordpress-ns
kubectl apply -f .\wordpressdeployment.yaml -n wordpress-ns
kubectl apply -f .\wordpressingress.yaml --namespace wordpress-ns
Konnte ich helfen? Ich freue mich über einen Drink!
💙