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:
tanshu committed 2026-10-16 10:11:39 +05:30
1 parent 1bc1d5f753
commit d04314ab1c
20 files changed
+535 -127

No files matched your search

+33 -30
View File
@@ -1,40 +1,43 @@
---
# Tasks for docker role
- name: Log in to Docker registry
docker_login:
registry: "{{ registry }}"
username: "{{ username }}"
password: "{{ password }}"
# The mozimo service itself: registry credentials, the pinned image, and the
# Quadlet unit that systemd turns into a user service.
#
# There is one unit, not two: the image's entrypoint runs the SSR server and
# PocketBase side by side, so the pair restart together.
- name: Check the rootless podman installation
ansible.builtin.command: podman --version
changed_when: false
- name: Pull Mozimo image
docker_image:
name: "{{ docker_image }}"
source: pull
state: present
force_source: yes
- name: Log in to the registry as the podman user
ansible.builtin.command:
cmd: "podman login --username {{ username }} --password-stdin {{ registry }}"
stdin: "{{ password }}"
no_log: true
changed_when: false
- name: Ensure PocketBase data directory exists
file:
path: "{{ host_directory }}/pb_data"
state: directory
owner: "1000"
group: "1000"
- name: Pull the image for this revision
ansible.builtin.command: "podman pull {{ image }}"
# the pull is a means to an end; the restart handler reports the real change
changed_when: false
- name: Create Mozimo container
docker_container:
name: "{{ docker_container }}"
image: "{{ docker_image }}"
state: started
restart_policy: "unless-stopped"
env_file: "{{ host_directory }}/.env"
volumes:
- "{{ host_directory }}/pb_data:/app/pb_data"
networks:
- name: "{{ docker_network }}"
- name: Install the mozimo Quadlet unit
ansible.builtin.template:
src: mozimo.container.j2
dest: "{{ quadlet_dir }}/{{ title }}.container"
mode: "0644"
notify: Restart Mozimo
# Explicit, and before the handlers run: the unit does not exist as a systemd
# service until the podman user generator has seen it, so generating it here
# means the restart handler has something to restart on a first deploy.
- name: Generate the user service from the Quadlet unit
ansible.builtin.systemd_service:
daemon_reload: true
scope: user
- name: Prune old mozimo images, keep newest 3 (opt-in via ./deploy.sh --prune)
ansible.builtin.shell: >
docker images "registry.tanshu.com/mozimo" --format "{{.ID}}" | tail -n +4 | xargs -r docker rmi
podman images -q {{ registry }}/{{ title }} | tail -n +4 | xargs -r podman rmi
when: mozimo_image_prune | default(false) | bool
failed_when: false
changed_when: true