Skip to Content

Docker container and image - export and save

All you want to know about extracting image or container from docker storage!

Share on:

From time to time we want export filesystem from container and make image from it.
Also sometimes there is need for giving someone our container image in single file without repository usage - on for example pendrive.

How to do this things?

Export and import container filesystem

Export

To export container filesystem we use command docker export.
This command will create output file with whole container filesystem - if we manually uncompress it - we will get directory structure like in / on Linux OS.

[lukas@docker-host ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              a187dde48cd2        2 weeks ago         5.6MB
ubuntu              latest              4e5021d210f6        3 weeks ago         64.2MB

In our example we have ubuntu image from which we will start container, there is no testfolder folder in / directory.
So ubuntu official image not include such folder.

Let’s add it in our container, with some file in it:

[lukas@docker-host ~]# docker run -it ubuntu /bin/bash
root@86b609d88376:/# pwd
/
root@86b609d88376:/# ls testfolder
ls: cannot access 'testfolder': No such file or directory
root@86b609d88376:/# mkdir testfolder
root@86b609d88376:/# touch testfolder/file
root@86b609d88376:/# ls testfolder/
file
root@86b609d88376:/# exit
exit

Now we can check name of container and perform export from it with docker export and -o parameter for output tar file location.

[lukas@docker-host ~]# docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
86b609d88376        ubuntu              "/bin/bash"         56 seconds ago      Exited (0) 8 seconds ago                       sharp_mclaren

[lukas@docker-host ~]# docker export -o ubuntu-export.tar 86b609d88376

[lukas@docker-host ~]# ll
total 65024
-rw-------. 1 lukas lukas 66584064 Apr 10 20:59 ubuntu-export.tar

Now we have our container filesystem exported into file which we can give to someone!

Import

From tar file we can now create(import) new image by docker import command.

It is important to notice that we will create from container export file docker image, not container!
Import command can take as input network directory also.

[lukas@docker-host ~]# docker import ubuntu-export.tar ubuntu-testfolder:1.0
sha256:c794b94e40a299a183af988fe6f6485bc065ac0fd95a0e190b2326c805e408f1

[lukas@docker-host ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu-testfolder   1.0                 c794b94e40a2        5 seconds ago       64.2MB
alpine              latest              a187dde48cd2        2 weeks ago         5.6MB
ubuntu              latest              4e5021d210f6        3 weeks ago         64.2MB

We can see that our imported image named ubuntu-testfolder:1.0 is on his place.

Let’s make container from it:

[lukas@docker-host  ~]# docker run -it ubuntu-testfolder:1.0 /bin/bash
root@8f2842c0158d:/# ls testfolder/
file

We have in our image previously created - folder and file.

Docker export never include files from volumes mounted to container!

If you want to add some instructions from Dockerfile before importing image - check in help --change parameter for docker import command.


Important!

docker import command always import image as single layer image, it ignores before export layer layout!

Compare ubuntu image from which we created container and made export and imported image:

[lukas@docker-host ~]# docker history ubuntu
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
4e5021d210f6        3 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           3 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>           3 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   745B
<missing>           3 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     987kB
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:594fa35cf803361e6…   63.2MB
[lukas@docker-host ~]# docker history ubuntu-testfolder:1.0
IMAGE               CREATED             CREATED BY          SIZE                COMMENT
c794b94e40a2        31 seconds ago                          64.2MB              Imported from -

Save and load docker image

Save and load operates only on images, it has nothing to do with containers.
So we save image to file, give it to someone, he or she can load image into his repository.

Save image

docker save will create file with layers and metadata about them instead of filesystem snapshot like in docker export.

Let’s save some image!

[lukas@docker-host ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              a187dde48cd2        2 weeks ago         5.6MB
ubuntu              latest              4e5021d210f6        3 weeks ago         64.2MB

[lukas@docker-host ~]# docker save -o ubuntu.tar ubuntu

[lukas@docker-host ~]# ll
-rw-------. 1 lukas lukas 66612224 Apr 10 21:44 ubuntu.tar

Additionally we can check what is inside output tar archive. As we mentioned earlier we should see files structure similar to /var/lib/docker/<storage_driver> location where docker stores images locally.

[lukas@docker-host ~]# mkdir ubuntu

[lukas@docker-host ~]# tar xvf ubuntu.tar -C ubuntu
4bea34c6cbddb48774fb9dea97758ae7148d309bb4f2b51ceda03904a8124b8b/
4bea34c6cbddb48774fb9dea97758ae7148d309bb4f2b51ceda03904a8124b8b/VERSION
4bea34c6cbddb48774fb9dea97758ae7148d309bb4f2b51ceda03904a8124b8b/json
4bea34c6cbddb48774fb9dea97758ae7148d309bb4f2b51ceda03904a8124b8b/layer.tar
4e5021d210f65ebe915670c7089120120bc0a303b90208592851708c1b8c04bd.json
a514b8e33bd194200e62e981fa0e9bb3c13c6cd04ff82e91f3e8f11bd4f3500c/
a514b8e33bd194200e62e981fa0e9bb3c13c6cd04ff82e91f3e8f11bd4f3500c/VERSION
a514b8e33bd194200e62e981fa0e9bb3c13c6cd04ff82e91f3e8f11bd4f3500c/json
a514b8e33bd194200e62e981fa0e9bb3c13c6cd04ff82e91f3e8f11bd4f3500c/layer.tar
ca00c330587678e46fabf95ff50e16d9cc64bc0de5fc684694ac5266c39f69e6/
ca00c330587678e46fabf95ff50e16d9cc64bc0de5fc684694ac5266c39f69e6/VERSION
ca00c330587678e46fabf95ff50e16d9cc64bc0de5fc684694ac5266c39f69e6/json
ca00c330587678e46fabf95ff50e16d9cc64bc0de5fc684694ac5266c39f69e6/layer.tar
d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2/
d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2/VERSION
d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2/json
d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2/layer.tar
manifest.json
repositories

In random matedata json file, we will see all metadata about layer:

[lukas@docker-host ~]# vi ubuntu/d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2/json
{"id":"d3bc4608f672143c84e7f1e0db9a00e5067213562f22fcd5b601a920d23859a2","parent":"a514b8e33bd194200e62e981fa0e9bb3c13c6cd04ff82e91f3e8f11bd4f3500c","created":"1970-01-01T01:00:00+01:00","container_config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":null,"Image":"","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"os":"linux"}

Load image

First, we remove ubuntu image from out local repository:

[lukas@docker-host ~]# docker image rm ubuntu
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:bec5a2727be7fff3d308193cfde3491f8fba1a2ba392b7546b43a051853a341d
Deleted: sha256:4e5021d210f65ebe915670c7089120120bc0a303b90208592851708c1b8c04bd
Deleted: sha256:1d9112746e9d86157c23e426ce87cc2d7bced0ba2ec8ddbdfbcc3093e0769472
Deleted: sha256:efcf4a93c18b5d01aa8e10a2e3b7e2b2eef0378336456d8653e2d123d6232c1e
Deleted: sha256:1e1aa31289fdca521c403edd6b37317bf0a349a941c7f19b6d9d311f59347502
Deleted: sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853

[lukas@docker-host ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              a187dde48cd2        2 weeks ago         5.6MB

Next we will perform load with docker load command:

[lukas@docker-host ~]# docker load -i ubuntu.tar
c8be1b8f4d60: Loading layer [==================================================>]  65.58MB/65.58MB
977183d4e999: Loading layer [==================================================>]  991.2kB/991.2kB
6597da2e2e52: Loading layer [==================================================>]  15.87kB/15.87kB
16542a8fc3be: Loading layer [==================================================>]  3.072kB/3.072kB
Loaded image: ubuntu:latest

[lukas@docker-host ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              a187dde48cd2        2 weeks ago         5.6MB
ubuntu              latest              4e5021d210f6        3 weeks ago         64.2MB

Other than import operation, loading adds all metadata and all layers of image as they were before load operation:

[lukas@docker-host ~]# docker history ubuntu
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
4e5021d210f6        3 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           3 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
<missing>           3 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   745B
<missing>           3 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     987kB
<missing>           3 weeks ago         /bin/sh -c #(nop) ADD file:594fa35cf803361e6…   63.2MB