Using and managing docker with portainer
Taking the pain out of command line docker
Why do I want to use this?
If you're inexperienced with managing *nix systems, or like me you use docker so infrequently that you find yourself having to constantly reach for the documentation, portainer can really help to keep you productive by providing a more intuitive UI than wading through pages of terminal command outputs.
Pre requisites
This guide will show how to create a docker swarm environment with two linux hosts, for this guide I will be using two Debian 10 virtual machines.
The purpose of showing how to use docker swarm is to provide an understanding of how you can centrally manage multiple low-resource docker hosts (such as Raspberry Pis for example) allowing you to quickly scale your infrastructure outwards should you eventually be running so many containers that you've outgrown your single host.
Installing docker-ce
One thing to note about using docker on Debian 10 is that at the time of writing, the default docker package (docker.io), whilst supporting docker swarm mode, has a bug due to an included package dependency which is not re-entrant. This means that the docker host service itself can crash. For more info see the debian bug report, and the author-rejected attempt to fix the bug on the dependency.
To get a stable docker swarm, I would recommend installing docker-ce instead. Instructions for how to do this can be found on the docker documentation.
Creating a swarm and starting portainer
Certificates
For my example I am using a wildcard certificate for my domain thecko.co.uk, this certificate will be used by traefik as the default TLS certificate to be used. A further blog post will come at a later date showing how to to configure the traefik service for portainer to use letsencrypt to dynamically retrieve and manage certificate for exposed service.
In my example I have create a folder called certificates, in which I have my .crt and .key files for my domain named cert.crt and cert.key respectively.
This folder also contains a file certificates.toml which specifies the certificate should be used as the default. The contents are as follows
[tls.stores]
[tls.stores.default]
[tls.stores.default.defaultCertificate]
certFile = "/certificates/cert.crt"
keyFile = "/certificates/cert.key"
Portainer service
In the same folder which contains your certificates folder, create a file called portainer-agent-stack.yml and copy and paste the following.
The contents of the file below are slightly modified from the information provided on the portainer documentation
This example is predicated on having a wildcard A record on your domain which points to the same address of the your main docker host.
version: '3.2'
networks:
public:
external: true
agent_network:
external: true
volumes:
portainer_data:
services:
traefik:
image: "traefik:latest"
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
- --providers.docker.swarmMode=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=public
- --providers.file.directory=/certificates/
- --providers.file.watch=true
- --api
- --log.level=DEBUG
ports:
- "80:80"
- "443:443"
networks:
- public
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./certificates:/certificates"
agent:
image: portainer/agent
environment:
# REQUIRED: Should be equal to the service name prefixed by "tasks." when
# deployed inside an overlay network
AGENT_CLUSTER_ADDR: tasks.agent
# AGENT_PORT: 9001
LOG_LEVEL: debug
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- agent_network
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
portainer:
image: portainer/portainer-ce
command: -H tcp://tasks.agent:9001 --tlsskipverify
volumes:
- portainer_data:/data
networks:
- public
- agent_network
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
labels:
- "traefik.enable=true"
- "traefik.http.routers.portainer.rule=Host(`portainer.your.domain`)"
- "traefik.http.routers.portainer.entrypoints=websecure"
- "traefik.http.routers.portainer.tls.certResolver=thecko"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
- "traefik.http.routers.portainer.service=portainer"
# Edge
- "traefik.http.routers.edge.rule=Host(`edge.your.domain`)"
- "traefik.http.routers.edge.entrypoints=websecure"
- "traefik.http.services.edge.loadbalancer.server.port=8000"
- "traefik.http.routers.edge.service=edge"
Starting the portainer service
Due to this configuration being setup to use docker swarm mode, you will need to first execute some commands to setup the docker environment. The shell script below will do this work for you. Copy the contents in to a file name of your choosing. For my example, I simply called it startportainer.sh
#!/usr/bin/bash
# This command checks to see if this host is already in a docker swarm
# If it is not, we can create the swarm appropriately
swarm_status=$(docker info 2>/dev/null | grep Swarm | awk '{print $NF}')
if [[ "${swarm_status}" == "inactive" ]]; then
echo "Initializing a swarm"
# ugly but functional way of finding the main IP address on the host, not all
# linux distributions uniformly name the first ethernet interface as
# eth0 anymore :(
address=$(ip route get 1.1.1.1 | grep -oP 'src \K\S+')
echo "Will advertise on address ${address}"
docker swarm init --advertise-addr ${address}
fi
if ! $(docker network inspect agent_network >/dev/null); then
echo "Creating agent_network network"
docker network create -d overlay agent_network
fi
if ! $(docker network inspect public >/dev/null); then
echo "Creating public network"
docker network create -d overlay public
fi
if ! $(docker volume inspect portainer_data >/dev/null); then
echo "Creating portainer_data volume"
docker volume create portainer_data
fi
docker stack deploy --compose-file=portainer-agent-stack.yml portainer
When executing the shell script, you will be given information as to how to join a new worker node to the swarm. Do not worry if you accidentally close the terminal and lose that information, you can always find it again by running the command
docker swarm join-token worker
First login to portainer
Once you have started the initial service, navigate to the host you specified in the portainer-agent-stack.yml for the portainer service. In my case, it's https://portainer.thecko.co.uk
You will need to set up the name and password for your initial administrator user.

Once you have logged in you will see a list of endpoints.

We will only using the primary endpoint here, click on the endpoint and you will be shown an overview of the stacks, services, containers, volumes, and networks which now exist on your docker host.
To start with, click the link near the top of this page titled "Go to cluster visualizer"

This will now show you that you have one node in your docker swarm cluster. It should be running three services, agent, portainer, and traefik.
Adding a worker node to the docker swarm
Now the first docker host is setup we can add our extra worker node to the swarm. As mentioned previously, if you didn't keep a note of the command you were given to join a worker node to the swarm during the initial setup, you can run the following command on your first docker host to retrieve it
docker swarm join-token worker
Run the "docker swarm join" command on your second host.
Once you have done this, go back to your web browser with the cluster visualization page still open, and you should see that you now have 2 nodes in your swarm cluster.
Deploying a service on to my new setup
Last updated
Was this helpful?