Thursday, September 19, 2024

Command to Build Docker Image from Custom Created Dockerfile

An extremely important skill when working with Docker containers is being able to build a Docker container from a custom-created dockerfile. This will allow you to create custom Docker images that may not be available for download elsewhere. Let’s take a look at this process and the command to build Docker image from custom created Dockerfile and see what steps are involved for a container image.

Docker Images vs Docker Containers

First of all, let’s understand the difference between Docker images and the actual Docker container. As a prerequisite, have Docker installed. The Docker image is the foundation of your Docker container. The image is a read-only “template” of sorts that provides the instructions for the Docker engine to create the container.

In fact, Docker containers are running instances of Docker images. They have everything needed to run a specific application. This should include code, runtime, libraries needed, and any settings and configuration specific to the application.

looking at docker image help command
looking at docker image help command

Building Docker Images

Building Docker images isn’t a difficult process and is a great skill for DevOps. At its most simple definition, it has you run the docker build command to create a new image. It then reads instructions from your Dockerfile. These instructions typically have the directive to pull a base image, like Ubuntu, and then execute commands and other instructions to create the final Docker image.

docker build help command
docker build help command

Creating a Custom Dockerfile

The Dockerfile is a special file that is a simple text file with the Docker image instructions. A Dockerfile is a text file containing the instructions needed to build a Docker image. The instructions are executed in order they appear in the text file. These can include commands to copy files, set environment variables, run commands, and other important directives to make your application work as intended.

Here is a simple example of a Dockerfile that runs a Python application. We can see the different directives in the file that tells Docker how to build the resulting image. The below is a simple docker image defined in the Dockerfile.

# Use an official Python runtime as a parent image
FROM python:3.8-slim

# Set the working directory in the container
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

Dissecting the commands in the Docker file

  • FROM: Specifies the base image to use.
  • WORKDIR: Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD instructions.
  • COPY: This copies new files or directories to the container’s filesystem.
  • RUN instruction: The run command directive executes any commands in a new layer on top of the current image and then commits the results to the resulting image
  • CMD instruction: This tells the image which command to run within the container.

Command to Build Docker Image

Use the docker build command to build a Docker image from a custom Dockerfile. This command takes several options and arguments to define how the build process should be carried out.

Using the Docker Build Command

Below is the command to build Docker image from custom created Dockerfile using the Docker build command from the command line and specifying the root directory (current working directory) for the Dockerfile, etc.

docker build -t mycustomimage:latest .
  • -t – Tags the image with a name and optionally a tag in the nameformat.
  • The “.” at the end – This specifies the build context. It tells Docker to look for files located in the specified directory. The period tells it to look in the current directory for local files. Here we start to see the build output that will result in the built image.
building a docker custom image
building a docker custom image

Build Context

The build context is the set of files located in the specified directory and its subdirectories. Docker sends these files to the Docker daemon when building the image. One important consideration is to keep the build context as small as possible. This helps to speed up the build process and reduce resource usage.

Managing Build Context

Use a .dockerignore file to exclude files and directories from the build context. This file works similarly to a .gitignore file, listing patterns for files and directories to ignore. As an example, we are ignoring node modules and log files below:

# Ignore the node_modules directory
node_modules

# Ignore all files with the .log extension
*.log

Multiple Build Stages

One of the advanced build features with Docker is performing a multi-stage build. These are an advanced build feature of Docker. When doing a multi-stage build, you use multiple FROM statements in a single Dockerfile.

One reason you might do this is to optimize your build and reduce the size of the resulting container. When you separate the build environment from the runtime environment, you can include all necessary dependencies for building your application in one stage. Then, only the final artifacts are copied to the runtime stage.

Example of Multi-Stage Build

Here’s an example of a multiple build stage in a Dockerfile:

# Stage 1: Build
FROM maven:3.6.3-jdk-8 as builder
WORKDIR /app
COPY . .
RUN mvn clean install

# Stage 2: Run
FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/app.jar .
CMD ["java", "-jar", "app.jar"]

In this example:

  1. The first stage uses a Maven image to compile the Java application.
  2. The second stage uses a lightweight OpenJDK runtime image to run the compiled application.
  3. This separation makes sure that the final image only contains the runtime dependencies that are necessary. It makes it result in a smaller image.

