Files
mozimo.in/deploy.sh
T
tanshu d04314ab1c 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.
2026-10-16 10:11:39 +05:30

55 lines
1.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Mozimo deploy — build the exact commit at origin/main with podman, tag it
# with its commit id, and hand that tag to ansible (which installs the Quadlet
# unit on emily and restarts the user service). Guards make it impossible to
# deploy anything other than what git knows about.
#
# ./deploy.sh deploy HEAD (must be pushed, tree must be clean)
# ./deploy.sh --prune also drop old mozimo images on the server (keep 3)
# ./deploy.sh --force skip the guards (know what you are doing)
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")"
git push
FORCE=false
PRUNE=false
for arg in "$@"; do
case "$arg" in
--force) FORCE=true ;;
--prune) PRUNE=true ;;
*)
echo "Usage: $0 [--force] [--prune]"
exit 1
;;
esac
done
# guards: only tracked-file state matters (untracked files never enter a
# `git archive HEAD` build); HEAD must equal origin/main
if [ "$FORCE" != true ]; then
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
echo "✗ tracked files modified — commit or stash first (or --force)" >&2
exit 1
fi
git fetch origin --quiet
if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]; then
echo "✗ HEAD != origin/main — push or pull first (or --force)" >&2
exit 1
fi
fi
git pull --ff-only
TAG=$(git rev-parse --short HEAD)
echo "▶ deploying commit $TAG"
make build-production COMMIT="$TAG"
PRUNE_FLAG=""
if [ "$PRUNE" = true ]; then
PRUNE_FLAG="-e mozimo_image_prune=true"
fi
cd ansible
# shellcheck disable=SC2086
ansible-playbook playbook.yml -e "image_tag=$TAG" $PRUNE_FLAG