Passing the host uid as a build argument makes the container write files the developer owns, at the cost of an image that is specific to one machine.
ARG UID=1000
ARG GID=1000
RUN apk add --no-cache shadow
&& usermod -u ${UID} www-data
&& groupmod -g ${GID} www-data
# docker-compose.override.yml, which is not committed
services:
php:
build:
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
The image is now developer-specific, which is fine for a development image and disqualifying for anything pushed to a registry — so this belongs in an override file and a production build must not inherit it. Reading the values from the environment with a default means a developer sets UID=$(id -u) once in a shell profile and never thinks about it again.