Deploy Private Registry on Kubernetes
Setting up a private Docker registry on Kubernetes provides secure, self-hosted container image storage for your development and production workflows. This comprehensive guide walks through deploying a fully configured private registry with TLS encryption, HTTP authentication, persistent storage, and seamless cluster integration.
A private registry offers several advantages over public registries: enhanced security for proprietary images, faster image pulls within your network, compliance with organizational policies, and complete control over your container artifacts. This setup uses the official Docker Registry v2 image with htpasswd authentication and self-signed certificates for secure access.
Prerequisites
Before starting this deployment, ensure you have:
- A running Kubernetes cluster with ingress controller (this guide uses Cilium)
- kubectl configured to access your cluster
- OpenSSL for certificate generation
- Docker installed on your local machine for testing
- Basic understanding of Kubernetes resources and YAML manifests
For related Kubernetes setup guides, see our complete Kubernetes cluster setup with Cilium networking.
Step 1: Create Namespace and Storage
Create Registry Namespace
Start by creating a dedicated namespace for the registry components:
kubectl create namespace registry
Configure Persistent Storage
Create a persistent volume claim to store registry data. This example uses a 20GB volume:
# registry-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: registry-pvc
namespace: registry
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 20Gi
storageClassName: nfs-client # Adjust to your storage class
Note: Replace nfs-client
with your cluster’s available storage class. Use kubectl get storageclass
to list available options.
Step 2: Generate TLS Certificates
Create Self-Signed Certificate
Generate a self-signed certificate for secure HTTPS access. Replace registry.ak8s.net
with your desired domain. For detailed certificate management and verification commands, see our OpenSSL certificate management guide:
openssl req -x509 -nodes -days 365 \
-addext "subjectAltName = DNS:registry.ak8s.net" \
-newkey rsa:2048 \
-keyout registry.ak8s.net.key \
-out registry.ak8s.net.crt \
-subj "/CN=registry.ak8s.net"
This command creates:
registry.ak8s.net.crt
: Public certificateregistry.ak8s.net.key
: Private key
Create TLS Secret
Generate the Kubernetes TLS secret YAML:
kubectl -n registry create secret tls registry-tls \
--cert=./registry.ak8s.net.crt \
--key=./registry.ak8s.net.key \
--dry-run=client -o yaml > registry-tls.yaml
Step 3: Configure Authentication
Generate htpasswd File
Create authentication credentials using Docker. This script generates a secure htpasswd file:
#!/bin/bash
export REGISTRY_USER='username'
export REGISTRY_PASS='password'
export DESTINATION_FOLDER=./registry-creds
# Backup credentials to local files
mkdir -p ${DESTINATION_FOLDER}
echo ${REGISTRY_USER} >> ${DESTINATION_FOLDER}/registry-user.txt
echo ${REGISTRY_PASS} >> ${DESTINATION_FOLDER}/registry-pass.txt
# Generate htpasswd file using Docker
docker run --rm xmartlabs/htpasswd ${REGISTRY_USER} ${REGISTRY_PASS} > htpasswd
# Clean up environment variables
unset REGISTRY_USER REGISTRY_PASS DESTINATION_FOLDER
Security Note: Store these credentials securely and use strong passwords for production deployments.
Create Authentication Secret
Generate the htpasswd secret YAML:
kubectl -n registry create secret generic registry-htpasswd \
--from-file=htpasswd \
--dry-run=client -o yaml > registry-htpasswd.yaml
Step 4: Deploy Registry Components
Registry Deployment
Create the main registry deployment with authentication and persistent storage:
# registry-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: registry
namespace: registry
spec:
replicas: 1
selector:
matchLabels:
app: registry
template:
metadata:
labels:
app: registry
spec:
containers:
- name: registry
image: registry:2
ports:
- name: registry
containerPort: 5000
volumeMounts:
- name: image-store
mountPath: /var/lib/registry
- name: auth
mountPath: /auth
readOnly: true
env:
- name: REGISTRY_AUTH
value: "htpasswd"
- name: REGISTRY_AUTH_HTPASSWD_REALM
value: "Registry Realm"
- name: REGISTRY_AUTH_HTPASSWD_PATH
value: "/auth/htpasswd"
volumes:
- name: image-store
persistentVolumeClaim:
claimName: registry-pvc
- name: auth
secret:
secretName: registry-htpasswd
Registry Service
Create a service to expose the registry deployment:
# registry-service.yaml
apiVersion: v1
kind: Service
metadata:
name: registry-svc
namespace: registry
spec:
selector:
app: registry
ports:
- protocol: TCP
port: 5000
targetPort: 5000
Registry Ingress
Configure ingress for external access with TLS termination. For comprehensive nginx configuration patterns and SSL best practices, refer to our nginx reverse proxy configuration guide:
# registry-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: registry-ingress
namespace: registry
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 16m
spec:
ingressClassName: cilium # Adjust to your ingress class
tls:
- hosts:
- registry.ak8s.net
secretName: registry-tls
rules:
- host: registry.ak8s.net
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: registry-svc
port:
number: 5000
Step 5: Deploy All Components
Apply all configuration files to your cluster:
kubectl apply -f registry-htpasswd.yaml \
-f registry-pvc.yaml \
-f registry-tls.yaml \
-f registry-deployment.yaml \
-f registry-service.yaml \
-f registry-ingress.yaml
Verify the deployment:
# Check all registry resources
kubectl -n registry get all
# Get ingress IP address
kubectl -n registry get ingress
Step 6: Configure DNS and Certificate Trust
Update DNS Resolution
Add the registry domain to your /etc/hosts
file on all nodes and client machines:
# Get the ingress IP address
REGISTRY_IP=$(kubectl -n registry get ingress registry-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
# Add to /etc/hosts
echo "${REGISTRY_IP} registry.ak8s.net" | sudo tee -a /etc/hosts
Trust the Certificate
On each Kubernetes node and client machine, trust the self-signed certificate:
# For Arch Linux nodes
sudo trust anchor --store registry.ak8s.net.crt
# Restart container runtime
sudo systemctl restart containerd
For other distributions, copy the certificate to the appropriate trust store and update the certificate cache.
Step 7: Configure Cluster Access
Update CoreDNS
To enable registry access from within the cluster, update the CoreDNS configuration:
kubectl -n kube-system edit configmap coredns
Add the registry entry to the Corefile:
data:
Corefile: |
.:53 {
# ... existing configuration ...
hosts {
192.168.1.100 registry.ak8s.net # Replace with your ingress IP
fallthrough
}
# ... rest of configuration ...
}
Restart CoreDNS to apply changes:
kubectl -n kube-system rollout restart deployment coredns
Create Image Pull Secret
Create a secret for authenticating with the private registry from within the cluster:
kubectl create secret docker-registry regcred \
--docker-server=registry.ak8s.net \
--docker-username=username \
--docker-password=password
Step 8: Testing the Registry
Build and Push Test Image
Create a simple test image to verify the registry:
# Dockerfile
FROM archlinux/archlinux
RUN pacman -Syu --noconfirm figlet
ENTRYPOINT ["figlet", "Hello, World!"]
Build and push the test image:
# Build the image
docker build . -t registry.ak8s.net/test_image:latest
# Login to the registry
docker login registry.ak8s.net
# Push the image
docker push registry.ak8s.net/test_image:latest
Test Cluster Access
Create a pod to test pulling from the private registry:
# test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: private-reg-test
namespace: default
spec:
containers:
- name: private-reg-container
image: registry.ak8s.net/test_image:latest
imagePullSecrets:
- name: regcred
Apply and check the pod:
kubectl apply -f test-pod.yaml
kubectl logs private-reg-test
If successful, you should see “Hello, World!” in ASCII art.
Security Considerations
Production Deployment Best Practices
For production environments, consider these security enhancements:
- Use Valid TLS Certificates: Replace self-signed certificates with certificates from a trusted CA
- Implement RBAC: Configure role-based access control for registry operations
- Regular Security Updates: Keep the registry image updated to the latest version
- Network Policies: Implement Kubernetes network policies to restrict registry access
- Vulnerability Scanning: Integrate image vulnerability scanning in your CI/CD pipeline
Authentication Alternatives
While htpasswd provides basic authentication, consider these alternatives for enhanced security:
- OAuth Integration: Configure OAuth providers for centralized authentication
- LDAP/Active Directory: Integrate with existing directory services
- Token-based Authentication: Implement JWT tokens for API access
- Mutual TLS: Use client certificates for enhanced security
Troubleshooting
Common Issues and Solutions
Certificate Trust Issues:
- Ensure the certificate is properly installed on all nodes
- Verify the certificate includes the correct SAN (Subject Alternative Name) using OpenSSL verification commands
- Restart the container runtime after adding certificates
Authentication Failures:
- Verify htpasswd file is correctly generated and base64 encoded
- Check that the authentication secret is properly mounted in the deployment
- Ensure credentials match those used in the htpasswd file
Network Connectivity:
- Confirm DNS resolution is working within the cluster
- Verify ingress controller is properly configured
- Check that firewall rules allow traffic on required ports
Storage Issues:
- Ensure the storage class supports ReadWriteOnce access mode
- Verify sufficient storage capacity is available
- Check that the persistent volume is properly bound
Monitoring and Maintenance
Monitor your private registry with these practices:
- Resource Usage: Monitor CPU, memory, and storage usage
- Image Cleanup: Implement garbage collection for unused images
- Backup Strategy: Regular backups of registry data and configuration
- Access Logs: Review access logs for security auditing
References and Resources
- Docker Registry Documentation
- Kubernetes Ingress Documentation
- OpenSSL Certificate Management
- Harbor - Enterprise Registry Alternative
Questions Answered in This Document
Q: How do I deploy a private Docker registry on Kubernetes? A: Deploy a private registry using the official registry:2 image with persistent storage, TLS encryption, and htpasswd authentication, configured through Kubernetes deployments, services, and ingress resources.
Q: How do I secure a private Docker registry with TLS certificates? A: Generate self-signed certificates using OpenSSL commands with proper Subject Alternative Names, create Kubernetes TLS secrets, and configure ingress to terminate TLS connections with the certificates.
Q: How do I configure authentication for a private Docker registry? A: Use htpasswd-based authentication by generating credential files with Docker, creating Kubernetes secrets, and mounting them in the registry deployment with appropriate environment variables. For additional security options, see certificate-based authentication methods.
Q: How do I enable private registry access from within a Kubernetes cluster? A: Configure CoreDNS for internal DNS resolution, trust certificates on all nodes, create docker-registry secrets for authentication, and use imagePullSecrets in pod specifications. Ensure proper ingress configuration for internal routing.
Q: How do I troubleshoot private registry connectivity issues? A: Verify certificate trust, check DNS resolution, confirm authentication credentials, validate network policies, and ensure proper ingress configuration with correct backend services.
Q: What storage considerations are important for a private Docker registry? A: Use persistent volumes with ReadWriteOnce access mode, provision adequate storage capacity for image storage, implement backup strategies, and consider performance requirements for concurrent access.
Q: How do I test if my private Docker registry is working correctly? A: Build and push test images, verify authentication by logging in with Docker, create test pods that pull from the registry, and check logs for successful image pulls and container startup.
Q: What are the security best practices for private Docker registries in production? A: Use valid TLS certificates from trusted CAs, implement strong authentication mechanisms, configure network policies, keep registry software updated, and integrate vulnerability scanning into your workflow.