Skip to content

Instantly share code, notes, and snippets.

@mosquito
Last active May 10, 2024 20:44
Show Gist options
  • Save mosquito/b23e1c1e5723a7fd9e6568e5cf91180f to your computer and use it in GitHub Desktop.
Save mosquito/b23e1c1e5723a7fd9e6568e5cf91180f to your computer and use it in GitHub Desktop.
Add doker-compose as a systemd unit

Docker compose as a systemd unit

Create file /etc/systemd/system/docker-compose@.service. SystemD calling binaries using an absolute path. In my case is prefixed by /usr/local/bin, you should use paths specific for your environment.

[Unit]
Description=%i service with docker compose
PartOf=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/etc/docker/compose/%i
ExecStart=/usr/local/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/local/bin/docker-compose down

[Install]
WantedBy=multi-user.target

Place your docker-compose.yml into /etc/docker/compose/myservice and call

systemctl start docker-compose@myservice

Docker cleanup timer with system

Create /etc/systemd/system/docker-cleanup.timer with this content:

[Unit]
Description=Docker cleanup timer

[Timer]
OnUnitInactiveSec=12h

[Install]
WantedBy=timers.target

And service file /etc/systemd/system/docker-cleanup.service:

[Unit]
Description=Docker cleanup
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
WorkingDirectory=/tmp
User=root
Group=root
ExecStart=/usr/bin/docker system prune -af

[Install]
WantedBy=multi-user.target

run systemctl enable docker-cleanup.timer for enabling the timer

JournalD support

Just add the following line to the /etc/docker/daemon.json:

{
    ...
    "log-driver": "journald",
    ...
}

And restart your docker service.

@xiaket
Copy link

xiaket commented Nov 24, 2018

The cleanup could be more conveniently done through cron.

@paulkitt
Copy link

@daswars I also dont understand why the volumes are deleted. You could use bind mount for e.g. /var/lib/postgresql/data. I just removed the commands/parameters deleting volumes.

@alobaidan
Copy link

Hi, I have created an authorisation plugin. when I add the user to the code I got error message from socket.

could you tell me how I add Linux user as a systemd unit to docker.service file.

many thanks

Ibrahim

@diglabsityler
Copy link

Thanks really helped me out!

@mxinden
Copy link

mxinden commented Apr 10, 2020

Thanks a bunch for publishing this.

Could you settle on one execution path for docker-compose? /usr/bin/docker-compose vs /usr/local/bin/docker-compose. The latter was the default installation path on Ubuntu with the docker docs.

@ptsneves
Copy link

ptsneves commented Apr 14, 2020

Thanks a bunch for publishing this.

Could you settle on one execution path for docker-compose? /usr/bin/docker-compose vs /usr/local/bin/docker-compose. The latter was the default installation path on Ubuntu with the docker docs.

run:
which docker-compose and put the applicable path

@mosquito
Copy link
Author

some distros have /usr/local/bin for docker-compose …

note added

@sarbian
Copy link

sarbian commented Apr 30, 2020

Requires and After are on the same line than Description with your last update.

Thanks for this. It does exactly what I need

@mosquito
Copy link
Author

Requires and After are on the same line than Description with your last update.

Thanks for this. It does exactly what I need

Fixed thank you

@Throdne
Copy link

Throdne commented May 11, 2020

I'm still new to docker and learning daily. I really like this configuration but I'm running into an issue.

My setup: I have created docker-compose.yml file for each of my docker container services
e.g.

/mnt/dockerdata/bitwarden/compose/docker-compose.yml
/mnt/dockerdata/bitwarden/data/
systemctl status docker-compose@bitwarden.service 

/mnt/dockerdata/portainer/compose/docker-compose.yml
/mnt/dockerdata/portainer/data/
systemctl status docker-compose@portainer.service

/mnt/dockerdata/nexcloud/compose/docker-compose.yml
/mnt/dockerdata/nextcloud/data/
systemctl status docker-compose@nextcloud.service

/mnt/dockerdata/portainer/compose/docker-compose.yml

version: '3'

services:
  portainer:
    image: portainer/portainer
    container_name: portainer
    ports:
      - "9000:9000"
      - "8000:8000"
    volumes:
      - /mnt/dockerdata/portainer/data:/data
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker/volumes:/var/lib/docker/volumesroot@Docker01:/mnt/dockerdata/bitwarden/compose#

/etc/syustemd/system/docker-compose@.service

[Unit]
Description=%i service with docker compose
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/mnt/dockerdata/%i/compose
ExecStart=/usr/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/bin/docker-compose down

[Install]
WantedBy=multi-user.target

My issue is with the --remove-orphans switch. When you start the systemd service it kills the other services. e.g. If I run systemctl start docker-compose@bitwarden.service I see "Removing orphan container "portainer"" in the logs for the bitwarden service and portainer and nextcloud are not running or vise-versa.

MY QUESTION: I want to clean up any orphan containers, but I don't want it to effect my other services. What would be and effective way of this within the systemd service file?

docker-compose issue
docker ps shows that only bitwarden is running
next I run docker-compose up in the portainer/compose directory. You can see that docker compose up is saying that the bitwarden container is an orphan container which it isn't.

