Because I didn’t want to push all my custom images and sourcecode to public repos like hub.docker.com, I was looking for a self-hosted solution. After checking out the features of the official Docker registry, I was a bit underwhelmed by the missing repo based auth and the lack of combining the use as repository and cache.
Why would you need private Docker registry?
First if you don’t feel comfortable in sharing all your images with a third party you’ll need to find a more
local way of distributing your images. Also Docker
changed their policies
and limit the maximum pulls you can do to 10 or 100 pulls per hour (depending if your autheticated or not), and while this may seem like a big number, I can assure
you it’s easy to reach it. Imagine you got a kubernetes cluster, and you restart some nodes because of an update. Now
every node is pulling every image it needs if you’ve set your imagePullPolicy
to Always
. I really like to keep my
deployments configured that way, because it makes updates via kubectl rollout restart deployment x
really easy for
uncritical services.
To mitigate the pull limits, we will use a cache in our private repository.
Candidates
I spent quite some time on digging through the different options. While doing so, I checked out the following projects:
- Portus (made by SUSE)
- JFrog Container Registry
- Harbor (CNCF Graduated project)
Portus
After looking into Portus, I quickly realised that this project is quite dead. The last commit dated back to Mar 25,
2020 and was only a change in the CHANGELOG.md
, also the last release is from Mar 19, 2019.
JFrog Container Registry
I know JFrog from work and know it works, but it’s closed source, and I think it’s quite overkill for my private use-cases.
Harbor
Checking out Harbor, I quickly noticed the CNCF banner on their website. The graduated state in CNCF means it’s stable and should be quite easy to handle.
Also, they have an official helm3 chart available.
Deploying
To get the helm chart we will use the bitnami chart via oci.
# get default values
helm show values oci://registry-1.docker.io/bitnamicharts/harbor > values.yaml
After fetching the values we need to change some stuff to match our infrastructure.
For example I needed to set the ingress to LoadBalancer
and change the StorageClass.
You should walk through the default values and adjust everything to your needs, here I’ll share my values file without any secrets (you’ll need to change all those xxx
)
registry:
secret: xxx
credentials:
password: xxx
jobservice:
secret: xxx
core:
secret: xxx
xsrfKey: xxx
expose:
type: ingress
tls:
enabled: true
certSource: secret
secret:
secretName: "hub.marschall.systems-tls"
ingress:
hosts:
core: "hub.marschall.systems"
controller: default
className: "nginx-dmz"
annotations:
ingress.kubernetes.io/ssl-redirect: "true"
ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
cert-manager.io/cluster-issuer: cloudflare-issuer
externalURL: https://hub.marschall.systems
ipFamily:
ipv6:
enabled: false
ipv4:
enabled: true
persistence:
enabled: true
resourcePolicy: "keep"
persistentVolumeClaim:
registry:
storageClass: "vsan-default"
accessMode: ReadWriteOnce
size: 200Gi
jobservice:
jobLog:
storageClass: "vsan-default"
accessMode: ReadWriteOnce
size: 1Gi
redis:
storageClass: "vsan-default"
accessMode: ReadWriteOnce
size: 1Gi
trivy:
storageClass: "vsan-default"
accessMode: ReadWriteOnce
size: 5Gi
imageChartStorage:
disableredirect: true
type: filesystem
filesystem:
rootdirectory: /storage
imagePullPolicy: IfNotPresent
updateStrategy:
type: Recreate
logLevel: info
existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD
harborAdminPassword: "xxx"
secretKey: "xxx"
database:
type: external
external:
host: "db1.marschall.management"
port: "5432"
username: "xxx"
password: "xxx"
coreDatabase: "harbor"
sslmode: "require"
maxIdleConns: 10
maxOpenConns: 50
metrics:
enabled: true
serviceMonitor:
enabled: true
trace:
enabled: false
Now we can install the application with
helm install --namespace harbor --name harbor --create-namespace oci://registry-1.docker.io/bitnamicharts/harbor -f values.yaml
Configuring pull through cache for DockerHub
To make use of the millions of public available images on DockerHub without running into the pull limits we no create a new upstream Registry in Harbor.


Now we need to map the Registry to a Project.


Congratulations you now have your own docker registry that can be used as pull through proxy!
To do so just substitute docker.io
with <yourregistry>/cache
in my case docker.io/hugomods/hugo:git
becomes hub.marschall.systems/cache/hugomods/hugo:git