Logo AppDev24 Login / Sign Up
Sign Up
Have Login?
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Login
New Account?
Recovery
Go to Login
By continuing you indicate that you agree to Terms of Service and Privacy Policy of the site.
Kubernetes

Setup a Private Container Registry

Updated on Sep 25, 2024

A private local container registry enables you to securely store and manage your Docker images, improving efficiency, control, and security. This guide will walk you through the setup of Docker Distribution Registry in Kubernetes cluster.

A private container registry is beneficial for organizations seeking full control over their container images. Instead of using a third-party registry like Docker Hub, a local registry offers improved security, data privacy, and network performance, particularly in environments where data sovereignty and fast access to large files are critical.

Docker Distribution Registry is an open source Distribution implementation for storing and distributing of container images and artifacts.

Create Self-Signed Certificate

Pre-requisite: openssl must be installed in MacOS

openssl req -x509 -nodes -days 365 \
    -subj "/C=DE/ST=Berlin/L=Berlin/O=appdev24/OU=dev/CN=registry.local" \
    -newkey rsa:4096 -keyout selfsigned.key \
    -out selfsigned.crt

-subj switch option:

  • Country Name (2 letter code): DE
  • State or Province Name (full name): Berlin
  • Locality Name (city): Berlin
  • Organization Name (company): appdev24
  • Organizational Unit Name (department): dev
  • Common Name (server FQDN): registry.local

Update hosts file

To ensure your system recognizes the registry domain, update the /etc/hosts file by adding the domain name and pointing it to your localhost or cluster IP:

sudo vi /etc/hosts

# Append the server entry
127.0.0.1	registry.local

Create Namespace

Next, create a dedicated namespace for your registry in your Kubernetes cluster:

kubectl create namespace mlops

Create Kubernetes Secret

Then, create Kubernetes secrets to store the TLS certificate and key within the cluster:

kubectl create secret tls registry-tls --namespace mlops --cert=selfsigned.crt --key=selfsigned.key

Create Basic Authentication User

You will also need to create a secret for basic authentication (username and password) for the registry.

Create a password file htpasswd with your username & password. For example  “admin” and “Passw0rd1234”.

docker run --entrypoint htpasswd httpd:2 -Bbn admin Passw0rd1234 > htpasswd
# cat htpasswd
# admin:$2y$05$QviwnrAyJWZayvYqw03znuhlaA2zG4NpCtNgQboysgzdah5qr7f3C

Create Kubernetes Secret

Create as Kubernetes Secret

kubectl create secret generic registry-auth --namespace mlops --from-literal=htpasswd='admin:$2y$05$QviwnrAyJWZayvYqw03znuhlaA2zG4NpCtNgQboysgzdah5qr7f3C'

Create Persistent Volumes

Persistent volumes are essential to store the container images in your private registry. Define a persistent volume (PV) and persistent volume claim (PVC) in Kubernetes:

# registry-sc-pv-pvc.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: docker-sc
provisioner: docker.io/hostpath
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: registry-pv
spec:
  storageClassName: docker-sc # hostpath
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/Users/saurav/Tech/Kubernetes/pv_pvc/data/registry" # Host path on MacOS
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: registry-pvc
  namespace: mlops
spec:
  storageClassName: docker-sc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
kubectl apply -f registry-sc-pv-pvc.yaml

Ensure that your PVC matches the configuration in your Kubernetes cluster.

Create Deployment

Now you’re ready to deploy your registry. Use the following configuration to create a Kubernetes deployment for your private container registry:

