We know how Docker can turn an Image into a Running Container. When we run that container again, we get the same thing we got the first time. The entire point of images is that they are fixed points where you know everything’s good, and you can always start from there. When you’ve got a Running Container, you make changes to that container and put files there. It’s beneficial when you want to be able to save those. The next step in the Docker flow is a Stopped Container. So the container that’s running is alive and has a process in it. The container is still there when that process exits, so any files you added to the container are still there. We can go back and see them, as Docker didn’t delete them. It’s just that it’s currently in a Stopped Container.
- Docker Bash
- Add Files To Container
- Last Exited Container
- Docker Commit
- Docker Tag
- Running New Images
Let’s get a container up and running using this command.
docker run -it ubuntu bash
The command above should now have a running container for us. Now we want to be able to use docker ps format vertically. To do this, we can use the string below at the terminal to store the formatting in the $FORMAT variable.
The use of vertical output is seen here.
docker ps --format="$FORMAT"
ID f3e8d5e3b007 NAME recursing_khayyam IMAGE ubuntu PORTS COMMAND "bash" CREATED 2022-11-11 12:30:22 -0500 EST STATUS Up 9 minutes
Add Files To Container
Let’s add a file in our container to demonstrate a few things.
root@f3e8d5e3b007:~# touch NEWFILE.txt root@f3e8d5e3b007:~# ls NEWFILE.txt
Now let’s stop the container which has a new file in it.
docker stop recursing_khayyam
Last Exited Container
So we can look at the most recently exited container with the docker ps command, just like we do when we want to look at the Running Containers, except Stopped Containers don’t show up by default. To see Stopped Containers, we can specify the -a argument to see all containers, a for all. And if we want to see the last container to exit, we can do docker ps -l. Now since we just exited a container right there, we’re going to say docker ps -l, because we want to look at the last one. Let’s put the format argument to fit it nicely on the screen.
docker ps -l --format="$FORMAT" ID f3e8d5e3b007 NAME recursing_khayyam IMAGE ubuntu PORTS COMMAND "bash" CREATED 2022-11-11 12:30:22 -0500 EST STATUS Exited (137) 3 minutes ago
We see we have a container. That’s the container ID from this one that we just exited. You see the image that the container started from it. The command we had run bash, we made it three minutes ago, and it exited with an exit code of 137. That’s just the return value of whatever process you ran. Zero generally means success. These exit codes can be a good clue as to why a container died. If you expected a container to be running and find it to be stopped for some reason, this could often give you a clue. This container doesn’t have any networking going on, and Docker can be newly made up a name for us. So now we have a Stopped Container. Alright, now say I’ve got a Stopped Container with a file we want to use for the future. We started from a base image. We installed our software, and I’ve got a container with our software installed.
The next step is the Docker Commit command. That takes containers and makes images out of them. It doesn’t delete the container. The container is still there. Now we have an image with the same content in that container. So Docker Run and Docker Commit are complementary to each other. Docker Run takes images to containers, and Docker Commit takes containers back to new images. It doesn’t overwrite the image that the container was made from. So now we can make a new image.
The stopped container has a new file on it. This is for simplicity. It could be that we made extensive changes or installed different software. We can take that new container and turn it back into an image. We do this with the docker commit command passing it the ID of the container we want to turn into an image.
% docker commit f3e8d5e3b007 sha256:978fbe5583de6cbd66bd42afbdb491abda1ba27d3a159430812742944686de21
We just got an image ID out of it. It looks very different from a container ID. Now we have made a new image. The original Ubuntu image is unchanged. We have a new image with a big number, which is not very convenient.
So the last step in the Docker flow is the tag command to give image names. We do this by using the docker tag command passing in the image id we got when running the docker commit command.
docker tag 978fbe5583de6cbd66bd42afbdb491abda1ba27d3a159430812742944686de21 my-new-image docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-new-image latest 978fbe5583de 5 minutes ago 69.2MB ubuntu latest 3c2df5585507 8 days ago 69.2MB hello-world latest 46331d942d63 7 months ago 9.14kB
When we run docker images, we see a new image called my-new-image. Now let’s launch that new image.
docker run -it my-new-image bash root@fe12fb60b6b9:/# cd ~ root@fe12fb60b6b9:~# ls NEWFILE.txt
Running New Images
We can say docker run to my-new-image, which has my important new file inside. Committing images and then tagging them is such a typical pattern that it’s built into the Docker Commit command. So you can skip the steps about copying the image name over to a Docker tag command and just run Docker Commit, the name of the container with its nice human-readable name, and then you can, as the following argument, say the name you’d like it to be tagged as.
docker commit recursing_khayyam my-2nd-image sha256:7147f810f60b90af135c75344d096b33342fdda1583153d3935fba3fedcba40f docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-2nd-image latest 7147f810f60b 5 seconds ago 69.2MB my-new-image latest 978fbe5583de 15 minutes ago 69.2MB ubuntu latest 3c2df5585507 8 days ago 69.2MB hello-world latest 46331d942d63 7 months ago 9.14kB
We can see from the steps above how we made a second image out of the container using my-2nd-image as the name. This is the approach you should probably use in your daily life. There’s no reason to go through the extra step of doing a commit, then running Docker tag, but it is essential to understand that that’s what’s happening under the hood.