Compose: How to make a Systemd Unit for docker-compose?

Created on 19 Dec 2016  ·  16Comments  ·  Source: docker/compose

I've tried to make a service Unit to initialize some Docker images by docker-compose in Systemd. I have saw somes examples at Internet, but the only works, there is one trap...

With these harbor.service file:
[Unit]
Description=Servico de manutencao do Harbor
After=network.target docker.service
[Service]
Type=simple
WorkingDirectory=/opt//harbor
ExecStart=/usr/local/bin/docker-compose -f /opt/harbor/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /opt/harbor/docker-compose.yml down
#Restart=always
[Install]
WantedBy=multi-user.target

I start de Unit and after I receive this status:
# systemctl start harbor
# systemctl status harbor
● harbor.service - Servico de manutencao do Harbor
Loaded: loaded (/etc/systemd/system/harbor.service; disabled; vendor preset: disabled)
Active: active (running) since Mon 2016-12-19 20:09:44 BRST; 16min ago
Main PID: 2028 (docker-compose)
Memory: 34.3M
CGroup: /system.slice/harbor.service
├─2028 /usr/local/bin/docker-compose -f /opt/harbor/docker-compose.yml up
└─2029 /usr/local/bin/docker-compose -f /opt/harbor/docker-compose.yml up

Everything is OK, all Dockers container running. I can stop the harbor service without any problem. But now I have two docker-compose process.

Is there normal? Could I have problems in Future with these two process? How to make service Unit file better for docker-compose?
Thanks.

kinquestion

Most helpful comment

Place following content to the /etc/systemd/system/[email protected]

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

[Service]
Restart=always

WorkingDirectory=/etc/docker/compose/%i

# Remove old containers, images and volumes
ExecStartPre=/usr/bin/docker-compose down -v
ExecStartPre=/usr/bin/docker-compose rm -fv
ExecStartPre=-/bin/bash -c 'docker volume ls -qf "name=%i_" | xargs docker volume rm'
ExecStartPre=-/bin/bash -c 'docker network ls -qf "name=%i_" | xargs docker network rm'
ExecStartPre=-/bin/bash -c 'docker ps -aqf "name=%i_*" | xargs docker rm'

# Compose up
ExecStart=/usr/bin/docker-compose up

# Compose down, remove containers and volumes
ExecStop=/usr/bin/docker-compose down -v

[Install]
WantedBy=multi-user.target

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

systemctl start docker-compose@myservice

See updates and other systemd tricks for docker here

All 16 comments

Hi!

I unfortunately do not have the systemd knowledge to help you here. I would recommend cross-posting your question on our community forums where I believe you'll be able to find more help.

thanks anyway.

@gunboe I can verify that this is correct. When docker-compose is run from the command line it still spawns to processes when looking at top

@gunboe I would try using this instead instead of Type simple

Type=oneshot
RemainAfterExit=yes

Here is what I am using ...

[Unit]
Description=myservice
Requires=docker.service
After=docker.service

[Service]
Restart=always

# Remove old containers, images and volumes
ExecStartPre=/usr/bin/docker-compose -f my.yml down -v
ExecStartPre=/usr/bin/docker-compose -f my.yml rm -v
ExecStartPre=-/bin/bash -c 'docker volume rm $(docker volume ls -q)'
ExecStartPre=-/bin/bash -c 'docker rmi $(docker images | grep "<none>" | awk \'{print $3}\')'
ExecStartPre=-/bin/bash -c 'docker rm -v $(docker ps -aq)'

# Compose up
ExecStart=/usr/bin/docker-compose -f my.yml up

# Compose down, remove containers and volumes
ExecStop=/usr/bin/docker-compose -f my.yml down -v

[Install]
WantedBy=multi-user.target

What did the trick in my case is setting the user

[Service]
Restart=always
User=myuser
ExecStart=/usr/bin/docker-compose -f my.yml up

UPDATE: I had to enable the service too systemctl enable my.service

Place following content to the /etc/systemd/system/[email protected]

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

[Service]
Restart=always

WorkingDirectory=/etc/docker/compose/%i

# Remove old containers, images and volumes
ExecStartPre=/usr/bin/docker-compose down -v
ExecStartPre=/usr/bin/docker-compose rm -fv
ExecStartPre=-/bin/bash -c 'docker volume ls -qf "name=%i_" | xargs docker volume rm'
ExecStartPre=-/bin/bash -c 'docker network ls -qf "name=%i_" | xargs docker network rm'
ExecStartPre=-/bin/bash -c 'docker ps -aqf "name=%i_*" | xargs docker rm'

# Compose up
ExecStart=/usr/bin/docker-compose up

# Compose down, remove containers and volumes
ExecStop=/usr/bin/docker-compose down -v

[Install]
WantedBy=multi-user.target

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

systemctl start docker-compose@myservice

See updates and other systemd tricks for docker here

For anyone coming here like myself wondering about the correct approach, you're better off using -d for docker-compose up to save on resources, and in that case this comment is the correct solution to use IMO

@mosquito Mad props (That's what the cool kids say, isn't it) for that modular script :+1: I think you might want to edit it to change the working directory, as some peeps might just copy-paste it to discover that it's writing into /etc.

@hickscorp I think you should change working directory in your docker-compose.yml

@mosquito Yep that's also an option.

On another note: I'm trying to get it to work, but it doesn't for me. Whether I enable or start it via sudo systemctl start docker-compose@drone, it errors with Failed to start [email protected]: Unit [email protected] not found.

EDIT: I know the file has to be renamed, I'm trying to point out that it should be clearer in the proposed solution ;)

@hickscorp so... I add the header to the comment. 😅

@mosquito Shouldn't you use -r (--no-run-if-empty) as an xargs option, so that it won't pollute the journal with the usage info in the case that the container doesn't have an image, volume or network?

@mosquito Shouldn't you use -r (--no-run-if-empty) as an xargs option, so that it won't pollute the journal with the usage info in the case that the container doesn't have an image, volume or network?

@TheDauthi I would personally opt to leave it in in the event that there was an issue with either the service or the docker commands at launch, especially with Restart=always.

The best way I have setup it:

# /etc/systemd/system/harbor.service
[Unit]
Description=Harbor Service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
StandardError=null
StandardOutput=null
WorkingDirectory=/opt/Harbor-Serpro/harbor-v1.7.4
ExecStart=/usr/local/bin/docker-compose -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.notary.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.clair.yml up -d
ExecStop=/usr/local/bin/docker-compose -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.notary.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.clair.yml down

[Install]
WantedBy=multi-user.target

Enjoy yourself!

The best way I have setup it:

# /etc/systemd/system/harbor.service
[Unit]
Description=Harbor Service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
StandardError=null
StandardOutput=null
WorkingDirectory=/opt/Harbor-Serpro/harbor-v1.7.4
ExecStart=/usr/local/bin/docker-compose -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.notary.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.clair.yml up -d
ExecStop=/usr/local/bin/docker-compose -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.notary.yml -f /opt/Harbor-Serpro/harbor-v1.7.4/docker-compose.clair.yml down

[Install]
WantedBy=multi-user.target

Enjoy yourself!

I am googled this post for Habor. So lucky!

Was this page helpful?
0 / 5 - 0 ratings