mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-09 12:17:13 +00:00
feat(backup): decide stop_required for every service with a backed-up volume
baudolo stops every container on a volume before the authoritative copy
unless its image is listed via --images-no-stop-required. Leaving the
marker out silently picked "stop": the Stalwart webmail start that the
backup cycle triggered got SIGKILLed mid `composer update` (CI run
40625679270), and 71 services that mount a named volume had never
decided either way.
- The marker is now `backup.stop_required` (true = stop first, false =
copy live), replacing the double-negated `no_stop_required`; the 50
existing declarations are inverted unchanged. backup_image takes the
marker and the wanted value explicitly:
lookup('backup_image', 'stop_required', false) still feeds
--images-no-stop-required, lookup('backup_image', 'disabled', true)
the skip list.
- The 71 undecided services carry researched values (repo files plus
upstream backup guidance: GitLab, Jenkins, Elastic, RabbitMQ, Typesense,
Qdrant, OpenLDAP, Prometheus, Moodle, ClamAV, Alertmanager, ...): engine
files, git repositories, SQLite, mnesia and multi-file state stop; image
code, write-once blob stores with metadata in the database and
atomically rewritten files copy live. Stalwart's main service stays
stopped until /var/lib/stalwart is verified to hold only logs.
- Re-obtainable data is no longer backed up at all (`backup: false` on
the volume): model weights, ClamAV signatures, SearXNG config/cache,
transient RabbitMQ queues, Funkwhale's Typesense index, the meta clone,
the agent-broker socket dir, coturn's unused data dir, and volumes no
image reads (Decidim's /app paths outside /code, BookWyrm's /app/data
which v0.9.3 never reads, FusionDirectory's measured-empty dir).
- The backup lookup only matches what actually runs once the role
declares it: Bluesky's broker (`custom: bluesky_broker`) and Decidim
(`custom: true`) declare their custom build, BookWyrm's worker/migrate,
EspoCRM's daemon/websocket, Moodle's cron and OpenProject's proxy use
their owner's image, and the templates drop their render-time
overrides. Decidim deploys decidim_custom:0.31.6 and BookWyrm
bookwyrm_custom:3.11-slim from now on; a BookWyrm ref bump still
rebuilds through the build-args digest.
- test_backup_stop_decision_declared requires the boolean on every
service with its own image that mounts a backed-up named volume;
test_stop_required replaces the old integrity test.
Measured against HEAD: 43 -> 78 services copied live, none moved the
other way; 14 -> 30 volumes skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a8923690c3
commit
fdf1a33c5f
113 files changed
+393
-123
No files matched your search
@@ -109,7 +109,7 @@ redis:
|
||||
|
||||
erpnext:
|
||||
backup:
|
||||
no_stop_required: false # Frappe's bench backup requires a quiesced site
|
||||
stop_required: true # Frappe's bench backup requires a quiesced site
|
||||
image: frappe/erpnext
|
||||
version: "X.Y.Z" # latest stable semver at the time of the PR
|
||||
name: erpnext
|
||||
|
||||
@@ -93,7 +93,7 @@ tor:
|
||||
version: "<pinned tor x.y.z>"
|
||||
name: tor
|
||||
backup:
|
||||
no_stop_required: false # stop for consistent key-volume copy
|
||||
stop_required: true # stop for consistent key-volume copy
|
||||
lifecycle: alpha
|
||||
# no public ports; SocksPort/ControlPort bind 127.0.0.1 only
|
||||
```
|
||||
|
||||
@@ -117,7 +117,7 @@ openbao:
|
||||
internal: { http: 8200 }
|
||||
local: { http: <allocate via the suggester> }
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
run_after:
|
||||
- svc-db-openldap
|
||||
- web-app-keycloak
|
||||
@@ -286,7 +286,7 @@ cluster_addr = "http://127.0.0.1:8201"
|
||||
|
||||
### Backup & restore
|
||||
|
||||
- [x] The `container_backup` service is wired with `backup.no_stop_required: false`, so the container is quiesced for a consistent copy of the raft volume.
|
||||
- [x] The `container_backup` service is wired with `backup.stop_required: true`, so the container is quiesced for a consistent copy of the raft volume.
|
||||
- [x] A restore procedure is documented and executed once end to end: restore the volume, redeploy, and confirm the instance auto-unseals and a previously stored secret is still readable. Drill run on the variant-2 stack: container quiesced, `openbao_data` archived (33 MB), the live volume **wiped to zero entries**, restored from the archive, and restarted — OpenBao came back `initialized: true, sealed: false` with the secret, the PKI root CA and all five policies recovered. This also confirms the documented dependency: the restored store is only readable because the seal key in the inventory was unchanged.
|
||||
- [x] The README states explicitly that the volume backup is **worthless without the seal key**, that the seal key's authoritative home is the encrypted inventory (it is not covered by `svc-bkp-secrets-2-local`, whose sources are `DIR_SECRETS`, the CA and the ACME material), and what the recovery keys can and cannot do.
|
||||
- [x] The README states the consequence of Decision #2 that surfaced during implementation: because the root token is revoked and the recovery keys are **not** persisted (persisting them would be the write-back the AppRole bootstrap exists to avoid), the Ansible AppRole is the *only* administrative path into the instance. Losing or out-of-band-changing those credentials means rebuilding from the volume backup plus the seal key.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
agent-broker:
|
||||
backup:
|
||||
stop_required: false
|
||||
modes:
|
||||
compose:
|
||||
enabled: true
|
||||
@@ -43,6 +45,8 @@ agent-broker:
|
||||
# nocheck: shared
|
||||
# nocheck: dynamic-flag
|
||||
socket-proxy:
|
||||
backup:
|
||||
stop_required: false
|
||||
bond: 1
|
||||
enabled: true
|
||||
image: wollomatic/socket-proxy
|
||||
|
||||
@@ -10,6 +10,7 @@ docker_sock:
|
||||
|
||||
engine_socket:
|
||||
type: volume
|
||||
backup: false
|
||||
mounts:
|
||||
- service: socket-proxy
|
||||
target: &engine_socket_dir /run/agent-engine
|
||||
|
||||
@@ -12,7 +12,7 @@ litellm:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ghcr.io/berriai/litellm
|
||||
version: main-v1.77.7-stable
|
||||
name: litellm
|
||||
|
||||
@@ -12,7 +12,7 @@ lmstudio:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ubuntu
|
||||
version: "22.04"
|
||||
custom: true
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
# nocheck: playwright-service-flag — translation engine without a browser surface of its own
|
||||
ltengine:
|
||||
backup:
|
||||
stop_required: false
|
||||
name: ltengine
|
||||
healthcheck:
|
||||
flavor: http_status
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# nocheck: embedded-state-on-nfs content-addressed GGUF weights, downloaded once and read-only after
|
||||
ltengine_models:
|
||||
type: volume
|
||||
backup: false
|
||||
mounts:
|
||||
- service: ltengine
|
||||
target: /models
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
# nocheck: playwright-service-flag — translation engine without a browser surface of its own
|
||||
nllb-engine:
|
||||
backup:
|
||||
stop_required: false
|
||||
name: nllb-engine
|
||||
healthcheck:
|
||||
flavor: http_status
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# nocheck: nfs-false-data-loss Reason: a node that fetched the checkpoint holds the same files every other node would fetch, so nothing written here has to reach another node
|
||||
nllb_models: # nocheck: embedded-state-on-nfs content-addressed checkpoint, read-only after the first download
|
||||
type: volume
|
||||
backup: false
|
||||
mounts:
|
||||
- service: nllb-engine
|
||||
target: /models
|
||||
@@ -11,7 +11,7 @@ ollama:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ollama/ollama
|
||||
version: 0.40.12
|
||||
name: ollama
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
# nocheck: playwright-service-flag - internal search backend consumed over the container network
|
||||
searxng:
|
||||
backup:
|
||||
stop_required: false
|
||||
modes:
|
||||
compose:
|
||||
enabled: true
|
||||
|
||||
@@ -9,6 +9,7 @@ searxng_settings:
|
||||
target: /etc/searxng/settings.yml
|
||||
searxng_config:
|
||||
type: volume
|
||||
backup: false
|
||||
# nocheck: nfs-false-data-loss Reason: holds the image's own /etc/searxng copy, which docker seeds per node on first start; the deployment's settings.yml is bind-mounted over it, so nothing a replica writes here has to reach another replica
|
||||
nfs: false
|
||||
mounts:
|
||||
@@ -16,6 +17,7 @@ searxng_config:
|
||||
target: /etc/searxng
|
||||
searxng_cache:
|
||||
type: volume
|
||||
backup: false
|
||||
# nocheck: nfs-false-data-loss Reason: derived search cache, rebuilt from the upstream engines on demand; shared over NFS every replica would write the same keys into one tree for no gain
|
||||
nfs: false
|
||||
mounts:
|
||||
|
||||
@@ -39,7 +39,7 @@ flowchart TD
|
||||
|
||||
- **Per-container snapshots:** rsync `--link-dest` snapshots deduplicate unchanged files across runs.
|
||||
- **Database-aware:** consumer apps seed their connection metadata into a central `databases.csv`, so the same run can dump SQL state alongside the file payload.
|
||||
- **Live-aware:** containers tagged `no_stop_required` stay running during the dump; others stop briefly and resume.
|
||||
- **Live-aware:** containers tagged `stop_required: false` stay running during the dump; others stop briefly and resume.
|
||||
- **Snapshot-aware:** on a btrfs data root the whole run is captured from one atomic filesystem snapshot with no container stopped; the host is probed before every run and falls back to the live copy when a snapshot would not be faithful.
|
||||
- **Systemd-driven:** a generated unit fires on the configured schedule (`SYS_SCHEDULE_BACKUP_CONTAINER_TO_LOCAL`), serialised against other backup/cleanup/repair groups by `sys-lock`.
|
||||
- **Self-cleaning:** failed backup attempts are torn down by `sys-ctl-cln-faild-bkps` so a broken run cannot poison the next.
|
||||
|
||||
@@ -10,8 +10,8 @@ from ansible.plugins.lookup import LookupBase
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
"""Exact deployed image references of every service whose ``backup.<marker>``
|
||||
is truthy and that carries an ``image`` or is ``custom``-built, for baudolo's
|
||||
exact ``--images-*`` matching.
|
||||
equals the wanted boolean and that carries an ``image`` or is
|
||||
``custom``-built, for baudolo's exact ``--images-*`` matching.
|
||||
|
||||
The ref is resolved via the ``image`` lookup, so it is byte-identical to the
|
||||
container's ``.Config.Image`` after deploy: swarm registry prefix included,
|
||||
@@ -20,8 +20,16 @@ class LookupModule(LookupBase):
|
||||
non-custom shared references are skipped: their owner role carries the
|
||||
image and marker.
|
||||
|
||||
Takes exactly one term: the backup marker key (e.g. ``no_stop_required`` or
|
||||
``disabled``). Reads the live merged ``applications`` config.
|
||||
Args:
|
||||
terms: exactly two, the backup marker key (e.g. ``stop_required`` or
|
||||
``disabled``) and the boolean the marker must equal (e.g. ``false``
|
||||
for the images baudolo may copy live, ``true`` for the images it
|
||||
must skip).
|
||||
variables: the play variables; the live merged ``applications``
|
||||
config is read through them.
|
||||
|
||||
Returns:
|
||||
One list: the sorted, de-duplicated image references.
|
||||
"""
|
||||
|
||||
def run(
|
||||
@@ -30,11 +38,18 @@ class LookupModule(LookupBase):
|
||||
variables: dict[str, Any] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> list[list[str]]:
|
||||
if not terms or len(terms) != 1:
|
||||
if not terms or len(terms) != 2:
|
||||
raise AnsibleError(
|
||||
"backup_image requires exactly one term: the backup marker key"
|
||||
"backup_image requires exactly two terms: the backup marker key "
|
||||
"and the boolean it must equal"
|
||||
)
|
||||
marker = str(terms[0])
|
||||
marker, wanted = terms
|
||||
if not isinstance(wanted, bool):
|
||||
raise AnsibleError(
|
||||
f"backup_image: the wanted value of '{marker}' must be a boolean, "
|
||||
f"got {wanted!r}"
|
||||
)
|
||||
marker = str(marker)
|
||||
|
||||
vars_ = variables or getattr(self._templar, "available_variables", {}) or {}
|
||||
|
||||
@@ -58,7 +73,9 @@ class LookupModule(LookupBase):
|
||||
continue
|
||||
for service_key, svc in services.items():
|
||||
backup = svc.get("backup") if isinstance(svc, Mapping) else None
|
||||
if not (isinstance(backup, Mapping) and backup.get(marker)):
|
||||
if not isinstance(backup, Mapping):
|
||||
continue
|
||||
if backup.get(marker) is not wanted:
|
||||
continue
|
||||
if not (svc.get("image") or svc.get("custom")):
|
||||
continue
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# Mapping logic for baudolo CLI arguments
|
||||
#
|
||||
# - BKP_VOLUME_2_LOCAL_DB_ROUTINE: Service names where backup.database_routine is set (for --database-containers)
|
||||
# - BKP_VOLUME_2_LOCAL_NO_STOP_REQUIRED: Exact deployed image refs where backup.no_stop_required is set (for --images-no-stop-required)
|
||||
# - BKP_VOLUME_2_LOCAL_DISABLED: Exact deployed image refs where backup.disabled is set (for --images-no-backup-required)
|
||||
# - BKP_VOLUME_2_LOCAL_NO_STOP_REQUIRED: Exact deployed image refs where backup.stop_required is false (for --images-no-stop-required)
|
||||
# - BKP_VOLUME_2_LOCAL_DISABLED: Exact deployed image refs where backup.disabled is true (for --images-no-backup-required)
|
||||
# - BKP_VOLUME_2_LOCAL_HARD_RESTART: Compose project (entity) names where backup.project_hard_restart is set (for --hard-restart-projects)
|
||||
# - BKP_VOLUME_2_LOCAL_SNAPSHOT_BIN: Launcher that appends --snapshot/--snapshot-subject per run when the mode allows it
|
||||
# - BKP_VOLUME_2_LOCAL_SNAPSHOT_MODE: services.volume-2-local.snapshot_mode normalised; YAML reads a bare off/no/false as a boolean
|
||||
@@ -51,10 +51,10 @@ BKP_VOLUME_2_LOCAL_DB_ROUTINE: >-
|
||||
{{ lookup('backup_database_containers') }}
|
||||
|
||||
BKP_VOLUME_2_LOCAL_NO_STOP_REQUIRED: >-
|
||||
{{ lookup('backup_image', 'no_stop_required') }}
|
||||
{{ lookup('backup_image', 'stop_required', false) }}
|
||||
|
||||
BKP_VOLUME_2_LOCAL_DISABLED: >-
|
||||
{{ lookup('backup_image', 'disabled') }}
|
||||
{{ lookup('backup_image', 'disabled', true) }}
|
||||
|
||||
BKP_VOLUME_2_LOCAL_VOLUMES_DISABLED: >-
|
||||
{{ lookup('backup_volume') }}
|
||||
|
||||
@@ -16,6 +16,7 @@ elasticsearch:
|
||||
min_storage: 1066MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "2.0"
|
||||
mem_reservation: 2g
|
||||
mem_limit: 4g
|
||||
|
||||
@@ -17,6 +17,7 @@ mariadb:
|
||||
min_storage: 308MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "2.0"
|
||||
mem_reservation: 2g
|
||||
mem_limit: 4g
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
openldap:
|
||||
backup:
|
||||
stop_required: true
|
||||
modes:
|
||||
compose:
|
||||
enabled: true
|
||||
|
||||
@@ -19,6 +19,7 @@ postgres:
|
||||
min_storage: 419MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "2.0"
|
||||
mem_reservation: 3g
|
||||
mem_limit: 6g
|
||||
|
||||
@@ -16,6 +16,7 @@ qdrant:
|
||||
min_storage: 270MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "2.0"
|
||||
mem_reservation: 1g
|
||||
mem_limit: 2g
|
||||
|
||||
@@ -16,6 +16,7 @@ rabbitmq:
|
||||
min_storage: 289MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "1.0"
|
||||
mem_reservation: 512m
|
||||
mem_limit: 1g
|
||||
|
||||
@@ -16,6 +16,7 @@ typesense:
|
||||
min_storage: 428MB
|
||||
backup:
|
||||
database_routine: true
|
||||
stop_required: true
|
||||
cpus: "1.0"
|
||||
mem_reservation: 512m
|
||||
mem_limit: 1g
|
||||
|
||||
@@ -46,7 +46,7 @@ akaunting:
|
||||
swarm:
|
||||
enabled: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: docker.io/akaunting/akaunting
|
||||
version: 3.1.21
|
||||
repository: https://github.com/akaunting/docker.git
|
||||
|
||||
@@ -64,7 +64,7 @@ baserow:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: baserow/baserow
|
||||
version: 2.4.1
|
||||
custom: true
|
||||
|
||||
@@ -113,6 +113,8 @@ prometheus:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
bbb-web:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-web
|
||||
version: "v3.0.39"
|
||||
update:
|
||||
@@ -123,6 +125,8 @@ bbb-web:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
freeswitch:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-freeswitch
|
||||
version: "v1.11.3-v3.0.39"
|
||||
update:
|
||||
@@ -134,6 +138,8 @@ freeswitch:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
nginx:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-nginx
|
||||
version: "v3.0.39-v5.4.8-1.29"
|
||||
update:
|
||||
@@ -157,6 +163,8 @@ bbb-shared-notes-server:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
bbb-export-annotations:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-bbb-export-annotations
|
||||
version: "v3.0.39"
|
||||
update:
|
||||
@@ -167,6 +175,8 @@ bbb-export-annotations:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
webrtc-sfu:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-webrtc-sfu
|
||||
version: "v2.24.0"
|
||||
update:
|
||||
@@ -187,6 +197,8 @@ fsesl-akka:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
apps-akka:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-apps-akka
|
||||
version: "v3.0.39"
|
||||
update:
|
||||
@@ -232,6 +244,8 @@ bbb-graphql-middleware:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
periodic:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-periodic
|
||||
version: "v3.0.0"
|
||||
update:
|
||||
@@ -242,6 +256,8 @@ periodic:
|
||||
# nocheck: playwright-service-flag: prebuilt upstream-compose image, mirror pre-pull only
|
||||
# nocheck: dynamic-flag: fixed upstream-compose sub-service, not group-gated
|
||||
recordings:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: alangecker/bbb-docker-recordings
|
||||
version: "v3.0.39"
|
||||
update:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
# nocheck: dockerfile-custom
|
||||
logout:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-svc-logout' in group_names }}"
|
||||
@@ -74,6 +73,8 @@ view:
|
||||
mem_limit: 256m
|
||||
pids_limit: 256
|
||||
pds:
|
||||
backup:
|
||||
stop_required: true
|
||||
image: ghcr.io/bluesky-social/pds
|
||||
version: 0.4.66
|
||||
min_storage: 290MB
|
||||
@@ -82,9 +83,12 @@ pds:
|
||||
mem_limit: 2g
|
||||
pids_limit: 1024
|
||||
broker:
|
||||
backup:
|
||||
stop_required: false
|
||||
name: bluesky-broker
|
||||
image: node
|
||||
version: 26-alpine
|
||||
custom: bluesky_broker
|
||||
ports:
|
||||
local:
|
||||
http: 8076
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
args:
|
||||
BLUESKY_BROKER_BASE_IMAGE: "{{ BLUESKY_BROKER_BASE_IMAGE }}"
|
||||
BLUESKY_BROKER_BASE_VERSION: "{{ BLUESKY_BROKER_BASE_VERSION }}"
|
||||
{{ lookup('container_image', application_id, BLUESKY_BROKER_SERVICE, image=BLUESKY_BROKER_IMAGE) }}
|
||||
{{ lookup('container_image', application_id, BLUESKY_BROKER_SERVICE) }}
|
||||
{{ lookup('compose_only', 'container_name', BLUESKY_BROKER_CONTAINER) }}
|
||||
hostname: {{ service_name }}
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
|
||||
@@ -150,7 +150,6 @@ BLUESKY_FRONT_PROXY_ENDPOINTS:
|
||||
|
||||
BLUESKY_BROKER_BUILD_CONTEXT: "{{ [ lookup('container', application_id, 'directories.services'), 'login-broker' ] | path_join }}"
|
||||
BLUESKY_BROKER_SRC_DIR: "{{ role_path }}/files/login-broker"
|
||||
BLUESKY_BROKER_IMAGE: "bluesky_broker_custom"
|
||||
BLUESKY_BROKER_BASE_IMAGE: "{{ lookup('config', application_id, 'services.broker.image') }}"
|
||||
BLUESKY_BROKER_BASE_VERSION: "{{ lookup('config', application_id, 'services.broker.version') }}"
|
||||
BLUESKY_BROKER_SERVICE: "broker"
|
||||
|
||||
@@ -47,6 +47,8 @@ redis:
|
||||
mem_limit: 512m
|
||||
pids_limit: 512
|
||||
bookwyrm:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
hostname: localhost
|
||||
@@ -85,7 +87,6 @@ bookwyrm:
|
||||
pids_limit: 512
|
||||
migrate:
|
||||
name: bookwyrm-migrate
|
||||
custom: true
|
||||
# nocheck: single-replica run-once bootstrap; concurrent migrate/initdb deadlock the migration graph and double-insert the SiteSettings singleton
|
||||
replicas: 1
|
||||
cpus: "0.5"
|
||||
@@ -97,7 +98,6 @@ migrate:
|
||||
# nocheck: playwright-service-flag — internal sub-component (multi-entity role)
|
||||
worker:
|
||||
name: bookwyrm-worker
|
||||
custom: true
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
cpus: "1.0"
|
||||
mem_reservation: 256m
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
data:
|
||||
type: volume
|
||||
name: bookwyrm_data
|
||||
backup: false
|
||||
mounts:
|
||||
- service: bookwyrm
|
||||
target: &app_data_target /app/data
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
BOOKWYRM_VERSION: "{{ BOOKWYRM_VERSION }}"
|
||||
BOOKWYRM_REPOSITORY: "{{ BOOKWYRM_REPOSITORY }}"
|
||||
BOOKWYRM_REF: "{{ BOOKWYRM_REF }}"
|
||||
{{ lookup('container_image', application_id, 'bookwyrm', version=BOOKWYRM_REF) }}
|
||||
{{ lookup('container_image', application_id, 'bookwyrm') }}
|
||||
{{ lookup('compose_only', 'container_name', BOOKWYRM_CONTAINER) }}
|
||||
hostname: "{{ container_hostname }}"
|
||||
{{ lookup('container_ports', ['bookwyrm', 'http', DOCKER_BIND_HOST]) | indent(4) }}
|
||||
@@ -30,7 +30,7 @@
|
||||
{% set service_name = 'worker' %}
|
||||
{{ service_name }}:
|
||||
{% include 'roles/sys-svc-container/templates/base.yml.j2' %}
|
||||
{{ lookup('container_image', application_id, 'worker', version=BOOKWYRM_REF) }}
|
||||
{{ lookup('container_image', application_id, 'bookwyrm') }}
|
||||
{{ lookup('compose_only', 'container_name', BOOKWYRM_WORKER_CONTAINER) }}
|
||||
command: "/venv/bin/celery -A celerywyrm worker -l INFO"
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
@@ -45,7 +45,7 @@
|
||||
{% set docker_restart_policy = 'on-failure' %}
|
||||
{{ service_name }}:
|
||||
{% include 'roles/sys-svc-container/templates/base.yml.j2' %}
|
||||
{{ lookup('container_image', application_id, 'migrate', version=BOOKWYRM_REF) }}
|
||||
{{ lookup('container_image', application_id, 'bookwyrm') }}
|
||||
{{ lookup('compose_only', 'container_name', BOOKWYRM_MIGRATE_CONTAINER) }}
|
||||
command: >-
|
||||
bash -c '
|
||||
|
||||
@@ -80,7 +80,7 @@ checkmk:
|
||||
image: checkmk/check-mk-raw
|
||||
version: "2.4.0p39"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: checkmk
|
||||
ports:
|
||||
internal:
|
||||
|
||||
@@ -35,7 +35,7 @@ chess:
|
||||
name: web-app-chess
|
||||
min_storage: 633MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: 0.5
|
||||
mem_reservation: 256m
|
||||
mem_limit: 512m
|
||||
|
||||
@@ -29,6 +29,8 @@ postgres:
|
||||
shared: "{{ 'svc-db-postgres' in group_names }}"
|
||||
# nocheck: playwright-service-flag self-provider
|
||||
confluence:
|
||||
backup:
|
||||
stop_required: false
|
||||
enabled: false
|
||||
shared: true
|
||||
healthcheck:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
---
|
||||
# nocheck: dockerfile-custom
|
||||
sso:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-keycloak' in group_names }}"
|
||||
@@ -27,6 +26,8 @@ postgres:
|
||||
shared: "{{ 'svc-db-postgres' in group_names }}"
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
decidim:
|
||||
backup:
|
||||
stop_required: false
|
||||
# nocheck: architecture-pin Reason: ghcr.io/decidim/decidim publishes a single linux/amd64 manifest and upstream offers no arm64 tag, so reaching arm64 means building the Rails application from source the way web-app-pretix does, which this role does not
|
||||
architectures:
|
||||
- amd64
|
||||
@@ -41,6 +42,7 @@ decidim:
|
||||
enabled: true
|
||||
image: ghcr.io/decidim/decidim
|
||||
version: 0.31.6
|
||||
custom: true
|
||||
min_storage: 1206MB
|
||||
name: decidim
|
||||
cpus: "1.0"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
uploads:
|
||||
type: volume
|
||||
name: decidim_uploads
|
||||
backup: false
|
||||
mounts:
|
||||
- service: decidim
|
||||
target: /app/public/uploads
|
||||
@@ -9,6 +10,7 @@ uploads:
|
||||
logs:
|
||||
type: volume
|
||||
name: decidim_logs
|
||||
backup: false
|
||||
mounts:
|
||||
- service: decidim
|
||||
target: /app/log
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
DECIDIM_PATCH_SCRIPT_DOCKER: "{{ DECIDIM_PATCH_SCRIPT_DOCKER }}"
|
||||
DECIDIM_PATCH_RUBY_HOST_REL: "{{ DECIDIM_PATCH_RUBY_HOST_REL }}"
|
||||
DECIDIM_PATCH_RUBY_DOCKER: "{{ DECIDIM_PATCH_RUBY_DOCKER }}"
|
||||
{{ lookup('container_image', application_id, 'decidim', version=DECIDIM_VERSION ~ '-infinito') }}
|
||||
{{ lookup('container_image', application_id, 'decidim') }}
|
||||
{{ lookup('compose_only', 'container_name', DECIDIM_CONTAINER) }}
|
||||
command: bash -c "until bundle exec rails db:migrate; do sleep 5; done; exec bundle exec puma -C config/puma.rb"
|
||||
{{ lookup('container_ports', ['decidim', 'http', DOCKER_BIND_HOST]) | indent(4) }}
|
||||
|
||||
@@ -53,7 +53,7 @@ docs:
|
||||
# nocheck: min-storage-headroom Reason: the image built on the python base (1.1 GB), the English sites of the deployed working tree and of the latest commit (2.3 GB each), one translated site of each (about 2 GB each, built without _sources) and the scratch of a running build (2.4 GB); every further version or translated language opened adds about 2.3 GB
|
||||
min_storage: 13GB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: docs
|
||||
ports:
|
||||
internal:
|
||||
|
||||
@@ -30,6 +30,8 @@ mariadb:
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
shared: "{{ 'svc-db-mariadb' in group_names }}"
|
||||
espocrm:
|
||||
backup:
|
||||
stop_required: false
|
||||
modes:
|
||||
compose:
|
||||
enabled: true
|
||||
@@ -67,7 +69,6 @@ daemon:
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "test -f /var/www/html/bootstrap.php && php -r \"require '/var/www/html/bootstrap.php'; echo 'OK';\""]
|
||||
retries: 5
|
||||
custom: true
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
cpus: 0.5
|
||||
@@ -75,7 +76,6 @@ daemon:
|
||||
mem_limit: 0.5g
|
||||
pids_limit: 384
|
||||
websocket:
|
||||
custom: true
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
cpus: 0.5
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
{% set service_name = 'daemon' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, 'daemon', version=ESPOCRM_VERSION) }}
|
||||
{{ lookup('container_image', application_id, 'espocrm') }}
|
||||
{{ lookup('compose_only', 'container_name', ESPOCRM_CONTAINER ~ '_' ~ service_name) }}
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
init: true
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
{% set service_name = 'websocket' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, 'websocket', version=ESPOCRM_VERSION) }}
|
||||
{{ lookup('container_image', application_id, 'espocrm') }}
|
||||
{{ lookup('compose_only', 'container_name', ESPOCRM_CONTAINER ~ '_' ~ service_name) }}
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
init: true
|
||||
|
||||
@@ -40,7 +40,7 @@ fider:
|
||||
name: fider
|
||||
min_storage: 400MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "0.5"
|
||||
mem_reservation: 128m
|
||||
mem_limit: 512m
|
||||
|
||||
@@ -57,7 +57,7 @@ flowise:
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
image: node
|
||||
# nocheck: docker-version
|
||||
version: "24-slim"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# nocheck: seaweedfs-required, object storage not implemented for this role
|
||||
# nocheck: playwright-service-flag, self-provider
|
||||
friendica:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: msmtp_curl
|
||||
modes:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
# nocheck: seaweedfs-playwright — the only objects this role writes are the branding images of tasks/01_manager.yml, and files/playwright/test-design.js fetches the sidebar logo from its bucket URL and compares it byte for byte with the configured asset; on an onion pick that fetch fails, because web-svc-seaweedfs publishes no onion vhost and the Tor-proxied browser cannot resolve its clearnet name; the document surface the shared scenario drives is the audio-library import flow, which needs a persona-owned library and a real track upload the role does not provision
|
||||
funkwhale:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: wget
|
||||
modes:
|
||||
@@ -33,6 +35,8 @@ funkwhale:
|
||||
mem_limit: 2g
|
||||
pids_limit: 1024
|
||||
api:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
path: api/v1/instance/nodeinfo/2.0
|
||||
@@ -57,6 +61,8 @@ migrate:
|
||||
pids_limit: 512
|
||||
# nocheck: image-healthcheck no internal port declared, so no probe can address it
|
||||
typesense:
|
||||
backup:
|
||||
stop_required: false
|
||||
bond: 1
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
shared: "{{ 'svc-db-typesense' in group_names }}"
|
||||
|
||||
@@ -62,6 +62,7 @@ design_admin_template:
|
||||
typesense_data:
|
||||
type: volume
|
||||
name: funkwhale_typesense_data
|
||||
backup: false
|
||||
mounts:
|
||||
- service: typesense
|
||||
target: /data
|
||||
@@ -41,6 +41,8 @@ sso:
|
||||
allowed_groups:
|
||||
- "{{ lookup('rbac_group_path', application_id='web-app-fusiondirectory', role='administrator') }}"
|
||||
fusiondirectory:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
modes:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
data:
|
||||
type: volume
|
||||
name: fusiondirectory_data
|
||||
backup: false
|
||||
mounts:
|
||||
- service: fusiondirectory
|
||||
target: /assets/fusiondirectory
|
||||
|
||||
@@ -53,7 +53,7 @@ gitea:
|
||||
replicas: 1 # nocheck: single-replica single-writer app state on swarm-shared NFS; concurrent multi-node writers corrupt app.ini
|
||||
min_storage: 270MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: gitea
|
||||
cpus: 1.0
|
||||
mem_reservation: 1g
|
||||
|
||||
@@ -75,6 +75,8 @@ gitlab:
|
||||
- web-app-mailu
|
||||
lifecycle: beta
|
||||
webservice:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: registry.gitlab.com/gitlab-org/build/cng/gitlab-webservice-ce
|
||||
version: v19.5.1
|
||||
name: gitlab-webservice
|
||||
@@ -91,6 +93,8 @@ webservice:
|
||||
mem_limit: 6g
|
||||
pids_limit: 2048
|
||||
sidekiq:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: tcp
|
||||
path: liveness
|
||||
@@ -105,6 +109,8 @@ sidekiq:
|
||||
internal:
|
||||
http: 3808
|
||||
workhorse:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: registry.gitlab.com/gitlab-org/build/cng/gitlab-workhorse-ce
|
||||
version: v19.5.1
|
||||
name: gitlab-workhorse
|
||||
@@ -115,6 +121,8 @@ workhorse:
|
||||
mem_limit: 512m
|
||||
pids_limit: 256
|
||||
gitaly:
|
||||
backup:
|
||||
stop_required: true
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
# nocheck: default-placement-manager the repositories live on a node-local volume (meta/volumes.yml nfs: false, gitaly does not support NFS), which a reschedule leaves behind on the old node
|
||||
@@ -132,6 +140,8 @@ gitaly:
|
||||
mem_limit: 2g
|
||||
pids_limit: 1024
|
||||
shell:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: registry.gitlab.com/gitlab-org/build/cng/gitlab-shell
|
||||
version: v19.5.1
|
||||
name: gitlab-shell
|
||||
@@ -143,6 +153,8 @@ shell:
|
||||
mem_limit: 256m
|
||||
pids_limit: 256
|
||||
migrations:
|
||||
backup:
|
||||
stop_required: false
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
image: registry.gitlab.com/gitlab-org/build/cng/gitlab-rails-ce
|
||||
|
||||
@@ -13,7 +13,7 @@ hermes:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: nousresearch/hermes-agent
|
||||
version: "v2026.9.24"
|
||||
name: hermes
|
||||
|
||||
@@ -13,7 +13,7 @@ homeassistant:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ghcr.io/home-assistant/home-assistant
|
||||
version: "2026.7"
|
||||
name: homeassistant
|
||||
|
||||
@@ -55,7 +55,7 @@ jellyfin:
|
||||
image: jellyfin/jellyfin
|
||||
version: "10.11.11"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
# nocheck: single-replica Jellyfin persists all state in embedded SQLite under the shared {{ lookup('volume', 'web-app-jellyfin', 'jellyfin_config').target }} volume; concurrent replicas corrupt the database (SQLite disk I/O error, malformed image in CI) and upstream has no multi-instance support
|
||||
replicas: 1
|
||||
name: jellyfin
|
||||
|
||||
@@ -47,6 +47,8 @@ ldap:
|
||||
shared: "{{ 'svc-db-openldap' in group_names }}"
|
||||
# nocheck: playwright-service-flag self-provider
|
||||
jenkins:
|
||||
backup:
|
||||
stop_required: true
|
||||
enabled: true
|
||||
shared: true
|
||||
bond: 1
|
||||
|
||||
@@ -29,6 +29,8 @@ postgres:
|
||||
shared: "{{ 'svc-db-postgres' in group_names }}"
|
||||
# nocheck: playwright-service-flag self-provider
|
||||
jira:
|
||||
backup:
|
||||
stop_required: true
|
||||
enabled: false
|
||||
shared: true
|
||||
healthcheck:
|
||||
|
||||
@@ -55,7 +55,7 @@ joomla:
|
||||
name: joomla
|
||||
min_storage: 478MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
upload:
|
||||
size_mb: 100
|
||||
autocreate_users: true
|
||||
|
||||
@@ -100,6 +100,8 @@ proxy:
|
||||
mem_limit: 512m
|
||||
pids_limit: 512
|
||||
backend:
|
||||
backup:
|
||||
stop_required: true
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
name: kix-backend
|
||||
@@ -114,6 +116,8 @@ backend:
|
||||
mem_limit: 4g
|
||||
pids_limit: 1024
|
||||
frontend:
|
||||
backup:
|
||||
stop_required: true
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
name: kix-frontend
|
||||
|
||||
@@ -49,7 +49,7 @@ listmonk:
|
||||
image: listmonk/listmonk
|
||||
version: "v6.2.0"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: listmonk
|
||||
ports:
|
||||
internal:
|
||||
|
||||
@@ -38,7 +38,7 @@ php:
|
||||
internal:
|
||||
fpm: 9000
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
min_storage: 660MB
|
||||
cpus: "0.5"
|
||||
mem_reservation: 256m
|
||||
@@ -49,7 +49,7 @@ nginx:
|
||||
version: "1.28"
|
||||
name: magento-nginx
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
min_storage: 235MB
|
||||
cpus: "0.5"
|
||||
mem_reservation: 256m
|
||||
|
||||
@@ -157,6 +157,8 @@ antispam:
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: playwright-service-flag — internal sub-component
|
||||
antivirus:
|
||||
backup:
|
||||
stop_required: false
|
||||
name: mailu-antivirus
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
shared: false
|
||||
|
||||
@@ -10,6 +10,7 @@ admin_data:
|
||||
clamav_db:
|
||||
type: volume
|
||||
name: mailu_clamav_db
|
||||
backup: false
|
||||
mounts:
|
||||
- service: antivirus
|
||||
target: /var/lib/clamav
|
||||
|
||||
@@ -50,7 +50,7 @@ mastodon:
|
||||
version: v4.6.2
|
||||
min_storage: 535MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: mastodon
|
||||
cpus: "1.0"
|
||||
mem_reservation: 1.5g
|
||||
|
||||
@@ -37,7 +37,7 @@ matomo:
|
||||
name: matomo
|
||||
min_storage: 404MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: 1.0
|
||||
mem_reservation: 512m
|
||||
mem_limit: 1g
|
||||
|
||||
@@ -98,7 +98,7 @@ synapse:
|
||||
image: matrixdotorg/synapse
|
||||
name: matrix-synapse
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
ports:
|
||||
internal:
|
||||
http: 8008
|
||||
@@ -132,6 +132,8 @@ element:
|
||||
mem_limit: 256m
|
||||
pids_limit: 256
|
||||
matrix-chatgpt-bot:
|
||||
backup:
|
||||
stop_required: false
|
||||
version: 3.1.5
|
||||
image: ghcr.io/matrixgpt/matrix-chatgpt-bot
|
||||
min_storage: 307MB
|
||||
|
||||
@@ -53,7 +53,7 @@ mattermost:
|
||||
ref: v11.11.1
|
||||
min_storage: 659MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: mattermost
|
||||
cpus: "1.0"
|
||||
mem_reservation: 512m
|
||||
|
||||
@@ -55,7 +55,7 @@ mediawiki:
|
||||
custom: true
|
||||
min_storage: 546MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: mediawiki
|
||||
ports:
|
||||
local:
|
||||
|
||||
@@ -26,6 +26,8 @@ redis:
|
||||
backup:
|
||||
disabled: true
|
||||
meta:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
modes:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
git:
|
||||
type: volume
|
||||
name: meta_git
|
||||
backup: false
|
||||
mounts:
|
||||
- service: meta
|
||||
target: /var/lib/mig
|
||||
@@ -33,7 +33,7 @@ minio:
|
||||
enabled: false
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
image: quay.io/minio/minio
|
||||
version: "RELEASE.2025-09-07T16-13-09Z" # nocheck: docker-version
|
||||
name: minio
|
||||
|
||||
@@ -30,6 +30,8 @@ postgres:
|
||||
- pg_trgm
|
||||
- unaccent
|
||||
mobilizon:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
modes:
|
||||
|
||||
@@ -36,6 +36,8 @@ mariadb:
|
||||
shared: "{{ 'svc-db-mariadb' in group_names }}"
|
||||
# nocheck: playwright-service-flag: shared provider entity; the app itself is covered by this role's own Playwright spec
|
||||
moodle:
|
||||
backup:
|
||||
stop_required: false
|
||||
modes:
|
||||
compose:
|
||||
enabled: true
|
||||
@@ -87,6 +89,8 @@ moodle:
|
||||
- web-app-keycloak
|
||||
lifecycle: beta
|
||||
nginx:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: nginx
|
||||
version: 1.31-alpine
|
||||
name: moodle-nginx
|
||||
@@ -100,7 +104,6 @@ nginx:
|
||||
http: 80
|
||||
cron:
|
||||
name: moodle-cron
|
||||
custom: true
|
||||
min_storage: 1GB
|
||||
cpus: "0.2"
|
||||
mem_reservation: 128m
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{{ service_name }}:
|
||||
{% include 'roles/sys-svc-container/templates/deploy.yml.j2' %}
|
||||
{{ lookup('compose_only', 'container_name', MOODLE_CRON_CONTAINER) }}
|
||||
{{ lookup('container_image', application_id, 'cron', version=MOODLE_VERSION) }}
|
||||
{{ lookup('container_image', application_id, 'moodle') }}
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
{{ lookup('depends_on', {'moodle': 'service_healthy'}) }}
|
||||
{{ lookup('container_volumes', service_name) | indent(4) }}
|
||||
|
||||
@@ -73,7 +73,7 @@ n8n:
|
||||
swarm:
|
||||
enabled: true
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
image: docker.n8n.io/n8nio/n8n
|
||||
version: "3.0.0"
|
||||
update:
|
||||
|
||||
@@ -71,7 +71,7 @@ nextcloud:
|
||||
custom: true
|
||||
min_storage: 553MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "2.0"
|
||||
mem_reservation: 2g
|
||||
mem_limit: 3g
|
||||
@@ -124,7 +124,7 @@ proxy:
|
||||
image: nginx
|
||||
version: 1.31.8-alpine
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "0.5"
|
||||
mem_reservation: 64m
|
||||
mem_limit: 256m
|
||||
@@ -143,7 +143,7 @@ context_agent:
|
||||
image: ghcr.io/nextcloud/context_agent
|
||||
version: 2.10.0
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
# nocheck: single-replica
|
||||
replicas: 1
|
||||
cpus: "1.0"
|
||||
@@ -199,7 +199,7 @@ talk:
|
||||
# nocheck: docker-version -- all 174 tags upstream publishes are AIO build stamps, none is a version
|
||||
version: latest
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
turn_server:
|
||||
onboard_enabled: "{{ not ( 'web-svc-coturn' in group_names ) }}"
|
||||
standalone_enabled: "{{ 'web-svc-coturn' in group_names }}"
|
||||
@@ -233,7 +233,7 @@ whiteboard:
|
||||
version: v1.5.9
|
||||
custom: nextcloud-whiteboard
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "1"
|
||||
mem_reservation: 128m
|
||||
mem_limit: 1g
|
||||
@@ -284,7 +284,7 @@ talk_recording:
|
||||
# nocheck: docker-version -- all 104 tags upstream publishes are AIO build stamps, none is a version
|
||||
version: latest
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "2.0"
|
||||
mem_reservation: 1g
|
||||
mem_limit: 3g
|
||||
|
||||
@@ -48,7 +48,7 @@ odoo:
|
||||
mem_limit: 4g
|
||||
pids_limit: 1024
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
email:
|
||||
from_name: ERP ({{ DOMAIN_PRIMARY }})
|
||||
ports:
|
||||
|
||||
@@ -40,7 +40,7 @@ This role deploys OpenBao as an Infinito.Nexus application at `openbao.<domain>`
|
||||
|
||||
### Backup and restore
|
||||
|
||||
Backups run through `svc-bkp-volume-2-local` with `backup.no_stop_required: false`, so the container is quiesced for a consistent copy of the raft volume. To restore:
|
||||
Backups run through `svc-bkp-volume-2-local` with `backup.stop_required: true`, so the container is quiesced for a consistent copy of the raft volume. To restore:
|
||||
|
||||
1. Restore the `openbao_data` volume from the backup generation.
|
||||
2. Confirm the inventory still holds the original `seal_key` — a different key makes the restored store unreadable.
|
||||
|
||||
@@ -59,7 +59,7 @@ openbao:
|
||||
version: "2.7.2"
|
||||
custom: true
|
||||
backup:
|
||||
no_stop_required: false
|
||||
stop_required: true
|
||||
# nocheck: single-replica single-node raft: a second replica would need a real raft join/bootstrap flow, and two tasks against one BoltDB directory corrupt the store
|
||||
replicas: 1
|
||||
name: openbao
|
||||
|
||||
@@ -12,7 +12,7 @@ openclaw:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ghcr.io/openclaw/openclaw
|
||||
version: "2026.7.1"
|
||||
name: openclaw
|
||||
|
||||
@@ -43,7 +43,7 @@ opencloud:
|
||||
# nocheck: default-placement-manager opencloud_data holds NFS-hostile engine state: NATS JetStream store (events, micro registry, posixfs id cache), bleve search index, idm.boltdb, posixfs xattr metadata; upstream says search cannot scale, so the volume must stay node-local
|
||||
placement: manager
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "2.0"
|
||||
mem_reservation: 1g
|
||||
mem_limit: 4g
|
||||
|
||||
@@ -47,7 +47,7 @@ web:
|
||||
version: "17"
|
||||
custom: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "3.0"
|
||||
mem_reservation: 3g
|
||||
mem_limit: 6g
|
||||
@@ -80,7 +80,6 @@ worker:
|
||||
min_storage: 5GB
|
||||
proxy:
|
||||
name: openproject-proxy
|
||||
custom: true
|
||||
cpus: "0.3"
|
||||
mem_reservation: 256m
|
||||
mem_limit: 512m
|
||||
|
||||
@@ -18,7 +18,7 @@ x-op-app: &app
|
||||
{% set service_name = 'proxy' %}
|
||||
{{ service_name }}:
|
||||
{% include 'roles/sys-svc-container/templates/base.yml.j2' %}
|
||||
{{ lookup('container_image', application_id, 'proxy', version=OPENPROJECT_VERSION) }}
|
||||
{{ lookup('container_image', application_id, 'web') }}
|
||||
{{ lookup('compose_only', 'container_name', OPENPROJECT_PROXY_CONTAINER) }}
|
||||
{{ lookup('compose_only', 'pull_policy', 'never') }}
|
||||
command: "./docker/prod/proxy"
|
||||
|
||||
@@ -72,7 +72,7 @@ opentalk:
|
||||
pattern: "OT_FRONTEND_IMAGE_TAG:-(v[0-9.]+)\\}"
|
||||
min_storage: 234MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "0.5"
|
||||
mem_reservation: 128m
|
||||
mem_limit: 512m
|
||||
@@ -95,7 +95,7 @@ controller:
|
||||
pattern: "OPENTALK_CONTROLLER_IMAGE_TAG:-(v[0-9.]+)\\}"
|
||||
min_storage: 291MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "1.5"
|
||||
mem_reservation: 512m
|
||||
mem_limit: 2g
|
||||
@@ -139,6 +139,8 @@ seaweedfs:
|
||||
enabled: true # nocheck: dynamic-flag
|
||||
shared: "{{ 'web-svc-seaweedfs' in group_names }}"
|
||||
rabbit:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "ping"]
|
||||
# nocheck: healthcheck-timing-override rabbitmq-diagnostics starts an Erlang CLI node, which does not finish inside the 5s default
|
||||
|
||||
@@ -21,6 +21,7 @@ minio:
|
||||
rabbit:
|
||||
type: volume
|
||||
name: opentalk_rabbit
|
||||
backup: false
|
||||
mounts:
|
||||
- service: rabbit
|
||||
target: /var/lib/rabbitmq
|
||||
|
||||
@@ -34,7 +34,7 @@ openwebui:
|
||||
enabled: true
|
||||
shared: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
image: ghcr.io/open-webui/open-webui
|
||||
version: 0.11.0
|
||||
name: open-webui
|
||||
|
||||
@@ -67,7 +67,7 @@ peertube:
|
||||
live:
|
||||
enabled: true
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
# nocheck: single-replica PeerTube has no multi-instance support upstream; the RTMP live ingest binds one instance with no VIP session affinity, and the OIDC state cookie uses a per-process key, so concurrent replicas break live streams and the auth callback
|
||||
replicas: 1
|
||||
cpus: 4
|
||||
|
||||
@@ -79,6 +79,8 @@ penpot:
|
||||
- web-app-mailu
|
||||
lifecycle: beta
|
||||
frontend:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: penpotapp/frontend
|
||||
version: "2.18.5"
|
||||
name: penpot-frontend
|
||||
@@ -87,6 +89,8 @@ frontend:
|
||||
mem_limit: 512m
|
||||
pids_limit: 256
|
||||
backend:
|
||||
backup:
|
||||
stop_required: false
|
||||
image: penpotapp/backend
|
||||
version: "2.18.5"
|
||||
name: penpot-backend
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
---
|
||||
# nocheck: seaweedfs-required — object storage not implemented for this role
|
||||
pgadmin:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
flavor: wget
|
||||
modes:
|
||||
|
||||
@@ -59,6 +59,8 @@ sso:
|
||||
allowed_groups:
|
||||
- "{{ lookup('rbac_group_path', application_id='web-app-pihole', role='administrator') }}"
|
||||
pihole:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
flavor: tcp
|
||||
modes:
|
||||
|
||||
@@ -53,7 +53,7 @@ pixelfed:
|
||||
name: pixelfed
|
||||
min_storage: 588MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: 0.75
|
||||
mem_reservation: 0.5g
|
||||
mem_limit: 0.75g
|
||||
|
||||
@@ -66,7 +66,7 @@ pretix:
|
||||
name: pretix
|
||||
min_storage: 1003MB
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "2.0"
|
||||
mem_reservation: 1.5g
|
||||
mem_limit: 3g
|
||||
|
||||
@@ -46,6 +46,8 @@ javascript:
|
||||
shared: "{{ lookup('config', 'web-app-prometheus', 'services.sso.enabled') | bool }}"
|
||||
# nocheck: playwright-service-flag — self-provider
|
||||
prometheus:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
flavor: wget
|
||||
path: -/healthy
|
||||
@@ -83,6 +85,8 @@ prometheus:
|
||||
lifecycle: beta
|
||||
min_storage: 307MB
|
||||
alertmanager:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: wget
|
||||
path: -/healthy
|
||||
|
||||
@@ -61,7 +61,7 @@ semaphore:
|
||||
image: semaphoreui/semaphore
|
||||
version: "v2.19.17"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
name: semaphore
|
||||
ports:
|
||||
internal:
|
||||
|
||||
@@ -48,6 +48,8 @@ seaweedfs:
|
||||
public: true
|
||||
# nocheck: playwright-service-flag self-provider
|
||||
snipe-it:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-q", "-O-", "http://localhost/health"]
|
||||
retries: 12
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
socialhome:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
flavor: http_status
|
||||
path: healthz
|
||||
|
||||
@@ -53,6 +53,7 @@ stalwart:
|
||||
name: stalwart
|
||||
backup:
|
||||
project_hard_restart: true
|
||||
stop_required: true
|
||||
migration:
|
||||
import_mailu: false
|
||||
mailbox_map: []
|
||||
@@ -114,7 +115,7 @@ webmail:
|
||||
flavor: curl
|
||||
version: "1.7.5-apache"
|
||||
backup:
|
||||
no_stop_required: true
|
||||
stop_required: false
|
||||
cpus: "0.3"
|
||||
mem_reservation: 256m
|
||||
mem_limit: 1g
|
||||
@@ -127,6 +128,8 @@ webmail:
|
||||
# nocheck: dynamic-flag — role-local sub-component, always deployed with the stack
|
||||
# nocheck: playwright-service-flag — antivirus milter, covered by role deploy test
|
||||
clamav:
|
||||
backup:
|
||||
stop_required: false
|
||||
enabled: true
|
||||
shared: false
|
||||
image: clamav/clamav-debian
|
||||
|
||||
@@ -20,6 +20,7 @@ webmail_data:
|
||||
clamav_data:
|
||||
type: volume
|
||||
name: stalwart_clamav_data
|
||||
backup: false
|
||||
mounts:
|
||||
- service: clamav
|
||||
target: /var/lib/clamav
|
||||
|
||||
@@ -42,6 +42,8 @@ redis:
|
||||
pids_limit: 256
|
||||
# nocheck: playwright-service-flag — self-provider entry; test_env_services_match.py:28-32 grants the forbidden-self-gate exemption
|
||||
suitecrm:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
flavor: curl
|
||||
# nocheck: healthcheck-timing-override boots slower than the ten minute window; the value predates this default and has not been measured against it
|
||||
|
||||
@@ -90,6 +90,8 @@ front:
|
||||
mem_limit: 512m
|
||||
pids_limit: 256
|
||||
gateway:
|
||||
backup:
|
||||
stop_required: false
|
||||
healthcheck:
|
||||
flavor: http
|
||||
ports:
|
||||
@@ -112,6 +114,8 @@ events:
|
||||
mem_limit: 512m
|
||||
pids_limit: 256
|
||||
async-rabbitmq:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
||||
retries: 5
|
||||
@@ -122,6 +126,8 @@ async-rabbitmq:
|
||||
mem_limit: 1.5g
|
||||
pids_limit: 512
|
||||
events-rabbitmq:
|
||||
backup:
|
||||
stop_required: true
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
||||
retries: 5
|
||||
|
||||
@@ -8,6 +8,7 @@ async-rabbitmq-data:
|
||||
events-rabbitmq-data:
|
||||
type: volume
|
||||
name: taiga_events_rabbitmq_data
|
||||
backup: false
|
||||
mounts:
|
||||
- service: events-rabbitmq
|
||||
target: *var_lib_rabbitmq_target
|
||||
|
||||
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user