Deploying Portainer and Agent in Docker Swarm Using a Compose File

In this post, we’ll walk through a Docker Compose file that deploys both the Portainer Server (Enterprise Edition) and the Portainer Agent on a Docker Swarm cluster

· 4 min read
Deploying Portainer and Agent in Docker Swarm Using a Compose File
Photo by Ian Taylor / Unsplash

When managing Docker Swarm clusters, having a user-friendly control panel can simplify operations significantly. Portainer is one such solution—a feature-rich graphical interface that makes container orchestration more approachable. In a Swarm setup, Portainer utilizes a lightweight agent on each node to handle communication and coordination.

In this post, we’ll walk through a Docker Compose file that deploys both the Portainer Server (Enterprise Edition) and the Portainer Agent on a Docker Swarm cluster. We’ll break down each part of the file, focusing on how these services are configured to work together securely and efficiently.


1. Introduction to the Compose File

Below is an anonymized Docker Compose file. Notice that certain paths and IP addresses have been replaced with generic placeholders (e.g., NFS_SERVER_IP and /path/to/swarmnfs/portainer/data) to protect specific environment details.

services:
  agent:
    image: portainer/agent:2.21.5
    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-ee:2.21.5
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    ports:
      - "9443:9443"
      - "9000:9000"
      - "8000:8000"
    volumes:
      - portainer_data:/data
    networks:
      - agent_network
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]
  
networks:
  agent_network:
    driver: overlay
    attachable: true
  
volumes:
  portainer_data:
    driver: local
    driver_opts:
      device: :/path/to/swarmnfs/portainer/data
      o: addr=NFS_SERVER_IP,nolock,soft,rw,nfsvers=4
      type: nfs

Let’s break down the significant components in detail.

2. Services

2.1 The Agent Service

services:
  agent:
    image: portainer/agent:2.21.5
    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]

Key Points:

  1. Image: portainer/agent:2.21.5
    • The Portainer Agent is a small container that relays instructions between Portainer and each Swarm node.
  2. Volumes:
    • - /var/run/docker.sock:/var/run/docker.sock
      Grants the agent container direct communication with the Docker daemon on each node.
    • - /var/lib/docker/volumes:/var/lib/docker/volumes
      Allows the agent to manage and inspect local Docker volumes if needed.
  3. Network:
    • Attached to agent_network, so it can communicate with Portainer over a secure overlay network.
  4. Deployment:
    • mode: global ensures one container is deployed to every node in the Swarm that meets the placement constraints.
    • placement.constraints: [node.platform.os == linux] ensures the agent only runs on Linux nodes.

With this configuration, every Linux-based node in the Swarm will host one instance of the Portainer Agent, allowing Portainer to discover and manage resources across the cluster.


2.2 The Portainer Service

  portainer:
    image: portainer/portainer-ee:2.21.5
    command: -H tcp://tasks.agent:9001 --tlsskipverify
    ports:
      - "9443:9443"
      - "9000:9000"
      - "8000:8000"
    volumes:
      - portainer_data:/data
    networks:
      - agent_network
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints: [node.role == manager]

Key Points:

  1. Image: portainer/portainer-ee:2.21.5
    • This is the Enterprise Edition of Portainer. Ensure you have the appropriate license for production environments (or use the Community Edition if that’s sufficient for your use case).
  2. Command:
    • -H tcp://tasks.agent:9001 --tlsskipverify
    • -H sets the agent endpoint. Using tasks.agent lets Portainer automatically discover all containers of the agent service.
    • 9001 is the default port on which the agent listens.
    • --tlsskipverify bypasses TLS verification—used commonly for internal or development setups.
  3. Ports:
    • 9443:9443: Exposes Portainer’s HTTPS interface.
    • 9000:9000: Exposes the HTTP interface (also used for admin if HTTPS is not enforced).
    • 8000:8000: Used for Edge agent features, if applicable.
  4. Volumes:
    • - portainer_data:/data
      Mounts the data volume, which stores Portainer’s settings, users, and other persistent data.
  5. Network:
    • agent_network ensures Portainer can talk to the agent containers.
  6. Deployment:
    • mode: replicated with replicas: 1 runs one instance of Portainer.
    • placement.constraints: [node.role == manager] places Portainer on a manager node, which is recommended for cluster management tools.

3. Networks

networks:
  agent_network:
    driver: overlay
    attachable: true
  • Overlay network driver allows containers across different nodes to communicate securely.
  • attachable: true makes it possible for other services or containers to attach to this network manually if required.

4. Volumes

volumes:
  portainer_data:
    driver: local
    driver_opts:
      device: :/path/to/swarmnfs/portainer/data
      o: addr=NFS_SERVER_IP,nolock,soft,rw,nfsvers=4
      type: nfs
  • portainer_data is defined using the local driver.
  • driver_opts specify NFS storage details:
    • device: :/path/to/swarmnfs/portainer/data indicates the remote NFS path.
    • o: addr=NFS_SERVER_IP,nolock,soft,rw,nfsvers=4 mounts the volume from the NFS server.
    • type: nfs explicitly sets NFS as the filesystem type.

Using an NFS-based volume ensures that Portainer’s data persists externally, which is critical for high availability and backup scenarios.


5. Deploying the Stack

If you save the above YAML as portainer-stack.yml, deploy it to your Docker Swarm with:

docker stack deploy -c portainer-stack.yml portainer

Where:

  • portainer-stack.yml is the Compose file name.
  • portainer is the name you assign to the stack.

6. Accessing Portainer

After your services successfully deploy:

  1. Open a web browser and go to https://<Swarm_Manager_IP>:9443 or http://<Swarm_Manager_IP>:9000.
  2. On first use, you’ll be prompted to create an administrative user.
  3. Once logged in, you should see the Portainer dashboard and be able to manage your Swarm cluster.

Note: If you’re using self-signed certificates or skipped TLS verification, your browser may prompt you about an insecure connection—confirming the exception is typically required.


7. Conclusion

This Docker Compose configuration lays out a standard approach for running Portainer in Docker Swarm:

  • Global Agent Deployment ensures each node is automatically managed.
  • Single Portainer Server on a manager node centralizes cluster administration.
  • NFS-Backed Data provides persistence and resilience for Portainer’s settings and metadata.
  • Overlay Network makes inter-container communication seamless and secure within the Swarm.