Important Docker Swarm Services That Everyone Need To Have

Photo by frank mckenna / Unsplash

4 Important Services Everyone Should Deploy In A Docker Swarm

Enhance your Docker Swarm with four important services that you will love: Traefik, Portainer, Registry, FTP

Paul Knulst  in  Docker Dec 1, 2021 6 min read

In my last article, I showed how a Docker Swarm is set up in ~15 minutes. Remember: Whenever you read “Docker Swarm” we are talking about “Docker Swarm mode”

Within this article, I will show and explain four services everyone should use in their Docker Swarm: traefik, Portainer, Docker-Registry, FTP.

Traefik

Makes Networking Boring
Cloud-Native Networking Stack That Just Works.

One important service in any Docker Swarm is traefik. I use this for assigning domains/subdomains to every docker service. A simple docker-compose.yml can be found on my FTP here. To use this file it is necessary to update the labels for your docker swarm by executing:

export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')
docker node update --label-add traefik-public.traefik-public-certificates=true $NODE_ID

These two commands assume that you want to have traefik on your manager node! To understand what a manager node have a look at the docker documentation.

Another VERY important step is creating a file named acme.json within the folder where the docker-compose will be stored and do:

chmod 600 acme.json

Furthermore, you have to define a TRAEFIK_USERNAME, TRAEFIK_HASHED_PASSWORD, TRAEFIK_DOMAIN and TRAEFIK_SSLEMAIL:

export TRAEFIK_USERNAME=admin
export TRAEFIK_HASHED_PASSWORD=$(openssl passwd -apr1 testpassword)
export TRAEFIK_DOMAIN=dashboard.YOUR_DOMAIN.tld
export TRAEFIK_SSLEMAIL=your_email@address.de

The last command which has to be executed before you can deploy the service is creating the traefik-public network which will be used across all containers:

docker network create --driver=overlay traefik-public

After this is done it is possible to deploy traefik to your docker swarm:

docker stack deploy -c docker-compose.traefik.yml

Just test it by launching https://dashboard.YOUR_DOMAIN.tld. This domain will use an SSL certificate and you can log in with admin/testpassword if you followed the above instructions.

Portainer

Portainer is a powerful, GUI-based Container-as-a-Service solution that helps organizations manage and deploy cloud-native applications easily and securely.

My docker-compose.yml for Portainer is not special. You can find it here if you need it. Normally there are no differences between my and the one you find if you google for Portainer service.

If you use mine you have to add a label to your manager! This is very important because Portainer needs a connection to your docker socket. You can add the label with these commands:

export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')
docker node update --label-add portainer.portainer-data=true $NODE_ID

Furthermore declare the PORTAINER_DOMAIN which will be used.

export PORTAINER_DOMAIN=portainer.$PRIMARY_DOMAIN

After you have done this you can deploy Portainer:

docker stack deploy -c docker-compose.portainer.yml portainer

Timing Note: Make sure you log in and create your credentials soon after Portainer is ready, or it will automatically shut down itself for security. If you didn’t create the credentials on time and it shut down itself automatically, you can force it to restart with:

docker service update portainer_portainer --force

Docker Registry

The Registry is a stateless, highly scalable server side application that stores and lets you distribute Docker images. The Registry is open-source, under the permissive Apache license.

The docker registry is important to have in a swarm environment if you don't want to upload your code/data to a public registry. If you don't have any private registry for yourself you have to upload the resulting image to docker-hub each time you extend an official image with your application code. While this is great if you only want to extend functionality in a general way it is not advisable if you copy your website with your closed source code into the image.

Imagine you have a modified Nginx image where the HTML folder is copied into the image:

FROM nginx
COPY html /usr/share/nginx/html

In many cases the html folder will contain your website which you don't want someone to use. If you have a private registry you can build the image and upload it but if you don't have one you have to use a public registry.

That's why I think that every swarm needs to have access to a private registry. And that's why I created one. Normally you can set up a registry with a simple docker run command but I wanted to have a registry that can be reached from everywhere. Because of that, I created a registry that could be accessed by username and password.

My personal docker-compose.yml can be downloaded here. It will run within my Traefik environment and create a new registry that I can use from every node in my swarm. To deploy the service you have to declare some environment variables which are used while deploying: REGISTRY_USERNAME, REGISTRY_HASHED_PASSWORD and REGISTRY_HOST:

