Deploy: create the data directories instead of assuming Docker will
"Bind mount failed: '/volume1/docker/webmail/data/postgres' doesn't exists" on Synology after the data directory was removed. Docker on ordinary Linux creates a missing bind-mount source silently; DSM's daemon refuses and fails the container. Every service mounted its own subdirectory, so every one of them needed to already exist — including the `init` service whose whole job was to create them, which could therefore never run. - init now mounts DATA_ROOT itself, once, and creates postgres/blobs/backups/ redis/meili/state inside it. Only DATA_ROOT has to pre-exist. - postgres gained the init dependency it was missing, so its data directory is never demanded before init has made it. - init only runs `chown -R` when ownership is actually wrong, rather than walking the whole blob store on every start. - webmail.sh up creates DATA_ROOT and, if it cannot, says so with the mkdir to run rather than leaving the daemon to produce the error above. Verified from an empty DATA_ROOT: init creates all six directories, postgres starts after it, migrations apply, stack serves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nux3LCu4zP9nih4BRhPyHw
This commit is contained in:
+9
-4
@@ -326,10 +326,15 @@ cmd_up() {
|
|||||||
ylw "SEARCH_BACKEND=meili — starting the Meilisearch container too"
|
ylw "SEARCH_BACKEND=meili — starting the Meilisearch container too"
|
||||||
profile=(--profile meili)
|
profile=(--profile meili)
|
||||||
}
|
}
|
||||||
# Best-effort only: Docker creates any missing bind-mount path itself, and
|
# DATA_ROOT must exist before compose runs: Synology's Docker daemon will
|
||||||
# the `init` service fixes ownership. This line must not be fatal, because
|
# not create a missing bind-mount source, it just fails the container. The
|
||||||
# DATA_ROOT is typically root-owned while you may be running as yourself.
|
# `init` service creates the subdirectories from there.
|
||||||
mkdir -p "${DATA_ROOT}"/{postgres,blobs,redis,backups,meili,state} 2>/dev/null || true
|
mkdir -p "${DATA_ROOT}" 2>/dev/null || true
|
||||||
|
if [ ! -d "${DATA_ROOT}" ]; then
|
||||||
|
die "cannot create ${DATA_ROOT} (running as $(id -un)). Create it first:
|
||||||
|
sudo mkdir -p ${DATA_ROOT}
|
||||||
|
then re-run this command."
|
||||||
|
fi
|
||||||
detect_compose
|
detect_compose
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
compose "${profile[@]}" up -d "${build[@]}" $COMPOSE_WAIT
|
compose "${profile[@]}" up -d "${build[@]}" $COMPOSE_WAIT
|
||||||
|
|||||||
+15
-8
@@ -96,17 +96,22 @@ services:
|
|||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
set -e
|
set -e
|
||||||
mkdir -p /mnt/blobs /mnt/backups /mnt/redis /mnt/meili
|
mkdir -p /mnt/postgres /mnt/blobs /mnt/backups /mnt/redis /mnt/meili /mnt/state
|
||||||
chown -R 10001:10001 /mnt/blobs # backend runs as uid 10001
|
# Only recurse when ownership is actually wrong: `chown -R` over a large
|
||||||
chown -R 999:999 /mnt/backups # pg_dump runs as postgres (999)
|
# blob store on every start would be minutes of pointless disk churn.
|
||||||
chown -R 999:999 /mnt/redis # redis runs as uid 999
|
[ "$$(stat -c %u /mnt/blobs)" = "10001" ] || chown -R 10001:10001 /mnt/blobs
|
||||||
|
[ "$$(stat -c %u /mnt/backups)" = "999" ] || chown -R 999:999 /mnt/backups
|
||||||
|
[ "$$(stat -c %u /mnt/redis)" = "999" ] || chown -R 999:999 /mnt/redis
|
||||||
chmod 700 /mnt/backups
|
chmod 700 /mnt/backups
|
||||||
echo "[init] data directories ready"
|
echo "[init] data directories ready"
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/blobs:/mnt/blobs
|
# ONE mount, of DATA_ROOT itself. Synology's Docker daemon refuses to
|
||||||
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/backups:/mnt/backups
|
# create a missing bind-mount source ("Bind mount failed: ... doesn't
|
||||||
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/redis:/mnt/redis
|
# exists") instead of creating it the way Docker does elsewhere, so every
|
||||||
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/meili:/mnt/meili
|
# subdirectory mounted below must exist before its container is created.
|
||||||
|
# Mounting the parent here means only DATA_ROOT has to pre-exist, and this
|
||||||
|
# service creates the rest — which is why everything now depends on it.
|
||||||
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}:/mnt
|
||||||
restart: "no"
|
restart: "no"
|
||||||
logging: *logging
|
logging: *logging
|
||||||
|
|
||||||
@@ -135,6 +140,8 @@ services:
|
|||||||
# Full page writes stay ON: NAS filesystems (btrfs/ext4) are not 8k-atomic.
|
# Full page writes stay ON: NAS filesystems (btrfs/ext4) are not 8k-atomic.
|
||||||
volumes:
|
volumes:
|
||||||
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/postgres:/var/lib/postgresql/data
|
- ${DATA_ROOT:-/NO-.env-FOUND-RUN-deploy_webmail.sh-init-FIRST}/postgres:/var/lib/postgresql/data
|
||||||
|
depends_on:
|
||||||
|
init: { condition: service_completed_successfully }
|
||||||
healthcheck:
|
healthcheck:
|
||||||
# -h 127.0.0.1 forces a TCP check. Without it pg_isready uses the Unix
|
# -h 127.0.0.1 forces a TCP check. Without it pg_isready uses the Unix
|
||||||
# socket, which the temporary server that the postgres image runs during
|
# socket, which the temporary server that the postgres image runs during
|
||||||
|
|||||||
Reference in New Issue
Block a user