# Podman Deployment ## Overview The bouncer runs in a rootless podman container with host networking. Source code and configuration are mounted as volumes -- the container image only contains Python and pip dependencies. ``` Container (bouncer) |- python:3.12-slim + deps |- /app/src <- ./src (read-only volume) |- /data <- ./config (read-write volume) ``` ## Prerequisites - `podman` and `podman-compose` - SOCKS5 proxy reachable at `127.0.0.1:1080` (host network) Verify: ```bash podman --version podman-compose --version ss -tlnp | grep 1080 ``` ## Quick Start ```bash cd ~/git/bouncer # create config from template cp config/bouncer.example.toml config/bouncer.toml $EDITOR config/bouncer.toml # build and start make build make up # check logs make logs ``` ## Container Image The image installs only runtime dependencies. Source code is not baked in. ```bash # build podman build -t bouncer -f Containerfile . # rebuild after dependency changes podman build --no-cache -t bouncer -f Containerfile . ``` ### Containerfile ```dockerfile FROM python:3.12-slim WORKDIR /app RUN pip install --no-cache-dir \ "python-socks[asyncio]>=2.4" \ "aiosqlite>=0.19" ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/app/src VOLUME /app/src VOLUME /data ENTRYPOINT ["python", "-m", "bouncer"] CMD ["-c", "/data/bouncer.toml"] ``` ## Compose ```yaml services: bouncer: build: context: . dockerfile: Containerfile container_name: bouncer restart: unless-stopped network_mode: host logging: driver: k8s-file volumes: - ./src:/app/src:Z,ro - ./config:/data:Z command: ["-c", "/data/bouncer.toml", "-v"] ``` ### Volume Mounts | Host Path | Container Path | Mode | Purpose | |-----------|---------------|------|---------| | `./src` | `/app/src` | read-only | Python source code | | `./config` | `/data` | read-write | Config + SQLite backlog | The `:Z` suffix applies the correct SELinux context for rootless podman. ### Host Networking `network_mode: host` is required because the bouncer needs access to: - `127.0.0.1:1080` -- SOCKS5 proxy (outbound IRC connections) - `127.0.0.1:6667` -- client listen port (inbound IRC clients) ### Log Driver `k8s-file` is used instead of the default `journald` driver to ensure `podman logs` works reliably in rootless mode. ## Operations ### Start / Stop / Restart ```bash podman-compose up -d # start (detached) podman-compose down # stop and remove podman-compose restart # restart ``` Or with make targets: ```bash make up # podman-compose up -d make down # podman-compose down ``` ### Logs ```bash podman logs -f bouncer # follow all logs podman logs --tail 50 bouncer # last 50 lines podman logs bouncer 2>&1 | grep -v aiosqlite # filter sqlite noise podman logs bouncer 2>&1 | grep -E 'INFO|WARN' # important events only ``` Or: ```bash make logs # podman logs -f bouncer ``` ### Status ```bash podman ps --filter name=bouncer podman inspect bouncer --format '{{.State.Status}}' ``` ### Shell Access ```bash podman exec -it bouncer bash podman exec bouncer python -c "import bouncer; print(bouncer.__version__)" ``` ### Inspect Backlog The SQLite database is stored in the config volume: ```bash sqlite3 config/bouncer.db "SELECT network, COUNT(*) FROM messages GROUP BY network;" ``` ## Updating After pulling new code: ```bash git pull podman-compose down podman-compose up -d ``` The image only needs rebuilding if dependencies change: ```bash podman-compose down make build podman-compose up -d ``` ## Troubleshooting ### Container exits immediately Check logs for config or proxy errors: ```bash podman logs bouncer ``` Common causes: - Missing `config/bouncer.toml` (not mounted) - SOCKS5 proxy not running on host - Invalid TOML syntax ### No log output Verify `PYTHONUNBUFFERED=1` is set in the Containerfile and the log driver is `k8s-file`: ```bash podman inspect bouncer --format '{{.HostConfig.LogConfig.Type}}' ``` ### Container can't reach SOCKS5 proxy `network_mode: host` must be set. Verify the proxy is listening: ```bash ss -tlnp | grep 1080 ``` ### Permission denied on volumes The `:Z` suffix handles SELinux relabeling. If issues persist: ```bash podman unshare ls -la config/ ``` ### Rebuild from scratch ```bash podman-compose down podman rmi bouncer podman build --no-cache -t bouncer -f Containerfile . podman-compose up -d ```