##Deploy Your Private Docker Registry as a Pod in Kubernetes
Docker Registry is an application that helps you in storing and distributing container images. The most popular container registry is DockerHub, which is the standard public registry for Docker and Kubernetes. But you might face a situation where you will not want your image to be publicly available over the internet. In that case, setting up a Private Docker Registry provides you with multiple storage and authentication options which can be customized as per your requirement.
In this tutorial, we shall look at deploying a TLS-enabled Private Docker Registry as a Pod in a Kubernetes environment. This will help us to push our custom built images to the registry, which later can be pulled by any of the worker nodes and run as containers in Pods. My k8s cluster here consists of 4 Ubuntu 18.04.4 (Bionic Beaver) VMs with 1 master and 3 worker nodes.
root@master1:~# docker -v
Docker version 19.03.12, build 48a66213fe
root@master1:~# kubectl version --short
Client Version: v1.18.5
Server Version: v1.18.5
root@master1:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready master 65d v1.18.5
worker1 Ready 65d v1.18.5
worker2 Ready 65d v1.18.5
worker3 Ready 65d v1.18.5
root@master1:~#
Step 1: Creating files for authentication
Let us start by creating self-signed certificates and user authentication to boost the security for our private Docker registry. The TLS certificates are created using openssl where we need to specify the name, with which we want to access our registry, in the Common Name “/CN=” field. Here, I wish to access my registry using the name docker-registry.
root@master1:~# mkdir -p /registry && cd "$_"
root@master1:/registry# mkdir certs
root@master1:/registry# openssl req -x509 -newkey rsa:4096 -days 365 -nodes -sha256 -keyout certs/tls.key -out certs/tls.crt -subj "/CN=docker-registry" -addext "subjectAltName = DNS:docker-registry"
Generating a RSA private key
...........................................................................................................................................++++
.............................................................++++
root@master1:/registry#
Let’s use htpasswd to add user authentication for registry access. My credentials for the private registry would be myuser/mypasswd.
root@master1:/registry# mkdir auth
root@master1:/registry# docker run --rm --entrypoint htpasswd registry:2.6.2 -Bbn myuser mypasswd > auth/htpasswd
Unable to find image 'registry:2.6.2' locally
2.6.2: Pulling from library/registry
486039affc: Pulling fs layer
ba51a3b098: Pulling fs layer
470e22cd43: Pulling fs layer
1048a0cdab: Pulling fs layer
ca5aa9d063: Pulling fs layer
1048a0cdab: Waiting
ca5aa9d063: Waiting
ba51a3b098: Verifying Checksum
ba51a3b098: Download complete
486039affc: Verifying Checksum
486039affc: Pull complete
470e22cd43: Verifying Checksum
470e22cd43: Download complete
ba51a3b098: Pull complete
1048a0cdab: Verifying Checksum
1048a0cdab: Download complete
ca5aa9d063: Verifying Checksum
ca5aa9d063: Download complete
470e22cd43: Pull complete
1048a0cdab: Pull complete
ca5aa9d063: Pull complete
Digest: sha256:c4bdca23bab136d5b9ce7c06895ba54892ae6db0ebfc3a2f1ac413a470b17e47
Status: Downloaded newer image for registry:2.6.2
root@master1:/registry#
At this point, our /registry directory looks like this:
root@master1:/# ls -R /registry/
/registry/:
auth certs
/registry/auth:
htpasswd
/registry/certs:
tls.crt tls.key
root@master1:/#
Step 2: Using Secrets to mount the certificates
In Kubernetes, a Secret is a resource that will enable you to inject sensitive data into a container when it starts up. This data can be anything like password, OAuth tokens or ssh keys. They can be exposed inside a container as mounted files or volumes or environment variables.
The below command creates a Secret of type tls named certs-secret in the default namespace from the pair of public/private keys we just created.
root@master1:/# kubectl create secret tls certs-secret --cert=/registry/certs/tls.crt --key=/registry/certs/tls.key
secret/certs-secret created
root@master1:/#
The Secret auth-secret that we create from the htpasswd file is of type generic which means the Secret was created from a local file.
root@master1:/# kubectl create secret generic auth-secret --from-file=/registry/auth/htpasswd
secret/auth-secret created
root@master1:/#
Step 3: Creating Persistent Volume and Claim for repository storage
The images that are pushed to our registry should be placed in a consistent storage location. Hence, we will be using a Persistent Volume of 1 GB hosted at a temporary location in the node where our registry Pod will be running. The Pod uses a Persistent Volume Claim which will be bound to the newly created volume as a one-to-one mapping.
apiVersion: v1
kind: PersistentVolume
metadata:
name: docker-repo-pv
spec:
capacity:
storage: 1Gi
accessModes:
NOTA: en containerd el directorio es
/etc/containers/certs.d/$REGISTRY_NAME/
Por lo que lo mejor es:
1) crear el directorio /etc/containers 2) establecer un enlace simbólico a /etc/dockers/certs.d con
sudo mkdir /etc/containers cd /etc/containers sudo ln -s /etc/docker/certs.d certs.d
y luego
sudo systemctl restart containerd
The above step forces Docker to verify our self-signed certificate even though it is not signed by a known authority.
Step 6: Testing our Private Docker Registry
Now, let us try to login to the registry from the master node, using the same credentials we created earlier:
root@master1:/# docker login docker-registry:5000 -u myuser -p mypasswd
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
root@master1:/#
Hurray! This worked!!
Before we start using our registry, let us create a Secret of type docker-registry which uses the credentials myuser/mypasswd for enabling all the nodes in our cluster to authenticate with our private Docker registry.
root@master1:/# kubectl create secret docker-registry reg-cred-secret --docker-server=$REGISTRY_NAME:5000 --docker-username=myuser --docker-password=mypasswd
secret/reg-cred-secret created
root@master1:/#
Let us try to push a custom image to our private Docker registry.
root@master1:/# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
bf59529304: Pull complete
cb9a6de05e: Pull complete
9513ea0afb: Pull complete
b49ea07d2e: Pull complete
a5e4a503d4: Pull complete
Digest: sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
root@master1:/#
root@master1:/# docker tag nginx:latest docker-registry:5000/mynginx:v1
root@master1:/#
root@master1:/# docker push docker-registry:5000/mynginx:v1
The push refers to repository [docker-registry:5000/mynginx]
550333325e: Layer already exists
22ea89b1a8: Layer already exists
a4d893caa5: Layer already exists
0338db614b: Layer already exists
d0f104dc0a: Layer already exists
v1: digest: sha256:179412c42fe3336e7cdc253ad4a2e03d32f50e3037a860cf5edbeb1aaddb915c size: 1362
root@master1:/#
We can actually verify that our custom image mynginx:v1 was indeed saved into our registry.
root@master1:/# kubectl exec docker-registry-pod -it -- sh
/ # ls /var/lib/registry/docker/registry/v2/repositories/
mynginx
/ #
Finally, let us create a new Pod that uses the image mynginx:v1 that we just pushed to our registry.
root@master1:/# kubectl run nginx-pod --image=docker-registry:5000/mynginx:v1 --overrides='{ "apiVersion": "v1", "spec": { "imagePullSecrets": [{"name": "reg-cred-secret"}] } }'
pod/nginx-pod created
root@master1:/#
root@master1:/# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
docker-registry-pod 1/1 Running 0 46m 10.38.0.1 worker2
nginx-pod 1/1 Running 0 38s 10.38.0.2 worker2
root@master1:/#
root@master1:/# curl 10.38.0.2:80
<!DOCTYPE html>
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
root@master1:/# Congratulations on making it this far!! We just created a Private Docker Registry running as a Pod where our images will be stored in a Persistent Volume and can be pulled by any of the worker nodes to run your application. Happy learning!!