Podman rootless with systemd

Hi,

i having trouble to setup a container with podman rootless and systemd. I’m testing on Nixos unstable.

In root mode, my container is working

 virtualisation = {
        podman = {
            enable = true;
            dockerCompat = true;
            defaultNetwork.dnsname.enable = true;
        };
        oci-containers = {
            backend = "podman";
            containers.pgadmin = {
                image = "dpage/pgadmin4";
                autoStart = true;
                ports = [ "8084:80" ];
                environment = {
                    PGADMIN_DEFAULT_EMAIL = "user@domain.com";
                    PGADMIN_DEFAULT_PASSWORD = "SuperSecret";
                };
            };
        };
    };

But when adding the systemd user config to exec my container with a dedicated user, the service is failing

 ...
 users.users.pgadmin= {
     isNormalUser = true;
 };
 systemd.services.podman-pgadmin.serviceConfig.User = "pgadmin";
 ...

see the log

Nov 28 02:29:16 sdserver systemd[1]: Starting podman-pgadmin.service...
Nov 28 02:29:16 sdserver podman-pgadmin-pre-start[32056]: time="2022-11-28T02:29:16+01:00" level=warning msg="RunRoot is pointing to a path (/run/user/1003/containers) which i>
Nov 28 02:29:16 sdserver podman-pgadmin-pre-start[32056]: Error: creating tmpdir: mkdir /run/user/1003: permission denied
Nov 28 02:29:16 sdserver podman-pgadmin-pre-start[32069]: rm: cannot remove '/run/podman-pgadmin.ctr-id': Permission denied
Nov 28 02:29:16 sdserver systemd[1]: podman-pgadmin.service: Control process exited, code=exited, status=1/FAILURE
Nov 28 02:29:16 sdserver podman-pgadmin-post-stop[32071]: time="2022-11-28T02:29:16+01:00" level=warning msg="RunRoot is pointing to a path (/run/user/1003/containers) which i>
Nov 28 02:29:16 sdserver podman-pgadmin-post-stop[32071]: Error: creating tmpdir: mkdir /run/user/1003: permission denied
Nov 28 02:29:16 sdserver systemd[1]: podman-pgadmin.service: Control process exited, code=exited, status=125/n/a
Nov 28 02:29:16 sdserver systemd[1]: podman-pgadmin.service: Failed with result 'exit-code'.
Nov 28 02:29:16 sdserver systemd[1]: Failed to start podman-pgadmin.service.
Nov 28 02:29:17 sdserver systemd[1]: podman-pgadmin.service: Scheduled restart job, restart counter is at 5.
Nov 28 02:29:17 sdserver systemd[1]: Stopped podman-pgadmin.service.
Nov 28 02:29:17 sdserver systemd[1]: podman-pgadmin.service: Start request repeated too quickly.
Nov 28 02:29:17 sdserver systemd[1]: podman-pgadmin.service: Failed with result 'exit-code'.
Nov 28 02:29:17 sdserver systemd[1]: Failed to start podman-pgadmin.service.

So /run/user/1003/containers does not exists. What did i miss in my config ?

Thanks

2 Likes

I face the same problem. The core issue is that Podman services created with virtualisation.oci-containers.containers.<name> are installed as /etc/systemd/user/podman-<name>.service.

When you do that (systemd.services.podman-pgadmin.serviceConfig.User = "pgadmin";), one would expect podman-pgadmin.service to be run/executed by user pgadmin. But, for that to happen, the unit file for podman-pgadmin.service needs to be placed inside /home/pgadmin/.config/systemd/user (not in /etc/systemd/user/).

The current workaround is to manually write a systemd service by hand for every container that you want and manage it using home-manager. For containers to be truly rootless (in the same sense as it works on RHEL/Fedora), there should an oci-containers “module” inside home-manager too.

When you do that (systemd.services.podman-pgadmin.serviceConfig.User = “pgadmin”;), one would expect podman-pgadmin.service to be> run/executed by user pgadmin. But, for that to happen, the unit file for podman-pgadmin.service needs to be placed inside> home/pgadmin.config/systemd/user (not in etc/systemd/user).

That’s not correct.

In the first case it will be run by system systemd instance but running as user pgadmin and started by systemctl start podman-pgadmin. So run by root as pgadmin.

