Skip to main content

Our CI Died at Midnight from Docker Hub's Pull Rate Limit. Designing a Harbor Private Registry for K3s/Kubo

1. The Night Our CI Died — Docker Hub's Pull Limit, an Invisible Dependency

section01

Late on a Friday night, right before a release, the CI pipeline suddenly went red. The error: "toomanyrequests." Everything had worked fine locally — it only failed the moment we tried to deploy to a production-equivalent K3s cluster.

The culprit was Docker Hub's pull rate limit. According to Docker's official documentation, anonymous pulls are limited to 100 per 6 hours per IPv4 address or IPv6 /64 subnet. Even authenticated free accounts are capped at 200 per 6 hours.

A K3s cluster has multiple worker nodes. When CI builds scale and a large volume of concurrent pulls all come through the same NAT gateway — the same global IP — that ceiling gets hit surprisingly fast. And this limit doesn't fire because production traffic actually increased; it fires simply because the requests "come from the same IP." Nobody did anything wrong, yet one day, deployment just stops. This is the invisible dependency that nearly every K3s operations team trips over at least once.

Dealing with this kind of invisible dependency is really part of a broader question about how you design K3s cluster operations overall. Whether you choose a managed K3s environment like Kubo, for instance, comes down to a design decision about how much of this operational burden you want to take on yourselves.

There are broadly two ways to address this problem: move to an authenticated paid plan, or route through your own private registry to reduce direct traffic to Docker Hub in the first place. At the center of the latter approach sits Harbor, a CNCF Graduated project.

2. What Harbor Actually Is — More Than "Just a Private Registry"

section02

Harbor joined CNCF in 2018 and reached Graduated status in 2020, making it an enterprise-grade container registry project. It isn't simply "a self-hosted Docker Hub."

According to its official positioning, Harbor's core capabilities fall into four categories:

  • Security: image vulnerability scanning, content trust verification, and project-level role-based access control (RBAC)
  • Replication: replicating images across multiple Harbor instances for disaster recovery and distributing content to multiple clusters
  • Extensibility: LDAP/AD authentication integration, support for multiple storage backends
  • Manageability: a user-friendly UI for managing projects, users, and images

Trivy is commonly built in for vulnerability scanning. Trivy is a single-binary scanner that handles CVE detection, Infrastructure-as-Code misconfiguration detection, SBOM generation, and secret scanning — the Harbor team itself has praised it for raising the bar on "both usability and performance."

For signature verification, Cosign is available. Cosign issues short-lived certificates via OIDC from Sigstore's certificate authority (Fulcio), enabling "keyless signing" with no key management required. Signing and verification records are stored in a transparency log called Rekor, so you can later trace exactly who signed which image and when.

In other words, adopting Harbor means more than just "dodging the pull rate limit." It's a decision to bring the mechanism that guarantees the provenance and safety of your images under your own control.

3. Solving the Pull Limit "By Design" with Harbor Proxy Cache

section03

Since v2.1, Harbor has shipped a Proxy Cache (pull-through cache) feature. The mechanism is simple:

  1. A K3s node pulls an image through Harbor.
  2. Harbor first checks its cache and compares it against the latest manifest on the target registry.
  3. If the image hasn't changed, it's served immediately from the cache.
  4. If it has changed, only the new image gets pulled and the cache is updated.

The key detail is how the update check works. According to Harbor's official documentation, Proxy Cache since v2.1.1 checks for layer updates using HEAD requests, and this check itself is designed not to trigger Docker Hub's rate limit. That means only actual new-image pulls count against the limit, dramatically cutting down on wasted pull requests.

Setup is just a matter of enabling "Proxy Cache" when creating a project and specifying the target registry endpoint (e.g. Docker Hub). Existing manifests or `image: https://cdn.kubo.hexabase.io/images/blog/k3s-harbor-private-registry-docker-hub-rate-limit/eyecatch.webp

4. Implementation Design for K3s/Kubo Clusters and Production Operations

section04

When actually wiring Harbor into a K3s/Kubo cluster, the Pod-side configuration is a standard procedure straight from Kubernetes' official documentation. You create registry credentials as an imagePullSecrets object with kubectl create secret docker-registry, then reference it in your Pod manifest's imagePullSecrets field. That's it.

Running Harbor itself at production quality, on the other hand, takes more design work than a single-instance install. CNCF's guide to making Harbor production-ready calls out at least the following considerations.

High availability and the data layer

Run Harbor's core, jobservice, portal, and registry components across multiple replicas so there's no single point of failure. It's recommended to move off the bundled PostgreSQL/Redis and onto an externally managed, highly available setup.

Security and monitoring

Enable TLS for internal communication as well, and centralize authentication via LDAP/OIDC. Build Trivy vulnerability scanning and Cosign/Notation signature verification into your operational workflow, monitor metrics with Prometheus/Grafana, and use an aggregated logging platform to catch early signs of trouble.

Storage and backups

Beyond picking the right StorageClass and planning capacity, you need backup operations paired with regular recovery testing. Don't forget periodic garbage collection to remove unreferenced blobs.

All of this means Harbor can't be treated as "install it and you're done" — it needs to be brought into your operational scope at the same level as other cluster components like monitoring and certificate management. With a managed K3s environment like Kubo, where Prometheus + Grafana monitoring and cert-manager + Let's Encrypt certificate automation come standard, part of the extra monitoring and certificate layer that Harbor operations demand can be covered by the cluster's built-in capabilities.

5. When You Actually Need a Self-Hosted Harbor — vs. Managed Registries

section05

Of course, not every team should run Harbor themselves. A cloud-managed registry like Amazon ECR — with free data transfer to AWS services in the same region, for example — carries a far lower operational burden if you're staying within a single cloud.

Running your own Harbor pays off when:

  • Multi-cloud/edge deployment: you want to distribute the same images consistently across cloud and on-prem/edge K3s clusters
  • Data sovereignty requirements: your industry (finance, healthcare, etc.) can't have container images sitting with an external cloud vendor
  • Unified scanning/signing policy: you want to enforce the same Trivy/Cosign policies across multiple clouds' managed registries

For environments with especially strict data sovereignty requirements, an option like Kubo On-Premise — which delivers fully managed K8s operations on your own infrastructure — is worth considering.

Conversely, if you're operating within a single cloud and a single cluster with no special compliance requirements, staying on a managed registry is often just fine. Harbor isn't a magic wand that always pays off — adopting it means accepting a trade-off between operational burden and control.

If you want to revisit your overall vulnerability scanning and signing policy for container images, our article on container image security from signing through admission control is a good companion read.

6. Summary

Docker Hub's pull rate limit goes unnoticed while a K3s cluster is still small. But as CI build frequency rises and node counts grow, this invisible dependency inevitably surfaces.

Running Harbor as a private registry isn't just a rate-limit workaround. On top of adding a caching layer via Proxy Cache, it's a design decision spanning your entire container supply chain — vulnerability scanning, signature verification, and replication. And operating it comes with added responsibilities: monitoring, certificate management, and backups.

You don't have to keep wrestling with EKS/AKS's high costs, complexity, and lock-in. With K3s-based Kubo, you get the full power of real Kubernetes while offloading part of that operational layer to built-in standard features — running production clusters at dramatically better cost efficiency. If you want to rethink your entire infrastructure design, registry operations included, feel free to reach out via our contact page.

Related articles

← Back to all posts