Skip to content

Commit 46d9ba2

Browse files
Lorenzo Rogaiclaude
andcommitted
fix(s6): make web services wait for their config oneshots to fix root-mode startup race
When a container built on the s6 images runs as root, php-fpm and the web server (nginx/apache2) are brought up in parallel with the entrypoint oneshots that configure them, because the long-running services have no dependency on those oneshots. As root this races: - php-fpm reads its pool before `5-fpm-pool-user` appends `user`/`group`, failing with "ALERT: [pool www] user has not been defined" -> "ERROR: FPM initialization failed". - the web server starts before `10-init-webserver-config` renders its config (e.g. nginx: open() "/etc/nginx/nginx.conf" failed). s6 restarts the crashed services so the container eventually recovers, which is why the failure is intermittent and hard to reproduce (see discussion #425), but it emits alarming errors, slows startup, and leaves a brief window with no service. docker-php-serversideup-s6-init now adds a dependency from each web service to the entrypoint oneshot that configures it. The oneshots are chained in alphabetical order, so depending on one transitively waits for all earlier ones (php-fpm -> 5-fpm-pool-user; nginx/apache2 -> 10-init-webserver-config). Dependencies are only added when both the service and the oneshot exist, so CLI/fpm/frankenphp images and images that remove a script are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 49039c2 commit 46d9ba2

1 file changed

Lines changed: 23 additions & 1 deletion

File tree

src/s6/usr/local/bin/docker-php-serversideup-s6-init

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,26 @@ for file in "$ENTRYPOINT_DIR"/*.sh; do
7777
echo "Skipping ${script_name} because it already exists at ${S6_HOME}/scripts/${script_name}"
7878
fi
7979

80-
done
80+
done
81+
82+
# Make the long-running services wait for the entrypoint oneshots that configure
83+
# them. When the container runs as root, php-fpm and the web server otherwise
84+
# start in parallel with these oneshots and can lose the race: php-fpm reads the
85+
# pool before "5-fpm-pool-user" adds "user = www-data" (ALERT: [pool www] user
86+
# has not been defined -> FPM initialization failed), and the web server starts
87+
# before "10-init-webserver-config" renders its config. s6 restarts the crashed
88+
# services so the container recovers, but it produces alarming errors, a slower
89+
# start, and a brief window with no service. The entrypoint oneshots are chained
90+
# in alphabetical order, so depending on one transitively waits for all earlier
91+
# ones. Each dependency is only added when both the service and the oneshot exist.
92+
add_startup_dependency() {
93+
# $1 = long-running service that must wait, $2 = entrypoint oneshot it needs
94+
if [ -d "${S6_HOME}/s6-rc.d/$1" ] && [ -d "${S6_HOME}/s6-rc.d/$2" ]; then
95+
mkdir -p "${S6_HOME}/s6-rc.d/$1/dependencies.d"
96+
touch "${S6_HOME}/s6-rc.d/$1/dependencies.d/$2"
97+
fi
98+
}
99+
100+
add_startup_dependency php-fpm 5-fpm-pool-user
101+
add_startup_dependency nginx 10-init-webserver-config
102+
add_startup_dependency apache2 10-init-webserver-config

0 commit comments

Comments
 (0)