Three follow-ups on the shower deployment branch:
1. containers/shower/default.nix now uses buildPythonPackage to install
the adelaide-baby-shower-app wheel + its deps at nix build time. The
wheel comes from the forge PyPI index with a pinned SRI hash. The
entrypoint no longer does pip-at-boot — it just runs migrations,
collectstatic, and execs gunicorn.
2. ansible/roles/borgmatic/defaults/main.yml:
- Adds shower to borgmatic_k8s_sqlite_dumps (context k3s-ringtail)
so /app/data/db.sqlite3 is dumped via kubectl exec on every run.
- Adds /Volumes/shower (sifaka SMB mount on indri) to
borgmatic_source_directories so prize-photo media gets archived.
3. NFS share docs corrected to match the real on-sifaka pattern:
exports allowlist 192.168.1.0/24 + 100.64.0.0/10 with all_squash to
admin (matching frigate/paperless/etc.), not "Squash=No mapping".
The pod's runAsUser doesn't need to match an on-disk uid because
all_squash rewrites every write to admin:users.
Also adds a missing service-versions entry for the tailscale container
introduced in PR #347 — pre-existing gap surfaced by the
container-version-check hook on this commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
121 lines
3.2 KiB
Nix
121 lines
3.2 KiB
Nix
# Nix-built shower app container — Adelaide / Heidi / Addie baby shower.
|
|
#
|
|
# The app is published as a wheel to the Forgejo PyPI index at
|
|
# https://forge.eblu.me/api/packages/eblume/pypi/. The wheel + its
|
|
# Python deps are baked in at build time via buildPythonPackage so the
|
|
# container boots cleanly with no pip-at-runtime. Build runs on the
|
|
# nix-container-builder runner (ringtail, amd64) so the image is native.
|
|
#
|
|
# To bump the version:
|
|
# 1. Update `version` below.
|
|
# 2. Update `wheelHash` — `nix-prefetch-url <url>` against the new wheel,
|
|
# or set it to `pkgs.lib.fakeHash` and let the build print the right one.
|
|
{ pkgs ? import <nixpkgs> { } }:
|
|
|
|
let
|
|
version = "1.0.0";
|
|
wheelHash = "sha256-9Xk3TCzl474As8n0RhLoy/QYw+K1DABBWEwLC8v1X0A=";
|
|
|
|
python = pkgs.python314;
|
|
|
|
showerWheel = pkgs.fetchurl {
|
|
name = "adelaide_baby_shower_app-${version}-py3-none-any.whl";
|
|
url = "https://forge.eblu.me/api/packages/eblume/pypi/files/adelaide-baby-shower-app/${version}/adelaide_baby_shower_app-${version}-py3-none-any.whl";
|
|
hash = wheelHash;
|
|
};
|
|
|
|
shower = python.pkgs.buildPythonPackage {
|
|
pname = "adelaide-baby-shower-app";
|
|
inherit version;
|
|
format = "wheel";
|
|
src = showerWheel;
|
|
doCheck = false;
|
|
propagatedBuildInputs = with python.pkgs; [
|
|
django
|
|
django-axes
|
|
pillow
|
|
scipy
|
|
segno
|
|
];
|
|
};
|
|
|
|
pyEnv = python.withPackages (ps: [
|
|
shower
|
|
ps.gunicorn
|
|
]);
|
|
|
|
# Settings shim — config/settings.py's `BASE_DIR = parent.parent` would
|
|
# otherwise resolve to site-packages, scattering db.sqlite3 / media /
|
|
# staticfiles into the venv. Pin them to /app/{data,media,data/static}.
|
|
localSettings = pkgs.writeText "local_settings.py" ''
|
|
from config.settings import * # noqa: F401,F403
|
|
|
|
DATABASES["default"]["NAME"] = "/app/data/db.sqlite3"
|
|
MEDIA_ROOT = "/app/media"
|
|
STATIC_ROOT = "/app/data/staticfiles"
|
|
'';
|
|
|
|
entrypoint = pkgs.writeShellScript "shower-entrypoint" ''
|
|
set -eu
|
|
|
|
export HOME=/app/data
|
|
export PYTHONPATH=/app
|
|
export DJANGO_SETTINGS_MODULE=local_settings
|
|
|
|
cd /app
|
|
|
|
mkdir -p /app/data /app/media
|
|
|
|
echo "shower: running migrations"
|
|
${pyEnv}/bin/python -m django migrate --noinput
|
|
|
|
echo "shower: collecting static files"
|
|
${pyEnv}/bin/python -m django collectstatic --noinput --clear
|
|
|
|
echo "shower: starting gunicorn"
|
|
exec ${pyEnv}/bin/gunicorn \
|
|
--bind 0.0.0.0:8000 \
|
|
--workers 2 \
|
|
--forwarded-allow-ips='*' \
|
|
config.wsgi:application
|
|
'';
|
|
in
|
|
|
|
pkgs.dockerTools.buildLayeredImage {
|
|
name = "blumeops/shower";
|
|
contents = [
|
|
pyEnv
|
|
pkgs.cacert
|
|
pkgs.tzdata
|
|
pkgs.bashInteractive
|
|
pkgs.coreutils
|
|
];
|
|
|
|
extraCommands = ''
|
|
mkdir -p app/data app/media tmp
|
|
chmod 1777 tmp
|
|
cp ${localSettings} app/local_settings.py
|
|
'';
|
|
|
|
fakeRootCommands = ''
|
|
chown -R 1000:1000 app
|
|
'';
|
|
enableFakechroot = true;
|
|
|
|
config = {
|
|
Entrypoint = [ "${entrypoint}" ];
|
|
Env = [
|
|
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
|
"TZDIR=${pkgs.tzdata}/share/zoneinfo"
|
|
"TZ=America/Los_Angeles"
|
|
"TMPDIR=/tmp"
|
|
"LANG=C.UTF-8"
|
|
"LC_ALL=C.UTF-8"
|
|
];
|
|
ExposedPorts = {
|
|
"8000/tcp" = { };
|
|
};
|
|
User = "1000";
|
|
WorkingDir = "/app";
|
|
};
|
|
}
|