Fun With Docker

Docker was initially released over 10 years ago and uses containers to bundle an application and all its dependencies. In theory, the app runs exactly the same in dev, prod. This is mostly true, at least with regards to installed software and library/framework dependencies and versioning.

Docker uses virtualization to deploy applications in containers

I personally use Docker Compose to spin up multiple containers: for my website server, API server, and databases. Instead of manually spinning up container, I use Compose to bring everything up and make sure they can talk to one another.

Docker Compose is a tool for defining and running multi-container applications

Docker Compose

Things to remember when using Docker Compose:

  • Let the docker-compose.yml be your base file. Use this to define container and configuration settings that will be true regardless of environment.
  • Include all the Compose files using -f. For example: docker compose -f docker-compose.yml -f docker-compose.dev.yml
  • Variable interpolation (values in a Compose file can be interpolated at runtime)
    • Compose uses a Bash-like syntax: ${VARIABLE} or $VARIABLE
    • Compose gets values from your shell environment and your Docker .env file
    • If you have multiple .env files (you probably do for dev/prod), you tell Docker which .env file to use with --env-file, for example: docker compose --env-file
    • If you don't specify an .env file using the --env-file parameter, then Docker will look in your current working directory for an .env file
    • To check your variable interpolation, you can do this: docker compose config --environment
    • A service's build context in the docker-compose.yml file applies to Docker's build process (including your .dockerignore file), and does not apply to Compose. In other words, everything that happens inside your Dockerfile is based on what you specify for build context in your Compose file:
service-1:
    build:
        context: ./src
        dockerfile: ../docker/prod/Dockerfile

Docker Context

If you have one Dockerfile, you can put it in the same directory as your Compose files, your .env file, and your .dockerignore file. And, if you have multiple Dockerfiles for different environments, for example Dockerfile.dev and Dockerfile.prod, you could even keep those in the same directory as your .env file and your Compose files.

However, if you have different .dockerignore files, there isn't a way to specify which one Docker uses when creating your image. Docker expects the .dockerignore file to be in the same directory as your build context, either specified in your Compose file, or passed to Docker when you run the build command. In this example ./my-app is the build context: docker build -t image-name ./my-app

Build context is the root directory Docker uses to:

  • Send files to the Docker daemon
  • Resolve COPY and ADD commands

Docker Ignore

To handle the .dockerignore file in situations where you have multiple Dockerfiles, you have a few options. First, remember that Docker always looks for .dockerignore in the root of the build context — and only there. So when you run docker build -t image-name ./my-app, Docker expects your .dockerignore file to exist at: ./my-app/.dockerignore. Your options are:

  1. Symlink the correct .dockerignore file before running a build
  2. Run a script to swap the right .dockerfile in before running a build

Personally, I do option #2, I run copy the right .dockerignore before running a build:

cp -f docker/dev/.dockerignore src/.dockerignore

And then delete it as soon as the build is done:

rm src/.dockerignore

The .dockerignore file is useful because it ensure that you never accidentally copy sensitive files into your Docker image and layer history. Each layer in an image contains a set of filesystem changes - additions, deletions, or modifications. You probably don't want to copy server keys, API key, passwords, and secrets into your image layers. The best way to do that is by being careful when creating your images. Having a good .dockerignore file is just to make sure nothing ever gets accidentally copied.

Write a comment


Required fields are missing Your comment was submitted

Comments