A Beginner’s Guide to Understanding and Building Docker Images
Edward Kisller
Introduction
A Docker image is a read-only template that contains a set of instructions for creating a container that can run on the Docker platform. It provides a convenient way to package up applications and preconfigured server environments, which you can use for your own private use or share publicly with other Docker users.
Docker images are also the starting point for anyone using Docker for the first time.
So, in this introduction, we’ll not only take you through the basics of Docker images, but also show you where to find ready-made off-the-shelf images, which will give you a head start in building your own containerized applications, tools and services.
As a new Docker user, you’ll also need to understand how to build your own custom images. So we’ll briefly cover how to create Docker images for deploying your code and assembling container-based services.
This guide includes:
- Anatomy of a Docker image
- Container registries
- Container repositories
- How to create a Docker image
- Learn more about Docker
- Take the Docker challenge
First, let’s look at the composition of a Docker image in more detail.
1. Anatomy of a Docker Image
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 in one of two ways:
- Interactive Method: 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 Method: By constructing a plain-text file, known as a Dockerfile, which provides the specifications for creating a Docker image.
We’ll cover each of these two methods in more detail later in this guide. But, for now, let’s focus on the most important Docker image concepts.
Image Layers
Each of the files that make up a Docker image is known as a layer. These layers form a series of intermediate images, built one on top of the other in stages, where each layer is dependent on the layer immediately below it.
The hierarchy of your layers is key to efficient lifecycle management of your Docker images, whereby you should organize layers that change the most often as high up the stack as possible.
This is because, when you make changes to a layer in your image, Docker not only rebuilds that particular layer but all layers built from it. Therefore a change to a layer at the top of the stack involves the least amount of computational work to rebuild the entire image.
Container Layer
Each time Docker launches a container from an image, it adds a thin writable layer, known as the container layer, which stores all changes to the container throughout its runtime.
As this layer is the only difference between a live operational container and the source Docker image itself, any number of like-for-like containers can potentially share access to the same underlying image while maintaining their own individual state.
Containers based on the same image share that image, reducing resource overhead
Parent Image
In most cases, the first layer of a Docker image is known as the parent image. It’s the foundation upon which all other layers are built and provides the basic building blocks for your container environments.
You can find a wide variety of ready-made images for use as your parent image on the public container registry Docker Hub . You can also find them on a small number of third-party services, such as Google Container Registry. Alternatively, you can use one of your own existing images as the basis for creating new ones.
A typical parent image may be a stripped-down Linux distribution or come with a preinstalled service, such as a database management system (DBMS) or content management system (CMS).
Base Image
In simple terms, a base image is an empty first layer, which allows you to build your Docker images from scratch. Base images give you full control over the contents of images, but are generally intended for more advanced Docker users.
Docker Manifest
Together with a set of individual layer files, a Docker image also includes an additional file known as a manifest. This is essentially a description of the image in JSON format and comprises information such as image tags, a digital signature and details on how to configure the container for different types of host platform.
2. Container Registries
Container registries are catalogs of storage locations, known as repositories, where you can push and pull container images. The three main types of registry are as follows.
- Docker Hub: Docker’s own official image resource where you can access more than 100,000 container images, shared by software vendors, open-source projects and Docker’s community of users. You can also use the service to host and manage your own private images.
- Third-party registry services: Fully managed offerings that serve as a central point of access to your own container images, providing a way to store, manage and secure them without the operational headache of running your own on-premises registry.
- Self-hosted registries: A registry model favored by organizations that prefer to host container images on their own on-premises infrastructure— typically because of security, compliance or lower latency requirements.
You can also set up your own private, remote and virtual Docker registry.
3. Container Repositories
The specific physical locations where your Docker images are actually stored, whereby each repository comprises a collection of related images with the same name.
Each of those images within a repository is referenced individually by a different tag and represents a different version of fundamentally the same container deployment.
For example, on Docker Hub, mysql is the name of the repository that contains different versions of the Docker image for popular open-source DBMS MySQL.
4. How to Create a Docker Image
In this final section, we cover the two different methods of creating Docker images in a little more detail, so you can start putting your knowledge into practice.
Interactive Method
Advantages: Quickest and simplest way to create Docker images. Ideal for testing, troubleshooting, determining dependencies and validating processes. |
Disadvantages: Difficult lifecycle management, requiring error-prone manual reconfiguration of live interactive processes. Easier to create unoptimized images with unnecessary layers. |
The following is a set of simplified steps to creating an image interactively:
- Install Docker and launch the Docker engine.
- Open up a terminal session.
- Use the following Docker run command to start an interactive shell session with a container launched from the image specified by image_name:tag_name.
$ docker run -it image_name:tag_name bash
If you omit the tag name then Docker automatically pulls the most recent image version, which is identified by the latest tag. If Docker cannot find the image locally then it will pull what it needs to build the container from the appropriate repository on Docker Hub.
In our example, we’ll launch a container environment based on the latest version of Ubuntu.
$ docker run -it ubuntu bash
- Now configure your container environment by, for example, installing all the frameworks, dependencies, libraries, updates and application code you need. The following simple example adds an NGINX server.
# apt-get update && apt-get install -y nginx
- Open up another Bash shell and type the following docker ps command to list active container processes.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e61e8081866d ubuntu "bash" 2 minutes ago Up 2 minutes keen_gauss
- Save your image using the Docker commit command, specifying either the ID or name of the container from you which want to create it.
$ docker commit keen_gauss ubuntu_testbed
- Now use the Docker images command to see the image you’ve just created.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 775349758637 5 minutes ago 64.2MB
- Finally return to your interactive container shell and type in exit to shut it down.
# exit
Dockerfile method
Advantages: Clean, compact and repeatable recipe-based images. Easier lifecycle management and easier integration into continuous integration (CI) and continuous delivery (CD) processes. Clear self-documented record of steps taken to assemble the image. |
Disadvantages: More difficult for beginners and more time consuming to create from scratch. |
The Dockerfile approach is the method of choice for real-world enterprise-grade container deployments.
It is a more systematic, flexible and efficient way to build Docker images and the key to compact, reliable and secure container environments.
In short, the Dockerfile method is a three-step process whereby you:
Create the Dockerfile and add the commands you need to assemble the image.
The following table shows you those Dockerfile statements you’re most likely to use:
Command |
Purpose |
FROM |
To specify the parent image. |
WORKDIR |
To set the working directory for any commands that follow in the Dockerfile. |
RUN |
To install any applications and packages required for your container. |
COPY |
To copy over files or directories from a specific location. |
ADD |
As COPY, but also able to handle remote URLs and unpack compressed files. |
ENTRYPOINT |
Command that will always be executed when the container starts. If not specified, the default is /bin/sh -c |
CMD |
Arguments passed to the entrypoint. If ENTRYPOINT is not set (defaults to /bin/sh -c), the CMD will be the commands the container executes. |
EXPOSE |
To define which port through which to access your container application. |
LABEL |
To add metadata to the image. |
Example Dockerfile
|
An example Dockerfile for building an image based on official ubuntu 18.04 with installing Nginx.
Next set up a .dockerignore file to list any files, which would be otherwise created during the Docker build process, that you want to exclude from the final build.
.dockerignore files play an important role in creating more compact, faster-running containers—by providing a way to prevent sensitive or unnecessary files and directories from making their way into your image builds.
Your .dockerignore file should be located in the root directory, known as the build context, from which you intend to build your image. This will be either your current working directory or the path you specify in the Docker build command that we discuss below.
Now use the Docker build command to create your Docker image. Use the -t flag to set an image name and tag$ docker build -t my-nginx:0.1 .
In the example above, we built the image from within the same directory as the Dockerfile and the context, as the . argument simply tells the Docker daemon to build the image from the files and folders in the current working directory.
Finally, as we saw in the interactive method, you can use the Docker images command to see the image you’ve just created.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx 0.1 f95ae2e1344b 10 seconds ago 138MB
ubuntu 18.04 ccc6e87d482b 12 days ago 64.2MB
Again, you should see your new image listed in the results.
5. Learn More about Docker
Docker Image Security: 6 Must-Know Tips Read more > |
Docker Hub and Docker Registries: A beginner’s guide Read more > |
Three Essential Steps to Securing Your Docker Container Deployments Read more > |
How to set up your own private, remote and virtual Docker registry. Read more > |