Harbor
Harbor is the platform’s private container image registry. It hosts images built by the Forgejo Actions runner (notably the data-workflows/scrapy and data-workflows/dbt images), backs in-cluster imagePullSecrets, and is reachable only over the VPN.
Deployment
Section titled “Deployment”| Field | Value |
|---|---|
| Flux path | flux-clusters/stefanzhelev/apps/harbor |
| Base path | flux-apps/harbor |
| Namespace | harbor |
| Sync wave | 6 |
| Depends on | cloudnative-pg-config, external-secrets-config, authentik-app-harbor |
What it deploys
Section titled “What it deploys”harbor-config— HelmRelease for the upstreamharborchart>= 1.13.0, configured with the shared CNPG database and admin password from External Secretsharbor-database— Terraform CR that provisions Harbor’s PostgreSQL databases on the shared CNPG clusterharbor-vault-secrets— Terraform CR generating the admin + secretKey atsecret/harborharbor-external-secrets— ExternalSecret rendering admin password, secretKey, and DB credentials into the namespaceharbor-oidc-bootstrap— one-shot Job that wires Harbor’s OIDC settings against Authentik via the Harbor admin API (Harbor doesn’t accept OIDC config through Helm values)
Endpoint
Section titled “Endpoint”| Hostname | harbor.internal.stefanzhelev.com |
| Reachable from | NetBird VPN only (internalsecure Traefik entrypoint) |
| TLS | cert-manager, letsencrypt-prod (DNS-01) |
| SSO | OIDC via Authentik — also accepts the bootstrap admin user/password |
| External URL | https://harbor.internal.stefanzhelev.com |
The registry is not exposed on the public Hetzner LB — traffic only arrives via the internalsecure entrypoint that’s routed exclusively from the VPN-internal CIDR.
Integrations
Section titled “Integrations”- CloudNative-PG: Harbor’s
core,notary, and related schemas live on the shared cluster - Vault + Tofu Controller: admin + secretKey originate in Vault, generated by
harbor-vault-secrets - Authentik: OIDC SSO, bootstrapped post-install by
harbor-oidc-bootstrap - Forgejo Actions runner: push robot accounts (created by
data-workflows-docker-registry) push freshly-built images here; in-cluster pods pull them via KubernetesimagePullSecrets
Docker login
Section titled “Docker login”# Connect to the NetBird VPN first, then:docker login harbor.internal.stefanzhelev.com# Username + password come from secret/harbor in Vault, or use SSO via the web UI to mint a CLI secret.Push an image
Section titled “Push an image”docker tag myapp:latest harbor.internal.stefanzhelev.com/library/myapp:latestdocker push harbor.internal.stefanzhelev.com/library/myapp:latestPull an image
Section titled “Pull an image”docker pull harbor.internal.stefanzhelev.com/library/myapp:latestKubernetes image pull
Section titled “Kubernetes image pull”spec: containers: - name: app image: harbor.internal.stefanzhelev.com/library/myapp:latest imagePullSecrets: - name: harbor-pull-secretThe data-workflows namespace already has a docker-registry Secret rendered by data-workflows-docker-registry’s pull robot, so the existing scrapy/dbt DAGs pull from Harbor without any per-DAG setup.