
Summary
The /app/html directory is created during the image build in the Containerfile, which places it in a lower (read-only) layer of the container image. This causes fuse-overlayfs to generate whiteout files whenever content inside /app/html is deleted and recreated — a pattern that is common and frequent in WordPress installations (cache plugins, theme updates, plugin upgrades).
Over time, whiteout accumulation degrades filesystem performance progressively until the container becomes unresponsive. Full context and technical background in Ez issue #173.
Root cause
The relevant line in the Containerfile:
RUN ... \
&& mkdir -p /app/logs/cron /app/logs/nginx /app/conf/pki /app/.trash \
&& mkdir -m 777 -p /app/html \
&& chown -R nobody:nogroup /app
Because /app/html is created in a RUN instruction, it becomes part of a lower layer of the image. When a container starts and the user writes files under /app/html, those files land in the upper (writable) layer. But when a file or directory under /app/html is deleted, fuse-overlayfs must create a whiteout to shadow it from the lower layer — because the parent /app/html has last_layer_idx > 0.
This is confirmed by the needs_whiteout logic in src/overlay.rs, lines 1245–1253: a whiteout is created when the node or its immediate parent has origin in a lower layer.
The other directories created in the same RUN (logs, conf, .trash) are intentionally written during the build with configuration files and can remain in the image. /app/html is different — it is always empty in the image and only receives content at runtime, per user workload.
Proposed fix
Remove /app/html from the Containerfile and create it at container startup instead, so it always originates in the upper layer.
Containerfile — remove /app/html from the RUN instruction:
RUN ... \
&& mkdir -p /app/logs/cron /app/logs/nginx /app/conf/pki /app/.trash \
&& chown -R nobody:nogroup /app
Entrypoint or supervisord bootstrap — create /app/html on first run if it does not exist:
mkdir -m 777 -p /app/html
chown nobody:nogroup /app/html
With this change, /app/html is created in the upper layer of each individual container. Deletions inside it never require whiteouts — the needs_whiteout condition evaluates to false because both the node and its parent (/app/html) have last_layer_idx = 0.
Existing containers are not affected by the image change — /app/html already exists in their upper layer from prior writes. The fix applies to newly created containers going forward.
References
Summary
The
/app/htmldirectory is created during the image build in the Containerfile, which places it in a lower (read-only) layer of the container image. This causesfuse-overlayfsto generate whiteout files whenever content inside/app/htmlis deleted and recreated — a pattern that is common and frequent in WordPress installations (cache plugins, theme updates, plugin upgrades).Over time, whiteout accumulation degrades filesystem performance progressively until the container becomes unresponsive. Full context and technical background in Ez issue #173.
Root cause
The relevant line in the Containerfile:
RUN ... \ && mkdir -p /app/logs/cron /app/logs/nginx /app/conf/pki /app/.trash \ && mkdir -m 777 -p /app/html \ && chown -R nobody:nogroup /appBecause
/app/htmlis created in aRUNinstruction, it becomes part of a lower layer of the image. When a container starts and the user writes files under/app/html, those files land in the upper (writable) layer. But when a file or directory under/app/htmlis deleted,fuse-overlayfsmust create a whiteout to shadow it from the lower layer — because the parent/app/htmlhaslast_layer_idx > 0.This is confirmed by the
needs_whiteoutlogic insrc/overlay.rs, lines 1245–1253: a whiteout is created when the node or its immediate parent has origin in a lower layer.The other directories created in the same
RUN(logs,conf,.trash) are intentionally written during the build with configuration files and can remain in the image./app/htmlis different — it is always empty in the image and only receives content at runtime, per user workload.Proposed fix
Remove
/app/htmlfrom theContainerfileand create it at container startup instead, so it always originates in the upper layer.Containerfile— remove/app/htmlfrom theRUNinstruction:RUN ... \ && mkdir -p /app/logs/cron /app/logs/nginx /app/conf/pki /app/.trash \ && chown -R nobody:nogroup /appEntrypoint or supervisord bootstrap — create
/app/htmlon first run if it does not exist:With this change,
/app/htmlis created in the upper layer of each individual container. Deletions inside it never require whiteouts — theneeds_whiteoutcondition evaluates tofalsebecause both the node and its parent (/app/html) havelast_layer_idx = 0.Existing containers are not affected by the image change —
/app/htmlalready exists in their upper layer from prior writes. The fix applies to newly created containers going forward.References
straceoutput, whiteout accumulation data, andfuse-overlayfsbehavior analysiscontainers/fuse-overlayfs src/overlay.rs#L1245—needs_whiteoutlogic