Cấu hình Persistent Storage và Helm Chart cho Harbor
Bước đầu tiên là chuẩn bị StorageClass trên Kubernetes để Harbor lưu trữ artifact và metadata một cách bền vững. Chúng ta sẽ sử dụng Helm để triển khai Harbor với cấu hình High-Availability (HA) cơ bản, bao gồm Redis và Database riêng biệt.
Tạo file cấu hình custom values tại đường dẫn /opt/harbor/harbor-values-ha.yaml với nội dung hoàn chỉnh như sau:
# /opt/harbor/harbor-values-ha.yaml
expose:
type: clusterIP # Sử dụng ClusterIP, sẽ có Ingress riêng sau
tls:
auto:
commonName: "harbor.local"
enabled: true
harborAdminPassword: "Harbor12345!" # Mật khẩu mặc định, đổi ngay sau khi deploy
# Cấu hình Redis cho HA (Sử dụng Cluster hoặc Sentinel tùy môi trường, ở đây dùng StatefulSet với 3 replica)
redis:
enabled: true
replicaCount: 3
master:
persistence:
enabled: true
storageClass: "standard-rwo"
size: 10Gi
slave:
persistence:
enabled: true
storageClass: "standard-rwo"
size: 10Gi
# Cấu hình Database (PostgreSQL cho HA)
database:
type: cluster
cluster:
enabled: true
persistence:
enabled: true
storageClass: "standard-rwo"
size: 20Gi
replicaCount: 2
# Cấu hình Harbor Core và các service phụ trợ
harborCore:
persistence:
enabled: true
storageClass: "standard-rwo"
size: 50Gi
registry:
persistence:
enabled: true
storageClass: "standard-rwo"
size: 100Gi
jobService:
persistence:
enabled: true
storageClass: "standard-rwo"
size: 20Gi
# Cấu hình Notary (tắt ở đây, sẽ bật ở phần 4)
notary:
enabled: false
Kết quả mong đợi: File cấu hình được lưu, sẵn sàng để Helm đọc các tham số persistence và replica cho việc tạo StatefulSet.
Thực hiện thêm Helm repository và cài đặt Harbor với file values vừa tạo:
helm repo add harbor https://helm.goharbor.io
helm repo update
helm install harbor harbor/harbor -f /opt/harbor/harbor-values-ha.yaml -n harbor-registry --create-namespace
Kết quả mong đợi: Kubernetes tạo ra các StatefulSet cho Redis, PostgreSQL và các pod của Harbor (core, registry, jobservice) với trạng thái Running. Kiểm tra bằng lệnh kubectl get pods -n harbor-registry sẽ thấy nhiều pod với suffix số (ví dụ: redis-0, redis-1, redis-2).
Verify kết quả cài đặt Storage và Pod
Chạy lệnh sau để xác minh các PersistentVolumeClaim đã được gán đúng StorageClass và kích thước:
kubectl get pvc -n harbor-registry | grep -E "harbor-redis|harbor-postgresql|harbor-registry"
Kiểm tra trạng thái pod, đảm bảo tất cả pod trong statefulset đều ở trạng thái Running và không có lỗi CrashLoopBackOff:
kubectl get pods -n harbor-registry -o wide
Cấu hình Load Balancer và Ingress cho Traffic Distribution
Để đảm bảo tính sẵn sàng cao, traffic phải được phân phối đều đến các pod backend. Chúng ta sẽ sử dụng Ingress Controller (giả định sử dụng Nginx Ingress) và cấu hình Ingress Resource để expose dịch vụ Harbor.
Tạo file định nghĩa Ingress tại /opt/harbor/harbor-ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: harbor-ingress
namespace: harbor-registry
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "0" # Hỗ trợ upload artifact lớn
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
tls:
- hosts:
- harbor.your-domain.com
secretName: harbor-tls-secret
rules:
- host: harbor.your-domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: harbor
port:
number: 80
Kết quả mong đợi: File YAML mô tả việc map domain harbor.your-domain.com vào service Harbor, với cấu hình timeout lớn để xử lý push/pull image nặng.
Áp dụng cấu hình Ingress vào cluster:
kubectl apply -f /opt/harbor/harbor-ingress.yaml
Kiểm tra trạng thái Ingress để đảm bảo External IP đã được cấp bởi Load Balancer:
kubectl get ingress harbor-ingress -n harbor-registry
Kết quả mong đợi: Cột ADDRESS hiển thị IP public của Load Balancer hoặc Internal IP tùy cloud provider. Trạng thái phải là Active.
Verify kết quả Load Balancer
Thử truy cập trực tiếp qua IP của Ingress để xem xét phản hồi của Nginx:
curl -k -I https://harbor.your-domain.com
Kiểm tra logs của Ingress Controller để đảm bảo không có lỗi 502 Bad Gateway khi phân phối traffic:
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=50
Thiết lập cơ chế Backup và Restore tự động
Dữ liệu registry (metadata và artifact) nằm trên PersistentVolume. Để đảm bảo HA, chúng ta cần cơ chế backup định kỳ ra object storage (S3) hoặc local storage bên ngoài. Harbor cung cấp script backup/restore, chúng ta sẽ đóng gói thành Job Cron.
Tạo file Job Cron để backup tự động tại /opt/harbor/harbor-backup-job.yaml:
apiVersion: batch/v1
kind: CronJob
metadata:
name: harbor-backup-cron
namespace: harbor-registry
spec:
schedule: "0 2 * * *" # Chạy lúc 2h sáng mỗi ngày
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: goharbor/harbor-core:latest
command:
- /bin/bash
- -c
- |
# Chờ database sẵn sàng
sleep 10
# Chạy lệnh backup
/harborctl backup --backup-dir /backup --backup-type full
# Upload lên S3 (giả định đã có biến môi trường AWS)
aws s3 cp /backup s3://your-bucket/harbor-backups/ --recursive
env:
- name: HARBOR_BACKUP_TYPE
value: "full"
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-credentials
key: access-key
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-credentials
key: secret-key
volumeMounts:
- name: backup-storage
mountPath: /backup
restartPolicy: OnFailure
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: backup-pvc
restartPolicy: OnFailure
Kết quả mong đợi: CronJob được tạo, sẽ tự động kích hoạt container, thực hiện backup và đẩy lên S3 vào khung giờ đã định.
Deploy CronJob và PVC cho lưu trữ tạm thời backup:
kubectl apply -f /opt/harbor/harbor-backup-job.yaml
Tạo Secret chứa key AWS (bước này cần thực hiện trước khi chạy job nếu chưa có):
kubectl create secret generic aws-credentials --from-literal=access-key=YOUR_ACCESS_KEY --from-literal=secret-key=YOUR_SECRET_KEY -n harbor-registry
Verify kết quả Backup
Kiểm tra lịch sử chạy của CronJob để xem lần backup gần nhất:
kubectl get cronjob harbor-backup-cron -n harbor-registry
kubectl get jobs -n harbor-registry | grep harbor-backup
Xác minh file backup đã được tạo trên S3 hoặc bucket đích bằng CLI của cloud provider tương ứng (ví dụ: aws s3 ls s3://your-bucket/harbor-backups/).
Tích hợp Harbor với Kubernetes RBAC
Để quản lý quyền truy cập an toàn, Harbor cần được cấu hình để tích hợp với Kubernetes ServiceAccount. Điều này cho phép các pod trong cluster (như CI/CD runners) pull image mà không cần hardcode credentials.
Cấu hình ServiceAccount trong Harbor để tạo Kubernetes secret tự động. Chúng ta sẽ tạo một project riêng cho CI/CD và cấp quyền cho ServiceAccount.
Đầu tiên, tạo Secret trong Kubernetes chứa thông tin đăng nhập Harbor (nên dùng API Key hoặc Robot Account, ở đây dùng Robot Account để minh họa):
kubectl create secret docker-registry harbor-robot-secret \
--docker-server=https://harbor.your-domain.com \
--docker-username=robot$ci-cd \
--docker-password=YOUR_ROBOT_PASSWORD \
--docker-email=nobody@example.com \
-n default
Kết quả mong đợi: Kubernetes tạo secret harbor-robot-secret trong namespace default.
Chỉnh sửa Deployment của ứng dụng để sử dụng secret này:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
template:
spec:
serviceAccountName: harbor-reader
containers:
- name: app
image: harbor.your-domain.com/my-project/my-app:latest
imagePullSecrets:
- name: harbor-robot-secret
Kết quả mong đợi: Pod của ứng dụng sẽ tự động pull image từ Harbor khi khởi tạo, sử dụng quyền của robot account đã cấu hình.
Cấu hình Role và RoleBinding để ServiceAccount harbor-reader có quyền pull image (trong Kubernetes, quyền pull image được kiểm soát bởi admission controller và imagePullSecrets, nhưng nếu dùng Pod Security Standards, cần cấp quyền phù hợp):
kubectl create serviceaccount harbor-reader -n default
kubectl create role harbor-reader-role --verb=get,list,watch --resource=pods -n default
kubectl create rolebinding harbor-reader-binding --role=harbor-reader-role --serviceaccount=default:harbor-reader -n default
Verify kết quả RBAC
Khởi tạo pod mới và kiểm tra logs để đảm bảo nó pull image thành công:
kubectl rollout restart deployment my-app -n default
kubectl describe pod -n default | grep -A 5 "ImagePullBackOff"
Nếu không có lỗi ImagePullBackOff hoặc ErrImagePull, nghĩa là RBAC và secret đã hoạt động đúng.
Xác minh tính sẵn sàng cao (HA) bằng mô phỏng sự cố
Bước cuối cùng là kiểm chứng kiến trúc HA. Chúng ta sẽ mô phỏng sự cố bằng cách xóa một pod quan trọng (ví dụ: registry hoặc database) và quan sát hệ thống tự phục hồi.
Mô phỏng sự cố bằng cách xóa pod registry chính:
kubectl delete pod harbor-registry-0 -n harbor-registry
Kết quả mong đợi: Kubernetes sẽ khởi tạo lại pod harbor-registry-0 ngay lập tức. StatefulSet đảm bảo pod mới gắn vào cùng PVC cũ, dữ liệu không mất.
Quan sát quá trình recovery:
kubectl get pods -n harbor-registry -w
Trong quá trình pod đang khởi động lại, thử push/pull một image nhỏ để kiểm tra tính liên tục của dịch vụ:
docker pull harbor.your-domain.com/library/alpine:latest
Kiểm tra logs của pod mới để đảm bảo nó kết nối lại được với Redis và Database mà không bị lỗi:
kubectl logs -f harbor-registry-0 -n harbor-registry
Kết quả mong đợi: Logs hiển thị Connected to Redis và Connected to PostgreSQL thành công, service trở lại trạng thái sẵn sàng.
Thực hiện tương tự với pod Database (PostgreSQL) hoặc Redis để kiểm tra khả năng failover của cluster:
kubectl delete pod harbor-postgresql-0 -n harbor-registry
kubectl delete pod harbor-redis-0 -n harbor-registry
Quan sát trạng thái của các pod còn lại, đảm bảo chúng tự động chuyển leader (nếu dùng Patroni cho Postgres hoặc Sentinel cho Redis) mà không làm sập toàn bộ registry.
Điều hướng series:
Mục lục: Series: Series: Xây dựng nền tảng Secure Multi-Cloud Container Registry với Harbor, Notary và Policy Engine để kiểm soát phân phối artifact an toàn
« Phần 1: Chuẩn bị môi trường và yêu cầu hệ thống cho Secure Multi-Cloud Registry
Phần 3: Cấu hình Harbor Multi-Cloud Replication để đồng bộ artifact an toàn »