Agent
Purpose
The Portainer Agent is a workaround for a Docker API limitation when using the Docker API to manage a Docker environment. The user interactions with specific resources (containers, networks, volumes and images) are limited to those available on the node targeted by the Docker API request.
Docker Swarm mode introduces a concept which is the clustering of Docker nodes. It also adds services, tasks, configs and secrets which are cluster-aware resources. Cluster-aware means that you can query for a list of services or inspect a task inside any node on the cluster, as long as you’re executing the Docker API request on a manager node.
Containers, networks, volumes and images are node specific resources, not cluster-aware. When you, for example, want to list all the volumes available on a node inside your cluster, you will need to send a query to that specific node.
The purpose of the agent aims to allow previously node specific resources to be cluster-aware. All while keeping the Docker API request format. As aforementioned, this means that you only need to execute one Docker API request to retrieve all these resources from every node inside the cluster. In all bringing a better Docker user experience when managing Swarm clusters.
Deployment
Instructions on how to deploy the Agent and how to connect it to Portainer.
Deploy it as a stack
Have a look at the deployment documentation Inside a Swarm cluster to
quickly deploy the agent and a Portainer instance inside a Swarm cluster
via docker stack deploy
.
Manual deployment
Overall, the setup consists of the following steps:
- Step 1: Create a new overlay network in your Swarm cluster for the Agent.
- Step 2: Deploy the Agent as a global service in your cluster (connected to the overlay network).
- Step 3: Connect your Portainer instance to any of the agents by using the Agent's IP:PORT as an endpoint.
Note: This setup assumes that you are executing the following instructions on a Swarm manager node.
Step 1, creating a new overlay network in your Swarm cluster:
$ docker network create --driver overlay --attachable portainer_agent_network
Step 2, deploying the Agent as a global service in your cluster:
$ docker service create \
--name portainer_agent \
--network portainer_agent_network \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
Step 3, deploying the Portainer instance as a service:
$ docker service create \
--name portainer \
--network portainer_agent_network \
--publish 9000:9000 \
--publish 8000:8000 \
--replicas=1 \
--constraint 'node.role == manager' \
portainer/portainer -H "tcp://tasks.portainer_agent:9001" --tlsskipverify
Step 4, deploying the Agent for all Windows Server nodes
Because of Docker limitation you need to deploy the Agent to all Windows Server nodes by running following command on each of them.
$ docker run -d --name portainer_agent --restart always --network portainer_agent_network -e AGENT_CLUSTER_ADDR=tasks.portainer_agent --mount type=npipe,source=\\.\pipe\docker_engine,target=\\.\pipe\docker_engine portainer/agent:windows1803-amd64
Note: If you're using Windows server 1803, you might need to open up DNS ports to support the DNS resolution of tasks.portainer_agent. See: https://success.docker.com/article/swarm-internal-dns-is-inaccessible-on-windows-server-1803
Connecting an existing Portainer instance to an agent
If you want to connect an existing Portainer instance to an agent, you can choose the Agent environment type when creating a new endpoint.
Ensure when deploying the agent, that you expose the Agent's port inside your Swarm cluster, and that the mode is set to host (default port is 9001):
$ docker service create \
--name portainer_agent \
--network portainer_agent_network \
--publish mode=host,target=9001,published=9001 \
--mode global \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
Note: Please be aware that this could potentially open up the Agent
for use by anybody in case the Docker host is reachable from the
internet. Publishing the Agent port 9001 in host mode basically means
opening up this port in the Docker hosts firewall for all interfaces.
Therefore it is highly recommended to use the AGENT_SECRET
environment
variable to define a shared secret, see Shared secret. The Agent
implements the Trust On First Use
(TOFU) principle, so
only the first Portainer to connect will be able to use it, but you want
to avoid an attacker beating you to it.
You can then use the address of any node in your cluster (with the agent port) inside the Agent URL field.
Alternatively, you can deploy the agent using the following stack:
version: '3.2'
services:
agent:
image: portainer/agent
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:
- portainer_agent
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
networks:
portainer_agent:
driver: overlay
attachable: true
Note: In case you are running only a single Agent cluster in the same Swarm overlay network as your Portainer instance, you can just omit publishing the Agent port 9001. Portainer and the Agents will be able to communicate with each other inside the same overlay network and there is no need for the Agents to be accessible from the outside.
Configuration
You can use variant agent configurations to achieve different setups or enable specific features.
Shared secret
By default, the agent will register the first Portainer instance that connects to it and prevent connections from any other instance after that.
To bypass this security mechanism, Portainer and the agent can be configured at deployment time to use a shared secret. This configuration allows multiple Portainer instances to connect to the same agent endpoint.
The AGENT_SECRET
environment variable can be used to define the shared
secret.
When deploying the agent as a service:
$ docker service create \
--name portainer_agent \
--network portainer_agent_network \
--publish mode=host,target=9001,published=9001 \
-e AGENT_SECRET=mysecrettoken \
--mode global \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
Via a stack file:
version: '3.2'
services:
agent:
image: portainer/agent
environment:
AGENT_SECRET: mysecrettoken
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:
- portainer_agent
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
networks:
portainer_agent:
driver: overlay
attachable: true
The AGENT_SECRET
must be specified when deploying Portainer as well:
$ docker run -d -p 9000:9000 -p 8000:8000 --name portainer --restart always -e AGENT_SECRET=mysecrettoken -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
Enable host management features
The following features are disabled by default for security reasons:
- Ability to manage the filesystem of the host where the agent is running
- Ability to retrieve hardware information about the host where the agent is running (PCI devices/disks)
In order to enable these features, the agent must be configured properly by:
- Enabling the host management features via the
CAP_HOST_MANAGEMENT
environment variable - Bind-mounting the root of the host in the agent container (must be
bind-mounted in
/host
)
Example when deploying the agent via a stack file:
version: '3.2'
services:
agent:
image: portainer/agent
environment:
CAP_HOST_MANAGEMENT: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
- /:/host
ports:
- target: 9001
published: 9001
protocol: tcp
mode: host
networks:
- portainer_agent
deploy:
mode: global
placement:
constraints: [node.platform.os == linux]
networks:
portainer_agent:
driver: overlay
attachable: true
Available options
You can change the configuration of the agent by using environment variables.
The following environment variables can be tuned:
- AGENT_PORT: Agent port (default:
9001
) - LOG_LEVEL: Agent log level (default:
INFO
) - AGENT_CLUSTER_ADDR: Address used by each agent to form a cluster.
- AGENT_SECRET: Shared secret used to authorize Portainer instances to connect to the agent
- CAP_HOST_MANAGEMENT: Enable host management features by setting
the value to
1
Usage
API
If you want to use the Portainer API to query containers running on a
specific node inside a Swarm cluster and when using the Portainer agent
setup, you can specify the X-PortainerAgent-Target
header in the HTTP
request to target a specific node in the cluster. The value must be set
to the name of a specific node that can be retrieved via the NodeName
property when querying cluster resources (containers, volumes...).