Nie wieder latest
: Unsere Dawarich-Odyssee auf Synology/Portainer
Kurzfassung:
Ein Upgrade auf freikin/dawarich:0.33.x
führte bei uns zu Asset-/Startproblemen (Sprockets/Webmanifest, gemountete Assets, fehlender Start-Command).
Das Rollback auf 0.32.0
mit fix gesetztem Command und ohne Asset-Mounts war sofort stabil.
Merke: In Produktion niemals latest
verwenden.
Ausgangslage
- Plattform: Synology NAS
- Orchestrierung: Portainer (Docker Compose)
- Services: PostGIS (PostgreSQL), Redis, Rails (Dawarich), Sidekiq
- Ziel: Update von stabil laufender
0.32.x
auf0.33.x
Symptome & Fehlerbilder
- Asset-Build bricht ab (Sprockets/Webmanifest):
Sprockets::Rails::Helper::AssetNotFound: The asset "favicon/android-chrome-192x192.png" is not present
Errno::EEXIST: File exists @ dir_s_mkdir - /var/app/public/assets/channels
- Mount blockiert Assets:
rm: cannot remove 'public/assets/channels': Device or resource busy
- Nicht vorhandene Rake/Build-Tasks:
Unrecognized command "tailwind:build"
- Container startet nicht / sofortiger Abbruch:
bundler: exec needs a command to run
In Portainer: „No log line matching the “ filter“ (der Prozess war sofort beendet). - Weitere Stolpersteine:
Fehlender Host-Ordner für Logs → Bind-Mount Fehler.
Die Ursachen in Klartext
- Gemountete
public/assets
(oder Unterordner) verhindern, dass Sprockets schreiben/aufräumen darf → EEXIST/Busy. - Webmanifest-Rake-Task erwartet Favicons im Asset-Pfad. Fehlen die Dateien, bricht die Precompilation ab.
- Entrypoint + Bundler: Das Image ruft intern
bundle exec "$@"
auf. Ohne expliziten Command endet es mit:
bundler: exec needs a command to run
.
So läuft’s stabil (Rollback auf 0.32.0
)
Bewährter Compose-Ausschnitt (anonymisiert):
version: "3.9"
services:
db:
image: postgis/postgis:17-3.5-alpine
container_name: app-db
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
POSTGRES_DB: app_production
TZ: Europe/Berlin
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d app_production"]
interval: 10s
retries: 5
start_period: 30s
volumes:
- /path/to/app/db:/var/lib/postgresql/data
restart: unless-stopped
networks: [appnet]
redis:
image: redis:7.4-alpine
container_name: app-redis
command: ["redis-server","--save","","--appendonly","no"]
healthcheck:
test: ["CMD-SHELL", "redis-cli ping || exit 1"]
volumes:
- /path/to/app/redis:/data
restart: unless-stopped
networks: [appnet]
web:
image: freikin/dawarich:0.32.0
container_name: app-web
# WICHTIG: Command explizit setzen
command: ["bin/rails","server","-p","3000","-b","0.0.0.0"]
environment:
RAILS_ENV: production
RAILS_SERVE_STATIC_FILES: "true"
RAILS_LOG_TO_STDOUT: "true"
REDIS_URL: redis://redis:6379
DATABASE_HOST: db
DATABASE_USERNAME: postgres
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
DATABASE_NAME: app_production
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
APPLICATION_HOSTS: app.example.com
TIME_ZONE: Europe/Berlin
SELF_HOSTED: "true"
STORE_GEODATA: "true"
MAP_TILES_URL: "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
MAP_TILES_ATTRIBUTION: "© OpenStreetMap contributors"
volumes:
- /path/to/app/watched:/var/app/tmp/imports/watched
- /path/to/app/storage:/var/app/storage
- /path/to/app/logs:/var/app/log
ports:
- "3639:3000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks: [appnet]
sidekiq:
image: freikin/dawarich:0.32.0
container_name: app-sidekiq
command: ["sidekiq"]
environment:
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: "true"
REDIS_URL: redis://redis:6379
DATABASE_HOST: db
DATABASE_USERNAME: postgres
DATABASE_PASSWORD: ${DATABASE_PASSWORD}
DATABASE_NAME: app_production
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
BACKGROUND_PROCESSING_CONCURRENCY: 10
SELF_HOSTED: "true"
STORE_GEODATA: "true"
volumes:
- /path/to/app/watched:/var/app/tmp/imports/watched
- /path/to/app/storage:/var/app/storage
- /path/to/app/logs:/var/app/log
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks: [appnet]
networks:
appnet:
driver: bridge
Hinweise:
- Keine Mounts auf
public/assets
,public/assets/channels
oderpublic/manifest.json
. - Host-Ordner
/path/to/app/logs
vorher anlegen, sonst scheitert der Bind-Mount. ${DATABASE_PASSWORD}
und${SECRET_KEY_BASE}
kommen aus einer.env
oder Portainer-UI (keine Secrets im Compose!).
Checkliste: sichere Deploys in Produktion
- Niemals
latest
verwenden. Immer konkrete Tags pinnen (z. B.0.32.0
). - Start-Commands explizit setzen (Rails/Sidekiq), Entrypoint nicht überschreiben.
- Keine Asset-Mounts (Sprockets braucht Schreibrechte bei Precompile).
- Host-Verzeichnisse anlegen, bevor man sie bind-mountet (
storage
,watched
,logs
). - Healthchecks/depends_on nutzen: DB/Redis erst „healthy“, dann App/Sidekiq.
- Logs richtig deuten: „No log line …“ in Portainer heißt oft: Prozess sofort beendet.
Upgrade-Plan (wenn 0.33.x reif ist)
- Changelog/Issues prüfen (bes. Webmanifest/Favicons, Asset-Build).
- Staging-Test mit identischem Compose (separates Netzwerk/Port).
- Vorher DB-Backup ziehen (Dump).
- Commands beibehalten, keine Asset-Mounts.
- Rollback-Pfad parat halten (Tags schnell wechselbar).