Portainer
Tip
Some time after originally publishing this recipe, I had the opportunity to meet the Portainer team, who are based out of Auckland, New Zealand. We now have an ongoing friendly working relationship. For a time, Portainer was my GitHub Sponsor , and in return, I maintained their official Kubernetes helm charts!
Portainer is a lightweight sexy UI for visualizing your docker environment. It also happens to integrate well with Docker Swarm clusters, which makes it a great fit for our stack.
Portainer attempts to take the "geekiness" out of containers, by wrapping all the jargon and complexity in a shiny UI and some simple abstractions. It's a great addition to any stack, especially if you're just starting your containerization journey!
I am all of the Sith!
In 2021, Portainer released "Dark Mode". Here's why I think this is 100% my fault :)
Portainer Requirements
Ingredients
Already deployed:
- Docker swarm cluster with persistent shared storage
- Traefik configured per design
- DNS entry for the hostname you intend to use (or a wildcard), pointed to your keepalived IP
Related:
- Traefik Forward Auth or Authelia to secure your Traefik-exposed services with an additional layer of authentication
Preparation
Setup data locations
Create a folder to store portainer's persistent data:
mkdir /var/data/portainer
Portainer Docker Swarm config
Create a docker swarm config file in docker-compose syntax (v3), something like the example below:
Fast-track with premix! 🚀
"Premix" is a git repository which includes necessary docker-compose and env files for all published recipes. This means that you can launch any recipe with just a git pull
and a docker stack deploy
👍.
🚀 Update: Premix now includes an ansible playbook, enabling you to deploy an entire stack + recipes, with a single ansible command! (more here)
version: '3.2'
services:
portainer:
image: portainer/portainer-ce
command: -H tcp://tasks.agent:9001 --tlsskipverify
ports:
- "9000:9000"
- "8000:8000"
volumes:
- /var/data/portainer:/data
networks:
- internal
- traefik_public
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.role == manager]
labels:
# traefik
- traefik.enable=true
- traefik.docker.network=traefik_public
# traefikv1
- traefik.frontend.rule=Host:portainer.example.com
- traefik.port=9000
# uncomment if you want to protect portainer with traefik-forward-auth using traefikv1
# - traefik.frontend.auth.forward.address=http://traefik-forward-auth:4181
# - traefik.frontend.auth.forward.authResponseHeaders=X-Forwarded-User
# - traefik.frontend.auth.forward.trustForwardHeader=true
# traefikv2
- "traefik.http.routers.portainer.rule=Host(`portainer.example.com`)"
- "traefik.http.routers.portainer.entrypoints=https"
- "traefik.http.services.portainer.loadbalancer.server.port=9000"
# uncomment if you want to protect portainer with traefik-forward-auth using traefikv2
# - "traefik.http.routers.portainer.middlewares=forward-auth"
agent:
image: portainer/agent
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
networks:
- internal
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
networks:
traefik_public:
external: true
internal:
driver: overlay
ipam:
config:
- subnet: 172.16.13.0/24
Note
Setup unique static subnets for every stack you deploy. This avoids IP/gateway conflicts which can otherwise occur when you're creating/removing stacks a lot. See my list here.
Umm.. didn't you just copy these from the official Portainer docs?
Almost word-for-word! I've made a few (opinionated) improvements though:
- Expose Portainer via Traefik with valid LetsEncrypt SSL certs
- Optionally protected Portainer's web UI with OIDC auth via Traefik Forward Auth
- Use filesystem paths instead of Docker volumes for maximum "swarminess" (We want an HA swarm, and HA Docker Volumes are a PITA, so we just use our ceph shared storage)
Serving
Launch Portainer stack
Launch the Portainer stack by running docker stack deploy portainer -c <path -to-docker-compose.yml>
Log into your new instance at https://YOUR-FQDN. You'll be prompted to set your admin user/password on first login. Start at "Home", and click on "Primary" to manage your swarm (you can manage multiple swarms via one Portainer instance using the agent):
Chef's notes 📓
-
There are some schenanigans you can do to install LinuxServer.io templates in Portainer. Don't go crying to them for support though! ↩
Tip your waiter (sponsor) 👏
Did you receive excellent service? Want to compliment the chef? (..and support development of current and future recipes!) Sponsor me on Github / Ko-Fi / Patreon, or see the contribute page for more (free or paid) ways to say thank you! 👏
Employ your chef (engage) 🤝
Is this too much of a geeky PITA? Do you just want results, stat? I do this for a living - I'm a full-time Kubernetes contractor, providing consulting and engineering expertise to businesses needing short-term, short-notice support in the cloud-native space, including AWS/Azure/GKE, Kubernetes, CI/CD and automation.
Learn more about working with me here.
Flirt with waiter (subscribe) 💌
Want to know now when this recipe gets updated, or when future recipes are added? Subscribe to the RSS feed, or leave your email address below, and we'll keep you updated.