How to Create Docker Images?

App deployment has become easier because of containerization. But what is containerization? Let's understand it using an example.

Think of a laptop box. It contains a laptop, a charger, a power cable, and a battery. The laptop is dependent on the charger and its accessories. This box has everything that the laptop needs to run. After packing it, we can ship and use it anywhere.

Containerization does the same thing for an app. It packages the application, or code, and all its dependencies into one image. The app can require additional software packages and libraries to run. So, everything that the app needs is packed into one image. This makes it portable and allows us to deploy it anywhere. The target operating system doesn't matter anymore. Normally, apps are dependent on what the operating system provides. But in this case, we provide everything it needs inside that image.

Why Create Docker images?

The traditional method of deploying apps can be troublesome. Imagine you have to deploy an app on five servers. How will you deploy it using the traditional method?

You need to download the app based on the operating system. For example, there will be different packages or installers for each OS. One for Ubuntu, one for CentOS, one for Debian, and so on. And you will also need to install the packages dependent on the app, and this can cause a problem in the servers.

Here are the benefits of containerization over the traditional deployment method.

  • One image, many operating systems: Every application is packaged into a Docker image, and it can be used on multiple operating systems.
  • Speed up the deployment process: The deployment process speeds up as you can directly copy or download the image to the server and create a container of the image to run the app.

Try our Docker Images Lab for free

Docker Images Lab
Docker Images Lab

How to Create Docker Images?

A Docker image contains everything that is needed to run an app. Most times, we create a Docker image by using a parent image which serves as a base. Then we add our app and whatever else it needs on top of that. And you end up with the final image, built specifically for your app.
There are two ways of creating a Docker image:

  • The first way is to create them using a Dockerfile. A Dockerfile contains a set of instructions that runs on top of the parent image and creates an intermediate container for every instruction. After completion of an instruction, the context is sent forward for the next instruction.
  • The second way is by creating the image from a container. We create a container of an existing image. We run commands inside the container that can perform tasks like copy files, installing packages, etc. When we are making these changes to a container, its environment is different from what the container was created with.

When you run another container of the same image, these changes will not be present. To make these changes persistent, we do what is called “commit a container.” It creates an image from the container and makes all the changes persistent, so when you run a container of this new image, all the changes will be there.

Now that we have a better understanding of what Docker images are, let's move on to the next step — learning how to create a Docker image.

Prerequisites for Running a Docker Image

To run a Docker image, use KodeKloud’s Docker Playground. The advantage? You don't have to set up anything. With one click, you get almost instant access to a Docker environment that is accessible in your web browser.

Sign up to KodeKloud to get instant access to the Playground and the free course, Docker for absolute beginners.

Alternatively, you can use Docker Desktop. If you don’t have a Docker Desktop, make sure to download and install it on your system first. You can find the official installation guide by following this link.

Create a Docker Image Using a Dockerfile

To get started, we will be cloning a git repository that contains all the files needed to create the Docker images.

git clone https://github.com/thakarprathamesh/python-hello-world-program.git

The snapshot below shows the files that are present in the git repository.

Contents of the git repo
Contents of the git repo

The Dockerfile is used to create the docker image using the first method. The app.py file contains code written in the Python programming language. The requirements.txt file contains all the Python dependencies to run that code. The app will return an answer when it receives an HTTP request, and we have configured the app to run on port 9999.

We’ll use the Dockerfile below to build an image of the Python app.

FROM python:alpine3.17
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python", "app.py"]

Let’s understand each of the keywords in the Dockerfile.

FROM - This represents the parent image, and in our case, we are using Python 3.17 as the parent image.

WORKDIR - It sets the working directory for the commands that follow it.

COPY - This keyword is used to copy the contents into the image

RUN - Tells the image builder to run a certain command inside a shell (within the image's environment).

ENTRYPOINT - This tells Docker how to start the container. Here, we instructed Docker to run the code in our app.py file

To tell Docker to construct this image, based on the instructions found in Dockerfile, we execute this command:

docker build . -t hello-python:1.0

Let’s see if the image has been created by listing all the images using the command below:

docker images

Here is the output we get after executing the command.

Docker images
Docker images

Perfect. Let’s now start a container based on this image.

In our Python image, we are running the code on port 9999. To access the app from the host, we need to publish a port, which involves mapping a host port to the container port.

We will do it by using the -p flag in the docker run command. Here, we are mapping the host port 9998 to container port 9999. So you will be able to access the app from the 9998 port of the host.

docker run -d -p 9998:9999 hello-python:1.0

Now we can test the application using curl as shown in the snapshot below:

Sending a request to the app
Sending a request to the app

That’s how you create an image from a Dockerfile. Now, let’s create an image from a container.

Create a Docker Image from a Container

In this method, we will create an image by running the container, making required changes to the container, and then committing the container to an image.

1. Create a container of the base image

Run the below command to create a container of the base image. We will make the changes in this container. Docker will pull the image if it is not present on the server.

docker run -itd --name python-base python:alpine3.17

2. Copy the required files into the container

We will need to copy the required files to the container using the docker cp command. We will copy the files from our local machine to a directory inside the container.

docker cp app.py python-base:/
docker cp requirements.txt python-base:/

3. Install the required dependencies

The code requires the Flask package to run (specified inside our requirements.txt file), and we install it using the pip command. We do this by telling Docker to execute the command inside this active container, as shown below:

docker exec -it python-base pip install -r requirements.txt

Learn more about this from this blog: Docker Exec: How to Enter Into a Docker Container's Shell?

4. Create the image of the container

Now, we need to create an image of this container. To do that, we will use the "docker commit" command. While doing that, we also change the entry point of the image.

docker commit --change='ENTRYPOINT ["python","app.py"]' python-base python-hello:1.0

The new image has been created. Let's run a container based on this image and see if our app.py file executes correctly. Like the first method, we will map a host port to the container port.

docker run -itd -p 9998:9999 python-hello:1.0

We can now test the application using curl, as shown in the snapshot below:

Sending a request to the app
Sending a request to the app

The app returns the expected output after sending an HTTP request to it.

Enroll in KodeKloud to access our Docker Learning Path:

Docker Learning Path | KodeKloud

Conclusion

We created Docker images using two different methods. The first method (creating images from Dockerfile) is very helpful when you try to automate certain processes. For example, it greatly helps when you want to automatically build images and launch containers with the help of a CI/CD pipeline.

The second method (creating images from containers) brings you better clarity in the case of debugging. If you are facing any issues while building the image using Dockerfile, create a container of the base image and run the same commands that you were running in Dockerfile.


More interesting reads: