Wordpress Kurulumu on Kubernetes

Yunus YAŞAR
6 min readApr 29, 2021

--

Wordpress-Kubernetes

Kubernetes cluster üzerinde Wordpress sitesini nasıl kurabileceğimizi anlatacağım. Bunun için temel olarak hangi Kubernetes objelerine ihtiyacımız olduğunu anlatacağım. Daha sonraki yazılarda ise bu Wordpress sitesini monitoring etmeyi yazacağım.

Eğer elinizde bir Kubernetes Cluster yok ise önceki yazılarımdan yararlanabilirsiniz:

Namespace

Öncelikle wordpress projemin limitlerini ayarlamak ve diğer projelerden ayırmak için bir namespace oluştaracağım.

$ cd wordpress_kubernetes
$ cat namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: wordpress
$ k create -f namespace.yaml
namespace/wordpress created
$ k get ns
NAME STATUS AGE
default Active 2d1h
ingress-nginx Active 2d1h
kube-node-lease Active 2d1h
kube-public Active 2d1h
kube-system Active 2d1h
wordpress Active 33s

ResourceQuota

Wordpress Namespace’ime Resorce Quota atayarak bu proje (namespace) altında bulunan bileşenlerin kaynak kullanım sınırlarını belirliyorum. Şimdilik sadece “CPU” ve “Memory” için kotalar belirliyorum. Ama isterseniz diğer Kubernetes API objeleri için kotalar belirliyebilirsiniz.

$ cat wp-resource-quota-mem-cpu.yaml                                                                                                                                                                               
apiVersion: v1
kind: ResourceQuota
metadata:
name: wp-resource-qouta
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "3"
limits.memory: 6Gi
$ k create -f wp-resource-quota-mem-cpu.yaml --namespace=wordpress
resourcequota/wp-resource-qouta created
$ k get resourcequotas -n wordpress
NAME AGE REQUEST LIMIT
wp-resource-qouta 75s requests.cpu: 0/2, requests.memory: 0/4Gi limits.cpu: 0/3, limits.memory: 0/6Gi
$ k describe ns wordpress
Name: wordpress
Labels: <none>
Annotations: <none>
Status: Active
Resource Quotas
Name: wp-resource-qouta
Resource Used Hard
-------- --- ---
limits.cpu 0 3
limits.memory 0 6Gi
requests.cpu 0 2
requests.memory 0 4Gi

Persistent Volumes (PV) ve Persistent Volumes Claims (PVC)

MySQL ve Wordpress verilerimin kalıcı olmasını istediğim için (yani uygulama podlarım ölünce ve yeniden yaratılınca) burada PV (Persistent Volume) ve PVC (Persistent Volume Claim) oluşturacağım. Ben cluster admin olarak clusterda bulunan Storage Class’tan bir PV yaratacağım ve uygumala podları PVC objesi ile bu yarattığım PV’ye erişmiş ve buradaki verileri kullanmış olacak. Böylelikle verilerimi kalıcı hale getirmiş olacağım. Burada NFS server’dan bir PV yaratacağım siz clusterınızda tanımlı diğer seçenekleri (Aws Elastic Block Store, Azure Disk, Google Cloud Persistent Disk) kullanabilirsiniz.

  • Wordpress PV:
$ cat pv-wordpress.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
name: wordpress-pv
labels:
app: wordpress
tier: wordpress
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.24
path: "/srv/wordpress/"
$ k create -f pv-wordpress.yaml
persistentvolume/wordpress-pv created
$ k describe pv wordpress-pv
Name: wordpress-pv
Labels: app=wordpress
tier=wordpress
Annotations: pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pv-protection]
StorageClass:
Status: Bound
Claim: default/mysql-pv-claim
Reclaim Policy: Retain
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 10Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 192.168.1.24
Path: /srv/wordpress/
ReadOnly: false
Events: <none>
  • MySQL PV:
$  cat pv-mysql.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
labels:
app: wordpress
tier: mysql
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.24
path: "/srv/mysql/"
$ k create -f pv-mysql.yaml
persistentvolume/mysql-pv created
$ k describe pv mysql-pv
Name: mysql-pv
Labels: app=wordpress
tier=mysql
Annotations: pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pv-protection]
StorageClass:
Status: Bound
Claim: default/wordpress-pv-claim
Reclaim Policy: Retain
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 10Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 192.168.1.24
Path: /srv/mysql
ReadOnly: false
Events: <none>
  • Wordpress PVC:
$ cat pvc-wordpress.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: wordpress
name: wp-pv-claim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 9Gi
selector:
matchLabels:
app: wordpress
tier: wordpress
$ k create -f pvc-wordpress.yaml
persistentvolumeclaim/wordpress-pv-claim created
  • MySQL PVC:
$ cat pvc-mysql.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: wordpress
name: mysql-pv-claim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 9Gi
selector:
matchLabels:
app: wordpress
tier: mysql
$ k create -f pvc-mysql.yaml
persistentvolumeclaim/mysql-pv-claim created

Şimdi oluşturduğumuz tüm storage objelerine aynı anda bakalım:

$ k get pv,pvc -n wordpress
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mysql-pv 10Gi RWX Retain Bound wordpress/mysql-pv-claim 19m
persistentvolume/wordpress-pv 10Gi RWX Retain Bound wordpress/wp-pv-claim 19m

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mysql-pv-claim Bound mysql-pv 10Gi RWX 19m
persistentvolumeclaim/wp-pv-claim Bound wordpress-pv 10Gi RWX 19m 5s

Secret

MySQL root parolasını için bir secret data oluşturalım. Bunu base64'e çevirip bu stringi saklayacağız.

$ echo -n "mysql-root-password" | base64                                                                                                                                                                                                                    
bXlzcWwtcm9vdC1wYXNzd29yZA==
$ cat secret-mysql-password.yaml
apiVersion: v1
kind: Secret
metadata:
namespace: wordpress
name: mysql-pass
type: Opaque
data:
password: bXlzcWwtcm9vdC1wYXNzd29yZA==
$ k create -f secret-mysql-password.yaml
secret/mysql-pass created
$ k describe secret -n wordpress mysql-pass
Name: mysql-pass
Namespace: wordpress
Labels: <none>
Annotations: <none>

Type: Opaque

Data
====
password: 19 bytes

Deployment ve Service

Artık MySQL servisini ve Wordpress uygulamasını yayınlayabiliriz gerekli tüm altyapımız hazır.

  • MySQL Deployment:
$ cat deployment-mysql.yaml                                                                                                                                                                                                          
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: wordpress
name: wordpress-mysql
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- image: mysql:5.7
imagePullPolicy: IfNotPresent
name: mysql
resources:
limits:
memory: "2Gi"
cpu: "2"
requests:
memory: "1Gi"
cpu: "1"
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
$ k create -f deployment-mysql.yaml
  • MySQL Service:
$ cat service-mysql.yaml                                                                                                                                                                                                             
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: wordpress-mysql
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
app: wordpress
tier: mysql
type: ClusterIP
$ k create -f service-mysql.yaml
service/wordpress-mysql created
$ k get svc -n wordpress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress-mysql ClusterIP None <none> 3306/TCP 30s
  • Wordpress Deployment:
$ cat deployment-wordpress.yaml                                                                                                                                                                                                      
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: wordpress
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: wordpress-fe
template:
metadata:
labels:
app: wordpress
tier: wordpress-fe
spec:
containers:
- image: wordpress:4.8-apache
imagePullPolicy: IfNotPresent
name: wordpress
resources:
limits:
memory: "2Gi"
cpu: "2"
requests:
memory: "1Gi"
cpu: "1"
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wp-pv-claim
$ k create -f deployment-wordpress.yaml deployment.apps/wordpress created
  • Wordpress Service:
$ cat service-wordpress.yaml                                                                                                                                                                                                         
apiVersion: v1
kind: Service
metadata:
namespace: wordpress
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
tier: wordpress-fe
type: NodePort
$ k create -f service-wordpress.yaml
service/wordpress created
k get svc -n wordpress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress NodePort 10.43.92.236 <none> 80:32664/TCP 18m
wordpress-mysql ClusterIP 10.43.99.216 <none> 3306/TCP 25m
  • “wordpress“ namespace’i altında yarattığımız tüm bileşenler:
$ k get all -n wordpress                                                                                                                                                                                                             
NAME READY STATUS RESTARTS AGE
pod/wordpress-c5d5c5445-wvcl7 1/1 Running 0 19m
pod/wordpress-mysql-d6664b65-vkxcr 1/1 Running 0 25m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/wordpress NodePort 10.43.92.236 <none> 80:32664/TCP 19m
service/wordpress-mysql ClusterIP 10.43.99.216 <none> 3306/TCP 25m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/wordpress 1/1 1 1 19m
deployment.apps/wordpress-mysql 1/1 1 1 25m
NAME DESIRED CURRENT READY AGE
replicaset.apps/wordpress-c5d5c5445 1 1 1 19m
replicaset.apps/wordpress-mysql-d6664b65 1 1 1 25m

Ingress Controller

Artık uygulamamız hazır ama herşey cluster içinde dönüyor biz faniler Wordpress uygulamasında erişemiyoruz. Bunun için bir Ingress yapısı yardımıyla dışardan içerdeki Wordpress servisine erişelim. Ingress Controller olarak Nginx kullanacağım.

$ cat ingress-wordpress.yaml                                                                                                                                                                                                         
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: wordpress-ingress
namespace: wordpress
spec:
rules:
- host: wordpress.localmahine
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
$ get ingress --all-namespaces -w
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
wordpress wordpress-ingress <none> wordpress.localmahine 80 12s
wordpress wordpress-ingress <none> wordpress.localmahine 192.168.1.21,192.168.1.22,192.168.1.23 80 45s

Verilen ip’lerden birinini ve ya hepsini “/etc/hosts” dosyama ekliyorum. Sonra da browser’dan verdiğim DNS ile erişebilirim.

Kurulumlar sırasında sık sık gerçekleşen eventları kontrol etmeyi unutmayın bir hata anında çok yardımcı olacaktır:

$ k get events --all-namespaces  --sort-by='.metadata.creationTimestamp' -w
...
wordpress 21m Normal Pulled pod/wordpress-c5d5c5445-wvcl7 Container image "wordpress:4.8-apache" already present on machine
wordpress 21m Normal Started pod/wordpress-c5d5c5445-wvcl7 Started container wordpress
wordpress 21m Normal Created pod/wordpress-c5d5c5445-wvcl7 Created container wordpress
wordpress 76s Normal CREATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress
wordpress 76s Normal CREATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress
wordpress 75s Normal CREATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress
wordpress 28s Normal UPDATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress
wordpress 28s Normal UPDATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress
wordpress 28s Normal UPDATE ingress/wordpress-ingress Ingress wordpress/wordpress-ingress

--

--