Chuyển tới nội dung chính

Hướng dẫn triển khai WordPress trên Vietnix Enterprise Cloud

Bài viết này hướng dẫn cách triển khai ứng dụng WordPress có khả năng mở rộng trên một cụm Kubernetes chạy trên Vietnix Enterprise Cloud. Một hệ thống WordPress điển hình gồm:

  • Máy chủ WordPress lưu trữ và phục vụ nội dung website.
  • Máy chủ MySQL lưu trữ người dùng, bài viết và cấu hình.
  • Load Balancer định tuyến lưu lượng từ mạng công cộng tới (các) máy chủ WordPress.

Để đảm bảo tính sẵn sàng cao và khả năng mở rộng, chúng ta chạy nhiều pod WordPress phía sau một Load Balancer, đồng thời giữ một máy chủ MySQL duy nhất. Trong môi trường production, bạn nên chạy nhiều máy chủ MySQL theo cấu hình active-active hoặc active-passive — nội dung này nằm ngoài phạm vi bài viết.

Thông tin

Container WordPress chứa mã ứng dụng, nhưng toàn bộ tệp tải lên và nội dung được lưu trong một persistent volume dùng chung cho mọi pod WordPress. Vì driver lưu trữ của Vietnix Cloud chỉ hỗ trợ chế độ truy cập ReadWriteOnce (RWO), volume dùng chung cho nhiều pod phải được cung cấp qua một NFS server bên ngoài với chế độ ReadWriteMany (RWX). Đó là lý do bài viết thiết lập NFS server trước.

Điều kiện tiên quyết

Trước khi bắt đầu, hãy đảm bảo bạn có:

  • Tài khoản Vietnix Enterprise Cloud với project đủ quota để chạy một cụm Kubernetes và thêm một VM. Đảm bảo quota project bao gồm CPU, RAM, disk, dung lượng block storage (Cinder) (cho volume MySQL), và Floating IP (cho Kubernetes API và Load Balancer của WordPress).
  • Một virtual networkvirtual router trong project (xem Tạo NetworkTạo Virtual Router).
  • Một SSH key đã thêm vào project (xem Quản lý SSH Key).
  • Một Floating IP cho Kubernetes API và Load Balancer của WordPress. Floating IP cho NFS server là tùy chọn (xem Bước 4.2 và Floating IP).
  • Một image TrueNAS ISO (Community Edition) đã upload vào project (xem Upload Image). Bài viết dùng TrueNAS 25.10.7:
  • Đã cài kubectl trên máy cá nhân. Cài kubectl.
  • Đã cài Helm trên máy cá nhân. Cài Helm.
  • Hiểu biết cơ bản về các khái niệm Kubernetes (Pod, Deployment, Service, PVC, StorageClass).

Bước 1: Tạo cụm Kubernetes

Làm theo bài Create Cluster để tạo cụm trên Vietnix Cloud Dashboard. Với ví dụ trong bài viết, cấu hình khuyến nghị là:

  • Phiên bản Kubernetes: phiên bản mới nhất được hỗ trợ (ví dụ v1.31.2)
  • Tên cụm: cluster01
  • SSH key: SSH key bạn đã tải lên
  • Network: mạng private của bạn
  • Floating IP address: For Kubernetes API (chỉ API server có IP public)
  • High Availability: bật (3 master node)
  • Flavor master node: large (tối thiểu 2 vCPU / 4 GiB RAM)
  • Worker nodes: 3 × flavor medium
  • Autoscaling: với demo, để tắt và dùng 3 node; với production, bật với Minimum 3Maximum 5 để cụm chịu được khi một node gặp sự cố và đáp ứng lưu lượng tăng vọt
  • Container volume: mặc định (20 GB) hoặc lớn hơn
  • Integrated monitoring: bật (tùy chọn, khuyến nghị)
Thông tin

Autoscaling phản ứng dựa trên resource requests của pod, vì vậy manifest WordPress và MySQL bên dưới có khai báo resources.requests. Xem Create Cluster để biết thêm cách chọn Minimum/Maximum.

