3

I have a systemd unit, that uses the command docker-compose to start and stop a given set of containers. It looks like this:

[Unit]
Description=...

[Service]

WorkingDirectory=/opt/tsc-docker

RemainAfterExit=true
ExecStart=/usr/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/bin/docker-compose down
Type=oneshot

[Install]
WantedBy=multi-user.target

It works mostly as expected. If I start this service, the containers come up and go down if I stop it.

What's missing - and what this question is about - is the ability to restart only some containers.

What I mean is, if I edit the docker-compose.yml and run the docker-compose up -d command, only the affected containers are recreated, instead of all of them.

The current unit configuration however doesn't give me the possibility to run systemctl start TscDocker again and have the affected containers recreated. Since the unit is already running, it just ignores my command. If I set RemainAfterExit=false, then the ExecStop command runs just after ExecStart, which is obviously not desirable.

What I need is the ability to start this service multiple times and have ExecStart run each time without ExecStop being run after each ExecStart.

What are my options, to create a configuration that checks all boxes?

1 Answers1

3

It sounds like you want to use a unstoppable oneshot service.. which would look like:

[Unit]
Description=...

[Service]

WorkingDirectory=/opt/tsc-docker

RemainAfterExit=false
ExecStart=/usr/bin/docker-compose up -d --remove-orphans
Type=oneshot

[Install]
WantedBy=multi-user.target

Which would allow you to start the service multiple times, as once your ExecStart finishes running, the service returns to an inactive state. Dealing with this fact would be the correct way to do this, as systemd's manpage specifies that you may not run multiple start commands in a stoppable one-shot service.

A dirty workaround to still be able to use ExecStop may be to use the ExecReload function like so

[Unit]
Description=...

[Service]

WorkingDirectory=/opt/tsc-docker

RemainAfterExit=true
ExecStart=/usr/bin/docker-compose up -d --remove-orphans
ExecReload=/usr/bin/docker-compose up -d --remove-orphans
ExecStop=/usr/bin/docker-compose down
Type=oneshot

[Install]
WantedBy=multi-user.target

As this is the only way to get a seperate command execution while your service is still considered active. You could then invoke this using

 systemctl reload TscDocker
ReedGhost
  • 443
  • 3
  • 7
  • very insightful, thank you – László Stahorszki Nov 03 '20 at 17:23
  • do you think your workaround is a "hack"? do I have any risks using this workaround? thinking something like when I run `systemctl daemon-reload` does the `ExecReload` get invoked? – László Stahorszki Nov 03 '20 at 17:24
  • 1
    According to [systemctl's manpage](https://man7.org/linux/man-pages/man1/systemctl.1.html) `systemctl daemon-reload` "Reload the systemd manager configuration. This will rerun all generators (see systemd.generator(7)), reload all unit files, and recreate the entire dependency tree." Meaning that you should **not** consider daemon-reload as a command that runs every unit's ExecReload directive. It's also worth noting that this was in the same paragraph `"This command should not be confused with the reload command"` So I think the workaround should be safe in that manner of speaking – ReedGhost Nov 03 '20 at 19:46