registry-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry-deployment
  namespace: mlops
  labels:
    app: registry-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
    spec:
      containers:
        - name: registry-server
          image: registry:2.8.3
          ports:
          - containerPort: 5000
          env:
            - name: REGISTRY_HTTP_TLS_CERTIFICATE
              value: /etc/ssl/docker/tls.crt
            - name: REGISTRY_HTTP_TLS_KEY
              value: /etc/ssl/docker/tls.key
            - name: REGISTRY_AUTH
              value: "htpasswd"
            - name: REGISTRY_AUTH_HTPASSWD_REALM
              value: "Registry Realm"
            - name: REGISTRY_AUTH_HTPASSWD_PATH
              value: "/auth/htpasswd"
            - name: REGISTRY_STORAGE_DELETE_ENABLED
              value: "true"
          command:
          - /bin/registry
          - serve
          - /etc/docker/registry/config.yml
          volumeMounts:
            - name: registry-storage
              mountPath: "/var/lib/registry"
            - name: registry-certs
              mountPath: "/etc/ssl/docker"
              readOnly: true
            - name: registry-auth
              mountPath: "/auth"
              readOnly: true
          resources:
            limits:
              cpu: 200m
              memory: 256Mi
            requests:
              cpu: 100m
              memory: 128Mi
          readinessProbe:
            httpGet:
              scheme: HTTPS
              path: /
              port: 5000
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /
              port: 5000
      volumes:
        - name: registry-storage
          persistentVolumeClaim:
            claimName: registry-pvc
        - name: registry-certs
          secret:
            secretName: registry-tls
        - name: registry-auth
          secret:
            secretName: registry-auth
            items:
            - key: htpasswd
              path: htpasswd
kubectl apply -f registry-deploy.yaml

This deployment will set up your container registry, running on port 5000.

Create Service

To access your registry, you’ll need to expose it as a service in Kubernetes. Use a ClusterIP or NodePort service type, depending on your environment:

registry-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: registry-service
  namespace: mlops
  labels:
    app: registry-service
spec:
  type: ClusterIP
  selector:
    app: registry
  ports:
  - name: tcp
    protocol: TCP
    port: 5000
    targetPort: 5000
kubectl apply -f registry-svc.yaml

Create Ingress

To make the registry accessible through an easy-to-remember URL, set up Nginx ingress:

registry-ing.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: registry-ingress
  namespace: mlops
  labels:
    app: registry-ingress
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: registry.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: registry-service
            port:
              number: 5000
  tls:
  - hosts:
    - registry.local
    secretName: registry-tls
kubectl apply -f registry-ing.yaml

This configuration will route traffic to the registry using Nginx ingress, secured by TLS.

Test Registry

Finally, test your setup by pushing and pulling Docker images from your private registry:

Test Authentication

docker login registry.local -u admin -p Passw0rd1234

Ensure you get the message Login Succeeded

Test Image Push

docker pull nginx:latest
docker tag nginx:latest registry.local/my-nginx:test
docker push registry.local/my-nginx:test

If you encounter an error message saying "413 Request Entity Too Large" you will need to modify the property proxy-body-size of Nginx Ingress Controller. For large image files, adjust Nginx settings to handle them.

For example-

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace \
  --set controller.config.proxy-body-size=0
/Users/saurav/Tech/Kubernetes/pv_pvc/data/registry
/Users/saurav/Tech/Kubernetes/pv_pvc/data/registry

Test Image Pull

Verify that the image is stored in your registry and can be pulled back into any environment.

# Remove Locally cached Images First
docker image remove nginx:latest
docker image remove registry.local/my-nginx:test

docker pull registry.local/my-nginx:test

By setting up a private local container registry with Docker Distribution Registry, you gain full control over your container image management. This setup provides a secure and efficient way to store and retrieve Docker images, especially for organizations focused on performance and privacy.

PrimeChess

PrimeChess.org

PrimeChess.org makes elite chess training accessible and affordable for everyone. For the past 6 years, we have offered free chess camps for kids in Singapore and India, and during that time, we also observed many average-rated coaches charging far too much for their services.

To change that, we assembled a team of top-rated coaches including International Masters (IM) or coaches with multiple IM or GM norms, to provide online classes starting from $50 per month (8 classes each month + 4 tournaments)

This affordability is only possible if we get more students. This is why it will be very helpful if you could please pass-on this message to others.

Exclucively For Indian Residents: 
Basic - ₹1500
Intermediate- ₹2000
Advanced - ₹2500

Top 10 Articles