Bước 2: Kết nối tới cụm

Khi cụm ở trạng thái Active, tải kubeconfig và kết nối từ máy cá nhân. Xem Connect Cluster để biết mọi cách. Cách nhanh nhất:

export KUBECONFIG=/path/to/your/cluster01.kubeconfig
kubectl get nodes

Bạn sẽ thấy các master và worker node ở trạng thái Ready:

NAME                              STATUS   ROLES    AGE   VERSION
cluster01-xxxxxxxx-master-0 Ready master 10m v1.31.2
cluster01-xxxxxxxx-master-1 Ready master 10m v1.31.2
cluster01-xxxxxxxx-master-2 Ready master 10m v1.31.2
cluster01-xxxxxxxx-node-0 Ready <none> 9m v1.31.2
cluster01-xxxxxxxx-node-1 Ready <none> 9m v1.31.2
cluster01-xxxxxxxx-node-2 Ready <none> 9m v1.31.2

Bước 3: Tạo StorageClass

Tạo file storage-class.yaml. StorageClass này dùng provisioner CSI (Cinder) của Vietnix Cloud và được đánh dấu là mặc định, để volume của MySQL được tạo tự động.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: default
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
parameters:
type: nvmer3
volumeBindingMode: Immediate
reclaimPolicy: Delete
allowVolumeExpansion: true

Áp dụng và kiểm tra:

kubectl apply -f storage-class.yaml
kubectl get storageclass
NAME                PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
default (default) cinder.csi.openstack.org Delete Immediate true 10s
Lưu ý

parameters.type chọn volume type của Cinder. Trên Vietnix Cloud là nvmer3. Nếu project của bạn dùng volume type khác, hãy đổi cho phù hợp — nếu không, việc tạo volume có thể lỗi gigabytes_default ... quota is 0G.

Bước 4: Triển khai NFS server

Các pod WordPress cần một volume dùng chung ở chế độ ReadWriteMany (RWX). Vì CSI Cinder chỉ hỗ trợ RWO, chúng ta triển khai một NFS server trên máy ảo (một instance TrueNAS) trong cùng mạng private.

4.1 Tạo máy ảo NFS

NFS server dùng ba thiết bị lưu trữ — đừng nhầm lẫn chúng:

Thiết bịKích thướcMục đích
Volume boot (1st boot)16–64 GiB (bài viết: 64 GiB)Đĩa hệ thống nơi cài TrueNAS
Volume CD/DVD (2nd boot)~2.5 GiBISO cài đặt TrueNAS 25.10.7 — chỉ là media cài đặt
Volume dữ liệu200 GiBVolume riêng, gắn sau khi tạo; chứa ZFS poolpool1 và NFS share
  1. Trên Vietnix Cloud Dashboard, vào Compute > Virtual Machines và nhấn Create Virtual Machine. Cấu hình:

    • Name: nas01
    • Volume boot: 64 GiB (16–100 GiB)
    • Volume CD/DVD: mount ISO TrueNAS 25.10.7 đã upload ở phần điều kiện tiên quyết
    • Flavor: large (4 vCPU, 8 GiB RAM)
    • Network: mạng private của bạn
  2. Deploy VM và mở console. VM sẽ khởi động vào trình cài TrueNAS từ volume CD/DVD:

    • Tại Choose destination media, chỉ chọn volume boot (~64–100 GiB) — nhấn Space để tick. Để trống đĩa dữ liệu 200 GiB: đĩa cài TrueNAS không thể dùng cho storage pool. Hãy chọn theo dung lượng, vì tên thiết bị (sda/sdb) có thể thay đổi.
    • Tại Web UI authentication method, chọn Administrative user (truenas_admin) và đặt mật khẩu. Đây là tài khoản dùng để đăng nhập TrueNAS Web UI. (Chỉ chọn Configure using Web UI nếu bạn muốn đặt thông tin admin sau, qua trình duyệt.)
    • Hoàn tất cài đặt và khởi động lại. Bạn có thể giữ hoặc gỡ ISO sau đó (xem Attach Volume để quản lý volume đã gắn).
  3. Tạo volume dữ liệu: vào Compute > Volumes > Create Volume, đặt Namenas01-data, Size200 GiB, rồi nhấn Create (xem Create Volume).

  4. Gắn volume vào VM: mở volume nas01-data, nhấn Attach Volume, chọn nas01, rồi nhấn Done.

  5. Khi tạo ZFS pool ở Bước 4.3, chọn đĩa dữ liệu 200 GiB (xuất hiện như đĩa thứ hai, ví dụ /dev/sdb) — không chọn volume boot hay CD/DVD.

