# Deploying Docker Registry on Kubernetes QUELLE: https://medium.com/geekculture/deploying-docker-registry-on-kubernetes-3319622b8f32 ## Howto ### Create Key and Certificate ```bash $ mkdir -p certs $ openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout certs/registry.key \ -addext "subjectAltName = IP:10.211.55.250" \ -x509 -days 3650 -out certs/registry.crt ``` The important bit here is that we set the subjectAltName to an IP number our MetalLB load balancer will assign. In our cluster we will assign 192.168.202.5 to the Docker Registry service (see later on). ### Store Key and Certificate in Cluster ```bash kubectl create secret tls registry-cert \ --cert=certs/registry.crt \ --key=certs/registry.key \ -n distribution ``` The above command will store registry.crt and registry.key in a TLS secret called registry-cert in the namespace distribution. We will be deploying our Docker Registry in this namespace. ### Create Persistant Volume for Docker Registry ```yaml --- # Namespace.yaml apiVersion: v1 kind: Namespace metadata: name: distribution ``` ```yaml # StorageClass.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: distribution-sc provisioner: nfs.csi.k8s.io parameters: server: 192.168.202.50 share: /srv/distribution/ # csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume # csi.storage.k8s.io/provisioner-secret-name: "mount-options" # csi.storage.k8s.io/provisioner-secret-namespace: "default" reclaimPolicy: Delete volumeBindingMode: Immediate mountOptions: - nfsvers=4.1 ``` ```yaml --- apiVersion: v1 kind: PersistentVolume metadata: annotations: pv.kubernetes.io/provisioned-by: nfs.csi.k8s.io name: distribution-pv spec: capacity: storage: 100Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: distribution-sc mountOptions: - nfsvers=4.1 csi: driver: nfs.csi.k8s.io # volumeHandle format: {nfs-server-address}#{sub-dir-name}#{share-name} # make sure this value is unique for every share in the cluster volumeHandle: 192.168.202.50/srv/distribution## volumeAttributes: server: 192.168.202.50 share: /srv/distribution ``` ```yaml # PersistantVolumeClaim.yaml --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: distribution-pvc namespace: distribution spec: accessModes: - ReadWriteMany resources: requests: storage: 100Gi volumeName: distribution-pv storageClassName: distribution-sc ``` Create Namespace.yaml, StorageClass.yaml and PersistantVolumeClaim.yaml with the above content. ### Deployment of registry container ```yaml # RegistryDeployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: run: registry name: registry namespace: distribution spec: replicas: 1 selector: matchLabels: run: registry template: metadata: labels: run: registry spec: nodeSelector: node-type: worker containers: - name: registry image: registry:2 ports: - containerPort: 5000 env: - name: REGISTRY_HTTP_TLS_CERTIFICATE value: "/certs/tls.crt" - name: REGISTRY_HTTP_TLS_KEY value: "/certs/tls.key" volumeMounts: - name: registry-certs mountPath: "/certs" readOnly: true - name: registry-data mountPath: /var/lib/registry subPath: registry volumes: - name: registry-certs secret: secretName: registry-cert - name: registry-data persistentVolumeClaim: claimName: distribution-pvc ``` Here we configure one pod to create a container from __registry:2__ image using the TLS key and certificate we created earlier. We tell the container that it can find those under the /certs directory. For this we use volume mounts. We define a read-only __volumeMount__ with the name __registry-certs__ to be mounted under /certs in the container. This registry-certs volumeMount references the secret volume registry-cert in the volumes section. We also mount the persistent volume claim distribution-pvc under directory /var/lib/registry in the container. ### Create Distribution Service ```yaml # Service.yaml apiVersion: v1 kind: Service metadata: name: distribution-service namespace: distribution spec: selector: # app.kubernetes.io/name: registry run: registry ports: - name: registry-tcp protocol: TCP port: 5000 targetPort: 5000 ``` ### Deployment ```yaml # kustomizastion.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: distribution-sc resources: - Namespace.yaml - StorageClass.yaml - PersistantVolumeClaim.yaml - RegistryDeployment.yaml - Service.yaml ``` Create above files kustomization.yaml and start the deployment: ```bash $ kubectl create -k . ``` Check deployment status with ```bash $ kubectl -n test get all ``` ### Additional things to do Since we are dealing with a self signed certificate, we need to instruct the host operating system to trust this certificate. Normally you would do that with a Certificate Authority (CA) certificate, but since this is self signed, the certificate is both the certificate for the registry service, as well as its own CA. So let’s load the registry.cert as a new CA on all the cluster nodes. We need to do this because the k3s service on all the cluster nodes will need to be able to pull from this repository, and it must trust this certificate. We can easily do this using Ansible: ```bash ansible -i hosts nodes -b -m copy -a "src=certs/registry.crt dest=/usr/local/share/ca-certificates/registry.crt" ansible -i hosts nodes -b -m shell -a "update-ca-certificates" ``` Final step is do restart the kubernetes-service on all nodes to make them use the self-signed certificates. ## Testing ```bash $ docker pull alpine $ docker tag alpine 10.211.55.250:5000/alpine:latest $ docker push 10.211.55.250:5000/alpine:latest ``` With this, you pull acontainer image from the official docker-hub and push it into our newly generated local distribution registry. Let’s now try to deploy a pod with this new image. Create a file called alpine-test-pod.yaml with the following content: ```yaml alpine-test-deployment.yaml apiVersion: v1 kind: Pod metadata: name: alpine-test # namespace: test spec: containers: - name: alpine image: 192.168.137.250:5000/alpine:latest command: ["sleep", "60s"] restartPolicy: "Never" ``` Deploy it: ```bash $ kubectl create -f alpine-test-deployment.yaml ``` Check the state of the pod: ```bash $ kubectl describe pod alpine-test ```