Running Docker Compose as a systemd Service: A Comprehensive Guide
Docker Compose is like a handy tool for putting together simple apps. It lets you start a bunch of connected parts (we call them containers) all at once, creating a single app. It's pretty easy to use and set up.
Managing Docker containers efficiently is crucial for seamless application deployment. Integrating Docker Compose with systemd allows for automatic startup and robust process management of your containerized applications. In this guide, we'll walk you through setting up Docker Compose as a systemd service, ensuring your applications are resilient and easy to manage.
Why Use systemd with Docker Compose?
Systemd is the init system for many Linux distributions, responsible for managing system services during boot and runtime. By creating a systemd service for your Docker Compose applications, you can:
- Ensure Automatic Startup: Your Docker containers will start automatically on system boot.
- Simplify Management: Utilize systemd commands to control your Docker services.
- Enhance Reliability: Systemd monitors services and can restart them upon failure.
Prerequisites
Before proceeding, ensure you have:
- A Linux system with systemd (e.g., Ubuntu 20.04).
- Docker and Docker Compose installed.
- A Docker Compose YAML file (
docker-compose.yml) defining your services.
What is systemd service?
A systemd service is a script or executable that is managed by the systemd process, which controls the behavior and status of these underlying services.
- Automatic Startup: Ensure that your Docker containers start automatically when the system boots.
- Unified Management: Use familiar systemctl commands to manage your Docker Compose applications.
- Enhanced Reliability: Leverage systemd's process management capabilities to monitor and restart services as needed.
- Handy & Simple to operate: Handling services is simple and easy as they can be used as system component instead of decoupled program.
Steps to Create systemd Service
To create systemd service we need to write a service file which will execute command or script in case of start, stop and restart actions.
So in case of docker-compose application we need to have docker-compose.yml file which has definition of all the services and then using docker-compose up -d command we can give start action for the service, similarly for stop we can use docker-compose stop command.
Let's see step by step:
- Write docker-compose.yml file with all services/components, below is the django app example taken from docker documentation.
version: "3.9"
services:
db:
image: postgres
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- dbExample from docs.docker.com
- For testing purpose you can bring the application up by using
docker-compose upcommand, additionally we can have-dflag for running application as daemon
# will bring up all services in docker-compose.yml
docker-compose up -d
# pass yml file with -f flag
docker-compose up -f application.yml- Once, application is working correctly we can have service for this application by writing service file and placing it in
/etc/systemd/systemdirectory - Create file
/etc/systemd/system/myapp.servicewith below content - noteExecStartandExecStopdirectives - each will be used as starting and stopping command for the service respectively
[Unit]
Description=Service for myapp
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
WorkingDirectory=/root/bootvar
Environment=COMPOSE_HTTP_TIMEOUT=600
ExecStart=/usr/bin/env /usr/bin/docker-compose -f /root/bootvar/docker-compose.yml up -d
ExecStop=/usr/bin/env /usr/bin/docker-compose -f /root/bootvar/docker-compose.yml stop
StandardOutput=syslog
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target/etc/systemd/system/myapp.service
- You can set environment variables using
Environmentdirective or pass variables from a file - Once file is created you need to reload all system services using
systemctl daemon-reloadcommand - Now you have created
myappservice, start the service usingsystemctl start myappwhich will execute command/script defined inExecStart - If you want to start your service whenever your server reboots then you need to enable it using
systemctl enable myappcommand which will ensure whenever your server boots upmyappservice will be started - Adjust the
WorkingDirectoryto the location of yourdocker-compose.yml. - Ensure the
ExecStartandExecStoppaths point to your Docker Compose binary.
# will enable service to start at server bootup
systemctl enable myapp
# start service ( Executes ExecStart command )
systemctl start myappThis way you can make sure your docker-compose service stays up and running after every server restart.
Best Practices
- Environment Variables: If your application requires environment variables, define them within the
docker-compose.ymlor specify them in the systemd service file using theEnvironmentdirective. - User Permissions: If running Docker as a non-root user, specify the
Userdirective in the[Service]section of the systemd service file. - Timeouts: Adjust
TimeoutStartSecand other timeout settings as needed to ensure that services have adequate time to start and stop. - Logging: Redirect logs to syslog or a specific file by configuring the
StandardOutputandStandardErrordirectives.
Troubleshooting
- Permission Issues: Ensure the user running the systemd service has the necessary permissions to manage Docker.
- Path Errors: Verify that the paths to
docker-composeand your working directory are correct. - Service Not Starting on Boot: Confirm that the service is enabled and that there are no errors in the service file syntax.
Conclusion
To turn a correctly working application into a service, you can write a service file and place it in the /etc/systemd/system directory. The service file, named myapp.service, should contain the starting and stopping commands for the service, specified in the ExecStart and ExecStop directives, respectively.
With a custom systemd service, the application can be automatically started when the server is restarted, overcoming the limitation of Docker Compose's lack of automatic start on reboot.
Frequently Asked Questions (FAQs)
1. Why should I use systemd instead of docker-compose up -d?
Using systemd ensures that your Docker Compose services automatically restart on reboot, can be monitored, and follow a structured logging mechanism.
2. How do I check if my systemd service for Docker Compose is running correctly?
You can use the following command to check the status:
sudo systemctl status my-docker-composeIf there's an issue, logs can be checked using:
journalctl -u my-docker-compose --no-pager --lines=503. What happens if a container crashes?
If you've set the restart policy in your docker-compose.yml to always or unless-stopped, systemd will restart the container automatically when it crashes.
4. Can I run multiple Docker Compose projects with systemd?
Yes, but each project should have a separate systemd service file. Ensure each service file points to the correct docker-compose.yml location.
5. How can I update my Docker Compose service without stopping the entire systemd service?
You can update containers and reload systemd as follows:
cd /path/to/your/docker-compose
docker-compose pull
docker-compose up -d
sudo systemctl daemon-reload
sudo systemctl restart myapp6. How can I ensure my Docker Compose service starts on boot?
Enable the service to start at boot using:
sudo systemctl enable myapp7. Does systemd support logging for Docker Compose services?
Yes, systemd captures logs for your services. View logs using:
journalctl -u my-docker-compose -f