Benefits of Multi-Stage Builds

There are many benefits to note for a multiple build stage Dockerfile. Note the following:

  • Smaller Image Size: By copying only the necessary artifacts to the final image, you can significantly reduce the size of the image.
  • Better Security: Smaller images with fewer components reduces the attack surface and vulnerabilities
  • Separation: By separating the build environment from the runtime environment it helps to make sure that the final image is clean. Also, it helps to know that it only contains what is needed to run the app.

Environment Variables in Docker

Environment variables are a good way to configure applications and services. You can set the build time variables in a Dockerfile using the ENV instruction.

Setting Environment Variables

Note the following environment variables where we are setting the app environment and debug settings:

ENV APP_ENV=production
ENV APP_DEBUG=false

Advanced Docker Build Options

Build Arguments

Build arguments (ARG) are used to pass variables at build time.

ARG VERSION=1.0
RUN echo "Version: $VERSION"

Using a Build Context

You can specify a different destination path directory as the build context rather than the local directory by the following syntax:

docker build -t my-image:latest /path/to/build/context

Using Docker Hub

The Docker Hub service is Docker’s cloud repository. It is where you can find Docker images and share your newly created image. To push your custom Docker images to Docker Hub, you need to log in and use the docker push command.

Note the following syntax for a Docker login tagging the image, and finally pushing it to the Docker Hub repo.

docker login
docker tag my-image:latest mydockerhubusername/my-image:latest
docker push mydockerhubusername/my-image:latest
docker login command allows connecting to docker hub
docker login command allows connecting to docker hub

Dockerfile and Docker Build Example

Let’s go through an example of building a Docker image for a Python application. First, create a Dockerfile:

FROM python:3.9-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir -r requirements.txt
CMD ["python", "app.py"]

Now, we can build the Docker Image:

docker build -t my-python-app:latest .

Finally, run the Docker Container:

docker run -d -p 5000:5000 my-python-app:latest

The Docker container starts up and runs from the custom image.

Load Build Definition

The build definition is an important part of Docker images. As you would expect, the Dockerfile is the build definition for the resulting Docker image. It details the steps needed to create the image. The definition must be correct and well-structured. By giving attention to this, it helps make sure the build process runs smoothly and produces the desired container image.

Best Practices for Building Docker Images

There are definitely best practices for building Docker image files that you want to keep in mind. Note the following

Minimize Image Size

  • Use a minimal base image – In other words, why use a bloated base image if you don’t need one?
  • Clean up temporary files and package managers – also use a docker ignore file to prevent unnecessary files from creeping in
  • Use multi-stage builds to separate the build environment from the runtime environment which results in a smaller image size as unnecessary files and resources are not inadvertently copied in.

Security Considerations

  • Regularly update your base images to include the newest security updates
  • Use official images from Docker Hub as these are properly vetted for security concerns
  • Scan images for vulnerabilities using third-party tools or native Docker tools like Docker Scout

Looking at Docker Scout:

looking at docker scout in docker desktop
looking at docker scout in docker desktop

Viewing vulnerabilities in Docker Desktop for a Docker image using Docker Scout:

looking at docker scout vulnerabilities for a sample docker image
looking at docker scout vulnerabilities for a sample docker image

Wrapping up

It is a great exercise to build Docker container images and looking at the command to build Docker image from custom created Dockerfile. By going through the process to build your own custom image with a custom Dockerfile, it helps you understand the components of a Docker image and the commands needed to bring everything together.

Practice in a lab environment building custom images so you understand the process. It will help you become proficient with building custom images. I used this process to build a custom arpwatch container for my home lab environment and learned a ton doing this.

Let me know what you guys think about building your own custom Docker images. Have you done this before? What projects and solutions make sense to build your own custom container image?

Brandon Lee
Brandon Leehttps://tek2cloud.com
Brandon Lee is the Senior Writer, Engineer and owner at tek2Cloud.com and has over two decades of experience in Information Technology. Brandon holds multiple industry certifications and loves IT automation, modern applications, and cloud technologies along with traditional servers and infrastructure.

Leave a Reply

Read more

Other Posts