Docker WORKDIR
Introduction
When building Docker containers, organizing your filesystem structure is essential for maintainability and security. The WORKDIR
instruction is a fundamental Dockerfile directive that helps you establish and change the working directory within your container. This directory becomes the default location where subsequent commands like RUN
, CMD
, ENTRYPOINT
, COPY
, and ADD
will execute.
Think of WORKDIR
as similar to running cd
in your terminal before executing commands - it sets the context for operations that follow.
Basic Syntax
The basic syntax for the WORKDIR
instruction is:
WORKDIR /path/to/directory
If the specified directory doesn't exist in the container filesystem, Docker will automatically create it.
Why Use WORKDIR?
Before diving into examples, let's understand why WORKDIR
is important:
- Organization: Keeps files in predictable, logical locations
- Clarity: Makes Dockerfiles more readable by providing context
- Security: Avoids operations in sensitive system directories
- Consistency: Creates a reliable environment for your application
- Prevents path-related errors: Reduces issues with relative paths
Basic Examples
Setting a Simple Working Directory
FROM ubuntu:20.04
WORKDIR /app
RUN echo "Hello from the app directory!" > greeting.txt
CMD ["cat", "greeting.txt"]
In this example:
- We start with an Ubuntu 20.04 base image
- Set
/app
as our working directory - Create a file called
greeting.txt
inside/app
- Configure the container to display the contents of this file when started
When you build and run this container:
docker build -t workdir-demo .
docker run workdir-demo
Output:
Hello from the app directory!
Using Multiple WORKDIR Instructions
You can change the working directory multiple times in a Dockerfile:
FROM ubuntu:20.04
WORKDIR /tmp
RUN echo "This file is in /tmp" > temp-file.txt
WORKDIR /app
RUN echo "This file is in /app" > app-file.txt
CMD ["ls", "-la"]
When you run this container, ls -la
will show the contents of /app
, not /tmp
, because the last WORKDIR
instruction set /app
as the current directory.
Working with Relative Paths
If you use a relative path in WORKDIR
, it's interpreted relative to the previous working directory:
FROM ubuntu:20.04
WORKDIR /base
WORKDIR subdir
WORKDIR another-level
RUN pwd
The pwd
command will output:
/base/subdir/another-level
This makes it convenient to create nested directory structures without repeating the full path each time.
Best Practices
1. Always Use Absolute Paths
While relative paths work, using absolute paths makes your Dockerfile more explicit and less prone to errors:
# Recommended
WORKDIR /app
# Avoid if possible
WORKDIR app
2. Avoid Using Root Directory
For security reasons, avoid using the root directory (/
) as your working directory:
# Not recommended
WORKDIR /
COPY . . # This copies files to the root filesystem!
# Better approach
WORKDIR /app
COPY . . # Files are contained in /app
3. Create a Dedicated Directory for Your Application
Create a dedicated directory for your application code rather than using system directories:
FROM node:14
# Create dedicated directory for application
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]
4. Combine with USER for Better Security
For enhanced security, combine WORKDIR
with the USER
instruction:
FROM node:14
# Create app directory
WORKDIR /usr/src/app
# Create a non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
# Change ownership of the working directory
RUN chown -R appuser:appuser /usr/src/app
# Switch to non-root user
USER appuser
# Now all subsequent commands run as non-root user in /usr/src/app
COPY --chown=appuser:appuser . .
RUN npm install
CMD ["npm", "start"]
Real-World Examples
Node.js Web Application
FROM node:14
# Set working directory
WORKDIR /usr/src/app
# Install dependencies first (leverages Docker cache)
COPY package*.json ./
RUN npm install
# Copy application code
COPY . .
# Expose port for the application
EXPOSE 3000
# Start the application
CMD ["node", "app.js"]
Python Data Processing Application
FROM python:3.9
# Set working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY ./src ./src
COPY ./data ./data
# Set working directory for scripts
WORKDIR /app/src
# Run the application
CMD ["python", "process_data.py"]
Common Issues and Solutions
Issue: Command Not Found
FROM ubuntu:20.04
WORKDIR /app
COPY script.sh .
CMD ["./script.sh"]
If you get "Command not found" when running this container, remember to:
- Make your script executable:
FROM ubuntu:20.04
WORKDIR /app
COPY script.sh .
RUN chmod +x script.sh
CMD ["./script.sh"]
- Use the correct path relative to your WORKDIR:
FROM ubuntu:20.04
WORKDIR /app
COPY script.sh .
RUN chmod +x /app/script.sh
CMD ["/app/script.sh"]
Issue: Files Not Found
If your application can't find files, check if you're using the correct paths relative to your working directory:
FROM python:3.9
WORKDIR /app
COPY app.py .
COPY data/input.csv /tmp/data/ # This goes to a different directory
CMD ["python", "app.py"]
If app.py
tries to open ./data/input.csv
, it will fail because the file is in /tmp/data/
, not /app/data/
.
Solution: Maintain consistent paths or adjust your application code:
FROM python:3.9
WORKDIR /app
COPY app.py .
COPY data/input.csv ./data/
CMD ["python", "app.py"]
How WORKDIR Affects Container Runtime
When a container starts, the working directory set by the last WORKDIR
instruction becomes the initial working directory for the container's main process.
Let's visualize this with a diagram:
Environment Variables in WORKDIR
You can use environment variables in the WORKDIR
instruction:
FROM ubuntu:20.04
ENV APP_DIR=/application
WORKDIR $APP_DIR
RUN pwd # Outputs: /application
This is useful for creating configurable Dockerfiles.
Summary
The WORKDIR
instruction is an essential part of Dockerfile best practices that:
- Sets the working directory for subsequent instructions
- Creates organization and structure in your container
- Prevents operations in sensitive system directories
- Makes Dockerfiles more readable and maintainable
- Works with both absolute and relative paths
Remember to use absolute paths when possible, create dedicated directories for your application, and combine with other security practices like using non-root users for optimal container configuration.
Exercises
-
Create a Dockerfile that sets up multiple working directories and creates a different file in each. Use the
find
command to verify where files are located. -
Modify an existing Dockerfile for a web application to use proper
WORKDIR
instructions instead of absolute paths in commands. -
Create a Dockerfile that uses environment variables to dynamically set the working directory based on the environment (development/production).
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)