$ mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/containers/systemd
[Unit]
Description=Traefik whoami demo container
After=network-online.target
Wants=network-online.target [Container]
ContainerName=whoami
Image=-weight: 500;">docker.io/traefik/whoami:v1.10.1
AutoUpdate=registry
PublishPort=127.0.0.1:8080:80 [Service]
Restart=always
RestartSec=5
TimeoutStartSec=180 [Install]
WantedBy=default.target
[Unit]
Description=Traefik whoami demo container
After=network-online.target
Wants=network-online.target [Container]
ContainerName=whoami
Image=-weight: 500;">docker.io/traefik/whoami:v1.10.1
AutoUpdate=registry
PublishPort=127.0.0.1:8080:80 [Service]
Restart=always
RestartSec=5
TimeoutStartSec=180 [Install]
WantedBy=default.target
[Unit]
Description=Traefik whoami demo container
After=network-online.target
Wants=network-online.target [Container]
ContainerName=whoami
Image=-weight: 500;">docker.io/traefik/whoami:v1.10.1
AutoUpdate=registry
PublishPort=127.0.0.1:8080:80 [Service]
Restart=always
RestartSec=5
TimeoutStartSec=180 [Install]
WantedBy=default.target
-weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">enable --now whoami.-weight: 500;">service
-weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">enable --now whoami.-weight: 500;">service
-weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">enable --now whoami.-weight: 500;">service
-weight: 500;">systemctl --user -weight: 500;">status whoami.-weight: 500;">service
podman ps --filter name=whoami
-weight: 500;">curl -fsS http://127.0.0.1:8080
-weight: 500;">systemctl --user -weight: 500;">status whoami.-weight: 500;">service
podman ps --filter name=whoami
-weight: 500;">curl -fsS http://127.0.0.1:8080
-weight: 500;">systemctl --user -weight: 500;">status whoami.-weight: 500;">service
podman ps --filter name=whoami
-weight: 500;">curl -fsS http://127.0.0.1:8080
FROM python:3.12-slim
RUN -weight: 500;">apt-get -weight: 500;">update \ && -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends -weight: 500;">curl systemd \ && rm -rf /var/lib/-weight: 500;">apt/lists/*
RUN -weight: 500;">pip -weight: 500;">install --no-cache-dir flask
WORKDIR /app
COPY app.py /app/app.py
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
EXPOSE 8000
CMD ["/app/entrypoint.sh"]
FROM python:3.12-slim
RUN -weight: 500;">apt-get -weight: 500;">update \ && -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends -weight: 500;">curl systemd \ && rm -rf /var/lib/-weight: 500;">apt/lists/*
RUN -weight: 500;">pip -weight: 500;">install --no-cache-dir flask
WORKDIR /app
COPY app.py /app/app.py
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
EXPOSE 8000
CMD ["/app/entrypoint.sh"]
FROM python:3.12-slim
RUN -weight: 500;">apt-get -weight: 500;">update \ && -weight: 500;">apt-get -weight: 500;">install -y --no--weight: 500;">install-recommends -weight: 500;">curl systemd \ && rm -rf /var/lib/-weight: 500;">apt/lists/*
RUN -weight: 500;">pip -weight: 500;">install --no-cache-dir flask
WORKDIR /app
COPY app.py /app/app.py
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
EXPOSE 8000
CMD ["/app/entrypoint.sh"]
from flask import Flask
app = Flask(__name__) @app.get("/healthz")
def healthz(): return {"ok": True} @app.get("/")
def index(): return "hello from podman auto--weight: 500;">update\n" if __name__ == "__main__": app.run(host="0.0.0.0", port=8000)
from flask import Flask
app = Flask(__name__) @app.get("/healthz")
def healthz(): return {"ok": True} @app.get("/")
def index(): return "hello from podman auto--weight: 500;">update\n" if __name__ == "__main__": app.run(host="0.0.0.0", port=8000)
from flask import Flask
app = Flask(__name__) @app.get("/healthz")
def healthz(): return {"ok": True} @app.get("/")
def index(): return "hello from podman auto--weight: 500;">update\n" if __name__ == "__main__": app.run(host="0.0.0.0", port=8000)
#!/bin/sh
set -eu python /app/app.py &
pid=$! for _ in $(seq 1 30); do if -weight: 500;">curl -fsS http://127.0.0.1:8000/healthz >/dev/null; then systemd-notify --ready wait "$pid" exit $? fi sleep 1
done echo "application failed readiness check" >&2
kill "$pid"
wait "$pid" || true
exit 1
#!/bin/sh
set -eu python /app/app.py &
pid=$! for _ in $(seq 1 30); do if -weight: 500;">curl -fsS http://127.0.0.1:8000/healthz >/dev/null; then systemd-notify --ready wait "$pid" exit $? fi sleep 1
done echo "application failed readiness check" >&2
kill "$pid"
wait "$pid" || true
exit 1
#!/bin/sh
set -eu python /app/app.py &
pid=$! for _ in $(seq 1 30); do if -weight: 500;">curl -fsS http://127.0.0.1:8000/healthz >/dev/null; then systemd-notify --ready wait "$pid" exit $? fi sleep 1
done echo "application failed readiness check" >&2
kill "$pid"
wait "$pid" || true
exit 1
[Container]
ContainerName=demo-api
Image=-weight: 500;">docker.io/yourname/demo-api:1.0.0
AutoUpdate=registry
Notify=true
PublishPort=127.0.0.1:8000:8000
HealthCmd=-weight: 500;">curl -fsS http://127.0.0.1:8000/healthz || exit 1
HealthInterval=30s
HealthTimeout=5s
HealthRetries=3
HealthOnFailure=kill [Service]
Restart=always
TimeoutStartSec=180 [Install]
WantedBy=default.target
[Container]
ContainerName=demo-api
Image=-weight: 500;">docker.io/yourname/demo-api:1.0.0
AutoUpdate=registry
Notify=true
PublishPort=127.0.0.1:8000:8000
HealthCmd=-weight: 500;">curl -fsS http://127.0.0.1:8000/healthz || exit 1
HealthInterval=30s
HealthTimeout=5s
HealthRetries=3
HealthOnFailure=kill [Service]
Restart=always
TimeoutStartSec=180 [Install]
WantedBy=default.target
[Container]
ContainerName=demo-api
Image=-weight: 500;">docker.io/yourname/demo-api:1.0.0
AutoUpdate=registry
Notify=true
PublishPort=127.0.0.1:8000:8000
HealthCmd=-weight: 500;">curl -fsS http://127.0.0.1:8000/healthz || exit 1
HealthInterval=30s
HealthTimeout=5s
HealthRetries=3
HealthOnFailure=kill [Service]
Restart=always
TimeoutStartSec=180 [Install]
WantedBy=default.target
podman auto--weight: 500;">update --dry-run
podman auto--weight: 500;">update --dry-run
podman auto--weight: 500;">update --dry-run
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Image}} {{.Updated}}'
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Image}} {{.Updated}}'
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Image}} {{.Updated}}'
-weight: 500;">systemctl --user -weight: 500;">start podman-auto--weight: 500;">update.-weight: 500;">service
-weight: 500;">systemctl --user -weight: 500;">start podman-auto--weight: 500;">update.-weight: 500;">service
-weight: 500;">systemctl --user -weight: 500;">start podman-auto--weight: 500;">update.-weight: 500;">service
journalctl --user -u podman-auto--weight: 500;">update.-weight: 500;">service -n 100 --no-pager
journalctl --user -u whoami.-weight: 500;">service -n 100 --no-pager
journalctl --user -u podman-auto--weight: 500;">update.-weight: 500;">service -n 100 --no-pager
journalctl --user -u whoami.-weight: 500;">service -n 100 --no-pager
journalctl --user -u podman-auto--weight: 500;">update.-weight: 500;">service -n 100 --no-pager
journalctl --user -u whoami.-weight: 500;">service -n 100 --no-pager
mkdir -p ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d
cat > ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d/override.conf <<'EOF'
[Timer]
OnCalendar=
OnCalendar=Sat *-*-* 03:15:00
Persistent=true
RandomizedDelaySec=15m
EOF -weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">restart podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer
mkdir -p ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d
cat > ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d/override.conf <<'EOF'
[Timer]
OnCalendar=
OnCalendar=Sat *-*-* 03:15:00
Persistent=true
RandomizedDelaySec=15m
EOF -weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">restart podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer
mkdir -p ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d
cat > ~/.config/systemd/user/podman-auto--weight: 500;">update.timer.d/override.conf <<'EOF'
[Timer]
OnCalendar=
OnCalendar=Sat *-*-* 03:15:00
Persistent=true
RandomizedDelaySec=15m
EOF -weight: 500;">systemctl --user daemon-reload
-weight: 500;">systemctl --user -weight: 500;">restart podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer
podman login -weight: 500;">docker.io
podman login -weight: 500;">docker.io
podman login -weight: 500;">docker.io
Image=nginx:latest
Image=nginx:latest
Image=nginx:latest
Image=-weight: 500;">docker.io/library/nginx:1.27-alpine
Image=-weight: 500;">docker.io/library/nginx:1.27-alpine
Image=-weight: 500;">docker.io/library/nginx:1.27-alpine
-weight: 500;">systemctl --user cat whoami.-weight: 500;">service
podman inspect whoami --format '{{.Config.Labels}}'
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Policy}} {{.Updated}}'
-weight: 500;">systemctl --user -weight: 500;">status podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user cat whoami.-weight: 500;">service
podman inspect whoami --format '{{.Config.Labels}}'
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Policy}} {{.Updated}}'
-weight: 500;">systemctl --user -weight: 500;">status podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user cat whoami.-weight: 500;">service
podman inspect whoami --format '{{.Config.Labels}}'
podman auto--weight: 500;">update --dry-run --format '{{.Unit}} {{.Policy}} {{.Updated}}'
-weight: 500;">systemctl --user -weight: 500;">status podman-auto--weight: 500;">update.timer
-weight: 500;">systemctl --user list-timers podman-auto--weight: 500;">update.timer - run the container through a systemd unit
- use a fully qualified image reference for registry-based updates
- add a readiness signal so rollback can detect bad starts reliably
- add a health check so broken containers do not look healthy by accident - registry, which checks the remote registry for a newer digest
- local, which compares the container image to a newer image already present in local storage - ~/.config/containers/systemd/
- $XDG_RUNTIME_DIR/containers/systemd/ - systemd-notify --ready tells systemd the -weight: 500;">service really started
- HealthCmd= keeps probing after startup and can kill the container if it becomes unhealthy - podman auto--weight: 500;">update --authfile /path/to/auth.json
- the io.containers.autoupdate.authfile label
- the REGISTRY_AUTH_FILE environment variable - the generated -weight: 500;">service exists
- the container carries the auto--weight: 500;">update policy
- dry run works cleanly
- the timer is active on the schedule you expect - a CI job pre-pulls or pre-loads images
- you import signed images into an offline host
- you promote images between local stores before -weight: 500;">restart - Quadlet for clean systemd ownership
- fully qualified image names
- health checks
- readiness notifications
- a deliberate timer schedule - Podman documentation, podman-auto--weight: 500;">update(1): https://docs.podman.io/en/stable/markdown/podman-auto--weight: 500;">update.1.html
- Podman documentation, podman-systemd.unit(5): https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html
- Podman documentation, podman-container.unit(5): https://docs.podman.io/en/latest/markdown/podman-container.unit.5.html
- systemd documentation, systemd.time(7): https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html
- systemd documentation, systemd.timer(5): https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html