iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
DevOps

30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記系列 第 17

【Day17】Kubernetes 實戰演練:打造 WordPress + MariaDB 部署

  • 分享至 

  • xImage
  •  

gh

前情提要

昨天我們看到 Kubernetes 如果將資料存儲脫離 Pod 的生命週期,從 VolumePersistentVolume (PV)PersistentVolumeClaim (PVC),最後再到 StorageClass。透過這些機制,我們看到了如何讓資料不再隨著 Pod 的生命週期而遺失,並且能夠根據需求彈性調度,為應用程式提供可靠的儲存基礎。

今天要實戰把這些概念真正落地,嘗試部署一個更完整的應用組合,WordPress 搭配 MariaDB。前端的 WordPress 負責網站服務,後端的 MariaDB 提供資料庫支持,而 PVC 則確保資料庫的內容能安全保存,不會因為 Pod 的重建而遺失。這將會一次把 Deployment、Service、Volumes 串起來的實戰,也算是鐵人賽進度過半後的一次驗收。

實戰 🔥

在開始之前,我們要將資料掛載 Volumes 才不會讓資料隨著 Pod 生命週期而消失。但我的環境是 KinD,它本身就把 Node 之間的資料夾共享處理好了,每個 Node 底下的 data 資料夾是共享的。所以不需要另外去設定 NFS 或雲端磁碟,直接用 hostPath 的方式掛載到 /data 資料夾即可。

⚠️ 在實際的雲端或實體機環境,hostPath 並不會自動跨 Node 同步,除非有設定 NFS,但這種作法不適合生產環境。最佳實踐應該是要使用 PV/PVC + StorageClass 搭配雲端磁碟 (像 GCP PD、AWS EBS)。

docker exec -it kind-worker bash

gh

MariaDB

我們從建立資料庫開始,首先先建立資料庫需要的密碼和時區,那當然 ConfigMap 儲存時區,而 Secrets 儲存密碼:

# ConfigMap
kubectl create configmap mydb-env --from-literal=TZ="Asia/Taipei" --dry-run=client -o yaml > db-configmap.yaml

# Secrets
kubectl create secret generic mydb-pwd --from-literal=MYSQL_ROOT_PASSWORD=IThome2025! --dry-run=client -o yaml > db-secretes.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: mydb-env
data:
  TZ: '"Asia/Taipei"'

---

apiVersion: v1
kind: Secret
metadata:
  creationTimestamp: null
  name: mydb-pwd
data:
  MYSQL_ROOT_PASSWORD: SVRob21lMjAyNSE=

gh

接下來建立 MariaDB Deployment,並將 ConfigMap / Secret 掛載成環境變數,資料目錄掛到 Node 的 /data/db

kubectl create deployment mydb --image=mariadb:10.5 --dry-run=client -o yaml > db-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: mydb
  name: mydb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mydb
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: mydb
    spec:
      containers:
      - image: mariadb:10.5
        name: mariadb
        resources: {}
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              key: MYSQL_ROOT_PASSWORD
              name: mydb-pwd
        - name: TZ
          valueFrom:
            configMapKeyRef:
              key: TZ
              name: mydb-env
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mydb-data
      volumes:
      - name: mydb-data
        hostPath:
          path: /data/db
          type: Directory
status: {}

Pod 狀態變成 Running 之後,可以用 describe 看一下環境變數有沒有成功掛載:

gh

也可以進入 Node 查看掛載的資料:

gh

建立 MariaDB Table,進入 Pod 並登入 MariaDB:

# 進入 Pod 裡面的 Container
kubectl exec -it mydb-974568569-lpk6d -- bash

# 登入 MariaDB(輸入前面在 Secrets 設定的密碼)
mysql -uroot -p

gh

建立 WordPress 專用的資料庫 wp:

create database wp;

gh

接下來為了要讓我們後面建立的 Wordpress 連接到 MariaDB,因此要幫 DB 開一個 ClusterIP 的 Service,MariaDB 對外只需要被 WordPress 存取,所以用 ClusterIP 就足夠:

kubectl expose deployment mydb --port=3306 --dry-run=client -o yaml > db-svc.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: mydb
  name: mydb
