Changing an image alters the rules mid-game
This is the second article in a series dedicated to visually explaining Docker and container concepts using a game of Tic-Tac-Toe and little or no code. It's focused on image immutability and tags, and demonstrates why images can't change.
The last post in this series used a game of Tic-Tac-Toe to show how containers are thin layers projected onto images. The image is the Tic-Tac-Toe board and includes the game's rules. It's shared by every Tic-Tac-Toe game container. Individual containers are layers that start out empty. As players add moves, they're recorded in the container layer.
The game only makes sense when you see both pieces together. On its own, the container layer is just random X's and O's. The game board in the image is perpetually empty because it can't change. In the container world, we say that images are immutable and, therefore, also stateless since altering the state requires saving those changes somewhere.
Change ≠ Replace
Is that really true, though? After all, I can change a Dockerfile and rebuild the image using the same name, which would seem to change the image. More accurately, I replaced the old image and assigned the same name.
It's an important distinction. To illustrate why, let's list the images on the system:
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
games tic-tac-toe ec616ed52b3b 1 hour ago 100KB
Then, start a new game container using that image. The "friendly" image name is its REPOSITORY
and TAG
, joined by a colon:
docker run games:tic-tac-toe
When I list the containers running on my system, I see my game:
> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8763546a856 ec616ed52b3b "/bin/tictactoe" 1 minute ago Up 1 minute (healthy) abundant_fun
Inside the container, players make a series of moves ending in a stalemate:
Recall that the moves are saved in the container layer, but the game board and all of the rules are part of the image. What if I could change the existing image used by a running container? Perhaps rewriting the Dockerfile and shifting the board to the right:
If the container used the changed image, moves in the leftmost column of the container layer would fall off the board, while three new spaces open up on the right! The game is no longer a stalemate! Now, Player O has two paths to victory courtesy of the repositioned game board in the new image, and Player X can block only one!
That demonstrates what would happen if you could change an existing image. But it does raise a question: what happens when you replace an image?
The Repo
Recall the original image was named games:tic-tac-toe
. If there were no containers using the image, Docker simply removes and replaces the image. But in the example above, a container was using the "old" image. So, does Docker respond by removing the container? Does it crash or stop responding when its image is replaced? Fortunately not!
In this case, Docker preserves the original image by un-tagging it—removing the friendly name—making the games:tic-tac-toe
tag available to the newly built image. Once untagged, the image no longer has a friendly name, which I'll see when I once again list the images on the system:
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
games tic-tac-toe 2fafb511dc00 1 hour ago 100KB
<none> <none> ec616ed52b3b 2 hours ago 100KB
One shows <none>
for the REPOSITORY
and TAG
. Look closely, and you'll see the IMAGE ID
matches the original image. By rebuilding the image, Docker untagged the old one but didn't delete it! Any containers that used the "old" image continue to work as before, without any change!
If you see <none>
listed for an image repository and tag, it just means it was untagged or replaced while still in use by a running container.
Top comments (0)