Chuyển một website từ VPS lên Kubernetes không khó. Chuyển hàng chục website mà không site nào bị gián đoạn thì cần một quy trình. Tài liệu này mô tả quy trình migrate website từ VPS lên cluster Kubernetes theo lô: chuẩn bị hạ tầng nhận site, pipeline khôi phục dữ liệu từ backup, thứ tự đổi DNS và bật HTTPS, cách kiểm tra site trên cluster mà không phụ thuộc DNS công khai, và đường lui khi có sự cố.
1. Trước khi migrate website: chuẩn bị chỗ chứa
Migrate website hàng loạt không chỉ là chạy nhiều lần một pipeline. Mỗi site cần một database, một thư mục NFS và một phần CPU, RAM trên node. Những việc phải xong trước đợt lớn:
- Database: máy MySQL nhận site đã sẵn sàng, pipeline tạo site đã biết tạo database ở đó (xem bài MySQL trong Kubernetes hay ngoài cluster: vì sao đưa database ra VPS).
- Lưu trữ: đủ máy NFS và dung lượng đĩa cho dữ liệu web của các site sắp chuyển.
- Chart ổn định: cách khai báo volume, probe, TLS đã chốt. Đừng vừa migrate website vừa đổi chart. Bài Helm chart với NFS PersistentVolume tĩnh, claimRef và ba loại probe mô tả một chart đủ ổn định cho việc này.
- Công tắc TLS theo từng site trong chart và pipeline (lý do ở mục 3).
- Sức chứa node: ước lượng request của các site sắp chuyển, thêm node trước nếu cần.
2. Pipeline migrate website: ghép hai pipeline có sẵn
Pipeline migrate website không cần viết lại từ đầu. Nó có thể là một parent pipeline ghép hai child pipeline đã chạy ổn trong mô hình Mỗi branch một pipeline vận hành: tự động hoá bằng GitLab CI: tạo site mới và khôi phục site từ backup.
migrate-site (parent)
├─ build: lấy .gitlab-ci.yml của branch "tạo site" và "restore" làm artifact
├─ deploy: trigger "tạo site" → namespace, database, thư mục NFS, helm install
└─ restore: trigger "restore" → lấy backup của site từ VPS cũ, nạp vào site mới
(needs: deploy, strategy: depend)Đầu vào cho mỗi lần migrate website gồm domain, máy nguồn đang chứa site, ngày của bản backup, loại site, máy database, máy NFS, node pool và cờ TLS. Mật khẩu database của site mới được sinh trong pipeline.
Bước khôi phục dữ liệu
Nguồn dữ liệu để migrate website là bản backup: mỗi site trên VPS có bản backup gồm file SQL và thư mục web trên object storage. Child pipeline restore làm các bước sau (lược bớt):
S3_PATH="s3://<bucket-backup>/<máy-nguồn>/${DATE_RESTORE}/${DOMAIN}"
s3cmd get ${S3_PATH}/${DOMAIN}_backup.sql.zip ./${DOMAIN}/
s3cmd get ${S3_PATH}/${DOMAIN}_web_folders.zip ./${DOMAIN}/
NAMESPACE_WEB="${DOMAIN//./-}"
POD_NAME=$(kubectl get pods -n "$NAMESPACE_WEB" --field-selector=status.phase=Running \
-o jsonpath='{.items[0].metadata.name}')
# đọc thông tin database ngay từ biến môi trường của pod
DATABASE_HOST=$(kubectl exec $POD_NAME -n $NAMESPACE_WEB -- sh -c 'echo "$DB_HOST"')
# nạp SQL trên máy database, nạp thư mục web vào volume NFS qua pod
scp ./${DOMAIN}/${DOMAIN}_backup.sql deploy@$DATABASE_HOST:/tmp/
ssh deploy@$DATABASE_HOST "mysql ... ${DATABASE_NAME} < /tmp/${DOMAIN}_backup.sql && rm /tmp/${DOMAIN}_backup.sql"
kubectl cp ./${DOMAIN}/${DOMAIN}_web_folders.zip ${NAMESPACE_WEB}/${POD_NAME}:/var/www/html/
kubectl exec ${POD_NAME} -n ${NAMESPACE_WEB} -- unzip -o /var/www/html/${DOMAIN}_web_folders.zip -d /var/www/html/
# xoá pod để initContainer và postStart chạy lại trên dữ liệu vừa nạp
kubectl delete pod ${POD_NAME} -n ${NAMESPACE_WEB}Bước xoá pod ở cuối là chi tiết dễ bỏ sót. Pod mới chạy lại migrate, xoá cache, tạo lại robots.txt theo domain, publish asset, tất cả trên dữ liệu thật vừa nạp thay vì trên dữ liệu trống lúc mới cài. Nhớ xoá file zip khỏi thư mục web sau khi giải nén.
3. Thứ tự đổi DNS và bật HTTPS
Đây là phần quyết định site có bị gián đoạn hay không khi migrate website. Trên VPS, site đang chạy với chứng chỉ riêng. Trên Kubernetes, chứng chỉ do cert-manager cấp qua HTTP-01 (xem bài ingress-nginx và cert-manager: HTTPS tự động trên Kubernetes), và HTTP-01 chỉ thành công khi domain đã trỏ về NodeBalancer của cluster (chi tiết trong tài liệu HTTP-01 của cert-manager). Bật TLS ngay khi tạo site, lúc DNS còn trỏ về VPS, chứng chỉ sẽ treo ở trạng thái chờ.
Thứ tự an toàn khi migrate website:
- Hạ TTL bản ghi DNS của site trước ngày chuyển, để lúc đổi thì thay đổi lan nhanh.
- Tạo site trên cluster với TLS tắt, hoặc dùng sẵn chứng chỉ wildcard nếu domain thuộc loại đó (ví dụ
tls.alreadyAvailable: true). Site có Cloudflare đứng trước thì HTTPS phía người dùng do Cloudflare đảm nhận. - Khôi phục dữ liệu từ bản backup mới nhất, ngay trước giờ đổi DNS.
- Kiểm tra site trên cluster khi DNS chưa đổi (mục 4).
- Đổi bản ghi A sang IP NodeBalancer.
- Bật TLS bằng
helm upgradevớitls.enabled: truekhi DNS đã trỏ đúng, rồi kiểm tra Certificate chuyểnReady.
Dữ liệu phát sinh trên VPS giữa lúc backup và lúc đổi DNS (đơn hàng, bài viết mới) sẽ không có trên cluster. Với site có cập nhật liên tục, phải đóng băng chỉnh sửa trong khung giờ chuyển, hoặc chạy backup mới ngay trước bước khôi phục. Chọn khung giờ thấp điểm, ngoài giờ biên tập nội dung.
4. Kiểm tra khi migrate website: đừng để VPS cũ trả lời thay
Pipeline tạo site thường có hai bước kiểm tra bằng curl https://$DOMAIN: bước đầu báo lỗi nếu domain đã trả 200 (tránh tạo trùng site đang chạy), bước sau chờ tới khi site trả 200. Với site đang sống trên VPS, cả hai đều sai: bước đầu luôn chặn, vì VPS vẫn trả 200; bước sau luôn qua ngay, vì người trả lời là VPS cũ chứ không phải cluster. Pipeline migrate website cần một biến thể bỏ qua hai bước này.
Kiểm tra thật phải gửi request thẳng vào NodeBalancer mà không phụ thuộc DNS công khai. Tuỳ chọn --resolve của curl làm đúng việc này (xem tài liệu curl):
# ép domain về IP NodeBalancer, bỏ qua DNS công khai
curl -sk -o /dev/null -w "%{http_code}\n" \
--resolve site-a.example:443:<ip-nodebalancer> https://site-a.example/
curl -s -o /dev/null -w "%{http_code}\n" \
--resolve site-a.example:80:<ip-nodebalancer> http://site-a.example/Danh sách nên kiểm tra cho mỗi site trước khi đổi DNS, cũng là điều kiện để coi một lần migrate website là xong:
- Trang chủ và vài trang con trả 200, nội dung đúng là dữ liệu mới nhất.
- Ảnh cũ hiển thị, upload thử một ảnh mới được (quyền ghi trên NFS).
- Trang quản trị đăng nhập được.
- Log của pod không có lỗi kết nối database hay lỗi quyền file.
- Pod qua cả startup và readiness probe, không restart liên tục.
5. Rollback khi migrate website
Khi migrate website, có hai loại sự cố cần đường lui riêng.
Pipeline lỗi giữa chừng. Job dọn dẹp (when: on_failure) xoá namespace vừa tạo và DROP DATABASE, DROP USER trên máy MySQL. Site trên VPS cũ không bị đụng tới, nên chỉ cần sửa nguyên nhân rồi chạy lại.
Site lỗi sau khi đổi DNS. Pipeline chỉ đọc bản backup, không đụng vào site trên VPS cũ. Chừng nào site cũ còn chạy, rollback chỉ là trả bản ghi A về IP cũ; TTL đã hạ giúp việc này có hiệu lực nhanh. Nhưng càng để lâu, dữ liệu mới ghi trên cluster càng nhiều, và rollback sau vài giờ phải mang database từ cluster về lại VPS chứ không chỉ đổi DNS. Vì vậy quyết định giữ hay lùi nên đưa ra sớm, trong giờ đầu sau khi chuyển. Chỉ gỡ site trên VPS cũ sau một thời gian theo dõi ổn định.
6. Chạy thử một lô nhỏ trước
Trước khi migrate website hàng loạt, chạy thử vài site để phát hiện những gì phải chỉnh. Các vấn đề hay lộ ra ở đợt thử:
- Request và limit phải chỉnh theo từng site. Trên VPS, các site dùng chung tài nguyên nên không ai biết từng site cần bao nhiêu. Sau khi lên cluster, mỗi site cần con số riêng, đo từ mức dùng thật (xem bài Requests và limits, QoS và nodeAffinity: xếp pod lên đúng node). Đo trước khi chuyển sẽ đỡ hơn chỉnh sau.
- TLS phải có công tắc. Site chưa đổi DNS hoặc đứng sau Cloudflare cần tắt TLS phía cluster để tránh chứng chỉ treo.
- Lỗi curl không được làm vỡ pipeline. Khi curl không kết nối được, biến trạng thái HTTP rỗng và phép so sánh số trong shell báo lỗi cú pháp. Viết
HTTP_STATUS=$(curl ... || true)và so sánh với${HTTP_STATUS:-000}.
7. Checklist migrate website lên Kubernetes
| Nên làm | Tránh |
|---|---|
| Ghép pipeline có sẵn (tạo site + restore) thay vì viết mới | Kiểm tra qua DNS công khai khi site cũ còn sống |
| Chạy thử một lô nhỏ, chỉnh xong mới làm đợt lớn | Để dữ liệu phát sinh giữa lúc backup và đổi DNS mà không có quy trình đóng băng |
| Pipeline chỉ đọc backup, giữ site trên VPS cũ làm đường lui | Bật TLS trước khi DNS trỏ về cluster |
| Chuẩn bị database, NFS, chart, sức chứa node trước | Vừa migrate vừa đổi chart |
Migrate website không khó ở từng lệnh. Cái khó nằm ở thứ tự: hạ tầng trước, dữ liệu sát giờ, kiểm tra không qua DNS, đổi DNS, rồi mới tới HTTPS. Giữ đúng thứ tự đó và tự động hoá được càng nhiều bước càng tốt, việc chuyển hàng chục site theo lô là trong tầm một đội nhỏ.
Bài tiếp theo
Backup cả cluster bằng GitLab parallel matrix và s3cmd. Khi số site trên cluster lên tới vài chục, backup tuần tự không còn kịp trong một đêm.
