fix(web-app-joomla): serialize first-boot copy and install across replicas

The stock image copies /usr/src/joomla into /var/www/html and runs the
auto-installer on every boot. With more than one replica sharing the
NFS volume they corrupt the tree and race the install. Add a custom
entrypoint that takes an atomic mkdir lock on the shared volume so one
leader runs the setup while the others block on a ready marker, wired
through the same host-path build args as the odoo entrypoint. Verified
locally: 2 concurrent replicas on a shared volume copy and install
exactly once and both serve HTTP 200. Sessions are already stored in
the database and caching is off, so the replicas stay stateless.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 4.8 committed 2026-07-05 21:41:43 +02:00
1 parent 819b5ecf82
commit d4e1103fc3
5 files changed
+56 -6

No files matched your search

+12 -6
View File
@@ -1,15 +1,21 @@
ARG JOOMLA_IMAGE
ARG JOOMLA_VERSION
ARG JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL
ARG JOOMLA_ENTRYPOINT_SCRIPT_DOCKER
FROM ${JOOMLA_IMAGE}:${JOOMLA_VERSION}
ARG JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL
ARG JOOMLA_ENTRYPOINT_SCRIPT_DOCKER
# Composer + tooling for the runtime build of the plg_system_keycloak
# OIDC plugin (requirement 013). The plugin's PHP dependencies
# (jumbojett/openid-connect-php) are vendored at deploy time inside
# the running container via `composer install`, so the host never
# needs PHP/Composer. `unzip` is required by Joomla's
# `extension:install --path=<zip>` CLI.
# composer + unzip are needed to vendor and package the OIDC plugin inside the running container
RUN rm -rf /var/lib/apt/lists/* \
&& apt-get update \
&& apt-get install -y --no-install-recommends git unzip curl ca-certificates \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& rm -rf /var/lib/apt/lists/*
COPY ${JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL} ${JOOMLA_ENTRYPOINT_SCRIPT_DOCKER}
RUN chmod +x "${JOOMLA_ENTRYPOINT_SCRIPT_DOCKER}" \
&& ln -sf "${JOOMLA_ENTRYPOINT_SCRIPT_DOCKER}" /usr/local/bin/entrypoint-joomla
ENTRYPOINT ["/usr/local/bin/entrypoint-joomla"]
CMD ["apache2-foreground"]
@@ -0,0 +1,27 @@
#!/bin/bash
# Serialize the stock image's first-boot copy+auto-install across replicas that
# share the /var/www/html NFS volume (mkdir is atomic on NFS: one leader runs it,
# the rest block on the ready marker). The setup only runs when $1 is apache2*/
# php-fpm, so the leader must drive it with `apache2 -v` (returns after setup) —
# a plain `true` skips the whole setup block and copies nothing.
target="/var/www/html"
lock="${target}/.infinito-init.lock"
ready="${target}/.infinito-init.ready"
if [ ! -e "${ready}" ] && [ ! -e "${target}/configuration.php" ]; then
if mkdir "${lock}" 2>/dev/null; then
/entrypoint.sh apache2 -v || true
if [ -e "${target}/configuration.php" ]; then
touch "${ready}"
fi
else
tries=0
while [ ! -e "${ready}" ] && [ ! -e "${target}/configuration.php" ] && [ "${tries}" -lt 300 ]; do
sleep 2
tries=$((tries + 1))
done
fi
fi
exec /entrypoint.sh "$@"
+10
View File
@@ -4,3 +4,13 @@
src: php-upload.ini.j2
dest: "{{ JOOMLA_UPLOAD_CONFIG }}"
mode: "0644"
- name: "📋 Copy Joomla entrypoint (first-boot copy serializer)"
copy:
src: "{{ JOOMLA_ENTRYPOINT_SCRIPT_FILE }}"
dest: "{{ JOOMLA_ENTRYPOINT_SCRIPT_HOST_ABS }}"
mode: "0755"
notify:
- compose build
- compose up
when: IS_STACK_HOST | bool
@@ -6,6 +6,8 @@
args:
JOOMLA_IMAGE: "{{ JOOMLA_IMAGE }}"
JOOMLA_VERSION: "{{ JOOMLA_VERSION }}"
JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL: "{{ JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL }}"
JOOMLA_ENTRYPOINT_SCRIPT_DOCKER: "{{ JOOMLA_ENTRYPOINT_SCRIPT_DOCKER }}"
{{ lookup('container_image', application_id, 'joomla', custom=True) }}
{{ lookup('compose_only', 'container_name', JOOMLA_CONTAINER) }}
{% include 'roles/sys-svc-container/templates/base.yml.j2' %}
+5
View File
@@ -14,6 +14,11 @@ JOOMLA_CONFIG_FILE: "/var/www/html/configuration.php"
JOOMLA_INSTALLER_CLI_FILE: "/var/www/html/installation/joomla.php"
JOOMLA_CLI_FILE: "/var/www/html/cli/joomla.php"
JOOMLA_ENTRYPOINT_SCRIPT_FILE: "docker-entrypoint-joomla.sh"
JOOMLA_ENTRYPOINT_SCRIPT_HOST_ABS: "{{ [ lookup('container', application_id, 'directories.volumes'), JOOMLA_ENTRYPOINT_SCRIPT_FILE ] | path_join }}"
JOOMLA_ENTRYPOINT_SCRIPT_HOST_REL: "volumes/{{ JOOMLA_ENTRYPOINT_SCRIPT_FILE }}"
JOOMLA_ENTRYPOINT_SCRIPT_DOCKER: "{{ [ '/usr/local/bin/', JOOMLA_ENTRYPOINT_SCRIPT_FILE ] | path_join }}"
JOOMLA_UPLOAD_CONFIG: "{{ [ lookup('container', application_id, 'directories.instance'), 'php-upload.ini' ] | path_join }}"
JOOMLA_UPLOAD_SIZE: "{{ lookup('config', application_id, 'services.joomla.upload.size_mb') }}"
JOOMLA_UPLOAD_MAX_FILESIZE: "{{ (JOOMLA_UPLOAD_SIZE | int) }}M"