• Home
  • Docker
  • Kubernetes
  • Java
  • Ubuntu
  • Maven
  • Big Data
  • CI
  • Install
  • Samples
  • Archived
Docker | Dockerfile
  1. Notes
  2. Dockerfile
  3. Example of a 'non-optimized' Dockerfile
  4. Example of an 'optimized' Dockerfile
  5. Dockerfile instructions: USER
  6. Dockerfile instructions: VOLUME
  7. Dockerfile instructions: WORKDIR

  1. Notes
    Please see these pages for more information:
    https://docs.docker.com/reference/dockerfile/
    https://docs.docker.com/build/building/best-practices/

    Docker introduced new backend for builing images (buildkit) which doesn't expose intermediate containers.
    To show intermediate containers, set the environment variable DOCKER_BUILDKIT before the docker build command:
  2. Dockerfile
    Dockerfile contains builds commands that are needed to create a Docker image. For each build command in the Dockerfile, Docker will generate a new filesystem layer. An image is a combination of all filesystem layers created by the build commands of the Dockerfile. Each layer is mapped to a specific build command in the Dockerfile.

    For a new created image, Docker will execute all the build commands in the Dockerfile. When building an already built image, Docker will always execute all the build commands that are bellow a parent build command that was either changed or it generated a new filesystem layer. Otherwise Docker will use the filesystem layer from its cache.

    Best practices: A build command that might create a new filesystem layer every time it's executed (e.g., update OS, library) should be placed at the bottom of the Dockerfile or placed in a parent Dockerfile and use the generated image as a parent image for the descendant Dockerfiles. The parent image can be re-built only when needed.

    Best practices: If possible, multiple build commands should be combined in one single build command.
  3. Example of a 'non-optimized' Dockerfile
    Example of a Dockerfile:

    Build Dockerfile:

    Let's inspect the layers of the ubuntu image (ubuntu:20.04):

    Let's inspect the layers of the new image (ubuntu-nginx:20.04):

    Note that the image 'ubuntu-nginx:20.04' inherit all the layers of the parent image 'ubuntu-nginx:20.04'.

    The five new layers are the ones created by executing the build steps in the Dockerfile.
  4. Example of an 'optimized' Dockerfile
    Let's optimize a bit the Dockerfile we used above:

    Build Dockerfile:

    Let's inspect the layers of the new image:

    First note that the build steps were reduced to only three steps. This result to only two new layers created for the new image instead of five with the 'non-optimized' Dockerfile.

    Note that the steps, in the Dockerfile, to create the mtitek group and user are placed before the installation instructions of curl and nginx. This is to show that the instructions that are more likely to generate the same exact result, no matter how many time they are executed, should be placed at the top of the Docker file. This will save time when building the image frequently.

    Note also the instruction rm -rf /var/lib/apt/lists/*, which is helpful to save some space disk on the final image.
  5. Dockerfile instructions: USER
    The USER instruction set the user that will be used to run the processes inside the container. By default, if the USER instruction is not set, docker run all processes as root.

    Let's check the current user running on the Docker host:

    Let's first try a Dockerfile without the USER instruction:

    Let's build the Dockerfile:

    Let's check the user within the container:

    Let's try now a Dockerfile with the USER instruction:

    Let's build the Dockerfile:

    Let's check the user within the container:

    Note that the Dockerfile create the group "tek" with the group id (gid) "1000". It also create the user "mti" with the user id (uid) "1000" and the group id (gid) "1000". The image that we create from this Dockerfile will run with the user "mti".

    Note that the group and user names are, more or less, just friendly names. The important part is the uid and gid. These two elements will map the container's user uid and group gid to the host's user uid and group gid. So, in the above example, the container will be running using the same uid and gid that match the ones of the Docker host. In the host I am using the uid 1000 and gid=1000 are mapped to the user and group "mtitek". This means that the container's user will get the same privileges that the user "mtitek" has.
  6. Dockerfile instructions: VOLUME
    Let's create a Dockerfile that will use the VOLUME instruction to mount a local directory. I will adapt a bit the nginx Dockerfie to print the logs in a directory.

    Here's the Dockerfile (this is for demo purposes only):

    Let's build the Dockerfile:

    Let's create a local directroy:

    Let's run the nginx image (the host's directory ~/nginx-loc-dir is mounted to the container's directory /var/log/nginx):

    Check the nginx process:

    Let's access nginx at the published port 8080:

    Check the nginx logs:

  7. Dockerfile instructions: WORKDIR
    The WORKDIR instruction set the working directory for the remaining build instructions.
    This working directory will also be the default directory for all processes running inside the container.

    Let's try a Dockerfile with the WORKDIR instruction set a '/tmp':

    Let's build the Dockerfile:

    Let's check the working directory within the container:
© 2025  mtitek