diff --git a/_snippets/recipe-standard-ingredients.md b/_snippets/recipe-standard-ingredients.md new file mode 100644 index 0000000..b9712d9 --- /dev/null +++ b/_snippets/recipe-standard-ingredients.md @@ -0,0 +1,12 @@ +## Ingredients + +!!! summary "Ingredients" + Already deployed: + + * [X] [Docker swarm cluster](/ha-docker-swarm/design/) with [persistent shared storage](/ha-docker-swarm/shared-storage-ceph.md) + * [X] [Traefik](/ha-docker-swarm/traefik) configured per design + * [X] DNS entry for the hostname you intend to use (*or a wildcard*), pointed to your [keepalived](/ha-docker-swarm/keepalived/) IP + + Related: + + * [X] [Traefik Forward Auth](ha-docker-swarm/traefik-forward-auth/) to secure your Traefik-exposed services with an additional layer of authentication \ No newline at end of file diff --git a/_snippets/reference-networks.md b/_snippets/reference-networks.md new file mode 100644 index 0000000..04304be --- /dev/null +++ b/_snippets/reference-networks.md @@ -0,0 +1,2 @@ +!!! 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](/reference/networks/) here. \ No newline at end of file diff --git a/manuscript/CHANGELOG.md b/manuscript/CHANGELOG.md index 49e05a5..7d0a69d 100644 --- a/manuscript/CHANGELOG.md +++ b/manuscript/CHANGELOG.md @@ -18,6 +18,7 @@ Recipe | Description Recipe | Description | Date ---------------------------------------------------------------|---------------------------------------|-------------- +[Portainer](/recipes/portainer/) | Bump to version 2, bringing "expert simplicity" to your Docker stack management | _25 Jan 2021_ [Traefik Forward Auth](/ha-docker-swarm/traefik-forward-auth/) | Now uses for latest @thomseddon image | _11 Jun 2020_ diff --git a/manuscript/images/portainer-home.png b/manuscript/images/portainer-home.png new file mode 100644 index 0000000..22d4f40 Binary files /dev/null and b/manuscript/images/portainer-home.png differ diff --git a/manuscript/images/portainer.png b/manuscript/images/portainer.png index 33481dc..7d19278 100644 Binary files a/manuscript/images/portainer.png and b/manuscript/images/portainer.png differ diff --git a/manuscript/recipes/portainer.md b/manuscript/recipes/portainer.md index 6593ae2..56b1759 100644 --- a/manuscript/recipes/portainer.md +++ b/manuscript/recipes/portainer.md @@ -2,15 +2,16 @@ hero: A recipe for a sexy view of your Docker Swarm # Portainer -[Portainer](https://portainer.io/) 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. +!!! tip + Some time after originally publishing this recipe, I had the opportunity to meet the [Portainer team](https://www.reseller.co.nz/article/682233/kiwi-startup-portainer-io-closes-1-2m-seed-round/), who are based out of Auckland, New Zealand. We now have an ongoing friendly working relationship. Portainer is my [GitHub Sponsor][github_sponsor] :heart:, and in return, I maintain their [official Kubernetes helm charts](https://github.com/portainer/k8s)! :thumbsup: + +[Portainer](https://portainer.io/) 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! ![Portainer Screenshot](../images/portainer.png) -## Ingredients - -1. [Docker swarm cluster](/ha-docker-swarm/design/) with [persistent shared storage](/ha-docker-swarm/shared-storage-ceph.md) -2. [Traefik](/ha-docker-swarm/traefik) configured per design -3. DNS entry for the hostname you intend to use, pointed to your [keepalived](/ha-docker-swarm/keepalived/) IP +--8<-- "recipe-standard-ingredients.md" ## Preparation @@ -29,19 +30,25 @@ Create a docker swarm config file in docker-compose syntax (v3), something like --8<-- "premix-cta.md" ``` -version: "3" +version: '3.2' services: portainer: image: portainer/portainer-ce - env_file: /var/data/config/portainer/portainer.env + command: -H tcp://tasks.agent:9001 --tlsskipverify + ports: + - "9000:9000" + - "8000:8000" volumes: - /var/data/portainer:/data networks: - - traefik_public - internal + - traefik_public deploy: + mode: replicated replicas: 1 + placement: + constraints: [node.role == manager] labels: # traefik - traefik.enable=true @@ -59,25 +66,14 @@ services: - "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 + # uncomment if you want to protect portainer with traefik-forward-auth using traefikv2 # - "traefik.http.routers.portainer.middlewares=forward-auth" - placement: - constraints: [node.role == manager] - command: -H "tcp://tasks.portainer_agent:9001" --tlsskipverify agent: image: portainer/agent - environment: - AGENT_CLUSTER_ADDR: tasks.portainer_agent - CAP_HOST_MANAGEMENT: 1 volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes - ports: - - target: 9001 - published: 9001 - protocol: tcp - mode: host networks: - internal deploy: @@ -88,16 +84,33 @@ services: networks: traefik_public: external: true + internal: + driver: overlay + ipam: + config: + - subnet: 172.16.13.0/24 ``` +--8<-- "reference-networks.md" + +!!! question "Umm.. didn't you just copy these from the [official Portainer docs](https://documentation.portainer.io/v2.0/deploy/linux/#docker-swarm)?" + + 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](/ha-docker-swarm/shared-storage-ceph/)*) + ## Serving ### Launch Portainer stack Launch the Portainer stack by running ```docker stack deploy portainer -c ``` -Log into your new instance at https://**YOUR-FQDN**. You'll be prompted to set your admin user/password. +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*): -[^1]: I wanted to use oauth2_proxy to provide an additional layer of security for Portainer, but the proxy seems to break the authentication mechanism, effectively making the stack **so** secure, that it can't be logged into! +![Portainer Home](../images/portainer-home.png) + +[^1]: There are [some schenanigans](https://www.reddit.com/r/docker/comments/au9wnu/linuxserverio_templates_for_portainer/) you can do to install LinuxServer.io templates in Portainer. Don't go crying to them for support though! :crying_cat_face: --8<-- "recipe-footer.md" \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index e85bedb..20ef262 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -15,7 +15,7 @@ repo_url: 'https://github.com/geek-cookbook/geek-cookbook' docs_dir: 'manuscript' # Copyright -copyright: 'Copyright © 2016 - 2020 David Young, Funky Penguin Limited' +copyright: 'Copyright © 2016 - 2021 David Young, Funky Penguin Limited' # Plugins plugins: @@ -85,6 +85,7 @@ nav: - NextCloud: recipes/nextcloud.md - phpIPAM: recipes/phpipam.md - Plex: recipes/plex.md + - Portainer: recipes/portainer.md - PrivateBin: recipes/privatebin.md - Restic: recipes/restic.md - Swarmprom: recipes/swarmprom.md @@ -112,7 +113,7 @@ nav: - OpenLDAP: recipes/openldap.md - OwnTracks: recipes/owntracks.md - Photoprism: recipes/photoprism.md - - Portainer: recipes/portainer.md + - Portainer: recipes/portainer.md - Realms: recipes/realms.md - Restic: recipes/restic.md - Tiny Tiny RSS: recipes/tiny-tiny-rss.md