Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add systemd service files #307

Open
tinywrkb opened this issue Jun 17, 2021 · 16 comments
Open

add systemd service files #307

tinywrkb opened this issue Jun 17, 2021 · 16 comments

Comments

@tinywrkb
Copy link

tinywrkb commented Jun 17, 2021

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/.

@mathstuf
Copy link

mathstuf commented Feb 1, 2022

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

@muayyad-alsadi
Copy link
Collaborator

the latest push
80e8527

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
Copy link
Collaborator

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
Copy link
Collaborator

muayyad-alsadi commented Mar 8, 2022

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
Copy link
Collaborator

@tinywrkb your feedback is highly appreciated

@tinywrkb
Copy link
Author

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.

@muayyad-alsadi
Copy link
Collaborator

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.

@tinywrkb
Copy link
Author

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.

@kronenpj
Copy link

kronenpj commented Apr 30, 2022

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 ...?

@yogo1212
Copy link

yogo1212 commented Sep 25, 2022

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

@tinywrkb
Copy link
Author

tinywrkb commented Sep 25, 2022

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.

@alexmaras
Copy link

@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.

@muayyad-alsadi
Copy link
Collaborator

muayyad-alsadi commented Apr 21, 2023

We ship systemd unit files

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

@alexmaras
Copy link

alexmaras commented Apr 21, 2023

@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 7f5ce26. 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.

@yogo1212
Copy link

@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 🤠 🏳️

@alechirsch
Copy link

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants