Categories DevOps

Using a Private Docker Registry with Minikube and K3s

Introduction

A private Docker registry is a crucial component for organizations looking to maintain control over their container images while ensuring secure and efficient distribution. This guide explores how to set up and manage a private Docker registry using the official registry container with Minikube and k3s environments.

Whether you’re a developer working on local projects or a DevOps engineer managing container deployments, having a private registry gives you complete control over your container images without relying on public registries like Docker Hub.

In this comprehensive guide, we’ll walk through the setup, configuration, and maintenance of a private Docker registry, specifically focusing on integration with Minikube and k3s environments.

Getting Started

Prerequisites Checklist

Before beginning, ensure you have the following components installed and configured:

  • Docker Engine (latest stable version)
  • Minikube or k3s cluster
  • kubectl command-line tool
  • Basic understanding of container concepts

If you need to deploy a Kubernetes cluster for this read our Minikube or K3s deployment guides.

Basic Concepts Overview

A container registry serves as a repository for storing and distributing Docker images. It plays a central role in:

  • Storing container images securely
  • Managing image versions and tags
  • Facilitating image distribution across environments
  • Supporting local development workflows

Setting Up a Registry with Minikube

Using the Built-in Registry Addon

Minikube provides a convenient registry addon that simplifies the setup process:

minikube addons enable registry

This command creates a registry service accessible at localhost:5000. Verify the setup with:

kubectl get pods -n kube-system | grep registry

Manual Deployment Method

For more control over the registry configuration, you can deploy it manually:

Create a persistent volume and claim:

# registry-storage.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: registry-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/registry"
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: registry-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Apply the storage configuration:

kubectl apply -f registry-storage.yaml

Deploy the registry with persistent storage:

# registry-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
      - name: registry
        image: registry:2
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: registry-storage
          mountPath: /var/lib/registry
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
          requests:
            memory: "256Mi"
            cpu: "100m"
      volumes:
      - name: registry-storage
        persistentVolumeClaim:
          claimName: registry-pvc

Create a service for the registry:

# registry-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: registry
spec:
  selector:
    app: registry
  ports:
  - port: 5000
    targetPort: 5000

Apply the deployment and service:

kubectl apply -f registry-deployment.yaml
kubectl apply -f registry-service.yaml

Configuration Validation Steps

Test the registry setup by:

Pushing a test image:

docker tag nginx:latest localhost:5000/test-nginx
docker push localhost:5000/test-nginx

Verifying the image listing:

curl http://localhost:5000/v2/_catalog

Setting Up Registry with k3s

Deployment Process

First, prepare the storage directory on your host:

sudo mkdir -p /data/registry
sudo chmod 755 /data/registry

Create the persistent volume and claim optimized for k3s:

# k3s-registry-storage.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: registry-pv
spec:
  storageClassName: local-path
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/registry"
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: registry-pvc
spec:
  storageClassName: local-path
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Create the registry configuration:

# registry-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: registry-config
data:
  config.yml: |
    version: 0.1
    storage:
      filesystem:
        rootdirectory: /var/lib/registry
    http:
      addr: :5000
      headers:
        X-Content-Type-Options: [nosniff]

Apply storage and config resources:

kubectl apply -f k3s-registry-storage.yaml
kubectl apply -f registry-config.yaml

Deploy the registry with persistent storage:

# k3s-registry-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
      - name: registry
        image: registry:2
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: registry-storage
          mountPath: /var/lib/registry
        - name: registry-config
          mountPath: /etc/docker/registry/config.yml
          subPath: config.yml
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
          requests:
            memory: "256Mi"
            cpu: "100m"
      volumes:
      - name: registry-storage
        persistentVolumeClaim:
          claimName: registry-pvc
      - name: registry-config
        configMap:
          name: registry-config

Deploy the service:

# registry-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: registry
spec:
  selector:
    app: registry
  ports:
  - port: 5000
    targetPort: 5000
  1. Apply deployment and service:
kubectl apply -f k3s-registry-deployment.yaml
kubectl apply -f registry-service.yaml

Storage Validation Steps

Verify that persistent storage is working correctly:

# Push a test image
docker tag nginx:latest localhost:5000/test-nginx
docker push localhost:5000/test-nginx

# Verify the image is in the registry
curl http://localhost:5000/v2/_catalog

# Delete the registry pod to force a restart
kubectl delete pod -l app=registry

# Wait for the new pod to be ready
kubectl get pods -l app=registry

# Verify the image is still available after pod restart
curl http://localhost:5000/v2/_catalog

Security Setup

For production environments, implement:

TLS configuration using certificates:

kubectl create secret tls registry-tls --cert=tls.crt --key=tls.key

Basic authentication:

htpasswd -Bbn username password > auth/htpasswd
kubectl create secret generic registry-auth --from-file=auth/htpasswd

Configuration and Best Practices

Insecure Registry Setup

Configure Docker daemon to trust your registry:

{
  "insecure-registries": ["localhost:5000"]
}

For k3s, add to /etc/rancher/k3s/registries.yaml:

mirrors:
  "localhost:5000":
    endpoint:
      - "http://localhost:5000"

Authentication Setup

Create user credentials:

mkdir auth
htpasswd -Bbn admin password > auth/htpasswd

Configure basic authentication in the registry:

auth:
  htpasswd:
    realm: basic-realm
    path: /auth/htpasswd

Storage Considerations

  1. For production environments, consider using cloud-native storage solutions instead of hostPath
  2. Set resource limits for your PVC to prevent excessive storage consumption
  3. Implement regular backups of the registry data
  4. Monitor storage usage and set up alerts for when storage is nearly full
  5. Consider implementing image retention policies to manage disk space automatically

Working with Your Private Registry

Basic Operations

Push images to your registry:

docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest

Pull images from your registry:

docker pull localhost:5000/myapp:latest

List available repositories:

curl -X GET http://localhost:5000/v2/_catalog

Maintenance and Operations

Regular Maintenance Tasks

Garbage collection:

registry garbage-collect /etc/docker/registry/config.yml

Health monitoring:

curl -X GET http://localhost:5000/v2/_catalog
kubectl get pods -l app=registry

Log management:

kubectl logs -f -l app=registry

Troubleshooting Guide

Common issues and solutions:

  1. Image Pull Errors
  • Check registry accessibility
  • Verify image tags
  • Confirm authentication credentials
  1. Storage Issues
  • Monitor disk space
  • Run garbage collection
  • Review retention policies
  1. Container “Creating” State
  • Check PV/PVC binding status: kubectl get pv,pvc
  • Verify host directory permissions: ls -la /data/registry
  • Check pod events: kubectl describe pod -l app=registry
  • Review logs: kubectl logs -l app=registry

Conclusion

A private Docker registry provides essential functionality for managing container images in Minikube and k3s environments. Key takeaways:

  • Choose between built-in addons or manual deployment
  • Implement proper persistent storage for durability
  • Apply appropriate security measures
  • Regular maintenance is crucial
  • Monitor performance and storage

By following this guide, you’ll be able to set up, configure, and maintain a reliable private Docker registry that enhances your container development and deployment workflows in both Minikube and k3s environments.

More From Author

You May Also Like