Cart

    Sorry, we could not find any results for your search querry.

    Deploying a docker registry in Kubernetes

    When using a Kubernetes cluster, sooner or later you often use custom container images. You can store these publicly or host them on your own container registry.

    In this tutorial, we will show you how to deploy a Docker Container Registry on a Kubernetes cluster and push your own container images to it.

    For this tutorial, we assume that you are using Traefik within your Kubernetes cluster, see our Traefik for Kubernetes tutorial. One handy advantage of this is that you don't need to create a separate load balancer and that Traefik provides a Let's Encrypt certificate to secure the connection to your Docker Container Registry.


     

    Step 1

    To connect to your upcoming Docker Registry, you need a username and password. Generate a password with the command below, replacing 'username' with a username of your choice.

    The addition 'tee registry.htpasswd' ensures that the output is saved in a file named registry.htpasswd in the current directory.

    htpasswd -nB username | tee registry.htpasswd

    You will now receive two prompts for a password and then in the output the username and the encrypted password:

    New password:
    Re-type new password:
    username:$5y$03$zn9rxGHYZBrRY45OT..VDO2oOISfl561Q0kvdDyvuZtlrOKV6KXVe

     

    Step 2

    Create a namespace for your Docker Registry, for example:

    kubectl create ns docker-registry

     

    Step 3

    Create a 'secret' based on the password you just generated. This will allow your Docker Registry to verify the username and password from the previous step when you connect to it.

    kubectl create secret generic registry-auth-secret --from-file=users=registry.htpasswd -n docker-registry

     

    Step 4

    Create a .yaml deployment file for your Docker Registry:

    nano registry-deployment.yaml

    Give the file the content below. Replace registry.yourdomain.com with a subdomain of your choice. Please note that the domain must be included in your TransIP account, otherwise Traefik cannot assign a Let's Encrypt certificate to it.

    # registry-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: docker-registry-deployment
      namespace: docker-registry
      labels:
        app: docker-registry
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: docker-registry
      template:
        metadata:
          labels:
            app: docker-registry
        spec:
          volumes:
          - name: registry-pv-storage
            persistentVolumeClaim:
              claimName: registry-pv-claim
          containers:
          - name: docker-registry-container
            image: registry:2
            ports:
            - name: docker-registry
              containerPort: 5000
            volumeMounts:
            - mountPath: "/var/lib/registry"
              name: registry-pv-storage
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: docker-registry
      namespace: docker-registry
    spec:
      ports:
      - name: http
        port: 5000
      selector:
        app: docker-registry
    ---
    apiVersion: traefik.containo.us/v1alpha1
    kind: Middleware
    metadata:
      name: registry-ingress-auth
      namespace: docker-registry
    spec:
      basicAuth:
        secret: registry-auth-secret
        removeHeader: true
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: registry-pv-claim
      namespace: docker-registry
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 5Gi
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: docker-registry-ingress
      namespace: docker-registry
      annotations:
        ingressClassName: traefik
        traefik.ingress.kubernetes.io/router.tls.certresolver: myresolver
        traefik.ingress.kubernetes.io/router.middlewares: traefik-registry-ingress-auth@kubernetescrd
    spec:
      rules:
      - host: registry.jouwdomein.nl
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: docker-registry
                port:
                  number: 5000

    Code explanation

    • The first block of the code specifically addresses deployment. Refer to our manual 'Creating an object based deployment in Kubernetes' for detailed information on how a deployment through .yaml file is structured. 
      ---
    • kind: Service: Create a service for the Docker Registry.
    • metadata.name: docker-registry: Name of the service.
    • metadata.namespace: docker-registry: Namespace where the component is deployed. You'll notice this element appears in multiple sections of the .yaml file to identify the namespace for that specific component.
    • spec.ports.name/port: Name and port number respectively that are exposed.
    • spec.selector.app: docker-registry: The pod to which this service routes traffic. 
      ---
    • kind: Middleware: Middleware is specific to Traefik and allows you to tweak traffic before it is sent to a service.
    • metadata.name: registry-ingress-auth: Name of the Middleware.
    • spec.basicAuth: Enable basic authentication.
    • spec.basicAuth.secret: registry-auth-secret: The secret you created in step 3 for authentication with your Docker Registry.
    • spec.basicAuth.removeHeader: true: Remove the Authorization header after successful authentication. 
      ---
    • kind: PersistentVolumeClaim: A PersistentVolumeClaim (PVC) is simply a request for extra disk space that your deployment can use to write data to.
    • metadata.name: registry-pv-claim: Name of the PersistentVolumeClaim.
    • spec.accessMode: ReadWriteOnce: The PVC can be used by a single node (but by multiple pods on that node) with Read Write permissions.
    • spec.resources.requests:storage: 5Gi: The size of the PersistentVolumeClaim. In this example, 5 gibibytes. You are free to use G for gigabyte, see also this page for more information on gibibytes. 
      ---
    • kind: Ingress: An API object that manages external access to services in a cluster, usually HTTP.
    • metadata.name: docker-registry-ingress: Name of the Ingress.
    • metadata.annotations: kubernetes.io/ingress.class: traefik: Which Ingress controller should be used to route traffic. In this case, Traefik.
    • metadata.annotations: traefik.ingress.kubernetes.io/router.tls.certresolver: myresolver: Configures a (Let's Encrypt) certresolver for HTTPS traffic.
    • metadata.annotations: traefik.ingress.kubernetes.io/router.middlewares: traefik-registry-ingress-auth@kubernetescrd: Adds a Middleware object to the router to handle authentication.
    • spec.rules.host: registry.yourdomain.com: The (sub)domain on which your Docker Registry is accessible.
    • spec.rules.http.paths.path.backend.service.name: docker-registry: The service to which traffic is routed.
    • spec.rules.http.paths.path.backend.service.port: 5000: The port to which traffic is routed.
     
     

    Save the changes and close the file (ctrl + x > y > enter).


     

    Step 5

    Deploy your Docker Registry with the command:

    kubectl apply -f registry-deployment.yaml

    Alternatively, you can remove the metadata.namespace from the various components in the .yaml file and use the command below (using -n docker-registry specifies the namespace the components are to be created in). This simplifies the .yaml file a little and makes it easier to deploy it across namespaces. On the other hand, having it in the .yaml file makes the .yaml file more complete and easier to troubleshoot.

    kubectl apply -f registry-deployment.yaml -n docker-registry

     

    Step 6

    Your Docker Registry is now deployed! It may take up to a minute or two to get a public IP address. Check the status of your services to retrieve the public IP address with the command:

    kubectl get svc -n docker-registry

    Set the public IP address in your DNS records for the subdomain from step 4. After this, it may take some time (varying from 5 minutes to a maximum of one or two hours) for Traefik to assign a Let's Encrypt certificate to your subdomain.


    Pushing containers to your Docker Registry

    To push a containerized application to your Docker Registry, you need to follow these three steps:

    Connect to your own registry using the username and password from step 1 of this article:

    docker login registry.yourdomain.com

    Tag your container image with the Harbor registry URL:

    docker tag my-image registry.yourdomain.com/my-image

    Push your container image to the Harbor registry:

    docker push registry.yourdomain.com/my-image

    We explain how to deploy your containerized application in a Kubernetes cluster in our guide 'Deploying your containerized image in a Kubernetes cluster'.

    Need help?

    Receive personal support from our supporters

    Contact us