Harbor with Portworx on Kubernetes
This reference architecture document shows how you can deploy Harbor, an open-source container image registry, and its dependencies with Portworx on Kubernetes. Under this architecture, Portworx provides reliable and persistent storage to ensure Harbor runs with HA.
Create StorageClass
All of the components will use a StorageClass
with 3 replicas, so create and apply the following spec:
kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: portworx-sc-repl3
provisioner: kubernetes.io/portworx-volume
parameters:
repl: "3"
priority_io: "high"
EOF
For details about the Portworx-specific parameters, refer to the Portworx Volume section.
If you're using Portworx with CSI, you must set the value of the provisioner
parameter to pxd.portworx.com
.
Setup Harbor
Prequisites
By default, the instructions in this document deploy everything in the
harbor
namespace, but you can change this by specifying your own namespace:kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
name: harbor
EOFHarbor is deployed using Helm, so it will need to be installed and have permissions on the
harbor
namespace. You can find instructions here.
Deploy dependencies
Harbor requires a PostgreSQL and Redis database.
Apply the following spec to deploy PostgreSQL, making sure to change the password and username to your preferred values:
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
namespace: harbor
annotations:
volume.beta.kubernetes.io/storage-class: portworx-sc-repl3
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: harbor
labels:
app: postgres
spec:
ports:
- port: 5432
selector:
app: postgres
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: harbor
labels:
app: postgres
spec:
strategy:
type: Recreate
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
schedulerName: stork
containers:
- name: postgres
image: postgres:13.2
readinessProbe:
exec:
command: ["psql", "-w", "-U", "postgres", "-c", "SELECT 1"]
initialDelaySeconds: 15
timeoutSeconds: 2
livenessProbe:
exec:
command: ["psql", "-w", "-U", "postgres", "-c", "SELECT 1"]
initialDelaySeconds: 45
timeoutSeconds: 2
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-persistent-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-persistent-storage
persistentVolumeClaim:
claimName: postgres-pvc
EOFApply the following spec to deploy Redis:
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
namespace: harbor
annotations:
volume.beta.kubernetes.io/storage-class: portworx-sc-repl3
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: harbor
spec:
ports:
- port: 6379
name: redis
clusterIP: None
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: harbor
labels:
app: redis
spec:
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
schedulerName: stork
containers:
- name: redis
image: redis:3.2-alpine
imagePullPolicy: Always
args: ["--requirepass", "password"]
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: redis-vol
mountPath: /data
volumes:
- name: redis-vol
persistentVolumeClaim:
claimName: redis-pvc
EOFEnter the following command to create the four PostgreSQL databases Harbor requires:
DB_POD=$(kubectl get pods -n harbor -l app=postgres | awk '/postgres/{print$1}')
kubectl exec $DB_POD -n harbor -- createdb -Upostgres registry
kubectl exec $DB_POD -n harbor -- createdb -Upostgres clair
kubectl exec $DB_POD -n harbor -- createdb -Upostgres notary_server
kubectl exec $DB_POD -n harbor -- createdb -Upostgres notary_signer
Deploy Harbor
Enter the following commands to add the Harbor repository and deploy Harbor. Replace myharbor
with a name of your choosing:
NAMESPACE=harbor
helm repo add harbor https://helm.goharbor.io
helm install myharbor harbor/harbor \
--set redis.type=external \
--set redis.external.addr=redis.$NAMESPACE:6379 \
--set redis.external.password=password \
--set database.type=external \
--set database.external.host=postgres.$NAMESPACE \
--set database.external.username=postgres \
--set database.external.password=password \
--set persistence.persistentVolumeClaim.registry.storageClass=portworx-sc-repl3 \
--set persistence.persistentVolumeClaim.chartmuseum.storageClass=portworx-sc-repl3 \
--set persistence.persistentVolumeClaim.jobservice.storageClass=portworx-sc-repl3 \
--set persistence.persistentVolumeClaim.trivy.storageClass=portworx-sc-repl3 \
--namespace $NAMESPACE
If you want to expose the portal as NodePort, you may add the flags:
--set expose.type=nodePort \
--set expose.tls.enabled=false \
--set externalURL=http://<hostname.domain>:30002 \
Clean up Harbor
To clean up the environment created above, run the following:
helm delete myharbor -n harbor
kubectl delete -n harbor \
deploy/redis \
svc/redis \
pvc/redis-pvc \
deploy/postgres \
svc/postgres \
pvc/postgres-pvc \
pvc/myharbor-harbor-chartmuseum \
pvc/myharbor-harbor-jobservice \
pvc/data-myharbor-harbor-trivy-0 \
pvc/myharbor-harbor-registry
kubectl delete sc/portworx-sc-repl3
Configuring snapshots
Scheduled snapshots can be configured. PostgreSQL does not require any special Pre or Post rules to be added; Redis is only used for cache and temporary storage, so it does not need a Pre rule to ensure it is flushed to disk. See the Create and use snapshots page for more details about snapsots.