A Docker image is made up of a collection of files that bundle together all the essentials – such as installations, application code, and dependencies – required to configure a fully operational container environment. You can create a Docker image by using one of two methods:
Interactive: By running a container from an existing Docker image, manually changing that container environment through a series of live steps, and saving the resulting state as a new image
Dockerfile: By constructing a plain-text file, known as a Dockerfile, which provides the specifications for creating a Docker image.
The main advantage of Docker over any other containerization technology is that Docker is aimed at developers and their upstack applications.
The Dockerfile consists of a set of rules that takes your application files (like binaries, source files, etc) along with various configuration parameters like file system layout, exposed ports, etc and turns them into a Docker image file. You can then share the image file with anyone who wants to run that application.
Create an Image From a Container
Tag the Image
Delete the Original Container
Consider Your Options
The source code of a Docker image is a Dockerfile. A Dockerfile is written in Docker specific language, and can be compiled into an image by the docker binary, using the docker build command.
Most images are based on another image. The base image is specified at the beginning of the Dockerfile, with the FROM directive. If the base image is not present in the local system, it is downloaded from Docker Hub. For example, we can build a mariadb-rocksdb:10.5 image starting from the debian:13 image. In this way, we’ll have all the software included in a standard Debian image, and we’ll add MariaDB and its configuration upon that image.
All the following Dockerfile directives are compiled into a new Docker image, identified by an MD5 string. Each of these images is based on the image compiled from the previous directive. A physical compiled image can serve as a base for any number of images. This mechanism saves a lot of disk space, download time and build time.
Each image is built from either a parent image (an image used as the starting point for the new image) or from an empty pseudo-image called scratch. Most parent images typically provide a filesystem structure that resembles a minimal Linux system, package management tools, and the core functionality that you’d expect from a command line environment. Parent images are available for most popular Linux distributions, often in a variety of configurations. Images are also available preconfigured for different programming languages and ecosystems.
Container images are built by applying “layers” onto previous images. Each filesystem layer represents a point-in-time record of the filesystem state after certain actions. Images that have common ancestry share filesystem layers, allowing for reduced overhead and greater consistency between images.
- Create an account Docker Hub.
- Install Docker on your local machine. [Refer to the Docker Getting Started Guide]
Login to Docker Hub:
docker loginwith your credentials. [Refer to the docker login docs for a complete reference]
- Create a GitHub repository that will hold the code to build the image.
- Your Dockerfile will look something like this:
Build and Push image
FROM readytalk/nodejs # Add our configuration files and scripts WORKDIR /app ADD . /app RUN npm install EXPOSE 80 ENTRYPOINT ["/nodejs/bin/npm", "start"]
DOCKER_ACCis the name of your account
$DOCKER_REPOis your image name and
$IMG_TAGis your tag
docker build -t $DOCKER_ACC/$DOCKER_REPO:$IMG_TAG .
sudo docker push $DOCKER_ACC/$DOCKER_REPO:$IMG_TAG
Most Dockerfiles start from a parent image. If you need to completely control the contents of your image, you might need to create a base image instead. Here’s the difference:
A parent image is the image that your image is based on. It refers to the contents of the from directive in the Dockerfile. Each subsequent declaration in the Dockerfile modifies this parent image. Most Dockerfiles start from a parent image, rather than a base image. However, the terms are sometimes used interchangeably.
A base image has FROM scratch in its Dockerfile. Now let us create an empty file named Dockerfile.
Open it with your favorite text editor, and write the following lines to it:
FROM scratch ADD hello / CMD ["/hello"]
scratch is not a parent image. Rather it indicates Docker that the image is not built on top of any other image. It is built from scratch. ADD command would take the static binary named hellofrom the current directory and add it to the root directory of the image file. When we would finally run a container based on this image, the hello executable will be seen inside the root directory itself at /hello.
Lastly, the CMD line has a string “/hello” this string will be executed as a shell command whenever a container is created from this image, thus the binary file that we added to our container and print the message that we wrote in our app. Let’s build the image by invoking the docker build command which would go through the Dockerfile’s contents and generate the image. Run the following command in the same directory as the Dockerfile and the executable binary.
$ docker build --tag hello .
The –tag hello flag sets the image name to hello and the dot ( “.” ) at the end tells docker build to look into the current directory for Dockerfile and related contents.
When working with Docker, we need to keep in mind that any layer added to the image is never removed. In other words, it’s smarter to update the apt cache, install some packages, and remove the cache in a single Docker RUN command.