Cảnh báo

Volume CD/DVD là ISO cài đặt (chỉ vài GiB), không phải đĩa dữ liệu. ZFS pool 200 GiB phải được tạo trên volume dữ liệu gắn ở bước 4.

Sau khi khởi động lại, TrueNAS hiển thị menu Console setup kèm địa chỉ Web UI (ví dụ http://192.168.1.32). Bạn không cần chọn mục nào ở đây — hãy tiếp tục cấu hình trên Web UI. Ghi lại private IP của VM: đây chính là <nas01_private_ip> dùng ở Bước 5. Nếu IP đó không nằm trong dải mạng private của bạn, chọn 1) Configure network interfaces (hoặc 2) Configure network settings) để đặt IP tĩnh trước khi tiếp tục.

4.2 (Tùy chọn) Gán Floating IP

Thông tin

Floating IP chỉ cần để truy cập TrueNAS Web UI từ máy của bạn. Lưu lượng NFS mà cụm Kubernetes dùng đi qua private IP (<nas01_private_ip>), nên Floating IP không cần thiết cho WordPress.

Vào Compute > Floating IPs, nhấn Add Floating IP, chọn public network và gán IP này với private IP của nas01. Điều này giúp bạn truy cập giao diện quản trị TrueNAS từ Internet.

Bạn có thể bỏ qua bước này nếu truy cập được TrueNAS Web UI qua mạng private (ví dụ qua VPN), hoặc cấu hình TrueNAS từ console.

4.3 Cấu hình NFS server

  1. Mở trình duyệt và truy cập http://<nas01_private_ip> (hoặc Floating IP đã gán ở Bước 4.2). Đăng nhập bằng:

    • Username: truenas_admin
    • Password: mật khẩu bạn đã đặt trong trình cài

    Đừng dùng administrator — tài khoản đó không tồn tại. Nếu quên mật khẩu, hãy đổi lại từ menu Console setup của TrueNAS bằng tùy chọn 4) Change local administrator password.

    Sau khi đăng nhập, Dashboard của TrueNAS hiện ra. Dùng menu bên trái để cấu hình services, storage và shares.

    Dashboard TrueNAS

  2. Bật dịch vụ NFS. Trong TrueNAS 25.10, Services nằm ở System > Services (không có trong menu trái chính). Tìm NFS, nhấn biểu tượng Edit (bút chì) và đặt:

    • Bind IP Addresses: để trống (nghe trên mọi interface)
    • Enabled Protocols: NFSv3, NFSv4
    • NFSv4 DNS Domain: để trống
    • Require Kerberos for NFSv4: tắt
    • Allow non-root mount: bật
    • Ports, RDMA và Manage Groups Server-side: giữ mặc định (trống/tắt)
    • Nhấn Save, sau đó gạt công tắc dịch vụ NFS sang ON (hoặc nhấn Start). Đảm bảo Start Automatically được bật để NFS tự chạy sau khi khởi động lại.
  3. Tạo ZFS pool: vào Storage > Create Pool (hoặc Storage > Pools > Add) và đặt Namepool1. Ở bước Data của wizard:

    • Layout: Stripe
    • Disk Size: chọn đĩa 200 GiB (volume dữ liệu)
    • Width: 1, Number of VDEVs: 1
    • Nhấn Next, rồi Save And Go To ReviewCreate.
    Cảnh báo

    Pool stripe không có dự phòng — nếu đĩa hỏng, pool và dữ liệu WordPress sẽ mất. Điều này chấp nhận được cho demo. Với NFS server production, hãy dùng layout mirror hoặc RAIDZ với nhiều đĩa.

  4. Đảm bảo pool pool1 đã được tạo và ở trạng thái Online (xem Storage > Pools). Sau đó vào Datasets, chọn pool1, nhấn Add Dataset, đặt Nameshare1 và giữ Dataset Preset = Generic, rồi nhấn Save.

    • Tên dataset chỉ được dùng chữ thường, chữ số và dấu gạch ngang — không dùng dấu cách, gạch dưới, dấu / hay ký tự đặc biệt khác.
  5. Tạo NFS share: vào Shares > Unix Shares (NFS) và nhấn Add. Đặt:

    • Path: /mnt/pool1/share1
    • Enabled: bật
    • Trong Advanced Options: Read Only = tắt, All Directories = bật (nếu có)
    • Mapall User / Group: root / root (để pod WordPress và NFS provisioner ghi được vào share); để trống Maproot
    • Nhấn Save.

    NFS share đã bật

    Lưu ý

    Cài đặt Mapall User/Group là bắt buộc để NFS provisioner tạo được thư mục /persistentvolumes bên trong share.