export REGISTRY_USERNAME=reg_adm
export REGISTRY_HASHED_PASSWORD=$(openssl passwd -apr1 regsupersecret)
export REGISTRY_HOST=reg.YOUR_DOMAIN.tld

With these variables you can deploy the service:

docker stack deploy -c docker-compose.registry.yml registry

To use the registry you have to do two more things. The first thing is a quality of life feature to easily change the domain of the registry without affecting every container which uses an image from the private registry. Add DOCKER_REGISTRY to .profile for root or whatever user you are using so it is known if docker-compose files should be pushed/downloaded. The second task is very important. You have to execute docker login on every node of your swarm so that every node is allowed to pull images.

Now you can start using your private registry in docker-compose.yml. If you created a DOCKER_REGISTRY environment variable you can use it like this in your docker-compose.yml:

myapp:
    image: ${DOCKER_REGISTRY}/simple-app
    build:
      context: ./
      dockerfile: Dockerfile

If you want to deploy a service that contains the above part you have to build and push your image to deploy it correctly:

docker-compose build
docker-compose push
docker stack deploy -c docker-compose.yml www

If you only build and deploy it other nodes in your swarm cannot pull the image and so the service cannot be deployed.

FTP

Another important service is an FTP server for saving files you want to use anywhere in any app or service you create while working with the swarm.

I decided to use “pure-ftp” because it was the one I found while googling for a nice FTP server that runs within a docker environment. Because I want to keep it simple I created an FTP server without any traefik configuration. BUT I did a simple trick in putting the FTP server together with a website in a docker-compose.yml. I have done this because I want to have the possibility to download files from the server over https which I uploaded with ftp.

After configuration, I came up with this docker-compose.yml. Within the file, you can see that I use a custom Dockerfile for the web service which contains:

FROM nginx
COPY html /usr/share/nginx/html

The trick I describe is just the defined volume within the docker-compose.yml. As you can see I defined data in both services. Within web-service I just have an extra folder within the Nginx HTML folder so that I can access it from the web. And within the ftp-service I define data as the place where user can upload their data.

Before it is possible to deploy this service you have to declare environment variables: FTP_USERNAME, FTP_PASSWORD, FTP_DOMAIN_FOR_CERT, FTP_ORG_FOR_CERT, FTP_COUNTRYCODE_FOR_CERT and WEBSERVICE_DOMAIN:

export WEBSERVICE_DOMAIN=www.MYDOMAIN.tld
export FTP_USERNAME=SUPERUSER
export FTP_PASSWORD=clearTextPW
export FTP_DOMAIN_FOR_CERT=$WEBSERVICE_DOMAIN
export FTP_ORG_FOR_CERT=mybusiness
export FTP_COUNTRYCODE_FOR_CERT=DE

Furthermore, you have to add a label to any node of your swarm. To achieve this use docker node ls to find out the ID from every node and execute:

docker node update --label-add www.ftp-data=true ID_OF_NODE_TO_USE

After this is done you can safely deploy your website with enabled FTP

docker stack deploy -c docker-compose.web.yml webandftp

Now it is possible to connect with an FTP client to your WEBSERVICE_DOMAIN and upload a file (test.txt) which then can be accessed by this URL: WEBSERVICE_DOMAIN/data/test.txt

The whole FTP docker service can be downloaded from my GitHub:

GitHub - paulscode-de/ftp-server: ftp server (pureftp) integrated in traefik with website where you can access files from ftp
ftp server (pureftp) integrated in traefik with website where you can access files from ftp - GitHub - paulscode-de/ftp-server: ftp server (pureftp) integrated in traefik with website where you can...

It is very important to say that you only can connect with your WEBSERVICE_DOMAIN if this domain also has an A record to your manager node!

5. Closing Notes

I hope you find this article helpful and can use my provided files to set up these services within your own Docker Swarm.

In my humble opinion, these four services should be present in every Docker Swarm environment because they are mandatory (or exchanged with function-like services).

Feel free to connect with me on Medium, LinkedIn, and Twitter.


🙌 Support this content

If you like this content, please consider supporting me. You can share it on social media, buy me a coffee, or become a paid member. Any support helps.

See the contribute page for all (free or paid) ways to say thank you!

Thanks! 🥰

By Paul Knulst

I'm a husband, dad, lifelong learner, tech lover, and Senior Engineer working as a Tech Lead. I write about projects and challenges in IT.