Using Docker Commit to Create and Change an Image

Written by: Ben Cane

5 min read

The Dockerfile is one of the key features to Docker's success. The ability to build a new container image from a simple text file changed the technology game.

When it comes to modifying a Docker image, our first thought is modifying the underlying Dockerfile. In today's article, I'm going to show you another way to create and change a Docker image. We will do this using the docker commit command.

Starting with a Base Image

In today's article, we are going to take a base Redis container image and add a new user to the container. While this example may be a bit generic, it shows how we can use the docker commit command.

Docker's commit command allows users to take a running container and save its current state as an image. This means to add our new user, we will need a running container. To get started, let's go ahead and launch a Redis container with the docker run command.

$ docker run -d redis
99eebc7db55d7039dcf6f36726c2492003ab06249b009e7b080648f4cc168015

In the above command, we can see that we started a container in the background using the redis image. Let's first verify that the container is in fact running with the docker ps command.

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
99eebc7db55d        redis               "docker-entrypoint..."   49 seconds ago      Up 47 seconds       6379/tcp            upbeat_panini

Now that we have a running container, let's verify that our new user doesn't already exist. To do this, we will be using another Docker command, docker exec.

$ docker exec -it upbeat_panini /bin/bash
root@99eebc7db55d:/data#

In the above output, we can see that the docker exec command worked, but what did it do? Let's take a second to explore what exactly the above command does.

The docker exec command is used to execute a command against a running Docker container. In the case above, we told the docker exec command to execute /bin/bash. This along with the -i (interactive) and -t (pseudo TTY) flags enabled us to log in to the running container.

We can see that we are logged into the container via the bash prompt, which now shows root@99eebc7db55d. If we look at the docker ps output above, we can see this same number. The number shows as the CONTAINER ID number of the upbeat_panini container. This is the same container we specified with our docker exec command.

Now that we are logged into the container, let's go ahead and verify if our "new" user already exists. We can do this by searching for the user's username in the /etc/passwd file.

root@99eebc7db55d:/data# grep example /etc/passwd

With the above output, we can see the user does not exist within this container.

Adding a User and Saving the Image

Since we have verified that the example user does not exist on a base redis container, let's go ahead and add that user to our running container. To do this, we will use the useradd command.

root@99eebc7db55d:/data# useradd -g redis example

If we once again execute the grep command against the /etc/passwd file, we should see this user now exists.

root@99eebc7db55d:/data# grep example /etc/passwd
example:x:1000:999::/home/example:/bin/sh

Now that our user is added, let's go ahead and exit our container going back to the host system. From there, we can execute the docker commit command to save our image changes.

When executing the docker commit command, we will need to provide two parameters: the name of the running container upbeat_panini and the name of our desired image output testredis:example.

$ docker commit upbeat_panini testredis:example
sha256:6f68e12ee78732258a4fdfedca3ab164a5c9ea330ed28c9cb0d531477706373b

In the above output, we can see that the docker commit command returned a sha256 hash. Seeing this hash indicates that our docker commit command was successful.

Let's double-check that our image was in fact created using the docker images command.

$ docker images testredis:example
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
testredis           example             6f68e12ee787        10 hours ago        183MB

With the above, we can see our testredis image is in fact created.

!Sign up for a free Codeship Account

Seeing the Differences

With our new container image saved, let's go ahead and see how well our docker commit worked. We can do this by issuing the same grep command via a docker run execution.

First, let's verify that our same base redis container doesn't have the example user.

$ docker run redis grep example /etc/passwd

From the above, we can see that the example user doesn't exist within our base redis image. This might be a bit confusing at first, but once we think about how Docker works, it makes complete sense.

Earlier when we logged into our upbeat_panini container, we added the example user. When we did this, we only added that user to the running container. Any changes we make to a running container has no effect on the original image. This is essentially the stateless nature of Docker containers.

While our base redis image doesn't have our example user, what about testredis:example?

$ docker run testredis:example grep example /etc/passwd
example:x:1000:999::/home/example:/bin/sh

As expected, our new testredis:example image does include an example user. From here, we can use this image to create new containers or push it to a registry such as DockerHub.

Summary

In today's article, we explored a way to make changes to Docker images without a Dockerfile. Learning about the docker commit functionality is interesting; in this author's humble opinion, docker commit should be used sparingly.

In the argument of using docker commit versus a Dockerfile, I personally believe that the Dockerfile method is more future-proof. A Dockerfile has the distinct advantage of being text, meaning it can be added to source control such as Git. This is in addition to being used to build a image and having that image pushed to a registry.

Do you have another opinion or a use case that a Dockerfile doesn't fit but docker commit does? Add your opinion in the comments below.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.