docker-compose issue2
docker ps shows that only portainer is running
when you run docker-compose up -d --remove-orphans within the bitwarden/compose directory it removes the portainer container.

@Yannis100
Copy link

Yannis100 commented May 11, 2020

Hey @Throdne, just replied on your reddit post
You don't need --remove-orphans unless you changed (add/remove/rename a service) a compose file and forgot to "down" it before the change
docker-compose down removes the containers and docker-compose up on running service will recreate it -> no orphan by design

Check docker system prune too

@gnat
Copy link

gnat commented May 8, 2021

docker image prune -a --force --filter "until=240h"

Only prune unused images, and only if older than 10 days.

@parisni
Copy link

parisni commented May 16, 2021

what about systemd security parameters such ? :

PrivateTmp=yes
UMask=077
NoNewPrivileges=yes
NotifyAccess=yes
PrivateMounts=yes
ProtectControlGroups=yes
ProtectKernelTunables=yes
ProtectProc=yes
ProtectHome=true
ProtectSystem=full
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=true
RestrictRealtime=true
SystemCallArchitectures=native
User=<the user>
Group=<the group>

@mosquito
Copy link
Author

@parisni It looks great, but this is not applicable to docker-compose. This is the python script that establishes a connection with the docker daemon, and executes everything that has been described in YAML through the Docker API. Docker, in turn, executes commands from the root user, and all the above restrictions will not be applied.

@gnat
Copy link

gnat commented May 17, 2021

Also this was required for me to get systemctl --user enable docker-compose@blah to work on Ubuntu 20.04 server (load on reboot).

[Install]
WantedBy=default.target

default.target should be an alias for multi-user.target, but apparently not in my situation.

@parisni
Copy link

parisni commented May 18, 2021

and all the above restrictions will not be applied.

well my experimentations have shown that some of them have impact: for example, if I turn off Notify then the docker-compose does not start up

@whistler
Copy link

Would it be better to remove -d after docker-compose up so logs get saved by systemctl?

@mosquito
Copy link
Author

Would it be better to remove -d after docker-compose up so logs get saved by systemctl?

The better way is the docker starts writing all logs to the journald

@chkpnt
Copy link

chkpnt commented Oct 4, 2021

I'm using WantedBy=docker.service so that the service is started when docker itself is (re)started.

@bigntallmike
Copy link

This is great but as said in the docker forums, "docker system prune is not safe to be used in production."

@so-jelly
Copy link

so-jelly commented May 1, 2022

@chkpnt I recommend using

PartOf=docker.service

PartOf=

Configures dependencies similar to Requires=, but limited to stopping and restarting of units. When systemd stops or restarts the units listed here, the action is propagated to this unit. Note that this is a one-way dependency — changes to this unit do not affect the listed units.

@dcd-arnold
Copy link

The better way is the docker starts writing all logs to the journald

@mosquito can you explain why?

@mosquito
Copy link
Author

@dcd-arnold It's simple, at the time of writing this note, the docker daemon storage all container logs in plain JSON files in the /var/lib/docker, which quite often grew to a rather indecent size if you do not does something for control them separately. Now the question is, why do you have to monitor this separately if there is already a daemon in the operating system that can effectively read/write/compress/sign structured log records? Thus, transferring responsibility for all logs to the JournalD level allows them to be efficiently stored, rotated, and read using journalctl filters (e.g. CONTAINER_ID or CONTAINER_NAME).

@mosquito
Copy link
Author

@so-jelly fixed thank you.

@dcd-arnold
Copy link

It's simple, at the time of writing this note, the docker daemon storage all container logs in plain JSON files in the /var/lib/docker, which quite often grew to a rather indecent size if you do not does something for control them separately. Now the question is, why do you have to monitor this separately if there is already a daemon in the operating system that can effectively read/write/compress/sign structured log records? Thus, transferring responsibility for all logs to the JournalD level allows them to be efficiently stored, rotated, and read using journalctl filters (e.g. CONTAINER_ID or CONTAINER_NAME).

@mosquito But docker-compose would not run in background, hence pushing its stdout to systemd, which is build to take such data in and store it. What am i missing here?

@mosquito
Copy link
Author

@dcd-arnold but /usr/local/bin/docker-compose up -d ... in the ExecStart=

@dcd-arnold
Copy link

@mosquito That was the original question:

Would it be better to remove -d after docker-compose up so logs get saved by systemctl?

If you omit -d, docker-compose pushes its stdout to systemd to do with it as it sees fit.

@mosquito
Copy link
Author

@dcd-arnold if you omit something from this recipe, you have to resolve following troubles :-).

@dcd-arnold
Copy link

@mosquito @dcd-arnold if you omit something from this recipe, you have to resolve following troubles :-).

sure thing.

@jest
Copy link

jest commented Jun 7, 2022

@dcd-arnold moreover, having docker-compose printing logs on stdout doesn't stop Docker daemon from saving logs. So you would end up using twice as much space -- once in Docker daemon and once in systemd -- as required for your logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment