Files
container.training/slides/k8s/harbor.md
2025-11-11 18:13:05 +01:00

5.9 KiB

Running a Harbor registry

  • There are many open source registries available out there

  • We're going to show an end-to-end example using a very popular one:

    Harbor (https://goharbor.io)

  • We will:

    • install Harbor

    • create a private registry on Harbor

    • set up an automated build pipeline pushing images to Harbor

    • configure an app to use images from the private registry


Requirements

  • Virtually all registry clients require TLS when communicating with registries

    (one exception: when the registry is on localhost)

  • This means that we'll need a valid TLS certificate for our registry

  • We can easily get one with cert-manager and e.g. Let's Encrypt

    (as long as we can associate a domain with our ingress controller)

  • To run the demos in this chapter, we need a domain name!


Alternatives

  • We could configure our build pipeline to ignore certificates

    (so that it can push images without complaining)

  • We could hack something so that the registry is available over localhost

  • Or we could add the registry's certificate everywhere

    (in our build pipeline, on our container engines...)

  • These extra steps are out of scope for this chapter

  • We need a domain name!


Automating TLS certificates

  • Let's install Traefik:

    kubectl apply -f ~/container.training/k8s/traefik.yml
    
  • And cert-manager:

    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.1/cert-manager.yaml
    
  • Edit the ClusterIssuer manifest and apply it:

    vim ~/container.training/k8s/cm-clusterissuer.yaml
    kubectl apply -f  ~/container.training/k8s/cm-clusterissuer.yaml
    

    ⚠️ Make sure to update the cluster issuer name to letsencrypt-production !


Checking that it works

  • Deploy a simple application and expose it with TLS:

    kubectl create deployment blue --image jpetazzo/color --replicas 2 --port 80
    kubectl expose deployment blue
    kubectl create ingress blue --rule=blue.`$DOMAIN`/*=blue:80,tls \
            --annotation cert-manager.io/cluster-issuer=letsencrypt-production
    
  • Check that the certificate was correctly issued:

    kubectl get cert
    curl https://blue.`$DOMAIN`/
    

Deploying Harbor

  • There is a Helm chart (https://artifacthub.io/packages/helm/harbor/harbor)

  • Let's install it:

    helm upgrade --install --repo https://helm.goharbor.io \
      --namespace harbor --create-namespace harbor harbor \
      --set persistence.enabled=false \
      --set expose.ingress.hosts.core=harbor.`$DOMAIN` \
      --set expose.ingress.annotations."cert-manager\.io/cluster-issuer"=letsencrypt-production \
      --version 1.18.0
    
  • Wait until all pods are Running in the harbor namespace


Logging into Harbor

  • Go to https://harbor.$DOMAIN/

  • The default login is admin

  • The default password is Harbor12345

    (yes, it would be a good idea to change that in production😁)


Creating a new repository

  • In Harbor, repositories are associated to "projects"

  • Create a new project named dockercoins


Creating Harbor users

  • We will create two "robot accounts":

    • one with push permission (for the build pipeline)

    • one with pull permission (for our Kubernetes workloads)

  • Create a first robot account, dockercoins-push

    • don't give any systems permission

    • for project permissions, check dockercoins

    • then select permissions, check push and pull

  • Write down the user and password!


Setting up the build pipeline

  • This part requires a GitHub account

  • On GitHub, fork https://github.com/jpetazzo/dockercoins

    (it has a GitHub Actions workflow that is almost ready to use!)

  • In your fork, go to settings / secrets and variables / actions

  • Create the following secrets:

    REGISTRY_ADDRESS = harbor.$DOMAIN (make sure to enter the real domain of course!)

    REGISTRY_USERNAME = the user name generated by Harbor

    REGISTRY_PASSWORD = the password generated by Harbor


Setting up the build pipeline

  • Edit .github/workflows/automated-build.yaml

  • Comment out the steps related to GitHub Container Registry and Docker Hub

  • Uncomment the steps related to the custom external registry

  • Commit

  • In your fork, click on the "Actions" button on top

  • You should see the workflow running

  • After a couple of minutes, it should (hopefully) report success


Creating the pull robot account

  • In Harbor, create another robot account

  • Let's name it dockercoins-pull

  • Again, don't give it any systems permission

  • Give it pull permissions for the dockercions project

  • Write down the user and password


Create a Secret for the pull account

  • Let's create a Kubernetes Secret holding the registry credentials:

    kubectl create secret docker-registry dockercoins-pull \
        --docker-username '`robot$dockercoins-pull``' \
        --docker-password `abcdefghijKLMNOPQRST` \
        --docker-server harbor.`$DOMAIN`
    
  • Make sure to quote the username (the $ will cause problems otherwise)


Use the Secret

  • We have two possibilities here:

    • add imagePullSecrets to every Pod template that needs them

    • add imagePullSecrets to the ServiceAccount used by the Pods

  • Let's patch the default ServiceAccount:

    kubectl patch serviceaccount default \
        --patch 'imagePullSecrets: [ name: dockercoins-pull ]'
    

Use the private registry

  • Make a copy of ~/container.training/k8s/dockercoins.yml

  • In that copy, replace every dockercoins/* image with harbor.$DOMAIN/dockercoins/*

    (put the actual domain, not $DOMAIN!)

  • Apply that YAML

  • Check that the application is up and running

  • Check that the number of pulls has increased in the Harbor web UI

  • Congratulations, you've deployed an image from a self-hosted private registry! 🎉

???

:EN:- Hosting private images with Harbor :FR:- Héberger des images privées avec Harbor