When working with official Docker images like Tomcat, you'll often encounter containers running as non-root users for security reasons. The tomcat image specifically runs as user tomcat
, which creates permission issues when you need to add or modify files.
During image building (Dockerfile
execution), commands run as root by default. However, when the container runs, it switches to the non-privileged user. This creates a permission mismatch for files copied during build.
Here are three effective approaches to handle file permissions in non-root containers:
Solution 1: Pre-set Permissions During Build
FROM tomcat
COPY --chown=tomcat:tomcat test.txt /usr/local/tomcat/webapps/
Solution 2: Use Appropriate Directory Permissions
FROM tomcat
RUN mkdir -p /usr/local/tomcat/webapps/myapp && \
chown -R tomcat:tomcat /usr/local/tomcat/webapps/myapp
COPY test.txt /usr/local/tomcat/webapps/myapp/
Solution 3: Volume Mount at Runtime
docker run -v $(pwd)/test.txt:/usr/local/tomcat/webapps/test.txt \
-e CATALINA_OPTS="-Dtomcat.util.scan.StandardJarScanFilter.jarsToSkip=*" \
tomcat
- Always prefer
COPY --chown
over manual permission changes - Consider using multi-stage builds for complex permission scenarios
- For configuration files, use environment variables or config maps instead
- When using volumes, ensure the host file permissions match the container user
If you still face permission issues:
docker exec -it container_id ls -la /path/to/file
docker exec -u root -it container_id chown tomcat:tomcat /path/to/file
When working with the official Tomcat Docker image, you might encounter a puzzling situation: files copied into the container become owned by root, but the container itself runs as the non-privileged tomcat
user. Let's examine this through a practical example:
FROM tomcat
COPY app.war /usr/local/tomcat/webapps/
RUN chown tomcat:tomcat /usr/local/tomcat/webapps/app.war
This Dockerfile fails with Operation not permitted
when trying to change ownership, despite running as root during build.
The official Tomcat image uses several security measures:
- Default USER directive sets
tomcat
as runtime user - Filesystem permissions are carefully configured
- The image follows principle of least privilege
Option 1: Leverage COPY's --chown Parameter
Modern Docker (17.09+) supports setting ownership during copy:
FROM tomcat
COPY --chown=tomcat:tomcat app.war /usr/local/tomcat/webapps/
Option 2: Pre-create Directory Structure
Set permissions before copying files:
FROM tomcat
RUN mkdir -p /usr/local/tomcat/webapps/myapp && \
chown -R tomcat:tomcat /usr/local/tomcat/webapps/myapp
COPY --chown=tomcat:tomcat app.war /usr/local/tomcat/webapps/myapp/
Option 3: Multi-stage Build Approach
For complex permission scenarios:
FROM tomcat as runtime
FROM alpine as builder
RUN apk add --no-cache shadow && \
adduser -D -u 1000 tomcat
COPY --from=builder --chown=tomcat:tomcat app.war /usr/local/tomcat/webapps/
To inspect permissions in a running container:
docker exec -it mycontainer ls -la /usr/local/tomcat/webapps/
For build-time debugging, add this to your Dockerfile:
RUN stat /usr/local/tomcat/webapps/app.war && \
id && \
ls -ld /usr/local/tomcat/webapps/