Docker

Docker File Management: Should You COPY or Use Volumes?

Zachary Carciu 4 min read

Docker File Management: Should You COPY or Use Volumes?

When you start building Docker images, one of the first questions you’ll likely ask is: How do we get our code into the Docker image? There are two primary methods to achieve this—using the COPY command in your Dockerfile or employing Docker volumes. Each method has distinct advantages and scenarios where it’s best suited, and understanding these differences can significantly streamline your development and deployment workflows.

Table of Contents

Understanding COPY

The COPY instruction in a Dockerfile tells Docker to copy your files into the Docker image when you run the build command.

This means your Docker image is fully self-contained, deployable, and predictable. This is perfect for when you’re happy with your code and you’re ready to deploy. However, during active development, rebuilding the image after each code change can slow down your workflow significantly.

Understanding Volumes

Docker volumes create a shared space between your host machine and the Docker container. When you use a volume, your container reads the code directly from your host system in real-time. This significantly accelerates development cycles because you don’t need to rebuild the container every time your code changes and updates appear instantly inside the container.

This is really nice if you’re building an app which uses a hot reload in your dev or local environment, and you see the changes in your app immediately.

Another great usecase for volumes is running local database containers because volumes allow your data to persist between starts and stops of your database container. Consider if you were to just run a database container with no volumes. Any data written would also be gone when the ephemeral container eventually terminates.

Here is a way I typically like to set up my local database container services so that the data persists between restarts:

services:
  database:
    build:
      dockerfile: ./Dockerfile_postgres
      context: .
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"
      - "POSTGRES_DB=db_name"
    ports:
      - 5432:5432
    networks:
      my-network:
        aliases:
          - database

But remember, with volumes, the code is not in your image! It simply accesses the same files your host machine has for the defined volume. So if you want to deploy this, you’ll either need another Dockerfile that uses the COPY instruction or allocate storage with the files wherever you’re running your container (e.g., EBS volumes with Persistent Volume Claims in AWS if using EKS).

Example of configuring volumes in docker-compose:

# This example mounts your local `src` folder into the `/app` directory in the container

services:
  client:
    build:
      context: ./
      dockerfile: dockerfiles/Dockerfile_node
    ports:
      - "5173:5173"
    volumes:
      - ./src:/app
    environment:
      - NODE_ENV=development

Example of configuring volumes with the docker run command:

# This mounts your current working directory (`.`) into `/app` in the container and launches an interactive bash session

docker run -it -v .:/app node:alpine bash

Choosing the Right Method

  • Development Environments: Volumes are typically the best choice, offering speed and convenience for frequent updates and debugging.
  • Production Environments: COPY ensures stability, consistency, and portability, making it ideal for deployment scenarios.

Configuring your CI/CD pipeline to use volumes during local development and COPY for production deployments allows you to benefit from fast iteration in development and consistent, reliable builds for your production environment.

Common Pitfalls and Gotchas

  • Incorrect Volume Mapping: If you incorrectly map your directories for volumes, you might accidentally create empty directories on your host machine.
  • Persisted Changes: Remember, if your code is updated by your container, these changes will persist on your host machine!
  • File Permission Issues: Containers modifying files within a volume may inadvertently alter file permissions. You may need to use commands like chown to reset or manage these permissions.

Conclusion

Understanding the strengths and appropriate scenarios for Docker’s COPY instruction and volumes enables you to optimize your workflow effectively. By leveraging each method appropriately, you can maintain a balance between rapid development and reliable, consistent deployments.