1. Cài đặt ConfigMap
Mục đích: Tách cấu hình ra khỏi mã nguồn ứng dụng, giúp thay đổi cấu hình mà không cần rebuild Docker image hoặc redeploy ứng dụng.
Lợi ích:
- Lưu trữ cấu hình dưới dạng key-value không nhạy cảm
- Truyền cấu hình vào container dưới dạng biến môi trường hoặc file
- Tăng tính tái sử dụng và nhất quán giữa các Pod
2. Chuẩn bị Dockerfile và Image
- Viết Dockerfile cho phần backend

- Build và push image lên Docker Hub

3. Tạo ConfigMap ecommerce-backend-application-properties-configmap
- Deployment đã có
volumeMountsvàvolumesđể sử dụng ConfigMap - Rebuild backend để áp dụng cấu hình mới

apiVersion: v1
kind: ConfigMap
metadata:
name: ecommerce-backend-application-properties-configmap
namespace: ecommerce
data:
application.properties: |
spring.datasource.url=jdbc:mysql://192.168.9.26:3306/full-stack-ecommerce #chú ý thay đổi địa chỉ IP của bạn
spring.datasource.username=ecommerceapp
spring.datasource.password=StrongPa55WorD
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.sql-script-encoding=UTF-8
spring.jpa.properties.hibernate.globally_quoted_i/dentifiers=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.data.rest.base-path=/api
spring.data.rest.detection-strategy=ANNOTATED
allowed.origins=http://ecommerce.hoatran.local
okta.oauth2.client-id=0oab0lzwjoN1Rjsar5d7
okta.oauth2.issuer=https://dev-82108115.okta.com/oauth2/default

4. Tạo Secret trong Kubernetes
Secret là đối tượng dùng để lưu trữ thông tin nhạy cảm như:
- Mật khẩu
- Token
- API key
Lợi ích:
- Tách biệt dữ liệu nhạy cảm khỏi mã nguồn
- Tăng cường bảo mật khi triển khai ứng dụng
5. File cấu hình Secret
yaml
apiVersion: v1
kind: Secret
metadata:
name: ecommerce-backend-database-connection
namespace: hoatraclocal-ecommerce
type: Opaque
stringData:
MARIADB_HOST: "192.168.9.26"
MARIADB_DB: "full-stack-ecommerce"
MARIADB_PORT: "3306"
MARIADB_USERNAME: "ecommerceapp"
MARIADB_PASSWORD: "StrongPa55WorD"
6. Điều chỉnh nội dung trong ConfigMap
spring.datasource.url=jdbc:mysql://${MARIADB_HOST}:${MARIADB_PORT}/${MARIADB_DB}
spring.datasource.username=${MARIADB_USERNAME}
spring.datasource.password=${MARIADB_PASSWORD}
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.sql-script-encoding=UTF-8
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.data.rest.base-path=/api
spring.data.rest.detection-strategy=ANNOTATED
allowed.origins=http://ecommerce.hoatran.local
okta.oauth2.client-id=0aab0lzvjoN1Rjsar5d7
okta.oauth2.issuer=https://dev-82108115.okta.com/oauth2/default
7. Thêm Secret vào Deployment backend
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: your-deployment
namespace: your-namespace
spec:
replicas: 1
selector:
matchLabels:
app: your-app
template:
metadata:
labels:
app: your-app
spec:
containers:
- name: your-container
image: hoatrancntt/befm:v1
imagePullSecrets:
- name: auth-registry
8. StorageClass trong Kubernetes
Là gì? Định nghĩa loại lưu trữ mà Kubernetes có thể cung cấp.
Tính năng:
- Cấp phát động PV khi tạo PVC
- Mô tả cách tạo PV với đặc tính như loại ổ đĩa, hiệu năng, vùng lưu trữ
Thành phần chính:
provisioner: Plugin tạo PV (ví dụ:kubernetes.io/aws-ebs)parameters: Loại ổ đĩa, zone, mã hóareclaimPolicy:Delete,Retain,RecyclevolumeBindingMode:Immediate,WaitForFirstConsumerallowVolumeExpansion: Cho phép mở rộng dung lượng
9. PV và PVC trong Kubernetes
Persistent Volume (PV)
- Tài nguyên lưu trữ trong cụm K8s
- Được cấp phát bởi admin hoặc tự động qua StorageClass
- Tồn tại độc lập với Pod
- Hỗ trợ NFS, iSCSI, CSI, hostPath…
Persistent Volume Claim (PVC)
- Yêu cầu sử dụng lưu trữ từ PV
- Xác định kích thước, loại truy cập, StorageClass
- PVC được mount vào Pod như một volume
Mối quan hệ
- PVC yêu cầu → K8s gán PV phù hợp → PVC mount vào Pod → Pod sử dụng lưu trữ
10. Triển khai NFS lưu trữ
Cài đặt NFS Server
bash
sudo apt install nfs-server -y
sudo mkdir /data
sudo chown -R nobody:nogroup /data
sudo chmod -R 777 /data
sudo vi /etc/exports
# Thêm dòng:
/data *(rw,sync,no_subtree_check)
sudo exportfs -rav
sudo systemctl restart nfs-server
Cài đặt NFS Client
Thực hiện trên các node: k8s-master-1, k8s-master-2, k8s-master-3

