How to Add Files to Non-Root Docker Containers (Tomcat Example with Permission Fix)


1 views

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/