Skip to content

Docker Swarm Best Practices with Portainer

Published by bobo on May 5, 2025

If you love the simplicity of Docker Swarm but want a UI-driven way to manage it, Portainer Business Edition (BE) is your best friend. With Portainer BE, you can deploy stacks, manage secrets/configs, label nodes, and monitor everything — all from your browser.

In this post, we’ll walk through Swarm best practices using Portainer BE for:

✅ Environment configs

✅ Secret management

✅ Clean stack deployments

✅ Labeling nodes and services

Let’s turn that CLI workload into a well-managed, GUI-powered orchestration setup.


What You’ll Need

  • Docker Swarm cluster (init using docker swarm init)
  • Portainer Business Edition installed (check portainer.io)
  • Portainer agent deployed to all nodes
  • Admin access to Portainer UI

1. Managing Configs with Portainer

  • Config in portainer only works if you are deploying via CLI or within portainer editor. This will not work for repository deployments from places like GitHub. in that scene configs can be stored via environment section of the stack, you will need to create for each stack you create.

Instead of hardcoding environment variables or editing containers manually, Portainer lets you centrally manage and reuse configuration files through its Configs feature.

This is super handy for things like:

  • Time zone settings
  • Paths for persistent storage
  • App behavior toggles

✅ Example 1: Define a Global Time Zone

You can standardize your container time zone across stacks.

  1. In Portainer, go to Configs > + Add Config
  2. Name it tz_config
  3. Add content:
TZ=America/Toronto
  1. In your docker-compose.yml:
configs:
  - source: tz_config
    target: /etc/config/tz_env
services:
  app:
    image: myapp
    env_file: /etc/config/tz_env

Your app now reads the TZ from the mounted config.


✅ Example 2: Storage Path for Volume Mounting

Set a common storage path used across stacks — especially useful when your host paths vary per environment.

  1. Add a new config:Name: storage_config
DATA_PATH=/mnt/swarm_storage/data
  1. Reference it in your container as a sourced environment file:
services:
  app:
    image: myapp
    configs:
      - source: storage_config
        target: /etc/config/storage_env
    volumes:
      - ${DATA_PATH}/app:/var/lib/app
    env_file: /etc/config/storage_env

This keeps your deployment logic clean and environment-aware without baking paths into your compose file.


✅ Best Practice: Use configs for anything you would normally keep in a .env file — but manage it securely and centrally in Portainer. This helps enforce consistency across environments (dev, staging, prod) while staying stateless and declarative.

Would you like me to add a diagram showing how these configs integrate into a container deployment via Portainer? centralized and version-controlled inside Portainer. It improves reusability and keeps your containers stateless.


2. Manage Secrets Securely in Portainer

Secrets should never live in .env files. Portainer BE lets you create and attach secrets directly in the UI with role-based access control.

*note: you can use the secrets method described below but need to add at the bottom pf the yaml file

secrets:
  external

✅ Steps in Portainer:

  1. Navigate to Secrets > + Add Secret.
  2. Name it db_password and paste your secret securely.
  3. In your stack file:
secrets:
  - db_password
services:
  db:
    image: postgres
    secrets:
      - source: db_password
        target: db_password
    environment:
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password

Secrets are mounted as read-only files at runtime — safe, elegant, and portable.

✅ Best Practice: Rotate secrets regularly and restrict access to teams/groups via Portainer RBAC.


3. Deploy Stacks the Smart Way

Using Portainer’s Stacks feature is a clean, versioned, and rollback-friendly way to deploy containers in Swarm mode.

✅ Steps to Deploy:

  1. Go to Stacks > + Add Stack.
  2. enter repository deployment type and enter access credentials for your GitHub repo.
  3. Set stack name: my_stack.
  4. Click Deploy Stack.

✅ Best Practices:

  • Always use the “deploy” key to control update strategy:
deploy:
  update_config:
    parallelism: 1
    delay: 10s
  restart_policy:
    condition: on-failure
  • Enable healthchecks to catch failing services early:
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000"]
  interval: 30s
  retries: 3

4. Use Labels for Structure and Placement

Portainer lets you manage labels on both nodes and services, which is essential for organizing workloads.

✅ Node Labels

  1. Go to Nodes > select a node.
  2. Click + Add Label, e.g., role=backend.

In your stack:

deploy:
  placement:
    constraints:
      - node.labels.role == backend

✅ Service Labels

  1. In your docker-compose.yml, add:
labels:
  com.example.stack: "api"
  traefik.enable: "true"

These help with service discovery, Traefik config, and UI filtering in Portainer.

✅ Best Practice: Use a consistent label naming scheme across your team.


Bonus: Prune and Monitor

Portainer BE includes:

  • Service health monitoring
  • Container logs and metrics
  • One-click cleanup tools for unused volumes, images, and stopped containers

Stay lean by regularly reviewing VolumesNetworks, and Stacks in Portainer’s dashboards.


Summary Table

FeaturePortainer Best Practice
EnvironmentUse Configs for static env vars instead of .env files
SecretsManage and mount via Portainer Secrets with _FILE support
DeploymentsUse Stacks with rolling update configs and health checks
LabelsUse Node/Service labels for scheduling and monitoring
MaintenanceUse Portainer’s UI for cleanups, monitoring, and access logs

Wrapping Up

Docker Swarm gets a bad rep for being “too simple,” but with Portainer Business Edition, you unlock enterprise-level control with almost no effort. It’s GUI-driven DevOps that still respects the CLI roots.

If you’re managing a homelab, dev cluster, or even staging environments — this combo gives you the flexibility of Swarm with the usability of a control panel.


Published inswarm