With three swarm replicas the PHP session files on the shared NFS volume
were read as empty under concurrent requests of one browser, so SuiteCRM
answered 403 on /api/graphql and dropped the session. Sessions now live in
Redis with session locking that waits like flock did; the phpredis version
is pinned in services.yml with its own update source, and the engine lookup
renders the save path.
Refs #879
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
display_errors=On makes PHP emit the warning before the fatal, so the
headers are already sent and the response is 200 instead of 500. The
healthcheck is a bare curl -f against index.php, so a dead PHP stack
reports healthy and the deploy goes green -- job 92930113419 logged
'GET / 200 674' next to 'Failed opening required autoload_runtime.php'
for fourteen minutes.
CI runs with ENVIRONMENT=development, which is exactly the branch that
turned display_errors on. Off everywhere; log_errors keeps the trace in
the container log, error_reporting keeps its previous non-development
value.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Baking the multi-GB tree into /var/www/html made dockerd's volume
copy-on-first-use flood the shared NFS export from every swarm node in
parallel, so the stack never converged. The Dockerfile becomes a
multi-stage build (shared base with PHP/Apache setup, builder producing
the tree without node_modules, final stage with one COPY --chown layer
under /usr/src/suitecrm) and the entrypoint seeds the empty webroot
volume once, under the existing cross-replica boot lock; installed
volumes are only stamped, never overwritten. Ownership and the
writable-dir modes are baked at build, dropping the runtime chown pass
that crashed on the read-only ldap.yaml config mount. start_period
grows to 20m with the lock ceilings recoupled (live lab NFS measures
the seed at roughly a minute). App dir, seed dir and web user/group are
single-point role vars threaded through build args, entrypoint and
php.ini; the FROM lint now accepts file-internal stage references.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
suitecrm_data is NFS-shared and the datastore is external MariaDB, so replicas share /var/www/html, uploads and cache. Two hazards remained: N replicas racing the first-boot suitecrm:app:install, and node-local PHP file sessions. Wrap the installer + cache pass in a flock on the shared volume so exactly one replica installs while the others block then skip, and pin session.save_path to /var/www/html/tmp on the shared volume so sessions are cluster-wide. flock is a no-op with a single replica, so compose is unchanged. Confidence ~95%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Introduce env-aware php.ini.j2 template
- Mount PHP config into container via docker-compose
- Add SUITECRM_PHP_CONFIG_HOST and SUITECRM_WELL_SOFTWARE_NAME variables
- Refactor LDAP extension path using normalized software name
https://chatgpt.com/share/69284194-cf6c-800f-b138-eb6ddf25592c