A hallmark of Docker containers is immutability. At any time, you can destroy and re-create containers to restore the initial state. With the docker commit command, you can commit new changes to a container image, but it’s not as straightforward as you’d expect.
Let’s explore how to commit changes to a new container image with the docker commit command!
When to commit changes to a
new container image
Containers are designed to be immutable (not changed), so why would you want to commit changes to a container? There are a few reasons.
During the development of a new
- containerized service to quickly test changes
- Perform a quick error correction of a production service without first correcting the source
- Use commit to create a snapshot of an image and export it to a new server.
Although they may not cover all potential scenarios, here are a few that make using docker commit a perfect use case.
Committing changes to
a simple image For a
seemingly simple command, this command goes a long way
Below is a simple example of a commit command. With a running container ID, d3fdd3517e0a This example creates a new image in a repository named myrepository and is named changedimage.
The original image is labeled as version2, which is not necessary, but is useful for tracking changes between images with similar names.
Both myrepository and changedimage are chosen arbitrarily, but usually reflect correctly tagged resources, such as customimages/alpine-linux.
Docker containers are a series of read-only images with a read-write layer on top. In the example above, Docker pauses the running container. This pause is to prevent accidental data corruption while Docker creates the image
Because this pause could cause service interruptions, you can use -pause=false. This could corrupt the data, as writes may not complete successfully.
In addition, the commit operation ignores data contained on volumes mounted within the container. Because the volumes are not part of the container’s own file system, Docker ignores them.
After the commit operation is complete, Docker creates a new layer with the changes from the original image under the new container image name.
The only prerequisite for this tutorial is Docker itself. This can be installed via Docker Desktop software on Windows or installed via a package on Linux.
Related: Deploying the first
Docker container on Windows
Commit changes to a new
Docker container image
Now let’s look at some common scenarios for which the docker commit command can be useful
First, deploy an Alpine Linux container image from the Docker public repository. Alpine is known for its slim containers, as noted by the ~5MB size.
Container development and testing
The primary use case for docker commit is the development of a new container image. Ultimately, this image can be used as a basis for other images or as a production container itself.
In the following example snippet, Docker is:
- Running the previously extracted alpine image
- Open an interactive shell to install a
the htop package
You can see below that the package is successfully installed in the container by running the htop command
Once you have installed the package on the new “layer”, you must now confirm that change in the original base image. To do this:
- Run docker ps
- Using the container ID, commit the contents of the current layer to a new base
-a to locate the container ID.
image. In the
following example, the new image is named alpine-htop and is labeled version1. The image is tagged to make it easier to track versions of Docker images that have similar names.
Correction of errors in production images
You can often have a production service that has some error. There may be a known fix, and you can apply it faster than modifying existing configurations and redeploying them. With docker commit, you can quickly apply the fix and then work in the background to update the other required components.
This example snippet below shows installing NGINX on an Alpine Linux Docker image.
Confirm the new NGINX container created earlier in a new image named alpine-nginx and labeled, version1. Tagging the image is a best practice to help differentiate different versions of the same image.
Not all executables will be able to run in the background, and NGINX is no different. To successfully run this container, with NGINX running in the background, pass the -g ‘daemon off;’ option to NGINX.
Finally, use the -change switch to expose port 80. When using the -change parameter, the EXPOSE 80 command will be written to the container’s DockerFile. After you make this change, start the new container. After the new container has started, proceed to stop the previous container that ran incorrectly without the exposed port. This will help make an elegant transition from the non-working container to the working container.
a Docker image
Finally, what about a scenario where you might need a snapshot, a point-in-time image, of a running container to move the container to a new server? The docker commit command works well to do that, as you can see below.
The following commands create a running container that we will stop and commit to a new version of alpine-nginx.
Export the Docker image to a file. In this example, the export file is named export.tar, but name the file according to your needs. Finally, import the export.tar file back into Docker, demonstrating the end-to-end process.
Be sure to export in the repo:tag format if you want those tags to be retained when you re-import the image.
Additional options for the
Taking advantage of the additional options available for the commit command, many different scenarios are supported
To avoid pausing the container while it is running, you can pass the -pause=false command to disable the pause feature. This is often used when backing up a production service and pausing that service would be harmful.
The pause command also has an abbreviation of -p that can be faster to use. However, keep in mind that by skipping the container pause, you risk data corruption, if a write occurs to the file system, which could cause incomplete or corrupted data to be written.
a confirmation message
familiar to many developers is to provide a correct confirmation message. As with using source control, the ideal is to give a useful message explaining why a new version of the container was confirmed.
This can be done using the command -message=”message to commit”. As before, there is a shortened version of this command, -m. To view the list of Docker confirmation messages, use the docker history command.
To correctly indicate who is creating the change, you can provide an author value that provides additional context to who is making the change. This can be used via -author=”Jane Author ([email protected])”. This command can also be used through the abbreviation of -a. With docker inspect you can retrieve a JSON list of container information, including tags as author.
Applying DockerFile changes side-by-side
Finally, the most complicated command that can be used in the docker commit command is the change parameter. This parameter applies changes to the container to the DockerFile at the same time as the commit.
You can use the change parameter by passing instructions to the Dockerfile like this, -change=”ENV TEST true”. This command places the text, ENV TEST true in the DockerFile. Now, when the container starts again, the changes you designate here are already applied.
Instead of the name -change, you can take a shortcut and use the alias -c
With this command, you can also chain multiple -change parameters together. This allows you to easily add multiple changes to a DockerFile in a commit command.
Change parameter options
You can only use some commands with the change parameter as shown below.
- – The CMD statement takes the form of CMD [“executable”,”parameter1″,”parameter2″]. This is the preferred method, but keep in mind that only one CMD can exist in a DockerFile at a time. The last CMD will be the one that takes effect. The primary purpose of CMD is to provide default execution commands for a container at creation time.
- – Similar to the CMD command, ENTRYPOINT uses the ENTRYPOINT syntax [“executable”,”parameter1″,”parameter2″]. This syntax raises the question of why use ENTRYPOINT over CMD? The ENTRYPOINT command runs an executable as the main PID 1 process. This action allows you to close the process using docker stop correctly. Also, you can use CMD with this by leaving out the executable part that passes those parameters to the ENTRYPOINT executable.
- ENV – Since most applications consume environment variables, the ENV command allows you to simply set them to the key-value format of ENV key=value. Access these key=value variables as standard Linux environment variables.
- – The EXPOSE command exposes a port and optional protocol outside the container. This command maps ports inside the container to the outside of the container and allows containers to interact with external resources, such as a web server serving content.
- : The LABEL command adds metadata to a container. You can add metadata using the format, LABEL version=”2.0″ to view additional metadata using the docker image inspect command.
- The ONBUILD command adds a statement to run later when the image is used as the basis for another container build. This parameter uses the ADD and RUN commands to add content with the ADD command or run an executable.
- – The USER command sets the user name (or UID) and, optionally, the user group (or GID) to use when running the image. This looks like USER myuser:mygroup in practice.
- VOLUME – With most containers, you need to access the data somehow. The VOLUME command will create a mount point with a specified name that marks it as containing an externally mounted volume. This is commonly used like this, VOLUME [“/data”].
- – Finally, the WORKDIR command sets the working directory of the CMD or ENTRYPOINT commands. This is used like this, WORKDIR /path/to/directory. WORKDIR is useful when you need to start an executable but the location is not in the default PATH environment variable.
The docker commit command is surprisingly complex. Although there is a simple syntax, with the ability to add DockerFile changes while using the commit command, you can quickly make changes that persist in the next container creation via DockerFile.
This command may not be necessary for all situations, but for quick troubleshooting and for snapshot containers that can be easily moved between servers, the commit command quickly becomes very useful.