mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
compose.yaml names the app services ghcr.io/karatektus/pl_mail:latest, and compose tags what it builds with the service's image name. The dev override adds a build of the frankenphp_dev stage to those same services, so every `docker compose up --build` replaced the published tag locally with a dev image. That image is app-less by design — the source arrives over the bind mount — so nothing is wrong with it until the override is not there. Then compose finds the tag locally, has no reason to pull, and starts a container with no composer.json, which sends the entrypoint into its `composer create-project symfony/skeleton` branch. All four app services crash-loop, and the tag looks correct throughout, so the image is the last place anyone would check. Hit exactly this today. The published image itself was fine: pulled and verified prod stage, app code present, APP_ENV=prod, multi-arch. Building under pl_mail-dev leaves the published tag alone — verified by rebuilding the dev stack and confirming ghcr.io/...:latest still carries its application code afterwards. compose.test.yaml already did the equivalent by having no `image` key at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
137 lines
4.5 KiB
Plaintext
137 lines
4.5 KiB
Plaintext
# Every app service builds the same dev stage, so they share one image — one
|
|
# build instead of six.
|
|
#
|
|
# The `image` line is the load-bearing part. compose.yaml names these services
|
|
# `ghcr.io/karatektus/pl_mail:latest`, and compose tags what it builds with the
|
|
# service's image name — so without this, every `docker compose up --build`
|
|
# overwrites the published tag locally with a dev image. That image carries no
|
|
# application code (the source arrives via the bind mount below), which is
|
|
# correct for dev and fatal anywhere else: if this override ever goes missing,
|
|
# compose finds that local tag, does not pull, and boots an app-less container
|
|
# that falls into the entrypoint's symfony/skeleton branch and crash-loops.
|
|
# Building under our own name leaves the published tag alone.
|
|
x-dev-build: &dev-build
|
|
image: pl_mail-dev:latest
|
|
build:
|
|
context: .
|
|
target: frankenphp_dev
|
|
|
|
services:
|
|
# Builds locally like every other app service. Without this it is the one
|
|
# service still pulling ghcr.io/karatektus/pl_mail, which would run emulated
|
|
# on an arm64 host — and since everything else waits on it completing
|
|
# successfully, that one container gates the whole stack.
|
|
secrets-init:
|
|
<<: *dev-build
|
|
|
|
php:
|
|
<<: *dev-build
|
|
volumes:
|
|
- ./:/app
|
|
- app_var:/app/var
|
|
# Durable mail data must be visible to BOTH the web container (which
|
|
# serves downloads) and the workers (which write during sync). php
|
|
# overlays /app/var with the private app_var volume to keep cache/logs
|
|
# off the bind mount, which otherwise hides these two directories from
|
|
# everything else.
|
|
- app_attachments:/app/var/attachments
|
|
- app_raw:/app/var/raw
|
|
- app_uploads:/app/var/uploads
|
|
- ./frankenphp/Caddyfile:/etc/frankenphp/Caddyfile:ro
|
|
- ./frankenphp/conf.d/20-app.dev.ini:/usr/local/etc/php/conf.d/20-app.dev.ini:ro
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
XDEBUG_MODE: "${XDEBUG_MODE:-off}"
|
|
extra_hosts:
|
|
- host.docker.internal:host-gateway
|
|
tty: true
|
|
|
|
imap-supervisor:
|
|
<<: *dev-build
|
|
volumes:
|
|
- ./:/app
|
|
# Durable mail data must be visible to BOTH the web container (which
|
|
# serves downloads) and the workers (which write during sync). php
|
|
# overlays /app/var with the private app_var volume to keep cache/logs
|
|
# off the bind mount, which otherwise hides these two directories from
|
|
# everything else.
|
|
- app_attachments:/app/var/attachments
|
|
- app_raw:/app/var/raw
|
|
- app_uploads:/app/var/uploads
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
|
|
messenger-worker:
|
|
<<: *dev-build
|
|
volumes:
|
|
- ./:/app
|
|
# Durable mail data must be visible to BOTH the web container (which
|
|
# serves downloads) and the workers (which write during sync). php
|
|
# overlays /app/var with the private app_var volume to keep cache/logs
|
|
# off the bind mount, which otherwise hides these two directories from
|
|
# everything else.
|
|
- app_attachments:/app/var/attachments
|
|
- app_raw:/app/var/raw
|
|
- app_uploads:/app/var/uploads
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
|
|
scheduler:
|
|
<<: *dev-build
|
|
volumes:
|
|
- ./:/app
|
|
environment:
|
|
APP_ENV: ${APP_ENV:-dev}
|
|
|
|
database:
|
|
ports:
|
|
- "5432:5432"
|
|
|
|
mailer:
|
|
image: axllent/mailpit
|
|
ports:
|
|
- "1025:1025"
|
|
- "8025:8025"
|
|
environment:
|
|
MP_SMTP_AUTH_ACCEPT_ANY: 1
|
|
MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
|
|
|
adminer:
|
|
image: adminer
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8080:8080"
|
|
environment:
|
|
ADMINER_DEFAULT_SERVER: database
|
|
|
|
tailwind:
|
|
<<: *dev-build
|
|
volumes:
|
|
- .:/app
|
|
# Runs bin/console, so it goes through the app entrypoint and needs the
|
|
# same secrets every other service uses. Without this it would generate
|
|
# its own and refuse to start.
|
|
- app_secrets:/app/var/secrets
|
|
- app_var:/app/var
|
|
command: php bin/console tailwind:build --watch
|
|
# The image healthcheck probes the FrankenPHP admin endpoint on :2019, but
|
|
# this service replaces the server with the Tailwind watcher, so nothing
|
|
# ever listens there and the container is reported unhealthy while working
|
|
# fine. Same reason imap-supervisor, messenger-worker and scheduler disable
|
|
# it in compose.yaml.
|
|
healthcheck:
|
|
disable: true
|
|
depends_on:
|
|
- php
|
|
|
|
###> symfony/mercure-bundle ###
|
|
mercure:
|
|
ports:
|
|
- "80"
|
|
###< symfony/mercure-bundle ###
|
|
volumes:
|
|
app_var:
|
|
app_attachments:
|
|
app_raw:
|
|
app_uploads:
|