If your docker swarm deployment uses images from publicly accessible image registries such as docker hub, you will not need this. But, what if your cluster uses customized build? You can of course build the custom image on each node so that all of them uses the same custom copy of the image. You can also create a private repository on Docker Hub. Or, as this article will guide you, establish a private local registry

So, creating a local registry is as easy as running

sudo docker run -d -p 8008:8008 --name registry registry:2

You should now have a working local image registry. Of course this would not work for our usecase. What we need is a local image registry, secured with TLS and user credential.

Prereqs

We will need a proper Fully Qualified Domain Name (FQDN) and a working SSL certificate to go along with it. Either get one from reputable CA, or follow this bit on getting it with Let’s Encrypt. We will also need to make sure that all of the nodes on the cluster can resolve the registry server’s domain name, either with proper DNS server configuration, or adding the record on the host file.  For the purpose of this article, let say the FQDN that I’ll be using is regs.mach5.web.id

We will also need to pick a port that is currently not in use to serve as the gateway into the registry. For the purpose of this article, I’ll be using 8443

In this post, we will be using the most basic authentication method that is supported by Docker registry, which is htpasswd. Prepare a directory to store the file, let say:

sudo mkdir /data/docker/auth/

To create a pair of user and password, do:

sudo docker run --entrypoint htpasswd registry:2 -Bbn awn1 securePassawn1 >> /data/docker/auth/htpasswd

The next step is to prepare a directory to store docker permanent storage on the host, for example:

sudo mkdir /data/docker/registry/

Now, let’s deploy our Registry container.

Establish Registry Container

To deploy the container, do

sudo docker run -d --restart=always --name registry -v /data/docker/auth:/auth  -v /data/docker/registry:/var/lib/registry -v /data/docker/certs:/certs -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -e REGISTRY_HTTP_ADDR=0.0.0.0:8443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/cert.pem -e REGISTRY_HTTP_TLS_KEY=/certs/privkey.pem -p 8443:8443 registry:2

We should now have a running local docker image registry and we can access it from the following URL:

https://regs.mach5.web.id:8443/v2/

Now, let see what we can do with it

Building Docker custom image and populating the registry

Let say that I need a custom php-apache container that has all the necessary modules required for Laravel deployment. Since no image on docker hub can cater this requirement, I need to build a customized image. This is how my Dockerfile looks like:

FROM php:7.3-apache
MAINTAINER ikhsan demonspeedster at gmail.com
RUN apt-get update && apt-get install -y --fix-missing \
    git \
    openssl \
    apt-utils \
    zlib1g-dev \
    libzip-dev \
    libbz2-dev \
    libxml2 \
    libxml2-dev \
    bzip2 \
    libpng-dev \
    gnupg

RUN apt-get update -y && apt-get install -y libmcrypt-dev openssl
RUN docker-php-ext-install ctype xml json bcmath tokenizer mysqli bz2 pdo pdo_mysql gd mbstring zip && docker-php-ext-enable ctype xml json bc
math tokenizer bz2 mysqli pdo pdo_mysql gd mbstring zip
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
RUN cp /etc/apache2/mods-available/authz_groupfile.load /etc/apache2/mods-enabled/
RUN cp /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/

Building the custom image based on the Dockerfile above can be done by running the command below on the directory where the Dockerfile is located:

surfer@AWN1:/data/docker/scripts/builds$ sudo docker build -t my-laravel .
[sudo] password for surfer: 
Sending build context to Docker daemon  6.144kB
Step 1/11 : FROM php:7.3-apache
 ---> dfe3bb4436a9
Step 2/11 : MAINTAINER surfer whoareyou at gmail.com
 ---> Using cache
 ---> add2787dffad
Step 3/11 : RUN apt-get update && apt-get install -y --fix-missing     git     openssl     apt-utils     zlib1g-dev     libzip-dev     libbz2-dev     libxml2     libxml2-dev     bzip2     libpng-dev     gnupg
 ---> Using cache
 ---> 246c98c954ff
Step 4/11 : RUN apt-get update -y && apt-get install -y libmcrypt-dev openssl
 ---> Using cache
 ---> f260c7091943
Step 5/11 : RUN docker-php-ext-install ctype xml json bcmath tokenizer mysqli bz2 pdo pdo_mysql gd mbstring zip && docker-php-ext-enable ctype xml json bcmath tokenizer bz2 mysqli pdo pdo_mysql gd mbstring zip
 ---> Using cache
 ---> de999c0e1358
