I recently played around with Docker, an application container and virtualization technology for Linux. It was pretty cool and I was able to create Docker images and containers within a couple of minutes. Everything was working right out of the box!
At the end of my day I wanted to persist my work. I stumbled over the Docker commands save
and export
and wondered what their difference is. So I went to StackOverflow and asked a question which was nicely answered by mbarthelemy. Here is what I found out.
How Docker works (in a nutshell)
Docker is based on so called images. These images are comparable to virtual machine images and contain files, configurations and installed programs. And just like virtual machine images you can start instances of them. A running instance of an image is called container. You can make changes to a container (e.g. delete a file), but these changes will not affect the image. However, you can create a new image from a running container (and all it changes) using docker commit <container-id> <image-name>
.
Let’s make an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# we pull a base Docker image called busybox # just like in the official Hello-World-example sudo docker pull busybox # let's check which images we have # we should see the image busybox sudo docker images # now we make changes to a container of this image # in this case we make a new folder sudo docker run busybox mkdir /home/test # let's check which containers we now have # note that the container stops after each command # we should see a busybox container with our command sudo docker ps -a # now we can commit this changed container # this will create a new image called busybox-1 # you see the <CONTAINER ID> with the command above sudo docker commit <CONTAINER ID> busybox-1 # let's check which images we have now # we should see the image busybox and busybox-1 sudo docker images # to see the difference between both images we # can use the following check for folders: sudo docker run busybox [ -d /home/test ] && echo 'Directory found' || echo 'Directory not found' sudo docker run busybox-1 [ -d /home/test ] && echo 'Directory found' || echo 'Directory not found' |
Now we have two different images (busybox
and busybox-1
) and we have a container made from busybox
which also contains the change (the new folder /home/test
). Let’s see how we can persist our changes.
Export
Export is used to persist a container (not an image). So we need the container id which we can see like this:
1 |
sudo docker ps -a |
To export a container we simply do:
1 |
sudo docker export <CONTAINER ID> > /home/export.tar |
The result is a TAR-file which should be around 2.7 MB big (slightly smaller than the one from save
).
Save
Save is used to persist an image (not a container). So we need the image name which we can see like this:
1 |
sudo docker images |
To save an image we simply do:
1 |
sudo docker save busybox-1 > /home/save.tar |
The result is a TAR-file which should be around 2.8 MB big (slightly bigger than the one from export
).
The difference
Now after we created our TAR-files, let’s see what we have. First of all we clean up a little bit – we remove all containers and images we have right now:
1 2 3 4 5 6 7 8 9 10 11 12 |
# first we see which containers we have sudo docker ps -a # now we remove all of them sudo docker rm <CONTAINER ID> # now we see which images we have sudo docker images # and we remove them too sudo docker rmi busybox-1 sudo docker rmi busybox |
We start with our export we did from the container. We can import it like this:
1 2 3 4 5 6 7 8 9 |
# import the exported tar ball: cat /home/export.tar | sudo docker import - busybox-1-export:latest # check the available images sudo docker images # and check if a new container made from this image # contains our folder (it does!) sudo docker run busybox-1-export [ -d /home/test ] && echo 'Directory found' || echo 'Directory not found' |
We can do the same for the saved image:
1 2 3 4 5 6 7 8 9 |
# import the exported tar ball: docker load < /home/save.tar # check the available images sudo docker images # and check if a new container made from this image # contains our folder (it does!) sudo docker run busybox-1 [ -d /home/test ] && echo 'Directory found' || echo 'Directory not found' |
So what’s the difference between both? Well, as we saw the exported version is slightly smaller. That is because it is flattened, which means it lost its history and meta-data. We can see this by the following command:
1 2 |
# shows the layers of all images sudo docker images --tree |
If we run the command we will see an output like the following. As you can see there, the exported-imported image has lost all of its history whereas the saved-loaded image still have its history and layers. This means that you cannot do any rollback to a previous layer if you export-import it while you can still do this if you save-load the whole (complete) image (you can go back to a previous layer by using docker tag <LAYER ID> <IMAGE NAME>
).
1 2 3 4 5 6 7 |
vagrant@ubuntu-13:~$ sudo docker images --tree ├─f502877df6a1 Virtual Size: 2.489 MB Tags: busybox-1-export:latest └─511136ea3c5a Virtual Size: 0 B └─bf747efa0e2f Virtual Size: 0 B └─48e5f45168b9 Virtual Size: 2.489 MB └─769b9341d937 Virtual Size: 2.489 MB └─227516d93162 Virtual Size: 2.489 MB Tags: busybox-1:latest |
Best regards,
Thomas
Thanks for clearing this question, I did see history on exported image is zero, where as on saved image is there
Do I need to stop container defore export it to tar file?
@Дмитрий No, you should also be able to export a running container.
Can I “pause” a computation, and then “resume” it using EXPORT container command? Or is It possible to do, using Docker?
Thanks for posting this Thomas – this isn’t a topic that is well covered in the documentation. I appreciate how you walked through the ‘experiment’ end to end, clearing the original images before loading them and showing the image tree.
Great post.
interesting post ! neatly done.
thanks for nice post
Why use sudo for docker commands? Its not necessary and will probably lead to permissions issues later.
You need sudo for using the “Docker socket” when running on Linux if your user is not in the Docker group. If you are working on OS X you probably are using HTTP over TCP for talking to the daemon.
Thanks for the Explanation Thomas, I have noticed the CREATED time difference.
busybox-1-export latest b3260e0c0c4a About a minute ago 1.113 MB
busybox-1 latest 1e40056b884e 48 minutes ago 1.113 MB
Export-Import creates new Container where as the Save-Load shows time of the original file created.
Hi,
Try the helicopterizer for Backup and Restore for Docker Container in the Cloud Providers.
https://github.com/frekele/helicopterizer
help us with your code, make a PR. 🙂
Thomas,
thank you for your post.
To be honest, after reading it and the referenced StackOverflow discussion, I’m no less confused than before.
Your tests show that both methods produce identical results, where it matters (search the post for “it does!” )
I understand that there will be a difference in size,layers,history, etc, however – what-the-heck-does-it-mean for people whose use case is to move a container with data from one host to another, which I believe was your use case as well, reading your SO post.
I think we should focus on what the person actually wants to achieve, rather than examine the verbiage of the question.
There should be only one “correct” answer as to which command to use for which use case, and I still don’t know it.
Am I the only one?
Now, docker images –tree options is removed
use docker history container_name/container_id
I just found this tool: https://github.com/wagoodman/dive, a great tool for browsing your docker images
Great explanation! Haven’t found a more clear explanation than this one! Thanks.
Thank you Thomas !!
Excellent, it is straight to the point. Thank you very much
Great post! Really helpful
Thank you for this useful and helpful guide for a important features.
Useful post. One minor suggestion would be to also cover import vs load.
Very well explained.
Great!
I just bought you a cup of coffe! 😉
Rgds
Stefan
(Rails Lover 😉
Beautiful, thank you 🙂
I see you don’t monetize tuhrig.de, don’t waste your traffic, you can earn extra bucks
every month with new monetization method. This is the best adsense
alternative for any type of website (they approve all websites), for more details simply search
in gooogle: murgrabia’s tools
Thanks for such great post to understand docker load/save and export/import command.
Great explanation!
I have a related question: what is the difference between these and commit?
Is it just that export and save pack the image to move it somewhere else?