Portainer

Introduction to Portainer

Portainer is a lightweight, open-source management user interface (UI) that provides a graphical interface for interacting with Docker environments, whether they’re Docker Swarm, Kubernetes, or even a standalone host with Docker installed. It removes the need to SSH on various machines to run Docker containers, making it easier to manage everything: containers, images, volumes, and networks.

One of Portainer’s key benefits in the infra-bootstrap-tools setup is its utility for rapid experimentation. If you want to quickly test a new application or service, Portainer allows you to deploy a container to one of your test servers with a few clicks. Using the preexisting set of templates or by creating your own, you can deploy and configure an extensive suite of solutions (N8N, nodeRED, MongoDB, Redis, WordPress, etc.).

Why not test things locally, you may ask? Well, you can, but it has limits, especially if you want to use your newly deployed software from anywhere. I am talking about deploying an application like N8N, or executing a long-running task like a mathematical solver. In the first N8N case, I would need to have the ability to receive webhooks to trigger the various automation workflows, which means it must be reachable over the internet. The second case, (while probably rare for most people reading those lines), running a long process is better on a computer I am not using here and there, so as not to affect the result of the experiments.

Portainer also allows you to manage your application in a GitOps fashion, meaning that your configuration files (docker-compose.yaml) live in a git repository. Those changes are reflected in your infrastructure whenever you update your repository, updating and redeploying your apps if needed. So, once you have played with something and liked it, you may want to make it more stable, save your configuration in a git repository, and have a “normal” development life cycle where changes happen over git. All this without ever running a single Docker command.

Finally, Portainer provides convenient access to essential operational data. You can easily view container logs in real-time, inspect configurations, and monitor basic resource usage (metrics). This is invaluable for debugging, understanding application behaviour, and getting a quick overview of your services’ health.

In essence, Portainer offers an intuitive visual interface, particularly beneficial for exploration, quick deployments, and straightforward access to logs and metrics.

Deployment Process

In the infra-bootstrap-tools Portainer is deployed as a Docker Swarm service using the docker_swarm_app_portainer Ansible role. This role automates the setup and deployment of Portainer and its agent.

Key actions performed by the Ansible role include:

  • Host Directory Creation: A directory, specified by the docker_swarm_app_portainer_host_dir variable, is created on the target host to store Portainer’s configuration files.
  • Copying Docker Compose File: The role templates a Docker Compose definition from portainer-agent-stack.yml.j2 to portainer-agent-stack.yml within the created host directory. This file defines the Portainer services. (Note: portainer-agent-stack.yml is a generated file, the link points to its template).
  • Deploying the Portainer Stack: The Portainer application is deployed as a Docker stack named portainer using the docker_stack Ansible module. This stack consists of two main services:
    • agent: This service runs the portainer/agent image. It is deployed globally on all Linux nodes in the Swarm. It mounts the Docker socket (/var/run/docker.sock) and Docker volumes directory (/var/lib/docker/volumes) to allow Portainer to interact with the Docker environment on each node.
    • portainer: This service runs the portainer/portainer-ce (Community Edition) image, acting as the Portainer server and UI. It is configured to run as a single replica on a manager node in the Swarm and communicates with the agent service.
      • Data Persistence: It uses a named Docker volume called portainer_data to persist its configuration and data.
      • Network Configuration: Both services connect to an overlay network named agent_network. If Caddy integration (controlled by the docker_swarm_app_portainer_caddy variable) is true, the portainer service also connects to the Caddy network (caddy_caddy). It’s then configured with labels to be automatically exposed via Caddy at portainer.YOUR_DOMAIN (where YOUR_DOMAIN is derived from docker_swarm_app_caddy_tls_domain), with access secured by the admins_policy.
      • Direct Port Exposure: If Caddy integration is disabled, Portainer’s web interface and API are exposed directly via ports: 9443 (HTTPS), 9000 (HTTP), and 8000 (Tunnel for Edge Agents).

Usage

Once Portainer is deployed, you can access its web interface. If Caddy integration is enabled (default in infra-bootstrap-tools), Portainer will be available at https://portainer.YOUR_DOMAIN (replace YOUR_DOMAIN with your actual domain). Access will require authentication via the configured Caddy admins_policy (typically GitHub OAuth). If Caddy integration is disabled, access it via http://YOUR_SERVER_IP:9000 or https://YOUR_SERVER_IP:9443.

Upon first login, Portainer will prompt you to create an administrator user and then connect to the local Docker environment (which is managed by the Portainer agent). Because of this behaviour, I appreciate knowing that Caddy would block any incoming requests from unauthenticated users.

Deploying New Applications

Portainer offers several ways to deploy applications:

  • Manual Container Deployment: You can deploy individual containers by specifying the image, ports, volumes, environment variables, and other Docker run parameters through the UI. This is useful for quick tests or simple, single-container applications.
  • App Templates: This is a highly recommended feature for deploying common applications. Portainer includes a list of predefined application templates.
    • Ease of Use: Deploying from an app template is straightforward. Select the application, fill in any required configuration (like passwords or specific settings), and Portainer handles pulling the Docker image and creating the container.
    • Custom Templates: You can extend Portainer by adding your own custom app templates. This is useful for standardizing deployments of your applications or frequently used third-party tools not in the default list. Custom templates are defined in a JSON format; the template file itself can be hosted in a Git repository and pointed to, or the JSON content can be added directly in the Portainer UI.
  • Stacks (Docker Compose): For multi-container applications, Portainer allows you to deploy and manage Docker Compose stacks. You can upload a docker-compose.yml file, paste its content into the web editor, or, for a more robust workflow, connect Portainer to a Git repository.

GitOps with Stacks

Portainer supports a GitOps-style workflow for managing your application stacks:

  1. Connecting to a Git Repository: In the “Stacks” section, create a new stack and choose “Git Repository” as the deployment method. Provide the repository URL, specify the path to your docker-compose.yml file within the repository, and optionally configure authentication (e.g., a Git access token for private repositories).
  2. Deploying and Managing: Portainer will pull the docker-compose.yml file and deploy the stack. You can later re-pull and redeploy the stack manually through the UI to apply changes from your Git repository.
  3. Automatic Updates:
    • Portainer Business Edition (BE) offers true GitOps with automatic updates via webhooks: pushing changes to your Git repository can trigger Portainer to re-pull the stack definition and redeploy the application.
    • Portainer Community Edition (CE), deployed by this role, does not include webhook-based automatic updates. To update a stack from Git, you must manually trigger a “Pull and redeploy” action in the Portainer UI or use external scripts to automate this process via Portainer’s API.
  4. Environment Variables: Define environment variables in the Portainer UI for your stack. These can be used within your docker-compose.yml file, which is useful for managing secrets or environment-specific configurations without hardcoding them.

Monitoring and Management

Portainer provides built-in tools for monitoring and managing running containers and services:

  • Container Logs: Access logs for any container directly from the Portainer UI. This provides a real-time stream of stdout and stderr from your application, essential for debugging and monitoring. Logs can also be downloaded.
  • Basic Metrics (Stats): Portainer displays basic, real-time resource usage statistics for each running container, including CPU usage, memory usage, and network I/O. These stats offer a quick performance overview but are not stored historically within Portainer. They are not a replacement for a dedicated, long-term monitoring solution like Prometheus and Grafana.
  • Container Lifecycle Management: Perform common lifecycle operations via the UI:
    • Stopping, starting, and restarting containers or services within a stack.
    • Removing containers or stacks.
    • Inspecting container details (environment variables, volume mounts, network settings).
    • Opening a console session (exec) into a running container for troubleshooting.