Mô hình triển khai

| Hostname | OS | IP | Mục đích |
| k8s-master-01 | Ubuntu 24.04 | 10.100.1.21 | Node control plane |
| k8s-worker-02 | Ubuntu 24.04 | 10.100.1.22 | Node worker 01 |
| k8s-worker-03 | Ubuntu 24.04 | 10.100.1.23 | Node worker 02 |
| srv025-npm-rancher | Ubuntu 24.04 | 10.100.1.25 | Server cài docker để cài npm và rancher |
| srv024-nfs-server | Ubuntu 24.04 | 10.100.1.24 | NFS Server |
| rancher | 10.100.1.55 | Rancher | |
| npm-server | 10.100.1.54 |
Hệ thống đã cài đặt xong cụm cluster k8s gồm 3 node (1 node control plane và 2 node worker).
Các bước triển khai
I. Cài đăt môi trường
1. Cài đặt nfs-server
Trên server 10.100.1.24 thực hiện các bước sau:
sudo apt install nfs-server -y
sudo mkdir -p /opt/nfs_data/{data,config}
sudo chown -R nobody:nogroup /opt/nfs_data
sudo chmod -R 777 /opt/nfs_data/data
sudo echo "/opt/nfs_data/data 10.100.1.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
sudo echo "/opt/nfs_data/config 10.100.1.0/24(rw,sync,no_subtree_check,no_root_squash)" >> /etc/exports
sudo exportfs -rav
sudo systemctl restart nfs-server
sudo systemctl restart nfs-kernel-server
Cài đặt và cấu hình NFS client trên tất cả các node của cụm k8s
sudo apt install nfs-common -y
2. Triển khai Dynamic Provisioner trên node master (k8s-master)
Add repo và update
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
Cài vào kube-system, đặt tên storageClass là nfs-storage
helm upgrade --install nfs-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
-n woocommerce \
--create-namespace \
--set nfs.server=10.100.1.24 \
--set nfs.path=/opt/nfs_data/data \
--set storageClass.name=nfs-storage \
--set storageClass.defaultClass=false
Kiểm tra
kubectl -n tonytechlab-storage get pods -l app=nfs-subdir-external-provisioner
kubectl get sc

Triển khai các thành phần chính của hệ thống
1. Tạo namespace 01-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: woocommerce
Áp dụng: kubectl apply -f 01-namespace.yaml
Tạo pvc tĩnh chứa các file config02-config-pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: config-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 10.100.1.24
path: /opt/nfs_data/config
persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: config-pvc
namespace: woocommerce
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
volumeName: config-pv
Áp dụng: kubectl apply -f 02-pvc-config.yaml
Kiểm tra: kubectl get pv
kubectl get pvc -n woocommerce

2. Triển khai MariaDB
03-–pvcmariadb.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mariadb-data-pvc
namespace: woocommerce
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-storage
Áp dụng kubectl apply -f 03-pvc-mariadb.yaml
04-mariadb-confimap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mariadb-configmap
namespace: woocommerce
data:
my.cnf: |
[mysqld]
max_connections=200
sql_mode=STRICT_ALL_TABLES
Áp dụng: kubectl apply -f 04-mariadb-confimap.yaml
05-mariadb-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mariadb-secret
namespace: woocommerce
type: Opaque
data:
mysql-root-password: Um9vdFBhc3NAMjAyNQ==
mysql-user: YmVfd29vX3VzZXI=
mysql-password: MkJKb2NzZnNMR0FfNmpuQg==
mysql-database: YmVfd29vX2Ri
Áp dụng: kubectl apply -f 05-mariadb-secret.yaml
06-mariadb-stateful.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mariadb
namespace: woocommerce
spec:
serviceName: mariadb
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
containers:
- name: mariadb
image: mariadb:11.3
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-root-password
- name: MYSQL_DATABASE
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-database
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-user
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-password
volumeMounts:
- name: mariadb-data
mountPath: /var/lib/mysql
- name: config-pvc
mountPath: /docker-entrypoint-initdb.d
- name: mariadb-configmap
mountPath: /etc/mysql/conf.d
volumes:
- name: mariadb-data
persistentVolumeClaim:
claimName: mariadb-data-pvc
- name: config-pvc
persistentVolumeClaim:
claimName: config-pvc
- name: mariadb-configmap
configMap:
name: mariadb-configmap
Áp dụng: kubectl apply -f 06-mariadb-stateful.yamlkubectl get po, sts -n woocommerce

