Deploy with rootless podman + Quadlet on emily
Retargets the build and the playbook off rootful Docker on monoco, following the conventions already in place on emily's other services: Quadlet units in ~/.config/containers/systemd, per-service data in ~/podman-data, and a shared Caddy that every service registers itself with — a network drop-in plus a marked block in its Caddyfile. Nothing is published on the host; Caddy reaches the containers by name over mozimo_net. - Makefile: podman build + push instead of docker buildx, PLATFORMS=linux/arm64 (both hosts are aarch64). podman has no built-in QEMU the way buildx's builder image does, so a foreign-platform failure now points at qemu-user-static. - deploy.sh: pass COMMIT= to make, which the Makefile actually reads; it was passing TAG=, so the tag silently came from `git rev-parse` instead. - ansible: hosts emily, become false, XDG_RUNTIME_DIR for rootless podman and systemctl --user. Docker modules become Quadlet templates with user-service handlers, and the network role now ships mozimo.network plus the Caddy drop-in rather than calling docker_network. - UserNS=keep-id maps the container's uid 1000 (node) and root (vince) onto the host user, so PocketBase and Vince write host-owned files instead of subuid-owned ones; the play asserts the pinned uid still matches the host. - ansible/README.md: the unit layout, the service-registration convention, and the monoco -> emily migration (PocketBase 23 MB + Vince 119 MB, DNS cutover, rollback). Verified by a check-mode rehearsal against emily (13 ok / 8 changed / 0 failed) and a disposable Quadlet unit on that host proving the uid mapping, the EnvironmentFile and the isolated network. The real build and cutover have not been run.
This commit is contained in:
1 parent
1bc1d5f753
commit
d04314ab1c
20 files changed
+535
-127
No files matched your search
+45
-13
@@ -1,4 +1,17 @@
|
||||
---
|
||||
# mozimo deployment — rootless Podman + Quadlet, on the host named emily.
|
||||
#
|
||||
# The layout follows the convention already in place on that host (see the
|
||||
# caddy / tandoor / postgres playbooks that manage its other services):
|
||||
#
|
||||
# ~/.config/containers/systemd/ Quadlet units, generated into user services
|
||||
# ~/podman-data/<service>/ each service's data
|
||||
# ~/podman-data/caddy/conf/Caddyfile the shared Caddy config; every service
|
||||
# appends its own block to it
|
||||
#
|
||||
# Nothing here needs root: podman runs as the ssh user, the units are user
|
||||
# services, and the shared Caddy is already a user service on that host.
|
||||
|
||||
registry: registry.tanshu.com
|
||||
username: ta-registry
|
||||
password: ff28a01f00c0f39315d94cd9dcb1e554968dba25676a8ea5f2be34e96a9a099f
|
||||
@@ -6,7 +19,25 @@ password: ff28a01f00c0f39315d94cd9dcb1e554968dba25676a8ea5f2be34e96a9a099f
|
||||
title: mozimo
|
||||
tag: latest
|
||||
|
||||
host_directory: "/var/lib/{{ title }}"
|
||||
# The unprivileged user that owns the containers. `ansible_user` on emily is
|
||||
# the same account, so no become is involved anywhere in this play.
|
||||
podman_user: tanshu
|
||||
# `id -u tanshu` on emily. Pinned rather than read from facts because the
|
||||
# play-level environment (XDG_RUNTIME_DIR) is templated before facts exist;
|
||||
# the upload role asserts the two still agree.
|
||||
podman_uid: 1001
|
||||
xdg_runtime_dir: "/run/user/{{ podman_uid }}"
|
||||
podman_data: "/home/{{ podman_user }}/podman-data"
|
||||
quadlet_dir: "/home/{{ podman_user }}/.config/containers/systemd"
|
||||
|
||||
# mozimo's data root: PocketBase database and files, the Shopify token cache,
|
||||
# and the runtime .env that the unit reads.
|
||||
host_directory: "{{ podman_data }}/{{ title }}"
|
||||
|
||||
# image tag: deploy.sh passes -e image_tag=<commit>; "tag" is the fallback
|
||||
# when running the playbook by hand — rollback = -e image_tag=<older-commit>
|
||||
image: "{{ registry }}/{{ title }}:{{ image_tag | default(tag) }}"
|
||||
app_container: "{{ title }}"
|
||||
|
||||
# apex is the canonical origin and serves the app; www 301-redirects to it
|
||||
apex_host: "mozimo.in"
|
||||
@@ -15,25 +46,26 @@ www_port: 3000
|
||||
cms_host: "cms.mozimo.in"
|
||||
cms_port: 8090
|
||||
|
||||
docker_network: "{{ title }}_net"
|
||||
# mozimo gets its own podman network, and registers itself with the shared
|
||||
# Caddy through a drop-in rather than by editing Caddy's unit.
|
||||
network_name: "{{ title }}_net"
|
||||
network_quadlet: "{{ title }}"
|
||||
|
||||
# image tag: deploy.sh passes -e image_tag=<commit>; "tag" is the fallback
|
||||
# when running the playbook by hand — rollback = -e image_tag=<older-commit>
|
||||
docker_image: "{{ registry }}/{{ title }}:{{ image_tag | default(tag) }}"
|
||||
docker_container: "{{ title }}"
|
||||
# The shared Caddy on emily. Each service owns a block in its Caddyfile
|
||||
# (blockinfile markers) and a drop-in that adds its network to Caddy.
|
||||
caddy_container: caddy
|
||||
caddy_service: caddy
|
||||
caddyfile_path: "{{ podman_data }}/caddy/conf/Caddyfile"
|
||||
caddy_dropin_dir: "{{ quadlet_dir }}/caddy.container.d"
|
||||
caddy_dropin_file: "50-{{ title }}.conf"
|
||||
|
||||
# self-hosted first-party analytics (Vince) — script/events proxied at
|
||||
# /stats/* on the www host, dashboard published on stats_host
|
||||
# /stats/* on the apex host, dashboard published on stats_host
|
||||
vince_container: vince
|
||||
vince_port: 8000
|
||||
vince_admin_name: admin
|
||||
# change this before first deploy — it (re)sets the dashboard login
|
||||
vince_admin_password: "ChangeMe-Vince-2025!"
|
||||
vince_site_domain: mozimo.in
|
||||
vince_directory: "{{ podman_data }}/vince"
|
||||
stats_host: stats.mozimo.in
|
||||
|
||||
# caddy publishes the apex site (SSR + /api/* + /_/* -> pocketbase), redirects
|
||||
# www to it, and publishes the cms admin host
|
||||
|
||||
caddy_container: caddy
|
||||
caddyfile_path: /var/lib/caddy/conf/Caddyfile
|
||||
Reference in new issue
Block a user