Docker is a popular set of tools for building and running containerized applications. Developing an application to run in a container means isolating the application from the underlying system/environment so that the application can run in any environment. The environment will be injected into the application at run time.
Docker provides a powerful command line interface (CLI) for working with containers. In this article, we’ll take a look at the commit command in particular and how we can use it to create a new image from a container.
overview of basic terms
- Image: An image is a set of files, including the source/binaries and settings needed for the application to run. An image is read-only. We can create one by providing a Dockerfile to the docker build command. We can also create an image with the commit command from a container.
- Container: A container is a version of the image, ready to run as an application. Contains the environment for the application to run (for example, file systems, environment variables, port assignments, and so on). We can use the create or run commands to create a container from an image. Create will only create the container, while run will also launch it. A container does not need to be running once created; You may also be in the detained state. The docker ps command lists the containers created.
- Local repository: Docker maintains a repository of images and containers on the machine where we use the Docker tool to build or run the images. If you need to work with an image that is not in your local repository, you can use the docker pull command. Some commands, like run, will do this automatically for you. If we want to save a local image in a remote repository, we can use the push command.
The commit command creates a new image from a container and, optionally, from the specified Dockerfile commands. The syntax of the command is as follows: The
REPOSITORY is sometimes also called an image name. Tags provide more information about the image, such as versioning (1.0, latest, and so on). We can extract and work with images by consulting specific tags.
If the image uses volumes, the commit operation will not take into account the data contained in them. This is because data written in volumes will be considered data created by the application and not as part of the application image. (Volumes are the preferred way to preserve data generated and used by Docker containers (for example, saving data to a database or files). By default, Docker will pause the container while the commit command is executed to avoid any possibility of data corruption due to concurrent use. We can override this with the -p flag.
Note that the command needs a reference to a container, not an image. (We can use the build command to create a new image from an existing one or from scratch.) Why would we want to create an image from a container? Suppose we have an application running in a container that does not behave as expected.
instead of making changes to the application code/configuration or the Dockerfile, we create a new image and run it. We then make changes to the files in the container using the exec command and observe the results. Then, we may want to share that container with other team members for their feedback. So we created an image containing the last state of the container and shared it.
While this is fine for quick testing/debugging, we’d eventually want to pick up the changes we made and propagate them to the application code/configuration or to the Dockerfile used for compilation. The diff command is useful in that case so that we know which files were changed.
Docker confirmation example Let’s look at
an example of using commit. Suppose we are working with the NGINX image and the index file needs to be changed to an enterprise-specific file. These changes are not in the image or Dockerfile used for the build, and we want to do a quick test. So we will make changes to the container itself.
Create and run the container Let’s create
and run the container
with the following: We can list the containers
that are currently running with this:
And with the -a flag, we can list all containers (including stopped ones as well). Verify that NGINX is running at localhost:8080. You should see the NGINX welcome page.
We want to change this index page to a company-specific one. So we enter the Linux shell inside the container with the following command:
We can get the container-id from the docker ps command. The previous exec command will give us access to the shell prompt. Now we replace the index file with the one we want (using echo here for simplicity):
And we exit the shell with an output command. We can verify our change by reloading localhost:8080 in the browser. We should see the new content. If we wanted to track the changes we made to the container, we could use the following:
We need to ignore some files that NGINX creates/modifies at runtime (for example, those under /var/cache). We can see that there is a “changed” entry for the index.html which we change.
Create New Image
Now we want to share this container with other team members. So we use the commit command:
have created a new image with the same repository/image name == nginx, but a different tag, which describes the change we made. We could also have specified a completely new image name as “test-new-index”. To confirm the creation of the image, we do this
We can verify that the new image has the changes by running it and checking localhost:8080. (First, we’d have to stop the old container, which you’re also listening to on 8080, with docker stop.)
What if we wanted to inspect the image files without first running it as a container and then running an interactive shell on it? The docker save command is useful, as it allows us to save the image as a tar file, which we can then view with archive tools such as tar or zip.
Command options These are the
docker commit command
. -author or -a Specify the
author of this commit (for example, -a “Big Joe <email@example.com>”, etc.).
change or -c
Apply a specified Dockerfile statement to the created image. So, instead of changing the Dockerfile and compiling and deploying the image, we can create a new image from the container by following these instructions. The supported ones are as follows
- CMD: This is the command that is executed when a Docker container is started. If multiple CMDs are specified, only the last CMD will be collected. This can be overridden by the command parameter to the create/run command.
- : This is similar to CMD above, except that it cannot be overridden with the command parameter in the create/run command as appended to the ENTRYPOINT. To override the entry point, you can use the ‘-entrypoint’ flag in the run command.
- ENV: Use this option to set environment variables in the key=value format.
- Add an “EXPOSE port” command to the Dockerfile. Please note that this is for documentation only; The actual port assignment is done using the -p parameter passed to create or run.
- LABEL: This adds metadata to the image (e.g. version=”3.1″.) We can inspect the labels of an image/container using the inspect command. We can also filter images by the tag using the -f flag.
- ONBUILD: Build statements that run when you create a new image with this image. This is useful when instructions must be executed on content that is available in the child’s build (for example, a reusable build image and package would work in the source code of a child build).
- USER: Specifies the user to use when running the image. You can also specify a group of users.
- VOLUME: This creates a mount point in the specified path and marks it as containing an externally mounted volume.
- WORKDIR: Sets the working directory for other commands. It is useful when we want to execute several statements after changing to another directory.
Below is an example of how to pass the CMD and ENV options to change
Here, we have overridden the CMD of the NGINX image to pass an additional setting of worker_processes = 2. In addition, we have passed an ENV variable debug=true. Note the use of multiple -c flags to pass various changes. We have created an image with a new tag: wproc-and-debug. Note that on Windows, the quotation marks and escape will change.
message or -m
Provide a confirmation message, describing the changes made, for the documentation
pause or -p true/false
This indicates whether to pause the container during an acknowledgement. The default value is true.
We’ve seen how we can use the docker commit command, along with supported options, to create a new image. This is useful in the case of debugging/testing and for sharing container state with other team members. Debugging issues in a containerized distributed environment can be challenging. Kosli can help you by tracking your changes and implementations and providing valuable insight into why something is broken.