Unix: add podman quadlet blog

This commit is contained in:
Akemi Izuko 2024-11-17 14:47:01 -07:00
parent 13136e302d
commit b6af976671
Signed by: akemi
GPG key ID: 8DE0764E1809E9FC

View file

@ -0,0 +1,215 @@
---
title: 'Docker -> Podman + Quadlet'
description: 'Moving from Docker Compose to Podman with Quadlet'
updateDate: 'Nov 17 2024'
---
Containers are light-weight virtual machines, often used to run isolated
services on a server. They (typically) use the host kernel and don't virtualise
resources, leading to higher performance with minimal overhead compared to
traditional virtual machines (like qemu).
[Docker](https://en.wikipedia.org/wiki/Docker_(software)) is the most widely
used container and has been at the head of the industry for a while. It uses a
daemon run by the root user to start its containers. This has long been a
security concern, as a malicious entity that [breaks out of the container](
https://pwning.systems/posts/escaping-containers-for-fun/) will have root access
to the system!
[Podman](https://www.redhat.com/en/topics/containers/what-is-podman), a tool
developed by Redhat, is quite similar to docker but crucially doesn't require a
daemon to run. This means unprivileged users can still get the benefits of
containerization! Docker has recently been experimenting with a similar
["rootless mode"](https://docs.docker.com/engine/security/rootless/), but it's
not nearly at feature parity. Further, since Podman is developed by Redhat, it
integrates with other Redhat projects very nicely, like systemd,
[nftables](https://wiki.archlinux.org/title/Nftables), and
[cockpit](https://wiki.archlinux.org/title/Cockpit).
## Summary
In this blog, we'll look at migrating an existing Docker Compose service to
Podman! We'll cover setting up our new Podman service with systemd's Quadlet
integration with a new unprivileged user.
Prerequisites:
- A computer with linux (root access required, if you want to make a new user)
Optional:
- Root access, if you'd like to make a new user
- An existing Docker Compose service. You can use the one in this tutorial too
I'm using archlinux for this example, but any systemd-based linux will work
(Ubuntu, Debian, Fedora, Redhat...). You might need to change a few of the
user-creating commands on other systems.
## New User
We will assume 2 users:
- `emily` is an existing sudoer who's running a Docker Compose service
- `kate` will be a new unprivileged user who will run our Podman Quadlet
Start by logging into `root` and setting up `kate` (optional if you want to use
`emily` to host your Quadlet):
```bash
sudo su -
useradd --create-home --shell /bin/bash kate
passwd kate # Set some sort of password
```
For Podman, we'll need to give `kate` a range of sub-ids, which the container
can use to differentiate users, while still all being `kate`:
```bash
cat /etc/subuid
cat /etc/subgid
# Based on output of above, find a range of 65536 ids which aren't overlapping
# with another user. For example, here we use 30000
usermod --add-subuids 70000-135536 --add-subgids 70000-135536 kate
```
Assuming we don't typically use the `kate` user, we also want to make sure our
containers aren't killed once we logout of `kate`:
```bash
loginctl enable-linger kate
```
Podman is also quite sensitive to XDG environment variables. Make sure you have
them setup properly. For example:
```bash
cat <<FILE >> /home/kate/.bashrc
export XDG_CONFIG_HOME=~/.config
export XDG_CACHE_HOME=~/.cache
export XDG_DATA_HOME=~/.local/share
export XDG_STATE_HOME=~/.local/state
export XDG_DATA_DIRS='/usr/local/share:/usr/share'
export XDG_CONFIG_DIRS='/etc/xdg'
export XDG_RUNTIME_DIR="/run/user/$(id -u kate)"
FILE
chown kate:kate /home/kate/.bashrc
```
Now to make sure that worked:
```bash
su -l kate
podman ps # This shouldn't give any warnings, just a blank table
podman info | grep rootless # This should give a line like "rootless: true"
```
## Migrating Docker Compose to Podman + Quadlet
Consider this docker-compose.yml:
```yaml
services:
open-webui:
image: ghcr.io/open-webui/open-webui:v0.3.35
restart: unless-stopped
environment:
OPENAI_API_BASE_URLS: https://api.mistral.ai/v1
OPENAI_API_KEYS: <key>
ports:
- "9130:8080"
volumes:
- type: bind
source: ./data
target: /app/backend/data
```
We could covert this to a simple Podman bash script. It's a good idea to try
this step as `kate` before proceeding. Notice that `kate` will need her own
`./data` directory. Try running this as `kate`:
```bash
#!/usr/bin/env bash
podman run \
--rm \
--name open-webui \
-e OPENAI_API_BASE_URLS="https://api.mistral.ai/v1" \
-e OPENAI_API_KEYS="<key>" \
-p 9130:8080 \
-v ./data:/app/backend/data \
ghcr.io/open-webui/open-webui:v0.3.35
```
A Quadlet file is similar to a systemd unit file, but describes the same things
as a docker-compose.yml:
```ini
[Unit]
Description=Open WebUI container
Wants=network-online.target
After=network-online.target
After=local-fs.target
[Container]
ContainerName=open-webui
Image=ghcr.io/open-webui/open-webui:v0.3.35
Environment=OPENAI_API_BASE_URLS="https://api.mistral.ai/v1"
Environment=OPENAI_API_KEYS="<key>"
PublishPort=9130:8080/tcp
Volume=/home/kate/Documents/servers/openwebui/data:/app/backend/data
[Service]
Restart=on-failure
TimeoutStartSec=900
[Install]
WantedBy=default.target
```
In this case, I put my Quadlet file at
`/home/kate/Documents/servers/openwebui/openwebui.container`. I put a
corresponding `/home/kate/Documents/servers/openwebui/data` directory to mount
in the container.
See [Erick Patrick's repository](https://github.com/fpatrick/podman-quadlet) for
a great Quadlet template with all the important options!
Quadlet files for a user should be at `~/.config/containers/systemd/`. To be a
bit more organized, we'll simply symlink our container out of
`~/Documents/servers` to here:
```bash
ln -s /home/kate/Documents/servers/openwebui/openwebui.container /home/kate/.config/containers/systemd/
```
## Running Quadlets
Use `kate` to test if our Quadlet is working:
```
/usr/lib/podman/quadlet -dryrun -user
```
This should print out a file it calls `openwebui.service`. It looks similar to
our `openwebui.container`, but added more to the `[Service]` section and added a
`[X-Container]` section. Quadlet essentially converts our `.container` files to
systemd `.service` files, so that systemd can run them normally. Let's try it!
Refresh your daemon:
```bash
systemctl --user daemon-reload
```
Now check the status:
```bash
systemctl --user status openwebui.service
```
We can start it just like any other systemd service:
```bash
systemctl --user enable --now openwebui.service
```
Then, the analog to `docker log` is `journalctl --user -fu openwebui.service`!