• Home
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • Ubuntu
  • Maven
  • Big Data
  • Archived
Docker | Dockerfile
  1. Notes
  2. Dockerfile
  3. Example of an unoptimized Dockerfile
  4. Example of an optimized Dockerfile
  5. FROM
  6. ARG
  7. LABEL
  8. ENV
  9. RUN
  10. COPY
  11. CMD
  12. ENTRYPOINT
  13. USER
  14. VOLUME
  15. WORKDIR

  1. Notes
    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 created image (assuming the cache was not cleared), Docker uses, for each command in the Dockerfile, the corresponding filesystem layer from its cache, only if:
    • The command and its parent were not updated.
    • The command and its parent are not generating a new filesystem layer.
    If any of the above conditions are met, Docker will automatically run all build commands in the Dockerfile that are below this updated build command.

    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. Another option is to place, when possible, that command in a parent Dockerfile and use the generated image as a parent image for the descendant Dockerfiles. In such case case, 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.

    Following best practices when designing Dockerfiles helps:
    • speed up the creation of Docker images by leveraging the cache.
    • reduce the size of Docker images.
    • speed up copying/downloading Docker images by skipping layers that have already been copied/downloaded.
  3. Example of an unoptimized Dockerfile
    Example of a Dockerfile:

    Build the Dockerfile:

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

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

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

    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 the 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 Dockerfile. This will save time when building the image frequently.

    Note also the instruction rm -rf /var/lib/apt/lists/*, which is useful to save disk space on the final image. The size of the image is now 140MB instead of 225MB.
  5. FROM
    The FROM instruction creates a new build stage from a base image.
  6. ARG
    The ARG instruction uses build-time variables (along with their default values).
  7. LABEL
    The LABEL instruction adds metadata to an image.

    Note that the label is using a variable name which, in this case, references the argument defined by the instruction ARG.

    Let's use a Dockerfile with the above instructions:

    Let's build the Dockerfile:

    You can inspect the created image to check the labels:
  8. ENV
    The ENV instruction sets environment variables (also available as regular variables during build-time).

    Let's use a Dockerfile with the above instructions:

    Let's build the Dockerfile:

    You can inspect the created image to check the labels.
    Note that the environment variable was used to set the label.
    Also note that this time the label used the default value of the argument because it was not set when the image was created.

    Let's check the env variable within the container:
  9. RUN
    The RUN instruction executes build commands.

    You should combine multiple build execution commands into a single instruction whenever possible.

    You should also avoid updating the operating system or upgrading libraries. If necessary, you should use a base image that you can build only when needed. The base image should also be used, where possible, to install third-party libraries.
  10. COPY
    The COPY instruction copies files and directories from the local filesystem into a Docker image.

    You can copy files or folders. When copying a folder, only its content is copied.

    Let's create few local folders/files:

    Let's use a Dockerfile to copy files/folders into the Docker image:

    Let's build the Dockerfile:

    You can check the copied files/folders
  11. CMD
    The CMD instruction specifies default commands.

    Let's use a Dockerfile:

    Let's build the Dockerfile:

    You can check the copied files/folders
  12. ENTRYPOINT
    The ENTRYPOINT instruction specifies default executable.

    Let's use a Dockerfile:

    Let's build the Dockerfile:

    You can check the copied files/folders
  13. USER
    The USER instruction sets 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.
    Unless there is a real reason for this, you should avoid running containers using root or privileged users.

    Let's check the mti existing 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) "1002". It also create the user "mti" with the user id (uid) "1002" and the group id (gid) "1002". 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 1002 and gid=1002 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.
  14. VOLUME
    The VOLUME instruction creates volume mounts.

    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 32770:

    Check the nginx logs:

  15. WORKDIR
    The WORKDIR instruction sets 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