Docker containers are generally ephemeral application instances which lack internal state. That’s the best practice way to handle them that lets you stop or restart your containers at any time.
Sometimes modifications to a container’s filesystem are unavoidable though. Perhaps you’re trying out software and want a snapshot to return to later. Another use case could be situations where the software inside a container’s stopped working and you want to save a replica you can debug in the future.
Here’s how to create a new Docker image from an existing container. You’ll then be able to start another container from that image which will be populated with the filesystem from the first one.
docker commit command is used to take a container and produce a new image from it. It works with either stopped or running containers.
The basic syntax is as follows:
docker commit example-container example-image:latest
This creates an image from the container named
example-container. You can also identify the container by ID if you prefer. Both pieces of information are available from the output of
docker ps which lists all the containers on your host.
The resulting image is assigned the tag given as the command’s second parameter. This is
example-image:latest in the example shown above. Just like a regular image tagging operation, the new image will replace the tag’s reference if it already exists.
Now you can use your image to restore the filesystem from
example-container into a new container instance:
docker run -d example-image:latest
The filesystem content will match the
example-container container at the time the
docker commit command was executed There is one important caveat: the content of mounted volumes will not be included, so their mount locations will be empty in the created container image. To run a new container with volume data intact, use the
-v flag to reattach the volumes from the first container when you start the second instance with
Another noteworthy sticking point is how Docker handles commits of running containers. For the most part, this should work seamlessly but it defaults to pausing the target container before the commit is created. All the processes within the container will be suspended and then resumed after the image creation is complete. This improves data consistency in the new image but leaves the container momentarily inaccessible. You can disable this behavior by including
--pause false with your
docker commit command.
Adding Commit Messages
docker commit command supports commit messages in a similar fashion to version control software like Git. Adding a message when you create an image from a container lets you document what’s changed and the reason behind your commit.
-m flag to apply a commit message:
docker commit -m "Example commit" example-container example-image:latest
You can add authorship information with a dedicated flag too. Supply a string in the common
First Name <email@example.com> format to the
-a flag. It’ll be saved alongside the commit message.
docker commit -a "Example Author <firstname.lastname@example.org>" -m "Example commit" example-container example-image:latest
Commit messages are displayed when you use the
docker history command to view the layers in an image. They’ll show up in the
COMMENT column on the far right.
Another way of accessing this information is to use
docker inspect in tandem with
grep to extract authorship and comment values from an image’s JSON representation:
docker inspect <image-id> | grep 'Created|Author|Comment'
This will show the data associated with the top-most layer in the image.
Changing Dockerfile Instructions
Committing an image gives you a chance to mutate some of its Dockerfile instructions. You can override the following values in your new image:
To set an instruction, use the
docker commit --change 'ENTRYPOINT ["sh"]' example-container example-image:latest
You can repeat the flag as many times as necessary to apply all your intended changes.
Only instructions which impact the top-most filesystem layer are supported. You can’t seamlessly extend a committed image with new layers via instructions such as
COPY. However you could take the result of a commit and write a new Dockerfile that adds new content if required:
# Created via `docker commit` FROM example-image:latest RUN apt install example-package
If you do change Dockerfile instructions at commit time, it’s worth adding a commit message that explains what you’re modifying and why. This will help anyone else with access to the image understand any behavior differences compared to the container it was created from.
Docker images are usually built from Dockerfiles and used to start disposable containers. Changes to the state of a container’s filesystem are made by rebuilding the image, destroying the existing container, and starting a new one. In an ideal world, containers don’t have any internal state but this isn’t always true in practice.
Committing a container gives you a way to restore its current filesystem in the future. Commits are useful for creating replicas of troublesome containers so you can debug in a separate environment while maintaining access to previously generated logs and temporary files.
Although container commits often feel similar to VM snapshots, they aren’t quite the same thing. VMs control virtual hardware and the state of that hardware will be present within the snapshot. Docker containers are just a set of processes running on the host; a commit is a new Docker image that represents the container’s filesystem but necessarily lacks any data about the state of processes, the kernel, and your hardware.