07-mariadb-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mariadb
namespace: woocommerce
spec:
ports:
- port: 3306
targetPort: 3306
selector:
app: mariadb
clusterIP: None
App dụng: kubectl apply -f 07-mariadb-service.yaml
Kiểm tra: kubectl get po,sts,svc -n woocommerce

3. Triển khai Redis
08-redis-stateful.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: woocommerce
spec:
serviceName: redis
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.4
args: [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
ports:
- containerPort: 6379
env:
volumeMounts:
- name: config-pvc
mountPath: /usr/local/etc/redis
- name: redis-data
mountPath: /data
volumes:
- name: config-pvc
persistentVolumeClaim:
claimName: config-pvc
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: nfs-storage
resources:
requests:
storage: 1Gi
Áp dụng: kubectl apply -f 08-redis-stateful.yaml
09-redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: woocommerce
spec:
selector:
app: redis
ports:
- name: redis
port: 6379
targetPort: 6379
clusterIP: None
Áp dụng: kubectl apply -f 09-redis-service.yaml
Kiểm tra: kubectl get po,svc,sts -n woocommerce

4. Triển khai woocommerce backend
10-wordpress-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wordpres-source-pvc
namespace: woocommerce
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-storage
11-wordpres-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: wordpres-secret
namespace: woocommerce
type: Opaque
stringData:
mysql-host: "mariadb.woocommerce.svc.cluster.local"
redis-host: "redis.woocommerce.svc.cluster.local"
wp-auth-key: "HN 6uo{dDGOKKwfjSA{@k>u^[=>^p,2shLbU,%$U%*:-&qy}Pkn^]dep%A*hfE|V"
wp-secure-auth-key: ">gcmuCuxI-yhl]hE0uQ3Q0Ilj=cB3s%q. i.$aSBwGfu{*Oj#SqZ=iPweU,HLLU>"
wp-logged-in-key: ")2z479gF0 hdiVnAB[Cz4GHtZU_8B>l-mGort2xCg?E!S9zYX<->iu/2tGVc}7pf"
wp-nonce-key: "u`|r|ty#2T(-#{V#n+diN=ZHQjh fs8F,d*d1b]!Pw)bB^)+tl=l>!@chm(Qjq|d"
wp-auth-salt: "|7$K+PhxA-z9(oK[7%V7ZC-zP`adx_6;!3- +$A:o$aF-YpAyVOJtgP*.t)yrnS@"
wp-secure-auth-salt: "hdNNnU~m-jJ1dC+Ba19E#9]q#yeK}^LtehHOzpz(f+rtPAku!kd05ll>97N~{[$*"
wp-logged-in-salt: "h?I|m/}.+1p ]:5v Y/7z;j5%=X;D7,{XNY/2^cGQ/dH_`**-|{j+;3^p<icc-Bd"
wp-nonce-salt: "<[$)~_Br7W:l&CjTK_40F ?yjG/4@vZ,%l9k-)Dtl%qVW0=#-N;qIhT FjP-oP-]"
Lưu ý: Nếu dữ liệu đưa vào đã đươc mã hóa base64 thì từ khóa stringData sẽ được thay bằng data, Nếu dúng từ khóa stingData thì dữ liệu sẽ được k8s mã hóa qua thuật toán base64 trước khi đưa vào secrect
Áp dụng: kubectl apply -f 11-wordpres-secret.yaml
12-wordpress-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: woocommerce-backend
namespace: woocommerce
spec:
replicas: 1
selector:
matchLabels:
app: woocommerce-backend
template:
metadata:
labels:
app: woocommerce-backend
spec:
containers:
- name: wordpress
image: beobeo/openlitespeed-wordpress:v2
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
valueFrom:
secretKeyRef:
name: wordpres-secret
key: mysql-host
- name: WORDPRESS_DB_USER
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-user
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-password
- name: WORDPRESS_DB_NAME
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mysql-database
- name: AUTH_KEY
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-auth-key
- name: SECURE_AUTH_KEY
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-secure-auth-key
- name: LOGGED_IN_KEY
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-logged-in-key
- name: NONCE_KEY
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-nonce-key
- name: AUTH_SALT
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-auth-salt
- name: SECURE_AUTH_SALT
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-secure-auth-salt
- name: LOGGED_IN_SALT
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-logged-in-salt
- name: NONCE_SALT
valueFrom:
secretKeyRef:
name: wordpres-secret
key: wp-nonce-salt
- name: REDIS_HOST
valueFrom:
secretKeyRef:
name: wordpres-secret
key: redis-host
- name: REDIS_PORT
value: "6379"
- name: WP_ENV
value: "production"
volumeMounts:
- name: wp-config
mountPath: /var/www/vhost/localhost/wp-config.php
subPath: wp-config.php
- name: wp-source
mountPath: /var/www/vhost/localhost
volumes:
- name: wp-config
persistentVolumeClaim:
claimName: config-pvc
- name: wp-source
persistentVolumeClaim:
claimName: wordpress-source-pvc
Áp dụng: kubectl apply -f 12-wordpress-deployment.yaml
Triển khai clusterip để gọi trong nội bố13-wordpress-cluserip.yaml
apiVersion: v1
kind: Service
metadata:
name: woocommerce-backend-cluster
namespace: woocommerce
spec:
selector:
app: woocommerce-backend
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
- name: admin
port: 7080
targetPort: 7080
type: ClusterIP
Áp dụng: kubectl apply -f 13-wordpress-cluserip.yaml
Triển khai Nodeport để truy cập từ ngoài vào và forward port qua NPM14-wordpress-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: woocommerce-backend-nodeport
namespace: woocommerce
spec:
selector:
app: woocommerce-backend
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30080
- name: https
port: 443
targetPort: 443
nodePort: 30443
- name: admin
port: 7080
targetPort: 7080
nodePort: 30780
type: NodePort
Áp dụng: kubectl apply -f 14-wordpress-nodeport.yaml
Kiểm tra hệ thống: kubectl get pod,svc,deploy,sts -n woocommerce

5. Triển khai frontend nodejs
Ta đã có image beobeo/frontend-nodejs:v1 chứa frontend15-frontend-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-config
namespace: woocommerce
data:
REACT_APP_WOOCOMMERCE_URL: "https://be.diendo.pro.vn"
REACT_APP_WC_CONSUMER_KEY: "ck_d0beb27226a3831d6b7e4ac6e046a5443fc1e85a"
REACT_APP_WC_CONSUMER_SECRET: "cs_2b97af95a2a5b110f57e7bb63f5e7cb1082d8f1f"
REACT_APP_API_BASE_URL: "https://be.diendo.pro.vn/wp-json/wc/"
Áp dụng: kubectl apply -f 15-frontend-configmap.yaml
16-frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-nodejs
namespace: woocommerce
spec:
replicas: 1
selector:
matchLabels:
app: frontend-nodejs
template:
metadata:
labels:
app: frontend-nodejs
spec:
containers:
- name: frontend-nodejs
image: beobeo/frontend-nodejs:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: frontend-config
Áp dụng: kubectl apply -f 16-frontend-deployment.yaml
17-frontend-service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-clusterip
namespace: woocommerce
spec:
selector:
app: frontend-nodejs
ports:
- port: 80
targetPort: 80
protocol: TCP
type: ClusterIP
Áp dụng: kubectl apply -f 17-frontend-service-clusterip.yaml
18-frontend-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-nodeport
namespace: woocommerce
spec:
selector:
app: frontend-nodejs
ports:
- port: 80
targetPort: 80
nodePort: 30090
protocol: TCP
type: NodePort
Áp dụng: kubectl apply -f 18-frontend-service-nodeport.yaml
Kiểm tra lai: kubectl get pod, svc, sts, deploy -n woocommerce

Đến đây ta có thể truy cập vào frontend và backend qua <IP_Node>:<PORT NodePort>
Tiếp theo ta sẽ tiến hành cài đặt các thành phần khác như Nginx Proxy, Rancher, Backup, Monitoring.
3. Triển khai các thành phần khác của hệ thống
1. Triển khai Nginx Proxy Manager
Trên onpremise tôi dùng Nginx Proxy Manager để làm Proxy đứng sau firewall để public các dịch vụ ra ngoài Internet.
Triển khai nginx proxy manager qua docker trên server 10.100.1.25
1.1 Tạo lớp mạng mới thông qua card mạng
docker network create -d macvlan --subnet=10.100.1.0/24 --ip-range=10.100.1.0/28 --gateway=10.100.1.8 -o macvlan_mode=bridge -o parent=ens160 proxy_network
1.2 Triển khai nginx proxy manager qua docker compose
file docker-composer.yaml
version: '3.9'
services:
nginx-proxy-manager:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: always
ports:
- '80:80' # HTTP
- '81:81' # Web UI
- '443:443' # HTTPS
environment:
DB_MYSQL_HOST: "10.100.1.54"
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: "npm"
DB_MYSQL_PASSWORD: "npm_password"
DB_MYSQL_NAME: "npm_db_1"
volumes:
- /opt/data/nginx/data:/data
- /opt/data/nginx/letsencrypt:/etc/letsencrypt
networks:
proxy_network:
ipv4_address: 10.100.1.55
npm-db-1:
image: 'mariadb:10.5'
container_name: npm-db-1
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'npm_rootpass'
MYSQL_DATABASE: 'npm_db_1'
MYSQL_USER: 'npm'
MYSQL_PASSWORD: 'npm_password'
volumes:
- /opt/data/mysql:/var/lib/mysql
networks:
proxy_network:
ipv4_address: 10.100.1.54
networks:
proxy_network:
external: true
docker compose up -d
1.3 Cấu hình domain và nginx proxy manager
Truy cập vào địa chỉ 10.100.1.55:81 để cấu hình npm dùng Email: [email protected] Password: changeme để đăng nhập vào để cấu hình.
Vào thay đổi email và password.

Cấu hình ssl trên NPM

Bấm vào Add SSL Certificate

Login vào Cloudflare để lấy API Token


Chọn Create Token

Chọn Edit zone DNS -> Use template

Chọn domain trong phần Zone Resourcer rồi chọn Continue to Summary

Chọn Create Token

Sau khi nhận được API Token copy vào NPM

Bấm Save để add domain

Add host để truy cập npm từ internetHost -> Proxy Hosts



Từ đây có thể vào nginx proxy manger qua địa chỉ https://npm.diendo.pro.vn
Cấu hình tên miền để web có thể vào từ ngoài internetHost -> Proxy Hosts

Chon SSL cho web.

Kiểm tra web từ ngoài vào: https://fe.diendo.pro.vn
2. Triển khai rancher
2.1 Triển khai rancher nằm ngoài cụm kubernetes để quản lý
thêm đoạn sau vào docker-compose.yaml
rancher:
image: rancher/rancher:v2.12.0
container_name: rancher
restart: always
privileged: true
environment:
CATTLE_BOOTSTRAP_PASSWORD: "BeoBeo@2025"
volumes:
- /opt/data/rancher/data:/var/lib/rancher
- /opt/data/rancher/ui:/usr/share/rancher/ui
networks:
proxy_network:
ipv4_address: 10.100.1.56
ports:
- "443:443"
sau đó triển khai: docker compose up -d
2.2 Cấu hình domain trên nginx proxy managerAdd Proxy Host


có thể truy cập vào rancher qua địa chỉ https://rancher.diendo.pro.vn
2.3 Phân quyền cho nhóm Dev, DevOps trong Rancher
Đăng nhập vào Rancher với quyền Admin

3. Triển khai hệ thống Monitoring, Alert sử dụng Prometheus – Grafana
3.1 Tạo namespace và add repo chart
kubectl create ns monitoring
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
3.2 Cấu hình values-prom.yaml
01-values-prom.yaml
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: nfs-storage
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
additionalScrapeConfigs:
- job_name: 'kube-state-metrics'
honor_timestamps: true
scrape_interval: 30s
scrape_timeout: 10s
metrics_path: /metrics
scheme: http
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name]
regex: kube-state-metrics
action: keep
service:
type: NodePort
nodePort: 30900
additionalService:
enabled: true
name: prometheus-clusterip
type: ClusterIP
port: 9090
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: nfs-storage
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
service:
type: NodePort
nodePort: 30902
additionalService:
enabled: true
name: alertmanager-clusterip
type: ClusterIP
port: 9093
grafana:
persistence:
enabled: true
storageClassName: nfs-storage
accessModes: ["ReadWriteOnce"]
size: 5Gi
service:
type: NodePort
nodePort: 30901
additionalService:
enabled: true
name: grafana-clusterip
type: ClusterIP
port: 80
ingress:
enabled: false
kube-state-metrics:
enabled: true
prometheusScrape: true
rbac:
create: true
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 100m
memory: 200Mi
prometheus-node-exporter:
enabled: true
# Bổ sung ServiceMonitor cho kube-controller-manager & kube-scheduler
kubeControllerManager:
enabled: true
service:
enabled: true
port: 10257
targetPort: 10257
type: ClusterIP
name: kube-controller-manager
selector:
component: kube-controller-manager
kubeScheduler:
enabled: true
service:
enabled: true
port: 10259
targetPort: 10259
type: ClusterIP
name: kube-scheduler
selector:
component: kube-scheduler
3.3 Cài đặt kube-prometheus-stack
helm upgrade --install monitoring prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace \
-f 01-values-prom.yaml
3.4 Bật servicemonitor-kube
02-servicemonitor-kube-components.yaml
apiVersion: v1
kind: Service
metadata:
name: kube-controller-manager
namespace: kube-system
labels:
k8s-app: kube-controller-manager
spec:
ports:
- name: http-metrics
port: 10257
targetPort: 10257
selector:
component: kube-controller-manager
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kube-controller-manager
namespace: monitoring
labels:
release: monitoring
spec:
selector:
matchLabels:
k8s-app: kube-controller-manager
namespaceSelector:
matchNames:
- kube-system
endpoints:
- port: http-metrics
scheme: https
tlsConfig:
insecureSkipVerify: true
interval: 30s
---
apiVersion: v1
kind: Service
metadata:
name: kube-scheduler
namespace: kube-system
labels:
k8s-app: kube-scheduler
spec:
ports:
- name: http-metrics
port: 10259
targetPort: 10259
selector:
component: kube-scheduler
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kube-scheduler
namespace: monitoring
labels:
release: monitoring
spec:
selector:
matchLabels:
k8s-app: kube-scheduler
namespaceSelector:
matchNames:
- kube-system
endpoints:
- port: http-metrics
scheme: https
tlsConfig:
insecureSkipVerify: true
interval: 30s
Áp dụng: kubectl apply -f 02-servicemonitor-kube-components.yaml
3.5 Dùng Nginx Proxy Manager để public các dịch vụ ra internet


Làm tương tự với các domain:grafana.diendo.pro.vn
promtheus.diendo.pro.vn
alert.diendo.pro.vn
4. Triển khai hệ thống Horizontal Pod Autoscaler (HPA)
Triển khai hệ thống HPA, yêu cầu như sau:
1. Khi CPU trên 75%, RAM trên 85%, CCU đặt 2000 thì sẽ scale Backend
2. Khi CPU trên 70%, RAM trên 80% CCU đạt 1500 thì sẽ scale Frontend
3. Khi CPU trên 85%, RAM trên 90% thì tăng statefulset mariadb
4.1 Đảm bảo Metrics API đang hoạt động
kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes" | jq
Có dữ liệu CPU, memory thì đã OK

4.2 Tạo HPA cho Backend và Frontend bằng CPU và RAM
01-hpa-backend.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: backend-hpa
namespace: woocommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: woocommerce-backend
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 75
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 85
Áp dụng: kubectl apply -f 01-hpa-backend.yaml
02-hpa-frontend.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: frontend-hpa
namespace: woocommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: frontend-nodejs
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Áp dụng: kubectl apply -f 02-hpa-frontend.yaml
03-hpa-statefulset.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: mariadb-hpa
namespace: woocommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: mariadb
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 85
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 90
Áp dụng: kubectl apply -f 03-hpa-mariadb.yaml
4.3 Thềm điều kiện Concurrent User (CCU)
Backend (scale khi CCU ≥ 2000)
Frontend (scale khi CCU ≥ 1500)
Sẽ nghiên cứu triển khai sau.
4.4 Triển khai kuma và cảnh báo qua email khi vượt quá ngưỡng alert
Cài đặt kuma bằng helm
helm repo add kuma https://kumahq.github.io/charts
helm repo update
helm upgrade --install kuma kuma/kuma \
--namespace kuma-system \
--create-namespace \
--set crds.enabled=true
kubectl get pods -n kuma-system
NAME READY STATUS RESTARTS AGE
kuma-control-plane-65d9c9cc9f-r7trj 1/1 Running 0 53s
Bật Prometheus Metrics cho Kuma
03-mesh-metrics.yaml
apiVersion: kuma.io/v1alpha1
kind: Mesh
metadata:
name: default
spec:
metrics:
enabledBackend: prometheus-1
backends:
- name: prometheus-1
type: prometheus
conf:
port: 5670
Áp dụng: kubectl apply -f 03-mesh-metrics.yaml
Cấu hình AlertManager gửi email
04-alertmanager.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: alertmanager-config
namespace: monitoring
labels:
app: alertmanager
data:
alertmanager.yaml: |
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.gmail.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'C5-FB-2E-60-AC-BF'
route:
receiver: email-alert
group_wait: 30s
group_interval: 5m
repeat_interval: 3h
receivers:
- name: email-alert
email_configs:
- to: '[email protected]'
send_resolved: true
Áp dụng: kubectl -n monitoring apply -f 04-alertmanager.yaml
Viết Alert Rules cho Kuma
Cảnh báo khi letency > 500ms hoặc error rate > 5%
05-kuma-alert-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: kuma-alert-rules
namespace: monitoring
spec:
groups:
- name: kuma.rules
rules:
- alert: HighLatency
expr: histogram_quantile(0.95, rate(kuma_dp_requests_latency_seconds_bucket[5m])) > 0.5
for: 2m
labels:
severity: warning
annotations:
summary: "High request latency detected"
description: "95th percentile latency > 500ms"
- alert: HighErrorRate
expr: rate(kuma_dp_requests_errors_total[5m]) / rate(kuma_dp_requests_total[5m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "High request error rate detected"
description: "Error rate > 5%"
Tạo Grafana Dashboard
kuma-grafana-dashboard.json
{
"id": null,
"title": "Kuma Service Mesh Metrics",
"tags": ["kuma", "service-mesh"],
"timezone": "browser",
"schemaVersion": 36,
"version": 1,
"refresh": "30s",
"panels": [
{
"type": "graph",
"title": "Request Latency (p95)",
"targets": [
{
"expr": "histogram_quantile(0.95, rate(kuma_dp_requests_latency_seconds_bucket[5m]))",
"legendFormat": "{{service}}"
}
],
"yaxes": [
{ "format": "s", "label": "Latency (s)" },
{ "format": "short" }
]
},
{
"type": "graph",
"title": "Request Throughput (RPS)",
"targets": [
{
"expr": "rate(kuma_dp_requests_total[1m])",
"legendFormat": "{{service}}"
}
],
"yaxes": [
{ "format": "reqps", "label": "Requests/s" },
{ "format": "short" }
]
},
{
"type": "graph",
"title": "Error Rate (%)",
"targets": [
{
"expr": "rate(kuma_dp_requests_errors_total[5m]) / rate(kuma_dp_requests_total[5m]) * 100",
"legendFormat": "{{service}}"
}
],
"yaxes": [
{ "format": "percent", "label": "Error Rate" },
{ "format": "short" }
]
}
]
}
Vào grafana -> Dashboard -> New -> Import



Đã có Dashboard để theo dõi
5. Backup và Restore trên công cụ Velero
5.1 Cài đặt MiniO
Triển khai trên nfs-server
Cài đặt docker để sử dụng
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list> /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose -y
#add user vào nhóm docker
sudo usermod -aG docker iadmin
Do server nfs phân vùng để /opt là lớn nhất nên cần chuyển vị trí lưu trữ của docker sang /opt
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 2G 0 part /boot
└─sda3 8:3 0 98G 0 part
├─vg01-lv--01--root 252:0 0 40G 0 lvm /
├─vg01-lv--01--opt 252:1 0 50G 0 lvm /opt
└─vg01-lv--03--swap 252:2 0 8G 0 lvm [SWAP]
edit file /etc/docker/daemon.json
{
"data-root":"/opt/docker",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"bip": "172.17.0.1/24",
"storage-driver": "overlay2"
}
Tạo thư mục /opt/docker và phân quyền
sudo mkdir /opt/docker
sudo chown -R iadmin:docker /opt/docker/
sudo chmod -R 775 /opt/docker
sudo systemctl restart docker.service docker.socket
Tạo lớp mạng để thực hiện kết nối với hệ thống
docker network create -d macvlan --subnet=10.100.1.0/24 --ip-range=10.100.1.0/28 --gateway=10.100.1.8 -o macvlan_mode=bridge -o parent=ens160 backup_network
Tạo thư mục chứa dữ liệu backup
sudo mkdir /opt/storage
Tạo file docker-compose.yaml để triển khai MiniO
version: '3'
services:
minio:
image: minio/minio
container_name: minio
ports:
- "9000:9000"
- "9001:9001"
volumes:
- /opt/storage:/data
environment:
MINIO_ROOT_USER: beobeo
MINIO_ROOT_PASSWORD: BeoBeo123@123a
command: server --console-address ":9001" /data
networks:
storage_network:
ipv4_address: 10.100.1.58
networks:
storage_network:
external: true
Triển khai: docker compose up -d
Dung NPM để public minio ra internet
Login vào với username và password như trong file docker-compose.yml.
Tạo bucket để chưa backup.


5.2 Tạo xác thực MiniO
Tại máy khác (máy cải rancher) ta tiến hành cài mc-client
Bước 1: Cài đặt MiniO Client
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo cp mc /usr/local/bin/mc
Bước 2: Cấu hình Alias kết nối đến MiniO Server
# mc alias set <TÊN_ALIAS> <ACCESS_KEY_GỐC> <SECRET_KEY_GỐC>
mc alias set beobeo-minio http://10.100.1.58:9000 beobeo BeoBeo123@123a

Bước 3: Tạo Service Account (Access Key & Secret Key mới)
# mc admin user svcacct add <TÊN_ALIAS> <TÊN_USER_SỞ_HỮU>
mc admin user svcacct add beobeo-minio beobeo
Kết quả:
Access Key: KSOWE6IW6G7M0ORM7OG9
Secret Key: PH7+kCuOObxWoyVaT5k+t+egcrSVeQIF1z2jc0Su
Expiration: no-expiry

5.3 Cài đặt Velero client thực hiện trên node master
Ta truy cập trực tiếp vào Releases · vmware-tanzu/velero để lấy bản mới nhất


# wget https://github.com/vmware-tanzu/velero/releases/download/v1.17.0-rc.1/velero-v1.17.0-rc.1-linux-amd64.tar.gz
# tar -xvf velero-*
# sudo cp velero-v1.17.0-rc.1-linux-amd64/velero /usr/local/bin
5.4 Cấu hình các biến MiniO – Thực hiện trên node master
cat << EOF > ./credentials-velero
[default]
aws_access_key_id=KSOWE6IW6G7M0ORM7OG9
aws_secret_access_key=PH7+kCuOObxWoyVaT5k+t+egcrSVeQIF1z2jc0Su
EOF
5.5 Cài đặt MiniO làm backend lưu trữ các bạn sao lưu của kubernetes
Thực hiện trên node master
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.10.0 \
--bucket beobeo-k8s-backup \
--namespace velero \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://10.100.1.58:9000
Đến đây ta có thể backup và restore tài nguyên trên k8s
Backup tài nguyên:
# Backup 1 namespace cụ thể
velero backup create backup-woocommerce-20250919 --include-namespaces woocommerce
# Kiểm tra trạng thái của backup
velero backup describe backup-woocommerce-20250919
#Backup cả cụm k8s
velero backup create full-cluster-except-system-20250919 --exclude-namespaces kube-system,velero
# Kiểm tra trạng thái của backup
velero backup describe full-cluster-except-system-20250919
Restore
# Restore toàn bộ từ môt bản backup
# velero restore create --from-backup <TÊN_BẢN_BACKUP>
velero restore create --from-backup full-cluster-except-system-20250919
velero restore describe full-cluster-except-system-20250919
# Restore một namespace cụ thể
# velero restore create <TÊN_RESTORE> --from-backup <TÊN_BẢN_BACKUP> --include-namespaces <TÊN_NAMESPACE>
velero restore create restore-woocommerce-only --from-backup full-cluster-except-system-20250919 --include-namespaces woocommerce
# Restore từ một namespace này sang một namespace khác
# velero restore create <TÊN_RESTORE> \
--from-backup <TÊN_BACKUP> \
--namespace-mappings <NAMESPACE_CŨ>:<NAMESPACE_MỚI>
velero restore create restore-prod-to-staging \
--from-backup backup-production-app \
--namespace-mappings production:staging
# Kiểm tra trạng thái
# Xem danh sách
velero restore get
# Xem chi tiết một lần phục hồi
velero restore describe <TÊN_RESTORE>
Lập lịch Backup tự động
# Backup vào lúc 2 giờ sáng mỗi ngày và tự động xóa các bản backup cũ hơn 30 ngày (720h)
velero schedule create daily-full-backup \
--schedule="0 2 * * *" \
--ttl 720h0m0s
# Backup namespace production vào 3 giờ sáng Chủ Nhật hàng tuần.
velero schedule create weekly-production-backup \
--schedule="0 3 * * 0" \
--include-namespaces production \
--ttl 720h0m0s
# Kiểm tra lịch đã tạo
velero schedule get