Solving Docker Hub Rate Limits with Azure Container Registry Cache Rules
by Tom Van Humbeeck
Docker Hub’s rate limiting has become a significant challenge for organizations running containerized workloads at scale. With anonymous users limited to 100 pulls per 6 hours and authenticated users to 200 pulls per 6 hours, busy Kubernetes clusters can quickly exhaust these quotas, leading to failed deployments and frustrated development teams.
Our solution? Implementing Azure Container Registry (ACR) cache rules to create a transparent caching layer that dramatically reduces our dependency on Docker Hub while maintaining seamless container image access.
The Challenge: Docker Hub Rate Limits
Docker Hub introduced rate limiting in November 2020 to manage the increasing load on their infrastructure. While understandable from Docker’s perspective, this change created immediate operational challenges for our Kubernetes clusters and CI/CD pipelines:
- Failed Pod Deployments: When rate limits were exceeded, new pods couldn’t pull required images
- Scaling Issues: Horizontal pod autoscaling became unreliable during high-traffic periods
- CI/CD Pipeline Failures: Build processes would fail when attempting to pull base images
- Development Friction: Local development environments would hit limits when multiple developers worked simultaneously
The Solution: ACR Cache Rules
Azure Container Registry cache rules provide an elegant solution by creating a transparent proxy cache for external registries. When configured, ACR will:
- Intercept pull requests for images from external registries
- Cache images locally on first pull
- Serve subsequent requests from the local cache
- Automatically update cached images based on configured policies
This approach reduces external registry calls by 80-90% in typical scenarios.
Implementation with Terraform
Here’s how we implemented ACR cache rules using Terraform HCL:
Basic ACR Setup
# Resource group for ACR
resource "azurerm_resource_group" "acr_rg" {
name = "rg-acr-cache"
location = "westeurope"
}
# Azure Container Registry
resource "azurerm_container_registry" "acr" {
name = "testacr"
resource_group_name = azurerm_resource_group.acr_rg.name
location = azurerm_resource_group.acr_rg.location
sku = "Premium" # Cache rules require Premium SKU
admin_enabled = false
# Enable anonymous pull access for easier K8s integration
anonymous_pull_enabled = true
}
Docker Hub Cache Rule
# Cache rule for Docker Hub
resource "azurerm_container_registry_cache_rule" "docker_hub" {
name = "docker-hub-cache"
container_registry_id = azurerm_container_registry.acr.id
target_repo = "docker.io/*"
source_repo = "library/*"
credential_set_id = azurerm_container_registry_credential_set.docker_hub.id
depends_on = [
azurerm_container_registry_credential_set.docker_hub
]
}
# Credential set for Docker Hub authentication
resource "azurerm_container_registry_credential_set" "docker_hub" {
name = "docker-hub-credentials"
container_registry_id = azurerm_container_registry.main.id
login_server_url = "docker.io"
identity {
type = "SystemAssigned"
}
}
# Store Docker Hub credentials in Key Vault
resource "azurerm_key_vault_secret" "docker_username" {
name = "docker-hub-username"
value = var.docker_hub_username
key_vault_id = azurerm_key_vault.main.id
}
resource "azurerm_key_vault_secret" "docker_password" {
name = "docker-hub-password"
value = var.docker_hub_password
key_vault_id = azurerm_key_vault.main.id
}
Variables and Key Vault Setup
# Variables
variable "docker_hub_username" {
description = "Docker Hub username for authenticated pulls"
type = string
sensitive = true
}
variable "docker_hub_password" {
description = "Docker Hub password or access token"
type = string
sensitive = true
}
# Key Vault for storing credentials
resource "azurerm_key_vault" "main" {
name = "kv-acr-cache-${random_string.suffix.result}"
location = azurerm_resource_group.acr_rg.location
resource_group_name = azurerm_resource_group.acr_rg.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = data.azurerm_client_config.current.object_id
secret_permissions = [
"Get",
"List",
"Set",
"Delete",
"Recover",
"Backup",
"Restore"
]
}
}
data "azurerm_client_config" "current" {}
resource "random_string" "suffix" {
length = 6
special = false
upper = false
}
Kubernetes Integration
Once the cache rules are configured, updating your Kubernetes cluster to use the cached images is straightforward:
Original Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: nginx:latest # Pulls from Docker Hub
ports:
- containerPort: 80
Updated Deployment with ACR Cache
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: mycompanyacrcache.azurecr.io/docker.io/library/nginx:latest
ports:
- containerPort: 80
Results and Benefits
After implementing ACR cache rules, we observed significant improvements:
Performance Metrics
- 95% reduction in Docker Hub API calls
- 60% faster image pull times for cached images
- Zero rate limit errors since implementation
- Improved reliability during peak scaling events
Operational Benefits
- Reduced Dependency: Less reliance on external registry availability
- Cost Optimization: Reduced bandwidth costs for repeated pulls
- Improved Security: Images are scanned and stored in our controlled environment
- Better Compliance: Easier to maintain image provenance and audit trails
Best Practices and Considerations
Cache Management
- Monitor Cache Usage: Regularly review storage consumption and costs
- Implement Cleanup Policies: Use ACR’s retention policies to manage old images
- Update Strategies: Plan for updating cached images when upstream changes occur
Security Considerations
- Image Scanning: Enable vulnerability scanning on cached images
- Access Control: Implement proper RBAC for registry access
- Credential Management: Use managed identities where possible
Conclusion
Azure Container Registry cache rules have proven to be an effective solution for managing Docker Hub rate limits while providing additional benefits around performance, security, and operational efficiency. The Terraform implementation makes it easy to deploy and manage these rules consistently across environments.
The initial setup investment pays dividends through improved reliability, reduced external dependencies, and better overall container image management. For organizations facing similar challenges with container registry rate limits, ACR cache rules offer a robust, enterprise-ready solution.
By proactively addressing Docker Hub rate limits with ACR cache rules, we’ve transformed a significant operational challenge into an opportunity for improved infrastructure resilience and performance.