Step 6/11 : RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
 ---> Using cache
 ---> 87dd79d4cbf7
Step 7/11 : RUN cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/
 ---> Using cache
 ---> 22012168ea6d
Step 8/11 : RUN cp /etc/apache2/mods-available/authz_groupfile.load /etc/apache2/mods-enabled/
 ---> Using cache
 ---> f210b628fea9
Step 9/11 : RUN cp /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/
 ---> Using cache
 ---> 2974a8a41445
Successfully built 2974a8a41445
Successfully tagged my-laravel:latest

We now have the perfect docker image for our project. The problem is, there let say 2 other swarm nodes that need access to this image so we can deploy the containers across all nodes in the swarm

Tagging and pushing image to Registry

To push our recently created custom image to our recently created local registry, first we need to log into the local registry using the user and password that we have created before by doing:

surfer@AWN1:~$ sudo docker login regs.mach5.web.id:8443
Username: awn1
Password: 
WARNING! Your password will be stored unencrypted in /home/surfer/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Once we are logged it, tag the image by doing

sudo docker tag my-laravel regs.mach5.web.id:8443/webapp

And push it to the local registry with:

surfer@AWN1:/data/docker/scripts/builds$ sudo docker push regs.mach5.web.id:8443/webapp
The push refers to repository [regs.mach5.web.id:8443/webapp]
97300f38cc34: Mounted from app 
2b80b9056019: Mounted from app 
aea8add70e90: Mounted from app 
97c5752e4057: Mounted from app 
046465b1360f: Mounted from app 
75e7ef1cd667: Mounted from app 
d4071c655272: Mounted from app 
679f9d7ab128: Mounted from app 
9349e9686881: Mounted from app 
18c63cd06302: Mounted from app 
98eebde476f8: Mounted from app 
9f56628995bb: Mounted from app 
de06f6a1de3c: Mounted from app 
7dcc21fa0198: Mounted from app 
91921db962d2: Mounted from app 
387f6270e938: Mounted from app 
448f57bab35d: Mounted from app 
66d3e4af6e09: Mounted from app 
389b7b5f40f8: Mounted from app 
4b017cb89a0f: Mounted from app 
9512a01c3d20: Mounted from app 
a619f62b61d0: Mounted from app 
1c95c77433e8: Mounted from app 
latest: digest: sha256:5d288c145f068b7769df34b5ba1feac8455bc4fbdef6d55932caaefc8593e13f size: 5120

Congrats, we just populated our local registry with our first custom image.

Alternatively, let say you want to make a generic traefik image available from your local registry, you can pull the image from Docker-hub:

surfer@AWN1:~$ sudo docker pull php:apache
apache: Pulling from library/php
Digest: sha256:1961e48f78c27f76ddcff0956155dd62419cc4e74cd03f3a812589c4e9b423a9
Status: Downloaded newer image for php:apache

tag the image

sudo docker tag php:apache regs.mach5.web.id:8443/webapp

And push it to the registry

surfer@AWN1:~$ sudo docker push regs.mach5.web.id:8443/webapp
The push refers to repository [regs.mach5.web.id:8443/webapp]
29075c48c151: Pushed 
afb5b0d685c2: Pushed 
88b92e4e5fea: Pushed 
latest: digest: sha256:99a4e99e0b5f9be2fc9a5be5b83fab4a732a7892b35371504aa55bf2f036beaa size: 949
Getting custom image from local registry

Just like when pushing an image to the local registry, to get an image off from the local registry, we need to log into the server by doing

surfer@AWN1:~$ sudo docker login regs.mach5.web.id:8443

After we have successfully log into the server, we can either pull the image just like this

surfer@AWN1:~$ sudo docker pull regs.mach5.web.id:8443/webapp
Using default tag: latest
latest: Pulling from traefik
Digest: sha256:99a4e99e0b5f9be2fc9a5be5b83fab4a732a7892b35371504aa55bf2f036beaa
Status: Downloaded newer image for regs.mach5.web.id:8443/webapp:latest

Or, to use it in service on a docker swarm:

sudo docker service create --with-registry-auth --name webaps regs.mach5.web.id:8443/webapp

The –with-registry-auth informs the master node  to forward the credential used to log into the local private registry to all the nodes in the swarm so each of them can independently pull the image from the local registry.

By ikhsan

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.