spec:
  type: ClusterIP
  ports:
  - port: 3306
    protocol: TCP
    targetPort: 3306
  selector:
    app: mydb
status:
  loadBalancer: {}

gh

Wordpress

建立一個 ConfigMap,存放 WordPress 需要的 DB 設定:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: wordpress-env
data:
  ServerName: localhost
  WORDPRESS_DB_HOST: mydb
  WORDPRESS_DB_NAME: wp
  WORDPRESS_DB_PASSWORD: IThome2025!
  WORDPRESS_DB_USER: root

gh

接下來建立 WordPress Deployment,將 /var/www/html 掛載到 /data/wordpress

kubectl create deployment myweb --image=wordpress --dry-run=client -o yaml > wp-dep.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: myweb
  name: myweb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myweb
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myweb
    spec:
      containers:
      - image: wordpress
        name: wordpress
        resources: {}
        env:
        - name: WORDPRESS_DB_NAME
          valueFrom:
            configMapKeyRef:
              key: WORDPRESS_DB_NAME
              name: wordpress-env
        - name: WORDPRESS_DB_USER
          valueFrom:
            configMapKeyRef:
              key: WORDPRESS_DB_USER
              name: wordpress-env
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            configMapKeyRef:
              key: WORDPRESS_DB_PASSWORD
              name: wordpress-env
        - name: ServerName
          valueFrom:
            configMapKeyRef:
              key: ServerName
              name: wordpress-env
        - name: WORDPRESS_DB_HOST
          valueFrom:
            configMapKeyRef:
              key: WORDPRESS_DB_HOST
              name: wordpress-env
        volumeMounts:
        - mountPath: /var/www/html
          name: myweb-data
      volumes:
      - name: myweb-data
        hostPath:
          path: /data/wordpress
          type: Directory
status: {}

gh

建立 Service,但因為我是 KinD,NodePort 還是 ClusterIP 對我來說不是很重要,但我一樣用 NodePort,因為實戰要給使用者存取是要用 NodePort:

kubectl expose deployment myweb --port=80 --type=NodePort --dry-run=client -o yaml > wp-svc.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: myweb
  name: myweb
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: myweb
  type: NodePort
status:
  loadBalancer: {}

查看結果

透過 port-forward 將 Service 開放到本機 30123,30123 是隨便訂的,要別的 Port 也行:

kubectl port-forward --address 0.0.0.0 services/myweb 30123:80

gh

發佈第一篇文章:

gh

登入 MariaDB 查看 wp_posts,確認文章被寫進資料庫:

SELECT ID, post_title, post_date FROM wp_posts;

gh

查看登入用戶的資訊:

SELECT ID, user_login, user_url FROM wp_users;

gh

👉 這證明 WordPress 成功連接 MariaDB,文章與使用者資訊都能正確保存到資料庫中!

總結

今天把 WordPress 和 MariaDB 跑起來之後,感覺算是把前面學過的東西串成一個完整的應用。雖然只是測試環境,用 hostPath 搭配 KinD 的共享資料夾就能讓資料保留下來,但這也讓我更清楚地了解 Volumes、ConfigMap、Secrets、Deployment、Service 這些概念在真實應用裡是怎麼互相搭配的。

在過程中有種「拼圖」的感覺:前端 WordPress、後端資料庫 MariaDB,透過 Service 打通彼此的連線,再加上 Volume 把資料固定下來。最後能在瀏覽器裡打開 WordPress,新增文章後到資料庫查到結果,這種驗證讓學習更具體,也更有成就感。

不過目前的服務對外方式還是靠 NodePort 或 port-forward,這並不是一個正式的網站的 Best Practice。明天要來看看 Ingress,把 HTTP/HTTPS 路由和網域管理帶進來,這樣才能更貼近實際的網站部署情境。

下一篇文章:Ingress 實戰:從 NodePort 到反向代理


上一篇
【Day16】Kubernetes 的資料掛載機制:PV / PVC 實戰
系列文
30 天挑戰 CKAD 認證!菜鳥的 Kubernetes 學習日記17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言