If placed inside /etc/systemd/user or /home/pgadmin/.config/systemd/user, it will be run by the user systemd instance and started by systemctl --user start podman-pgadmin when logged in as pgadmin. So by and as pgadmin.

1 Like

I misspoke. With systemd.services.<name>.serviceConfig.User, the unit file will be in /etc/systemd/system/ but the User field will be occupied with the value mentioned. The behaviour that I mentioned applies to systemd.user.services. My bad.


Doing a systemctl --user status podman-<name>.service (as the non-root user) gave me the error that the given service doesn’t exist for this user (Unit podman-<name>.service could not be found.). I also did a podman ps with this non-root user; that came up empty.

But then, I logged in as root (didn’t just prefix commands with sudo; I was logged in as root, in root’s shell) and ran systemctl status podman-<name>.service and got the details I would expect. I also did a podman ps and found out that the containers are running by the user root but also as the user root.

If you define a service through systemd.services.foo, that will run by the system systemd instance regardless of what you put into serviceConfig.User. Many system level services do this as you absolutely want to run as few things as possible as root.

1 Like

I found a workaround months ago.

As reminder, i wanted to :

  • start podman container at boot.
  • rootless container so run by simple user and NOT root
  • allow the user start/stop… the container

In the configuration.nix

    # create my user
    users.users."pgmadin" = {
        isNormalUser = true;
        uid = 1003;
    };

    # In order for our user to run containers automatically on boot, 
    # we need to enable systemd linger support.
    # This will ensure that a user manager is run for the user at boot and kept around after logouts.
    system.activationScripts = {
        enableLingering = ''
            # remove all existing lingering users
            rm -r /var/lib/systemd/linger
            mkdir /var/lib/systemd/linger
            # enable for the subset of declared users
            touch /var/lib/systemd/linger/pgadmin
        '';
    };

    virtualisation = {
        ## setup podman
        podman = {
            enable = true;
            dockerCompat = true;
            defaultNetwork.settings.dns_enable = true;
        };
        ## declare containers
        oci-containers = {
            ## use podman as default container engine
            backend = "podman";
        };
    };

    ## pgadmin container
    systemd.user.services.pgadmin = {
        enable = true;
        unitConfig = { ConditionUser = "pgadmin"; };
        wantedBy = [ "default.target" ];
        after = [ "network.target" ];
        description = "pgadmin container";
        path = [ "/run/wrappers" ];
        serviceConfig =
        let
            bash = "${pkgs.bash}/bin/bash";
            podmancli = "${config.virtualisation.podman.package}/bin/podman";
            podname = "pgadmin";
            image = "dpage/pgadmin4:6.19";
            cid = "%t/podman/%n.cid";
            pid = "%t/podman/%n.pid";
            startpre = [
                "${pkgs.coreutils-full}/bin/rm -f ${cid} ${pid}"
                "-${podmancli} stop --ignore ${podname}"
                "${podmancli} rm --force --ignore ${podname}"
            ];
            stoppost = [
                "${podmancli} stop --ignore ${podname}"
                "${podmancli} rm --force --ignore ${podname}"
                "${pkgs.coreutils-full}/bin/rm -f ${cid} ${pid}"
            ];
        in
        {
            ExecStartPre = startpre;
            ExecStart = "${podmancli} run " +
                "--rm " +
                "--replace " +
                "--name=${podname} " +
                "--conmon-pidfile=${pid} " +
                "--cidfile=${cid} " +
                "--cgroups=no-conmon " +
                "--sdnotify=conmon " +
                "--log-driver=journald " +
                "--name=${podname} " +
                "-p 127.0.0.1:5050:80 " +
                "-v pgadmin_data:/var/lib/pgadmin " +
                "-e PGADMIN_DEFAULT_EMAIL='admin@localhost.fr' "+
                "-e PGADMIN_DEFAULT_PASSWORD='pgadmin' "+
                "-d " +
                "${image}";
            ExecStop = "${podmancli} stop ${podname}";
            ExecStopPost = stoppost;
            Type = "notify";
            NotifyAccess = "all";
            Restart = "no";
            TimeoutStopSec = 70;
        };
    };

Then in the pgadmin session

# start user service
systemctl --user start pgadmin
# check status
systemctl --user status pgadmin
# it works so start at boot
systemclt --user enable pgadmin

This way only my user pgadmin can control the service and my podman container is rootless.

2 Likes