Q: Your team hardened an application Dockerfile to run as non-root user `appuser` (UID 1000). When developers run `docker run -v $(pwd)/data:/data my-app`, the container crashes immediately with `EACCES: permission denied, open '/data/app.log'`. On the host, the mounted directory is owned by host root or another user ID. When an engineer added `RUN chown -R 1000:1000 /data` to an entrypoint script, production startup hung for 12 minutes because the volume contained 500GB of files. You must implement a clean, production-grade permission reconciliation pattern.
Fix permission denied errors when mounting host directories or named volumes into unprivileged non-root containers (`USER 10001`). Understand why running `chown` on large volumes at entrypoint causes startup timeouts, and implement `gosu` or `fixuid`.
Want to master this scenario in a live sandbox? KodeKloud's Docker Certified Associate (DCA) Hands-On Lab Course covers this exact problem with hands-on terminal drills.
🛠️ Production Runbook & Step-by-Step Resolution
Understand Linux Kernel UID/GID Ownership on Volume Mounts
Docker bind mounts and named volumes inherit the filesystem permissions and numeric UID/GID from the host OS. If host directory `/opt/data` is owned by UID 0 (root) with mode `755`, a container running as `USER 1000` will be denied write access (`EACCES`) by the Linux VFS kernel layer.
# Inspect host directory permissions
ls -ld /opt/data
# Output: drwxr-xr-x 2 root root 4096 ... /opt/data (Owner is UID 0)
# Container fails because UID 1000 does not match UID 0 and lacks write permission
Analyze Why Recursive Chown in Entrypoint is an Anti-Pattern
Executing `chown -R appuser:appuser /data` in an entrypoint script requires running the entrypoint as root, and more critically, it forces the kernel to read and update metadata for every single file in the volume. On large volumes with millions of files, this causes severe I/O thrashing and multi-minute boot delays.
# Broken Entrypoint Anti-pattern:
# #!/bin/sh
# chown -R 1000:1000 /data <-- Freezes container startup on large volumes!
# exec su-exec appuser "$@"
Implement Gosu or Fixuid for Graceful Privilege Dropping
Use `gosu` (written in Go) instead of `sudo` or `su`. Unlike `su`, `gosu` uses `execvp` to replace the calling shell with the target process, preserving PID 1 status, environment variables, and TTY signal handling.
# entrypoint.sh using gosu
#!/bin/sh
set -e
# Check if ownership is mismatched and fix ONLY the top-level directory
if [ "$(stat -c '%u' /data)" != "1000" ]; then
echo "Adjusting ownership of /data mount point..."
chown 1000:1000 /data
fi
# Drop privileges to UID 1000 and execute application command
exec gosu 1000:1000 "$@"
Utilize Kubernetes SecurityContext fsGroup and Init Containers
In Kubernetes, avoid in-container chown altogether. Use `fsGroup: 1000` in the Pod's `securityContext`, which instructs the kubelet to set group ownership at mount time, or use `fsGroupChangePolicy: "OnRootMismatch"` so permissions are only touched if the top-level directory does not match.
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
fsGroup: 1000
fsGroupChangePolicy: "OnRootMismatch" # Prevents recursive chown on every restart
containers:
- name: app
image: my-app:latest
securityContext:
runAsNonRoot: true
runAsUser: 1000
- W
- e
- r
- e
- s
- o
- l
- v
- e
- d
- v
- o
- l
- u
- m
- e
- p
- e
- r
- m
- i
- s
- s
- i
- o
- n
- c
- o
- n
- f
- l
- i
- c
- t
- s
- w
- i
- t
- h
- o
- u
- t
- i
- n
- t
- r
- o
- d
- u
- c
- i
- n
- g
- c
- o
- n
- t
- a
- i
- n
- e
- r
- s
- t
- a
- r
- t
- u
- p
- l
- a
- g
- s
- b
- y
- e
- l
- i
- m
- i
- n
- a
- t
- i
- n
- g
- r
- e
- c
- u
- r
- s
- i
- v
- e
- `
- c
- h
- o
- w
- n
- `
- e
- n
- t
- r
- y
- p
- o
- i
- n
- t
- s
- .
- F
- o
- r
- D
- o
- c
- k
- e
- r
- l
- o
- c
- a
- l
- d
- e
- v
- e
- l
- o
- p
- m
- e
- n
- t
- ,
- w
- e
- i
- m
- p
- l
- e
- m
- e
- n
- t
- e
- d
- a
- l
- e
- a
- n
- e
- n
- t
- r
- y
- p
- o
- i
- n
- t
- u
- t
- i
- l
- i
- z
- i
- n
- g
- `
- g
- o
- s
- u
- `
- t
- h
- a
- t
- o
- n
- l
- y
- a
- d
- j
- u
- s
- t
- s
- t
- h
- e
- t
- o
- p
- -
- l
- e
- v
- e
- l
- d
- i
- r
- e
- c
- t
- o
- r
- y
- b
- e
- f
- o
- r
- e
- d
- r
- o
- p
- p
- i
- n
- g
- r
- o
- o
- t
- p
- r
- i
- v
- i
- l
- e
- g
- e
- s
- .
- I
- n
- K
- u
- b
- e
- r
- n
- e
- t
- e
- s
- ,
- w
- e
- c
- o
- n
- f
- i
- g
- u
- r
- e
- d
- `
- f
- s
- G
- r
- o
- u
- p
- C
- h
- a
- n
- g
- e
- P
- o
- l
- i
- c
- y
- :
- O
- n
- R
- o
- o
- t
- M
- i
- s
- m
- a
- t
- c
- h
- `
- ,
- a
- l
- l
- o
- w
- i
- n
- g
- p
- o
- d
- s
- w
- i
- t
- h
- 5
- 0
- 0
- G
- B
- v
- o
- l
- u
- m
- e
- s
- t
- o
- m
- o
- u
- n
- t
- i
- n
- u
- n
- d
- e
- r
- 2
- s
- e
- c
- o
- n
- d
- s
- .