Install Inmanta with Podman and Systemd

This page explains how to setup an Inmanta orchestration server using Podman and Systemd. This guide assumes you already have Podman installed on your machine and that you are running a Linux distribution using Systemd.

Note

The instructions below will show you how to install the orchestrator, and make the orchestrator run as a non-root user on the host. To achieve this you can either follow the rootless instructions (User setup), running them as a simple user without elevated privileged, or as root (Root setup). If you follow the latter, make sure to create a system user that we will use to run the orchestrator process. We will assume in the next steps that such system user is named inmanta and its HOME folder is /var/lib/inmanta.

Podman configuration

Follow the Podman documentation to make sure that:

  1. The user that will run the orchestrator (your unprivileged user, or the inmanta system user) has a range of subuids and subgids available to use. You can check it is the case running those commands:

    $ podman unshare cat /proc/self/uid_map
            0       1000          1
            1     524288      65536
    $ podman unshare cat /proc/self/gid_map
            0       1000          1
            1     524288      65536
    
    # sudo -i -u inmanta -- podman unshare cat /proc/self/uid_map
            0        976          1
            1    1000000      65536
    # sudo -i -u inmanta -- podman unshare cat /proc/self/gid_map
            0        975          1
            1    1000000      65536
    

    If it is not the case, you can set these up following the podman documentation referred above.

  2. The user that will run the orchestrator has the runRoot folder configured as follow.

    $ podman info | grep runRoot
      runRoot: /run/user/1000/containers
    

    The value 1000 should match the id of your user.

    $ id -u
    1000
    
    # sudo -i -u inmanta -- podman info | grep runRoot
      runRoot: /run/inmanta/containers
    

    We overwrite the default value that podman will set for this system user for two reasons:

    1. The default values it picks depends on the way you used podman for the first time with this user.

    2. The default values it picks will contain the id of the inmanta user in its path, which we don’t want to make any assumption about in the next steps.

    You can change this value by updating the file at /var/lib/inmanta/.config/containers/storage.conf, making sure this entry is in the configuration:

    [storage]
    runroot = "/run/inmanta/containers"
    

    Then create the folder and reset podman.

    # mkdir -p /run/inmanta
    # chown -R inmanta:inmanta /run/inmanta
    # sudo -i -u inmanta -- podman system reset -f
    A "/var/lib/inmanta/.config/containers/storage.conf" config file exists.
    Remove this file if you did not modify the configuration.
    

Pull the image

Use podman pull to get the desired image:

$ podman pull ghcr.io/inmanta/orchestrator:latest
# sudo -i -u inmanta -- podman pull ghcr.io/inmanta/orchestrator:latest

This command will pull the latest version of the Inmanta OSS Orchestrator image.

Prepare the orchestrator configuration

  1. Get the default configuration file:

    As of now, the container cannot be configured with environment variables, we should use a configuration file, mounted inside the container. To do this, you can get the current configuration file from the container, edit it, and mount it where it should be in the container.

    Let’s create a file on the host at ~/.config/inmanta/inmanta.cfg. We can take as template the default file already packaged in our container image.

    $ mkdir -p ~/.config/inmanta
    $ podman run --rm ghcr.io/inmanta/orchestrator:latest cat /etc/inmanta/inmanta.cfg > ~/.config/inmanta/inmanta.cfg
    

    Let’s create a file on the host at /etc/inmanta/inmanta.cfg. We can take as template the default file already packaged in our container image.

    # mkdir -p /etc/inmanta
    # chown -R inmanta:inmanta /etc/inmanta
    # sudo -i -u inmanta -- podman run --rm ghcr.io/inmanta/orchestrator:latest cat /etc/inmanta/inmanta.cfg | sudo -i -u inmanta -- tee /etc/inmanta/inmanta.cfg
    
  2. Update database settings:

    It is very unlikely that your database setup will match the one described in the default config we just got. Update the configuration in the [database] section to reflect the setup you have.

    Note

    The setup described here assumes you already have a PostgreSQL instance available that the orchestrator can use for its persistent storage. If it is not the case, please jump to the end of this document, where we explain to you how to easily deploy a database using Postman and Systemd.

  3. Make sure that there is a folder on your host that can persist all the logs of the server and that it is owned by the user running the orchestrator service.

    In this setup, the log folder on the host will be ~/.local/share/inmanta-orchestrator-server/logs.

    $ mkdir -p ~/.local/share/inmanta-orchestrator-server/logs
    

    In this setup, the log folder on the host will be /var/log/inmanta.

    # mkdir -p /var/log/inmanta
    # chown -R inmanta:inmanta /var/log/inmanta
    

    Warning

    Inside of the container, this folder will be mounted at /var/log/inmanta as it is the default location where the orchestrator saves its logs. This location is configurable in the orchestrator configuration file. If you for any reason would change this location in the configuration, make sure to update any usage of the /var/log/inmanta folder in the next installation steps.

