Container Registry (Harbor)
Push, pull, scan, and manage container images with your private Harbor registry.
Harbor is your private container registry, running on the service cluster at
registry.<CUSTOMER_ID>.truefullstaq.cloud. Every image you run on the production cluster
should live here, not on Docker Hub or another public registry. Harbor also scans your
images for known vulnerabilities (CVEs).
Throughout this page, replace <CUSTOMER_ID> with your 5-digit ID (e.g. 01234) and
<project> with your Harbor project name.
# Signing in to the UI
Open https://registry.<CUSTOMER_ID>.truefullstaq.cloud and click Login via OIDC
Provider to sign in with TrueFullstaq SSO. This is where you browse repositories, read
scan results, and create robot accounts.
# Projects
Harbor organises images into projects (think: one per team or application). A project
holds repositories (<project>/<image>), each with tags. Images you push must go into a
project you have access to. If you need a new project created, ask your TrueFullstaq
engineer, or create one in the UI if your account permits.
# Logging in with Docker
To push from your laptop or a CI runner you need a CLI secret, because OIDC accounts can’t use your SSO password directly for Docker:
- UI → click your username (top right) → User Profile.
- Copy the CLI secret (regenerate it any time from the same screen).
- Log in:
docker login registry.01234.truefullstaq.cloud
# Username: your SSO username
# Password: the CLI secret from your profile
Podman/nerdctl work the same way:
podman login registry.01234.truefullstaq.cloud.
# Pushing an image
# Build
docker build -t my-app:latest .
# Tag for Harbor: registry / project / image : tag
docker tag my-app:latest registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2
# Push
docker push registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2
Use immutable tags (e.g.
v1.4.2or a git SHA) rather thanlatest. ArgoCD deploys whatever tag is in your manifest, and fixed tags make rollbacks and audits unambiguous.
# Pulling an image
On the production cluster, Kubernetes pulls from Harbor automatically using the image pull secret provisioned in your namespace. Just reference the full image path in your manifest:
spec:
containers:
- name: my-app
image: registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2
If your namespace does not yet have a pull secret, ask your TrueFullstaq engineer, or create one from a robot account (below):
kubectl create secret docker-registry harbor-pull \
--docker-server=registry.01234.truefullstaq.cloud \
--docker-username='robot$my-project+ci' \
--docker-password='<robot-token>' \
-n my-namespace
Then reference it:
spec:
imagePullSecrets:
- name: harbor-pull
containers:
- name: my-app
image: registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2
To pull locally for testing: docker pull registry.01234.truefullstaq.cloud/my-project/my-app:v1.4.2.
# Robot accounts for CI/CD
Don’t bake personal credentials into pipelines. Use a robot account scoped to a project:
- UI → your project → Robot Accounts → + New Robot Account.
- Name it (e.g.
ci), set an expiry, grant Push and Pull on repositories. - Copy the generated token now; it is shown only once.
The robot’s username is robot$<project>+<name> (note the $). Quote it to stop your shell
expanding $:
docker login registry.01234.truefullstaq.cloud \
--username 'robot$my-project+ci' \
--password '<robot-token>'
Store the token in OpenBao and surface it to your pipeline via the External Secrets Operator, and never commit it to Git.
# Hosting Helm charts (OCI)
Harbor stores Helm charts as OCI artifacts. A chart lives in your project just like a
container image, at registry.<CUSTOMER_ID>.truefullstaq.cloud/<project>/<chart> with the
chart version as its tag, so you push and pull charts over the same registry endpoint as
your images.
# Pushing a chart
# Log in (robot account or your CLI secret, same as for images)
helm registry login registry.01234.truefullstaq.cloud \
--username 'robot$my-project+ci' \
--password '<robot-token>'
# Package and push. The chart name + version become the repo path + tag:
helm package ./my-chart # -> my-chart-0.0.370.tgz
helm push my-chart-0.0.370.tgz oci://registry.01234.truefullstaq.cloud/my-project
# -> registry.01234.truefullstaq.cloud/my-project/my-chart:0.0.370
# Deploying a chart with ArgoCD
1. Register the repository as type helm with Enable OCI turned on, over the
HTTP/HTTPS connection method. Set the Repository URL to the registry host + project, with
no oci:// prefix and without the chart name:
| Field | Value |
|---|---|
| Type | helm |
| Repository URL | registry.01234.truefullstaq.cloud/my-project |
| Enable OCI | ✅ checked |
| Username | robot$my-project+ci |
| Password | <robot-token> |
Declaratively, that repository is a Secret in ArgoCD’s namespace on the service cluster:
apiVersion: v1
kind: Secret
metadata:
name: harbor-helm
namespace: argo # ArgoCD's namespace
labels:
argocd.argoproj.io/secret-type: repository
stringData:
name: harbor-helm
type: helm
enableOCI: "true"
url: registry.01234.truefullstaq.cloud/my-project # host + project; no oci://, no chart name
username: 'robot$my-project+ci'
password: '<robot-token>'
2. Reference the chart from your Application. Point source.repoURL at the same URL,
name the chart in chart, and the version in targetRevision:
spec:
project: project-customer
source:
repoURL: registry.01234.truefullstaq.cloud/my-project # same URL as the repo Secret
chart: my-chart # i.e. <project>/my-chart in Harbor
targetRevision: 0.0.370 # a fixed version, or a range like 0.0.*
helm:
valuesObject: {} # optional values overrides
destination:
server: https://87.233.10.20:6443 # your production cluster
namespace: my-app
syncPolicy:
automated: { prune: true, selfHeal: true }
syncOptions: [ CreateNamespace=true ]
ArgoCD pulls registry.01234.truefullstaq.cloud/my-project/my-chart:0.0.370, which is
repoURL + chart + targetRevision joined together.
# Vulnerability scanning
Harbor scans every pushed image. To review results: UI → your project → Repositories → select a repository → a tag → Vulnerabilities. You’ll see CVEs by severity with fixed versions where available.
# Trigger/refresh a scan from the CLI is done in the UI; to check a digest locally you can
# inspect the manifest, but scan results live in the Harbor UI.
Depending on your project’s policy, pulls of images with Critical CVEs may be blocked (“Prevent vulnerable images from running”). If a deploy fails to pull for this reason, rebuild on a patched base image and push a new tag.
# Housekeeping
- Tag retention / cleanup: old tags accumulate. Configure retention rules under your project → Policy → Tag Retention to keep, say, the last 10 tags per repo.
- Garbage collection (reclaiming disk from deleted tags) runs on a schedule managed by TrueFullstaq, so you don’t need to trigger it.