podman-compose icon indicating copy to clipboard operation
podman-compose copied to clipboard

add systemd service files

Open tinywrkb opened this issue 4 years ago • 9 comments

It would be great if podman-compose could be shipped with systems services files.

I'm attaching my systemd service files. They are pretty basic, probably need to be improved so I'm not adding these myself in a PR, but they are working for me.

/usr/lib/systemd/system/[email protected]

[Unit]
Description=%i rootful pod (podman-compose)
After=network-online.target
Wants=network-online.target

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

[Install]
WantedBy=multi-user.target

/usr/lib/systemd/user/[email protected]

[Unit]
Description=%i rootless pod (podman-compose)

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=%h/.config/containers/compose/%i
ExecStart=/usr/bin/podman-compose up -d --remove-orphans
ExecStop=/usr/bin/podman-compose down

[Install]
WantedBy=default.target

Previously I was using environment file in /etc/conf.d to set the compose file, but now that podman-compose defaults prioritize compose.yaml and compose.yml, I don't see a reason why we need this configurable.

If it's not obvious, each pod should have a folder in /etc/containers/compose/ ~~and~~ (edit:) or ~/.config/containers/compose/.

tinywrkb avatar Jun 17 '21 14:06 tinywrkb

I feel like podman pod has this now. Maybe the ability to create a pod from a compose file would be useful?

mathstuf avatar Feb 01 '22 23:02 mathstuf

the latest push 80e852717d9598ed95dd54b9c7b0ba7c99b6b5f5

creates a pod and put containers in it and passes proper dependencies --requires so podman pod start pod_<project_name> will work fine.

please test that commit

muayyad-alsadi avatar Feb 15 '22 00:02 muayyad-alsadi

for this compose

https://github.com/containers/podman-compose/blob/devel/tests/testlogs/docker-compose.yml

running podman generate systemd --new --name pod_testlogs

# container-testlogs_loop1_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:08:21 EET 2022

[Unit]
Description=Podman container-testlogs_loop1_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-pod_testlogs.pod-id --sdnotify=conmon --replace --name=testlogs_loop1_1 -d --label io.podman.compose.config-hash=123 --label io.podman.compose.project=testlogs --label io.podman.compose.version=0.0.1 --label com.docker.compose.project=testlogs --label com.docker.compose.project.working_dir=/home/alsadi/proj/podman-compose/tests/testlogs --label com.docker.compose.project.config_files=docker-compose.yml --label com.docker.compose.container-number=1 --label com.docker.compose.service=loop1 --net testlogs_default --network-alias loop1 busybox /bin/sh -c "for i in `seq 1 10000`; do echo \"loop1: $$i\"; sleep 1; done"
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target default.target
# pod-pod_testlogs.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:08:21 EET 2022

[Unit]
Description=Podman pod-pod_testlogs.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=
Requires=container-testlogs_loop1_1.service container-testlogs_loop2_1.service container-testlogs_loop3_1.service
Before=container-testlogs_loop1_1.service container-testlogs_loop2_1.service container-testlogs_loop3_1.service

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/pod-pod_testlogs.pid %t/pod-pod_testlogs.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-pod_testlogs.pid --pod-id-file %t/pod-pod_testlogs.pod-id --name=pod_testlogs --share= --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-pod_testlogs.pod-id
ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-pod_testlogs.pod-id -t 10
ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-pod_testlogs.pod-id
PIDFile=%t/pod-pod_testlogs.pid
Type=forking

[Install]
WantedBy=multi-user.target default.target
# container-testlogs_loop2_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:08:21 EET 2022

[Unit]
Description=Podman container-testlogs_loop2_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-pod_testlogs.pod-id --sdnotify=conmon --replace --name=testlogs_loop2_1 -d --label io.podman.compose.config-hash=123 --label io.podman.compose.project=testlogs --label io.podman.compose.version=0.0.1 --label com.docker.compose.project=testlogs --label com.docker.compose.project.working_dir=/home/alsadi/proj/podman-compose/tests/testlogs --label com.docker.compose.project.config_files=docker-compose.yml --label com.docker.compose.container-number=1 --label com.docker.compose.service=loop2 --net testlogs_default --network-alias loop2 busybox /bin/sh -c "for i in `seq 1 10000`; do echo \"loop2: $$i\"; sleep 3; done"
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target default.target
# container-testlogs_loop3_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:08:21 EET 2022

[Unit]
Description=Podman container-testlogs_loop3_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStartPre=/bin/rm -f %t/%n.ctr-id
ExecStart=/usr/bin/podman run --cidfile=%t/%n.ctr-id --cgroups=no-conmon --rm --pod-id-file %t/pod-pod_testlogs.pod-id --sdnotify=conmon --replace --name=testlogs_loop3_1 -d busybox /bin/sh -c "for i in `seq 1 10000`; do echo \"loop3: $$i\"; sleep 3; done"
ExecStop=/usr/bin/podman stop --ignore --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm -f --ignore --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target default.target

without --new

# pod-pod_testlogs.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:11:22 EET 2022

[Unit]
Description=Podman pod-pod_testlogs.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=
Requires=container-testlogs_loop1_1.service container-testlogs_loop2_1.service container-testlogs_loop3_1.service
Before=container-testlogs_loop1_1.service container-testlogs_loop2_1.service container-testlogs_loop3_1.service

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start e8f34acbcfce-infra
ExecStop=/usr/bin/podman stop -t 10 e8f34acbcfce-infra
ExecStopPost=/usr/bin/podman stop -t 10 e8f34acbcfce-infra
PIDFile=/run/user/1000/overlay-containers/ef5bf3551aa8ca1bf4937259026e678d150c9031697d2ffa83715e9dbdbefd8e/userdata/conmon.pid
Type=forking

[Install]
WantedBy=multi-user.target default.target
# container-testlogs_loop2_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:11:22 EET 2022

[Unit]
Description=Podman container-testlogs_loop2_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start testlogs_loop2_1
ExecStop=/usr/bin/podman stop -t 10 testlogs_loop2_1
ExecStopPost=/usr/bin/podman stop -t 10 testlogs_loop2_1
PIDFile=/run/user/1000/overlay-containers/19a1ffdc6d4ff0c0dcd51637de42ad5f7f0e439c9d711b397bee82d7ea0d7d42/userdata/conmon.pid
Type=forking

[Install]
WantedBy=multi-user.target default.target
# container-testlogs_loop3_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:11:22 EET 2022

[Unit]
Description=Podman container-testlogs_loop3_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start testlogs_loop3_1
ExecStop=/usr/bin/podman stop -t 10 testlogs_loop3_1
ExecStopPost=/usr/bin/podman stop -t 10 testlogs_loop3_1
PIDFile=/run/user/1000/overlay-containers/32ef151142f1096c29f81ae2263d78ee0c1e884879c714a754cd6ea028d35fcf/userdata/conmon.pid
Type=forking

[Install]
WantedBy=multi-user.target default.target
# container-testlogs_loop1_1.service
# autogenerated by Podman 3.4.2
# Thu Feb 17 17:11:22 EET 2022

[Unit]
Description=Podman container-testlogs_loop1_1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start testlogs_loop1_1
ExecStop=/usr/bin/podman stop -t 10 testlogs_loop1_1
ExecStopPost=/usr/bin/podman stop -t 10 testlogs_loop1_1
PIDFile=/run/user/1000/overlay-containers/f3e7af7caff32a9c7cc1459bcdf885223ad20a9dacc1be9a28ba03a33f0713ad/userdata/conmon.pid
Type=forking

[Install]
WantedBy=multi-user.target default.target

muayyad-alsadi avatar Feb 17 '22 15:02 muayyad-alsadi

run

sudo podman-compose systemd --action create-unit

to create /etc/systemd/user/[email protected]

now enter your project and type

podman-compose systemd --action register

now at any directory, you can type

systemctl --user enable --now podman-compose@<PROJECT>
systemctl --user start podman-compose@<PROJECT>
systemctl --user status podman-compose@<PROJECT>
systemctl --user stop podman-compose@<PROJECT>

muayyad-alsadi avatar Mar 08 '22 21:03 muayyad-alsadi

@tinywrkb your feedback is highly appreciated

muayyad-alsadi avatar Mar 12 '22 20:03 muayyad-alsadi

Sorry for the late reply.

  1. It should be possible to set a different root filesystem target when creating the unit with podman-compose systemd --action create-unit.
    My system is immutable, meaning /usr is read-only, so I would like to be able to package the generated unit.
    A--root option should solve this, and the expected value during packaging would be similar todestdir's value of the installation target of the buildsystem. I expect that I would need to set PYTHONPATH to $destdir/lib/python-$pyver/site-packages in order to be able to run podman-compose systemd when packaging podman-compose. The alternative is to generate the unit during build time, and install it with the default installation target.
    If the create-unit action is expected to be called the by user during run-time, not when packaging podman-compose, then by default it should create the unit in ~/.config/systemd/user.
  2. A system unit is missing.
    Most of my containers are rootful, as rootless is not always practical. For example, some images were designed to run as rootful. Systemd 250 broke idmapping for systemd-homed users.

tinywrkb avatar Mar 20 '22 16:03 tinywrkb

My bad! Actually /usr/lib/systemd/ is meant for package manager owned units not admin generated units. I'll change it to /etc/systemd

If the create-unit action is expected to be called the by user during run-time, not when packaging podman-compose, then by default it should create the unit in ~/.config/systemd/user.

It should be done once.

muayyad-alsadi avatar Mar 21 '22 04:03 muayyad-alsadi

My bad! Actually /usr/lib/systemd/ is meant for package manager owned units not admin generated units. I'll change it to /etc/systemd