Start the server with systemd

Here is a systemd unit file that can be used to deploy the server on your machine.

[Unit]
Description=Podman
Documentation=https://docs.inmanta.com
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
        --cidfile=%t/%n.ctr-id \
        --cgroups=no-conmon \
        --sdnotify=conmon \
        -d \
        --replace \
        --publish=127.0.0.1:8888:8888 \
        --uidmap=997:0:1 \
        --uidmap=0:1:997 \
        --uidmap=998:998:64539 \
        --gidmap=995:0:1 \
        --gidmap=0:1:995 \
        --gidmap=996:996:64541 \
        --name=inmanta-orchestrator-server \
        --volume=%E/inmanta/inmanta.cfg:/etc/inmanta/inmanta.cfg:z \
        --volume=%h/.local/share/inmanta-orchestrator-server/logs:/var/log/inmanta:z \
        --entrypoint=/usr/bin/inmanta \
        --user=997:995 \
        ghcr.io/inmanta/orchestrator:latest \
        --log-file /var/log/inmanta/server.log --log-file-level 2 --timed-logs server
ExecStop=/usr/bin/podman stop \
        --ignore -t 10 \
        --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
        -f \
        --ignore -t 10 \
        --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target

You can paste this configuration in a file named inmanta-orchestrator-server.service in the systemd folder for your user. This folder is typically ~/.config/systemd/user/.

[Unit]
Description=Podman
Documentation=https://docs.inmanta.com
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/inmanta/containers

[Service]
User=inmanta
Group=inmanta
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
        --cidfile=/run/inmanta/%n.ctr-id \
        --cgroups=no-conmon \
        --sdnotify=conmon \
        -d \
        --replace \
        --publish=127.0.0.1:8888:8888 \
        --uidmap=997:0:1 \
        --uidmap=0:1:997 \
        --uidmap=998:998:64539 \
        --gidmap=995:0:1 \
        --gidmap=0:1:995 \
        --gidmap=996:996:64541 \
        --name=inmanta-orchestrator-server \
        --volume=/etc/inmanta/inmanta.cfg:/etc/inmanta/inmanta.cfg:z \
        --volume=/var/log/inmanta:/var/log/inmanta:z \
        --entrypoint=/usr/bin/inmanta \
        --user=997:995 \
        ghcr.io/inmanta/orchestrator:latest \
        --log-file /var/log/inmanta/server.log --log-file-level 2 --timed-logs server
ExecStop=/usr/bin/podman stop \
        --ignore -t 10 \
        --cidfile=/run/inmanta/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
        -f \
        --ignore -t 10 \
        --cidfile=/run/inmanta/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target

You can paste this configuration in a file named inmanta-orchestrator-server.service in the systemd folder /etc/systemd/system.

Note

In the configuration above, you can observe that the usage of the --uidmap and --gidmap options. We use them three times to do the following:
  1. Map the user 997 inside of the container (the container’s inmanta user) to the user 0 in the podman user namespace. This user 0 in the user namespace is actually itself mapped to the user running the podman run command on the host.

  2. Map all users from 0 to 65536 (except for 997) inside of the container to subids of the host user running the container.

