🤖
Musings
  • Welcome
  • Azure DevOps
  • Pull Request bots with Azure DevOps
  • Responding to new threats with BeyondTrust Endpoint Privilege Management
  • Docker/Container stuff
    • Using and managing docker with portainer
  • Random
    • Using Qwen-2.5-coder:14b locally
      • Latest stable release of Tokio crate for Rust as of October 2023 is version 1.35
      • Nushell Script for Interacting with Open Source Docker Registry
Powered by GitBook
On this page
  • Why do I want to use this?
  • Pre requisites
  • Installing docker-ce
  • Creating a swarm and starting portainer
  • Certificates
  • Portainer service
  • Adding a worker node to the docker swarm
  • Deploying a service on to my new setup

Was this helpful?

  1. Docker/Container stuff

Using and managing docker with portainer

Taking the pain out of command line docker

PreviousResponding to new threats with BeyondTrust Endpoint Privilege ManagementNextUsing Qwen-2.5-coder:14b locally

Last updated 4 years ago

Was this helpful?

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 , and the 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 .

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"

If you do not have a certificate you can use, or you are happy for traefik to service requests with a self generated TLS certificate, then you can modify the portainer-agent-stack.yml example below to remove the lines referencing "-- providers.file"

Given browsers are becoming ever more stringent on the validity of TLS certificates, I would recommend looking in to cheaply buying a domain you can use to create certificates from via letsencrypt.

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.

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"

Remember to replace "your.domain" in the file with the domain name you will be using

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

To be continued ... I'll post an update in to the lunch & learn chat on teams when I have finished writing up this section

The contents of the file below are slightly modified from the information provided on the

debian bug report
author-rejected attempt to fix
docker documentation
portainer documentation