Cấu hình PV
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
path: /data
server: 192.168.9.29 # Server NFS của bạn
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-storage
Cấu hình PVC
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
namespace: hoatranlocal-ecommerce
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
storageClassName: nfs-storage
Mount dữ liệu từ Pod vào thư mục /data
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-blog
namespace: hoatranlocal-ecommerce
spec:
replicas: 1
selector:
matchLabels:
app: wordpress-blog-selector
template:
metadata:
labels:
app: wordpress-blog-selector
spec:
containers:
- name: blog
image: litespeedtech/openlitespeed:latest
ports:
- containerPort: 7080
- containerPort: 80
volumeMounts:
- mountPath: /var/www
name: wwwdata
volumes:
- name: wwwdata
persistentVolumeClaim:
claimName: nfs-pvc
Kết quả kiểm tra
- PVC chuyển từ
Pending→Bound
/datatrên NFS server đã mount thành công
- Dữ liệu upload vào
/var/wwwtrong Pod sẽ lưu trực tiếp vào NFS
11. Triển khai MariaDB với StatefulSet
Cấu hình NFS Server
bash

# Trong /etc/exports
/data *(rw,sync,no_subtree_check,no_root_squash)
no_root_squash: Cho phép container ghi dữ liệu với quyền root (chỉ dùng cho môi trường test/lab)
StatefulSet MariaDB
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mariadb
namespace: hoatranlocal-ecommerce
spec:
serviceName: mariadb-service
replicas: 1
selector:
matchLabels:
app: mariadb
template:
metadata:
labels:
app: mariadb
spec:
securityContext:
fsGroup: 65534
containers:
- name: mariadb
image: mariadb:latest
env:
- name: MYSQL_ROOT_PASSWORD
value: "tonytechlab"
ports:
- containerPort: 3306
volumeMounts:
- mountPath: /var/lib/mysql
name: mariadb-storage
volumes:
- name: mariadb-storage
persistentVolumeClaim:
claimName: nfs-pvc
Service NodePort
yaml
apiVersion: v1
kind: Service
metadata:
name: mariadb-service
namespace: hoatranlocal-ecommerce
spec:
selector:
app: mariadb
type: NodePort
ports:
- port: 3306
targetPort: 3306
nodePort: 31306
Service ClusterIP
yaml
apiVersion: v1
kind: Service
metadata:
name: mariadb
namespace: hoatranlocal-ecommerce
spec:
type: ClusterIP
ports:
- name: mysql
port: 3306
targetPort: 3306
selector:
app: mariadb
DNS nội bộ để kết nối: mariadb.hoatranlocal-ecommerce.svc.cluster.local
Kiểm tra kết nối từ Pod OpenLiteSpeed
bash
mysql -h mariadb.hoatranlocal-ecommerce.svc.cluster.local -u root -p
Hoặc dùng telnet