This allow us to easily share files between the host user and the inmanta user inside the container, avoiding any ownership conflict as they are then the same user (just seen from a different user namespace). Strictly speaking, if the image is already pulled on the host, you might get away with mapping only the inmanta (--uidmap=997:0:1 --gidmap=995:0:1) and the root (--uidmap=0:1:1 --gidmap=0:1:1) user and group inside of the container. But you would face issue if the container image was deleted from your host and the run command in the unit file tried to automatically pull the image, as the container image does contain a lot more users and groups than inmanta and root in its filesystem.

Once the systemd unit files are in place, make sure to enable them and reload the systemctl daemon.

$ systemctl --user daemon-reload
$ systemctl --user enable inmanta-orchestrator-server.service
# systemctl daemon-reload
# systemctl enable inmanta-orchestrator-server.service

Then start the container by running the following command:

$ systemctl --user start inmanta-orchestrator-server.service
# systemctl start inmanta-orchestrator-server.service

You should be able to reach the orchestrator at this address: http://127.0.0.1:8888 on the host.

Setting environment variables

You might want your inmanta server to be able to use some environment variables. You can set the environment variables by updating your Systemd unit file, relying on the --env/--env-file options of the podman run command. Those variables will be accessible to the inmanta server, the compiler and any agent started by the server.

Log rotation

By default, the container won’t do any log rotation, we let you the choice of dealing with the logs according to your own preferences. We recommend you to setup some log rotation, for example using a logrotate service running on your host.

Deploy postgresql with podman and systemd

  1. Pull the postgresql image from dockerhub.

    $ podman pull docker.io/library/postgres:16
    
  2. Create a podman network for your database and the orchestrator.

    $ podman network create --subnet 172.42.0.0/24 inmanta-orchestrator-net
    
  3. Create a systemd unit file for your database, let’s name it ~/.config/systemd/user/inmanta-orchestrator-db.service.

    [Unit]
    Description=Podman
    Documentation=https://docs.inmanta.com
    Wants=network-online.target
    After=network-online.target
    RequiresMountsFor=%t/containers
    
    [Service]
    Environment=PODMAN_SYSTEMD_UNIT=%n
    Restart=on-failure
    TimeoutStopSec=70
    ExecStart=/usr/bin/podman run \
            --cidfile=%t/%n.ctr-id \
            --cgroups=no-conmon \
            --sdnotify=conmon \
            -d \
            --replace \
            --network=inmanta-orchestrator-net:ip=172.42.0.2 \
            --uidmap=999:0:1 \
            --uidmap=0:1:999 \
            --uidmap=1000:1000:64537 \
            --gidmap=999:0:1 \
            --gidmap=0:1:999 \
            --gidmap=1000:1000:64537 \
            --name=inmanta-orchestrator-db \
            --volume=%h/.local/share/inmanta-orchestrator-db/data:/var/lib/postgresql/data:z \
            --env=POSTGRES_USER=inmanta \
            --env=POSTGRES_PASSWORD=inmanta \
            docker.io/library/postgres:16
    ExecStop=/usr/bin/podman stop \
            --ignore -t 10 \
            --cidfile=%t/%n.ctr-id
    ExecStopPost=/usr/bin/podman rm \
            -f \
            --ignore -t 10 \
            --cidfile=%t/%n.ctr-id
    Type=notify
    NotifyAccess=all
    
    [Install]
    WantedBy=default.target
    
  4. Create the folder that will contain the persistent storage for the database: ~/.local/shared/inmanta-orchestrator-db/data.

    $ mkdir -p ~/.local/share/inmanta-orchestrator-db/data
    
  5. Reload the systemd daemon, enable the service, and start it.

    $ systemctl --user daemon-reload
    $ systemctl --user enable inmanta-orchestrator-db.service
    $ systemctl --user start inmanta-orchestrator-db.service
    
  6. In the unit file of the orchestrator (as described here), make sure to attach the orchestrator container to the network the database is a part of, using the --network option of the podman run command.

  7. Don’t forget to update the ip address of the database in the inmanta server configuration file (~/.config/inmanta/inmanta.cfg)!

For a proper install of postgres on your host system as root, please refer to the postgres documentation regarding your operating system.