Docker Commit Demo: Save Container as Image & Practical Tutorial
In this practical deep-dive tutorial, we explore how to capture the state of a running Docker container and persist it as a brand-new custom image using the docker commit command. We examine the underlying storage layers on the host filesystem, perform live modifications inside an Nginx container, commit those changes, wipe our environment clean, and spin up a brand-new container from our custom image.
1. Why Do We Need docker commit? (Problem Statement & Status Quo)
Normally, Docker best practices dictate that images should be built declaratively using a Dockerfile. A Dockerfile ensures reproducibility, version control, and clean separation of concerns.
However, during active troubleshooting, emergency debugging, or rapid experimental prototyping, an engineer often makes manual configuration fixes directly inside a running container. If that container is deleted, those unsaved modifications vanish instantly.
docker commit acts as an "emergency snapshotting" tool. It takes a running container, captures its exact filesystem delta, and packages it into a brand-new local image.
2. Core Mental Model: The Container Snapshot Analogy
Think of a running Docker container as a writable whiteboard mounted on top of a stack of read-only reference books (the base image layers).
- Base Image (
nginx:latest): The printed textbook pages (read-only, immutable). - Running Container (
webapp): The whiteboard where you scribble notes, cross things out, and draw custom diagrams. docker commit: Taking a high-resolution snapshot photograph of the whiteboard, laminating it, and saving it on your shelf as a brand-new, standalone reference manual (webapp:v2).
3. Pulling the Base Image and Exploring Storage Layers
We begin our hands-on demonstration by pulling the official nginx image from Docker Hub without specifying a version tag (which defaults to latest).
docker pull nginx
Observing Image Layers
When pulling the image, Docker outputs multiple SHA hashes. These represent the individual read-only layers that comprise the image.
To see where Docker physically stores these layers on the host machine, we can navigate into the container runtime's internal storage path (assuming root access):
cd /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
ls -la
We can cross-reference the SHA hash of our downloaded Nginx image using docker images and filter the long list on the host filesystem to verify that the layer blobs match our image metadata.
4. Launching and Inspecting the Nginx Container
With the base image present locally, we spin up an Nginx container in detached mode (-d), map host port 80 to container port 80, and name the container webapp.
docker run -d -p 80:80 --name webapp nginx
Validating Container Status & Default Response
We verify that the container is up and running:
docker ps
To test that Nginx is actively serving traffic, we execute a curl request against localhost or retrieve the container's internal IP address using docker inspect:
# Inspect container to find its internal IP address
docker inspect webapp | grep -i -A 4 "IPAddress"
# Curl the container directly
curl <CONTAINER_IP>
Output: The standard default welcome message: Welcome to nginx!
5. Modifying Container Files Interactively
Next, we intentionally alter the state of the running container by modifying its hosted HTML file.
We enter the container using an interactive bash shell (docker exec -it ... bash):
docker exec -it webapp bash
Once inside the container shell, Nginx's default HTML file is located at /usr/share/nginx/html/index.html. We overwrite its contents using a simple echo command:
echo "Welcome to docker commit" > /usr/share/nginx/html/index.html
We verify the modification:
cat /usr/share/nginx/html/index.html
Result: Displays Welcome to docker commit.
We exit the container shell (exit) and run curl against the container's IP again to confirm the live web server is now serving our modified text.
6. Creating the Snapshot Image with docker commit
Now that our container contains custom modifications that do not exist in the base nginx:latest image, we capture its current state into a new image named webapp with tag v2.
Syntax
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Execution
docker commit webapp webapp:v2
We validate that our new custom image has been successfully created and stored locally:
docker images
Result: You will see webapp with tag v2 listed alongside its unique image ID and creation timestamp.
7. Wiping the Environment Clean
To prove beyond a shadow of a doubt that our custom image is completely self-contained and independent of the original container, we perform a total purge of our current working environment.
-
Force-remove the running container (
webapp):BASHdocker rm -f webapp -
Delete the original base image (
nginx:latest):BASHdocker rmi nginx -
Verify clean state:
BASHdocker ps -a docker imagesAt this point, the original container is gone, the original Nginx base image is gone, and only our custom
webapp:v2image remains on the system.
8. Spun-Up Verification: Running the Committed Image
We now instantiate a brand-new container directly from our committed custom image (webapp:v2), mapping host port 8080 to container port 80.
docker run -d -p 8080:80 --name new-docker-app webapp:v2
We verify that the container is up and running:
docker ps
Inspecting and Testing the New App
We retrieve the new container's IP address and test it:
# Find IP Address
docker inspect new-docker-app | grep -i -A 4 "IPAddress"
# Test via curl using host port mapping
curl http://localhost:8080
Output:
Welcome to docker commit
The modified HTML file persisted successfully inside the committed image (webapp:v2), proving that docker commit successfully captured the filesystem delta.
9. Architectural Workflow Walkthrough
The end-to-end workflow executed in this tutorial follows this precise sequence:
10. Summary and Key Takeaways
- Definition of
docker commit: A Docker command used to take a snapshot of a running container's filesystem and save it as a new local Docker image. - Storage Layers: Docker images are composed of immutable SHA-256 layers stored internally in the host runtime filesystem (e.g., under
/var/lib/containerd/...). - Live Modification: Changes made to a container's filesystem (such as editing
/usr/share/nginx/html/index.html) exist in the container's writable top layer. - Preservation:
docker commit [CONTAINER_NAME] [IMAGE_NAME:TAG]freezes these writable layer deltas into a brand-new reusable image. - Port Mapping Strategy: When running containers mapping port conflicts (e.g., port
80already in use or freed), mapping host port8080to container port80allows clean external access. - Use Case Limitation: While
docker commitis extremely handy for quick testing, debugging, and experimentation, avoid using it in production environments. Production images should always be built declaratively using reproducibleDockerfilescripts.