4.4 Kiểm tra NFS share

Mount share từ máy cá nhân để xác nhận hoạt động (ví dụ với macOS):

mkdir -p ~/Desktop/nfs
sudo mount -t nfs <nas01_private_ip>:/mnt/pool1/share1 ~/Desktop/nfs
cd ~/Desktop/nfs && touch test-file && rm test-file
Mẹo

Để bảo mật, hãy giới hạn truy cập NFS server bằng Security Group: chỉ cho phép Any inbound từ dải IP private của bạn, và cho phép HTTPS chỉ từ IP public của bạn. Giữ nguyên outbound rules mặc định.

Bước 5: Triển khai NFS subdir external provisioner

NFS subdir external provisioner tự động tạo persistent volume trên NFS server. Thêm Helm repository và cài đặt:

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update

helm install nfs-external nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=<nas01_private_ip> \
--set nfs.path=/mnt/pool1/share1 \
--set storageClass.accessModes=ReadWriteMany \
--set storageClass.name=nfs

Trong đó:

  • nfs.server — địa chỉ IP private của NFS server.
  • nfs.path — đường dẫn share (/mnt/pool1/share1).
  • storageClass.accessModes — chế độ truy cập của PV, ReadWriteMany.
  • storageClass.name — tên StorageClass mới (nfs).

Kiểm tra StorageClass mới:

kubectl get storageclass
NAME                PROVISIONER                                                    RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
default (default) cinder.csi.openstack.org Delete Immediate true 15m
nfs cluster.local/nfs-external-nfs-subdir-external-provisioner Delete Immediate true 30s

Bước 6: Triển khai WordPress và MySQL

Tạo các file sau trong cùng một thư mục. kustomization.yaml liên kết mọi thứ: tạo secret cho MySQL, sau đó áp dụng manifest MySQL và WordPress.

secretGenerator:
- name: mysql-pass
literals:
- password=ChangeMe123!
resources:
- mysql-deployment.yaml
- wordpress-deployment-nfs.yaml
apiVersion: v1
kind: Service
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
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:8.0
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
- name: MYSQL_DATABASE
value: wordpress
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pvc
apiVersion: v1
kind: Service
metadata:
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
tier: frontend
type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wp-pv-claim
labels:
app: wordpress
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
replicas: 3
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:6-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
- name: WORDPRESS_DB_NAME
value: wordpress
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wp-pv-claim

Triển khai toàn bộ:

kubectl apply -k ./

Kiểm tra các tài nguyên đã tạo:

kubectl get secrets
kubectl get pvc
kubectl get deployment
kubectl get pod
NAME                    TYPE     DATA   AGE
mysql-pass-xxxxxxxxxx Opaque 1 1m

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pvc Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 20Gi RWO default 1m
wp-pv-claim Bound pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 20Gi RWX nfs 1m

