Docker has revolutionized how developers package and deploy their applications, making creating and running containerized applications easier and faster. However, managing Docker containers and orchestrating them across multiple hosts can be challenging.
What is Portainer?
With Portainer, you can manage your Docker containers, images, networks, and volumes through a simple and intuitive interface. This tutorial will explore using Portainer with Docker Compose to automate container applications.
With the Portainer agents, you can manage your other Docker hosts from your main Portainer dashboard.
Below is a look at the container list found in Portainer.
Docker & Installing Docker Compose
Before we can start using Portainer, we must have Docker Engine and Docker Compose installed on our system. If you don’t have them installed yet, follow these steps:
To install Docker on your Linux server, run the following command:
sudo apt-get update sudo apt-get install docker.io
With Docker installed, we can Install Docker Compose:
To install Docker Compose, run the following command:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose
With Docker and Docker Compose installed, we can now proceed to install and configure Portainer to create Portainer stacks, or create your own compose files for all the containers. Prewritten compose files are abundance from online git repository resources.
There are different versions of Portainer available, including Portainer CE (Community Edition) and Portainer Business. In this tutorial, we’ll be using Portainer CE.
To install Portainer, we’ll run it as a container. Here are the steps:
Create a directory where the Portainer data will be stored:
sudo mkdir -p /opt/portainer/data
Run the Portainer container:
sudo docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v /opt/portainer/data:/data portainer/portainer-ce
The above command will pull the latest version of Portainer CE and run it as a container with the name “portainer”. The “-p” option maps the container port (9000) to the host port (9000), allowing us to access the Portainer UI on port 9000. The “-v” options mount the Docker socket and the Portainer data directory to the container, enabling Portainer to manage the Docker environment. With Portainer running:
Connect to Portainer UI:
To connect to the Portainer UI, navigate to http://<your-server-ip>:9000 in your web browser. You’ll be prompted to create an admin user and set a password. After setting up your credentials, you’ll be redirected to the Portainer dashboard.
Using Portainer with Docker Compose
Now that we have Portainer installed and running, we can use it to manage Docker Compose applications.
Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file (docker-compose.yml) to define the services, networks, and volumes that make up an application. With Portainer, we can easily create, manage, and deploy Docker Compose stacks.
Creating a Compose file
To create a Docker Compose file, we need to define the services that make up our application, including the image to use, the ports to expose, and the environment variables to set.
Here’s an example of a simple Compose file for a web application that uses a Node.js image:
version: "3" services: web: image:
To complete the example Compose file, here are the remaining contents:
build: context: . dockerfile: Dockerfile ports: - "3000:3000" environment: - NODE_ENV=production
In the above file, we’ve defined a service called “web” that uses a Node.js image. We’ve also specified that the application should run in production mode by setting the “NODE_ENV” environment variable. Additionally, we’ve exposed port 3000 on the host, allowing us to access the application from a web browser.
We can save the above Compose file as “docker-compose.yml” in a directory on our server.
Creating a Stack
With our Compose file in place, we can create a new stack in Portainer that details each Docker container. A stack is a collection of services that make up an application. Here are the steps to create new Portainer stacks:
Navigate to the “Stacks” screen in Portainer.
Click on the “Add stack” button.
Give your stack a name and select the “Web editor” option.
In the editor, copy and paste the contents of the Compose file.
Click on the “Deploy the stack” button.
Portainer will now create a new stack based on the Compose file. You’ll be able to see the status of the stack, the containers that make up the stack, and the logs for each container.
Using the upload feature to upload a Docker Compose file.
You can pull a stack configuration from a git repository.
Updating a Stack
If you make changes to your Compose file, you can easily update the stack in Portainer. Here are the steps:
Navigate to the “Stacks” screen in Portainer.
Click on the stack that you want to update.
Click on the “Update the stack” button.
In the editor, make the necessary changes to the Compose file.
Click on the “Update the stack” button.
Portainer will now update the stack based on the updated Compose file.
Creating Custom Templates
Portainer also allows you to create custom Compose file templates. This can be useful if you have a standard set of services across different applications. Here are the steps to create a custom template:
Navigate to the “App Templates” screen in Portainer.
Click on the “Create a new template” button.
Give your template a name and description.
Copy and paste the contents of your Compose file into the editor.
Define any variables that you want to make configurable.
Save the template.
You can now use your custom template to create new stacks in Portainer. Below, we have pasted some Docker Compose YML code into the Web editor of the Custom Templates screen. This way, we can save the application stack as a template and easily deploy it across our entire Docker landscape.
Managing Multiple Docker Hosts with Portainer
Portainer also allows you to manage multiple Docker hosts through a single Portainer instance using Portainer agents. This can be useful if you have different applications running on different hosts.
Here are the steps to manage multiple Docker hosts with Portainer:
Install Portainer on each host.
Create a Portainer stack on one of the hosts.
In the Portainer UI, navigate to “Settings” and select “Endpoints”.
Click on the “Add endpoint” button.
Enter the URL of the Docker host that you want to add.
Enter the necessary authentication details.
Connect Portainer to the agent
Save the endpoint.
You can now manage all your Docker hosts through a single Portainer instance.
Manually creating a Docker Compose file
Here is an example of a Docker Compose file that includes Traefik, Nginx, and Up-time Kuma, with Traefik acting as a reverse proxy for each service. This example file also creates a Docker network called “traefik” and creates all the required volumes:
version: "3.8" services: traefik: image: "traefik:v2.6" command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" - "--email@example.com" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "./letsencrypt:/letsencrypt" networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.traefik.rule=Host(`traefik.mydomain.com`)" - "traefik.http.routers.traefik.entrypoints=websecure" - "traefik.http.routers.traefik.tls.certresolver=myresolver" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.routers.traefik.middlewares=redirect-to-https" - "traefik.http.services.traefik.loadbalancer.server.port=8080" nginx: image: "nginx:latest" volumes: - "./nginx/conf.d:/etc/nginx/conf.d" networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.nginx.rule=Host(`nginx.mydomain.com`)" - "traefik.http.routers.nginx.entrypoints=websecure" - "traefik.http.routers.nginx.tls.certresolver=myresolver" - "traefik.http.services.nginx.loadbalancer.server.port=80" uptime: image: "uptime-kuma:latest" environment: - "PORT=3000" volumes: - "./uptime:/data" networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.uptime.rule=Host(`uptime.mydomain.com`)" - "traefik.http.routers.uptime.entrypoints=websecure" - "traefik.http.routers.uptime.tls.certresolver=myresolver" - "traefik.http.services.uptime.loadbalancer.server.port=3000" networks: traefik: external: true volumes: letsencrypt: uptime:
This specific Docker Compose file creates three services:
- Traefik, Nginx, and Up-time Kuma.
- It also creates a network called “traefik”
- And two volumes for storing Let’s Encrypt SSL certificates and Up-time Kuma data.
Traefik is configured to act as a reverse proxy for each service, using the labels section to define the routing rules for each. The other services (Nginx and Up-time Kuma) are configured with labels that enable Traefik to route traffic to them.
- Why do we mount the /var/run/docker.sock location? The Traefik service mounts the Docker socket at “/var/run/docker.sock” to dynamically discover Docker containers running on the host. In addtionTraefik is configured to use Let’s Encrypt to automatically generate SSL certificates for the services, with the certificates stored in a volume called “letsencrypt”.
- The Nginx service is configured with a volume to store its configuration files, which can be used to define custom routing rules for the service. The Up-time Kuma service is configured with a volume to store its data.
- Finally, the Compose file defines an external network called “traefik” that is used by all three services. This allows Traefik to route traffic to the other services using the network name as the hostname.
Portainer is a powerful tool for managing Docker environments, and when combined with Docker Compose, it can be used to automate full application stacks. With Portainer, you can easily create, manage, and deploy Docker Compose stacks and create custom Compose file templates.
You should be able to successfully install and use Portainer with Docker Compose and manage multiple Docker hosts with a single Portainer instance using the steps included.
Remember that when using Portainer, following best practices for securing your Docker environment is important.
Recapping the following:
- Ensure the Docker group is not accessible to non-root users, and avoid running Portainer as a container on the same host as your other containers. Additionally, you should avoid exposing the Docker socket to untrusted users.
Portainer and Docker Compose can greatly simplify managing and deploying containerized applications. Using Portainer to manage your Docker environment, you can use its powerful features, such as creating custom Compose file templates and managing multiple Docker hosts. With these tools, you can streamline your workflow and focus on developing great applications.