For the user service, during run-time (not while packaging), I think it's more appropriate to put the service into ~/.config/systemd/user. This will allow creating the service by a non-root user without privilege escalation, which might not be allowed for the user.
A --global command-line option should change this default, and create the service in /etc/systemd/user.

tinywrkb avatar Mar 25 '22 12:03 tinywrkb

For the user service, during run-time (not while packaging), I think it's more appropriate to put the service into ~/.config/systemd/user. This will allow creating the service by a non-root user without privilege escalation, which might not be allowed for the user. A --global command-line option should change this default, and create the service in /etc/systemd/user.

Or perhaps add a --user option, consistent with systemd --user start ...?

kronenpj avatar Apr 30 '22 15:04 kronenpj

Hi :-)

The systemd unit files posted here are used by a lot of people. It is kind of official and peope are seen using it all over the internet in forum posts and SO questions.

But it has a big problem: RemainAfterExit. Systemd won't know when the service terminates with an error and any Restart related logic won't work. If the service dies for any reason (oom-killer, for instance), systemd won't bring it back up. I could even stop or bring down the container myself and systemd would still think it's running.

Setting Type=simple and removing the -d would work - if ExecStop worked (which it doesn't, in my experience).

I use a small wrapper script:

#!/bin/sh

podman-compose up "$@" &
pid=$!

trap "kill -s TERM '$pid'" TERM
trap "kill -s INT '$pid'" INT

wait

podman-compose down -t "${COMPOSE_DOWN_TIMEOUT-80}"

Service file for completeness:

[Unit]
Description=%i service with podman compose
After=network.target

[Service]
Type=simple
WorkingDirectory={{ podman_compose_dir }}/%i
Environment=COMPOSE_DOWN_TIMEOUT=30
ExecStart=/usr/bin/wrap_compose_up --build --remove-orphans --abort-on-container-exit
TimeoutStopSec=40
Restart=always
RestartSec=10

[Install]
WantedBy=default.target

That's the best I have atm. I've given up trying to add an --bring-down-on-exit - here's the last state on that.

EDIT: added fix from @alexmaras

yogo1212 avatar Sep 25 '22 12:09 yogo1212

It is kind of official and peope are seen using it all over the internet in forum posts and SO questions.

Well..., it's not in any way official, and I'm not affiliated with this project in any way. People should not copy-paste code or config files without understanding how it will affect their system.
These users should instead try to improve and fit the services to their needs, like you're trying to do here.

As I mentioned in my first post when I filed this ticket, these systemd service files are basic, and I can add here and say that I put minimal effort when constructing them.
I posted them here to start a discussion about adding and distributing service files with this project, and try to refine and improve them.

But it has a big problem: RemainAfterExit. Systemd won't know when the service terminates with an error and any Restart related logic won't work. If the service dies for any reason (oom-killer, for instance), systemd won't bring it back up. I could even stop or bring down the container myself and systemd would still think it's running.

Maybe switch the service type to forking, and get a PID file with from Podman with the podman run argument --pidfile=path. See --podman-run-args argument of podman-compose, PIDFile= option in man:systemd.service(5), and Instance name specifier in man:systemd.unit(5) for setting the PID file name.

tinywrkb avatar Sep 25 '22 20:09 tinywrkb

@yogo1212 your script has an issue - it uses $1 to try to get the PID, but that's getting --build from your passed args. It should be $! if you're trying to get the PID of the podman-compose up process.

alexmaras avatar Apr 21 '23 12:04 alexmaras

We ship systemd unit files

podman-compose help systemd
podman-compose systemd --action register
systemctl --user start|stop podman-compose@<PROJECT>

muayyad-alsadi avatar Apr 21 '23 13:04 muayyad-alsadi

@muayyad-alsadi I'm aware, I've tried using them. I hit issues similar to @yogo1212's, so I'm reworking that solution to make it reliable for me. I didn't want someone else to also try that code snippet and hit issues.

I'll file a separate issue with some reliability issues I have with the stock systemd unit files.

EDIT: Never mind, it looks like my issues will be solved by the default use of --in-pod=1 in https://github.com/containers/podman-compose/commit/7f5ce26b1b8103f48d5702dce7d52afe8b76daa5. SystemD unit files don't work properly on 1.0.6 in my experience because it brings the containers up without a pod, then the pod has zero containers and it fails to start.

alexmaras avatar Apr 21 '23 13:04 alexmaras

@alexmaras good point - thank you! tbh, i wrote that script directly into the comment because the script i'm using productively does a few more things than are relevant here :cowboy_hat_face: :white_flag:

yogo1212 avatar Apr 22 '23 11:04 yogo1212

@muayyad-alsadi The steps provided do not seem to work with the -f flag for providing a different compose file. I have some people using docker and some using podman, and the particular image (localstack) I am doing this for requires different setup for each. I can workaround this by moving files around during setup, but a functional -f flag would be appreciated.

alechirsch avatar May 09 '23 00:05 alechirsch