NAME READY UP-TO-DATE AVAILABLE AGE
nfs-external-nfs-subdir-external-provisioner 1/1 1 1 10m
wordpress 3/3 3 3 1m
wordpress-mysql 1/1 1 1 1m

Bước 7: Truy cập WordPress

Lấy địa chỉ public của service WordPress:

kubectl get services wordpress
NAME        TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
wordpress LoadBalancer 10.254.158.185 203.0.113.20 80:30717/TCP 2m

EXTERNAL-IP chính là Floating IP được tự động gán cho load balancer tạo ra cho service WordPress này trong project của bạn. Mở địa chỉ đó bằng trình duyệt:

http://<EXTERNAL-IP>/

Bạn sẽ nhận được trình cài đặt WordPress. Điền Site Title, Username quản trị, Password mạnh và Email, rồi nhấn Install WordPress để hoàn tất.

Trang cài đặt WordPress

Bước 8: Kiểm thử tính sẵn sàng cao và mở rộng

Vì đã triển khai 3 replica WordPress phía sau Load Balancer, WordPress vẫn hoạt động ngay cả khi một worker node gặp sự cố.

  1. Trên Dashboard, vào Compute > Virtual MachinesPower off một trong các worker node của Kubernetes (...-node-...).

  2. Liệt kê các pod WordPress:

    kubectl get pod | grep wordpress

    Bạn sẽ thấy một pod ở trạng thái Terminating và một pod mới đang được tạo. Với cấu hình Kubernetes mặc định, việc lập lịch lại có thể mất tới 5 phút, và website vẫn truy cập được trong thời gian này.

  3. Để xử lý lưu lượng lớn hơn, scale deployment WordPress:

    kubectl scale --replicas=5 deployment/wordpress
    kubectl get pod | grep wordpress

Bạn cũng có thể sửa giá trị replicas trong wordpress-deployment-nfs.yaml và áp dụng lại:

kubectl apply -k ./
Mẹo

Scale Deployment giúp thêm pod, nhưng pod vẫn cần tài nguyên của worker node. Nếu bạn đã bật Autoscaling cho worker group (Bước 1), cụm sẽ tự thêm worker node khi pod không thể được lập lịch — đó là lý do deployment có khai báo resources.requests.

Bước 9 (Tùy chọn): Triển khai bằng Helm và Bitnami

Để có cấu hình sẵn sàng cao hoàn chỉnh, bạn có thể triển khai WordPress bằng Bitnami WordPress chart, bao gồm MariaDB (có replication), Memcached và metrics — chỉ với một lệnh. Cách này cần StorageClass nfs từ Bước 5.

Tạo file values mặc định và xem qua:

helm show values oci://registry-1.docker.io/bitnamicharts/wordpress > wordpress.yaml

Chỉnh các thiết lập quan trọng trong wordpress.yaml:

global:
storageClass: nfs
wordpressUsername: admin
wordpressPassword: "ChangeMe123!"
replicaCount: 3

mariadb:
enabled: true
architecture: replication
primary:
persistence:
storageClass: default
secondary:
persistence:
storageClass: default

memcached:
enabled: true

metrics:
enabled: true

Cài đặt chart:

helm install -f wordpress.yaml my-wp oci://registry-1.docker.io/bitnamicharts/wordpress

Sau đó làm theo hướng dẫn hiển thị trên màn hình để lấy URL WordPress:

export SERVICE_IP=$(kubectl get svc --namespace default my-wp-wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}")
echo "WordPress URL: http://$SERVICE_IP/"
echo "WordPress Admin URL: http://$SERVICE_IP/admin"

Dọn dẹp

Xóa toàn bộ tài nguyên tạo bởi manifest kustomize:

kubectl delete -k ./

Xóa release Bitnami (nếu đã cài):

helm uninstall my-wp
Cảnh báo

Việc xóa PersistentVolumeClaim có thể xóa luôn volume bên dưới tùy theo reclaim policy. Hãy sao lưu nội dung WordPress và database trước khi dọn dẹp.

Bài viết liên quan