Harbor Deployment with CloudNativePG
3 minute read
Harbor Deployment with CloudNativePG on Kubernetes using Kosi
This guide provides a detailed guide to deploy Harbor on Kubernetes using a CloudNativePG (CNPG) PostgreSQL cluster managed by the CloudNativePG operator, installed via Kosi.
Precondition: Log in to the preprod environment with Kosi before beginning.
Step 1 — Install CloudNativePG operator
Deploy the operator with Kosi:
kosi install --hub kubeops kubeops/cloudnative-pg-operator:1.28.1 --dname cnpg-operator
With this step, it Installs the CloudNativePG operator into the cluster and the operator manages PostgreSQL clusters and their lifecycle.
Step 2 — Create PostgreSQL cluster for Harbor
1. Apply the following Cluster manifest to create a Postgres cluster with 2 instances and 1Gi storage:
cat <<EOF | kubectl apply -f -
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cloudnative-pg
namespace: harbor
spec:
instances: 2
imagePullSecrets:
- name: registry-pullsecret
storage:
size: 1Gi
EOF
2. Services and pods created for the cluster cloudnative-pg:
cloudnative-pg-rw → primary (read/write) cloudnative-pg-ro → replicas (read-only) cloudnative-pg-r → all pods
3. Verify pods are Running:
kubectl get pods -n harbor
Step 3 — Retrieve application user credentials
CNPG automatically creates a Secret named cloudnative-pg-app in the harbor namespace.
1. Inspect it:
kubectl get secret cloudnative-pg-app -n harbor
2. Decode the base64-encoded fields:
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.username}" | base64 -d
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.password}" | base64 -d
kubectl get secret cloudnative-pg-app -n harbor -o jsonpath="{.data.dbname}" | base64 -d
Example values (for illustration only):
username: app
password: Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2
database: app
Important:
Use the non-superuser application credentials from this Secret in Harbor’s configuration.
Step 4 — Update Harbor tools.yaml for an external database
Edit your tools.yaml and set Harbor values under the helm chart configuration.
Example snippet:
- name: harbor
enabled: true
values:
standard:
namespace: harbor
harborpass: "password"
databasePassword: "<DB_PASSWORD>"
redisPassword: "Redis_Password"
externalURL: <your_domain_name>
nodePort: 30002
hostname: <your_domain_name>
harborPersistence:
persistentVolumeClaim:
registry:
size: 40Gi
storageClass: "rook-cephfs"
jobservice:
jobLog:
size: 1Gi
storageClass: "rook-cephfs"
database:
size: 1Gi
storageClass: "rook-cephfs"
redis:
size: 1Gi
storageClass: "rook-cephfs"
trivy:
size: 5Gi
storageClass: "rook-cephfs"
advanced:
database:
type: external
external:
host: "cloudnative-pg-rw.harbor.svc.cluster.local"
port: "5432"
username: "app"
password: "Hw2t7hXuKPfZrVjVDwCc4PeKTevlB7ORmzQeW50JtEqiwHl40xkxuhVHeRIU3fX2"
coreDatabase: "app"
Important: Use the -rw service host (cloudnative-pg-rw…) for write operations.
Do not use a superuser account.
Ensure the password matches the CNPG Secret.
Step 5 — Install Harbor with Kosi
- Deploy Harbor using the updated tools.yaml:
kosi install --hub kubeops kubeops/harbor:2.0.3 -f tools.yaml --dname harbor
- Verify Harbor pods:
kubectl get pods -n harbor
- Access Harbor at: <your_domain_name>:30002 (or as configured)
Notes and best practices
- Always decode the CNPG app Secret to obtain the correct username, password, and database name used by Harbor.
- Use the cloudnative-pg-rw service for write traffic; use -ro services for reads if required.
- Production recommendations (follow your organizational security policies):
- Create a dedicated DB user (for example, harbor) rather than reusing the default app user.
- Enable TLS for Postgres connections.
- Implement backups (for example, CNPG Barman or object storage like S3).
- To scale the CNPG cluster, update the instances field in the Cluster spec and reapply.