Python: Docker image build -- save to and load from *.tar files.
Tags: docker, image, save, load
Published: 2022-07-27 03:51:34

We can save Docker images to local .tar files, and later load and run those Docker images from local .tar files. I'm documenting my learning experimentations in this post.

I'm aware that we can create a *local registry* and push *Docker images* into this *registry* instead of the public ones. I like local files, I'm exploring this option first.

The code used in this post is the exact code developed for <a href="https://behainguyen.wordpress.com/2022/07/25/python-docker-image-build-the-werkzeug-problem-%f0%9f%a4%96/" title="Python: Docker image build -- “the Werkzeug” problem 🤖!" target="_blank">Python: Docker image build -- “the Werkzeug” problem 🤖!</a> It can be cloned with:

```
git clone -b v1.0.2 https://github.com/behai-nguyen/flask-restx-demo.git
```

<strong>Please note</strong>, in this post, all *Docker images* are built on *Windows 10 Pro*.

<!--------------------------------------------------------------------------------->

<h2>Table of contents</h2>

<ul>
	<li style="margin-top:5px;"><a href="#environments">Environments</a></li>
	
	<li style="margin-top:10px;"><a href="#build-save-windows-images">Build and Save Windows images</a></li>
	
	<li style="margin-top:10px;"><a href="#build-save-linux-arm64-images">Build and Save linux/arm64 images</a></li>
	
	<li style="margin-top:10px;"><a href="#load-run-windows-images">Load and run Windows images</a>
		<ol>
			<li style="margin-top:10px;"><a href="#load-run-windows-image-id">flask_restx_demo-win-by-id.tar</a></li>

			<li style="margin-top:10px;"><a href="#load-run-windows-image-tag">flask_restx_demo-win-by-name.tar</a></li>
		</ol>
	</li>

	<li style="margin-top:10px;"><a href="#load-run-linux-arm64-image">Load and run linux/arm64 image on Synology DS218</a></li>
</ul>

<!--------------------------------------------------------------------------------->
<h3 style="color:teal;">
  <a id="environments">Environments</a>
</h3>

<ol>
<li style="margin-top:5px;">
Synology DS218 -- DSM 7.1-42661 Update 3.
</li>

<li style="margin-top:10px;">
Windows 10 Pro -- version 10.0.19044 build 19044.
</li>

<li style="margin-top:10px;">
Windows “docker” CLI -- version 20.10.12, build e91ed57.
</li>

<li style="margin-top:10px;">
Windows Docker Desktop -- version 4.4.3. The latest version is 4.10.1.
</li>

<li style="margin-top:10px;">
Synology DS218 -- it's accessed via its device name <strong>omphalos-nas-01</strong> instead of its IP address.
</li>
</ol>

<!--------------------------------------------------------------------------------->
<h3 style="color:teal;">
  <a id="build-save-windows-images">Build and Save Windows images</a>
</h3>

Please see also this official document  <a href="https://docs.docker.com/engine/reference/commandline/save/" title="docker save" target="_blank">docker save</a>.

To make it clean, I also removed all related containers and images before testing.

❶ Build as normal:

```
F:\flask_restx_demo\>docker build --tag flask-restx-demo .
```

We can save images by using **standard output redirection >** or by the **--output** option. Images can be identified by their *names*, i.e. the values in the *REPOSITORY* column when listing images, or by their *Ids*.

❷ Save by *image name*:

```
F:\flask_restx_demo\>docker save flask-restx-demo > E:\docker-images\flask_restx_demo-win-by-name.tar
```

❸ Save by *image Id*: 

*Images' Ids* can be obtained via command:

```
docker images
```

Saving the same image using its *Id* and *--output* option:

```
F:\flask_restx_demo\>docker save 1bbe6c6752a2 --output E:\docker-images\flask_restx_demo-win-by-id.tar
```

The *docker save* command does not seem to print out anything:

![031-01-windows-windows-save-to-files-a.png](https://behainguyen.files.wordpress.com/2022/07/031-01-windows-windows-save-to-files-a.png)

The two ( 2 ) output files and their sizes. Please note the slight difference in sizes:

![031-01-windows-windows-save-to-files-b.png](https://behainguyen.files.wordpress.com/2022/07/031-01-windows-windows-save-to-files-b.png)

<!--------------------------------------------------------------------------------->
<h3 style="color:teal;">
  <a id="build-save-linux-arm64-images">Build and Save linux/arm64 images</a>
</h3>

We've previously discussed how to prepare for and to build *multi-arch* images on *Windows 10 Pro*. Please see <a href="https://behainguyen.wordpress.com/2022/07/20/synology-ds218-unsupported-docker-installation-and-usage/#test-installation" title="Synology DS218: unsupported Docker installation and usage... | Test installation" target="_blank">Synology DS218: unsupported Docker installation and usage... | Test installation</a> -- points ❶ and ❸.

Basically, to prepare *multi-arch* build profile **mybuilder**, run:

```
C:\>docker buildx create --name mybuilder --driver-opt network=host --use
```

Then to build, and to push to <a href="https://hub.docker.com/" title="https://hub.docker.com/" target="_blank">https://hub.docker.com/</a> after finishing building:

```
F:\some_project>docker buildx build --platform linux/arm64 --tag username/some-project --push .
```

❶ Try building an image for *linux/arm64* only, that is, do not push the image onto the registry afterward:

```
F:\flask_restx_demo>docker buildx build --platform linux/arm64 --tag flask-restx-demo-arm64 .
```

No image loaded: this should make sense, since this build is for *linux/arm64* not *Windows*.

While research for the problem, I found this post <a href="https://github.com/docker/buildx/issues/166" title="Where did the built multi-platform image go? #166" target="_blank">Where did the built multi-platform image go? #166</a>, answers by user <a href="https://github.com/barcus" title="barcus" target="_blank">barcus</a> provide the solution.

❷ To build and to save locally:

```
F:\flask_restx_demo>docker buildx build --platform linux/arm64 --output "type=docker,push=false,name=flask-restx-demo-arm64,dest=E:\docker-images\flask-restx-demo-arm64.tar" .
```

Image file **E:\docker-images\flask-restx-demo-arm64.tar**, its size is less than half of the previous two ( 2 ):

![031-02-windows-linux-arm64-save-to-files.png](https://behainguyen.files.wordpress.com/2022/07/031-02-windows-linux-arm64-save-to-files.png)

<!--------------------------------------------------------------------------------->
<h3 style="color:teal;">
  <a id="load-run-windows-images">Load and run Windows images</a>
</h3>

Please see also this official document  <a href="https://docs.docker.com/engine/reference/commandline/load/" title="docker load" target="_blank">docker load</a>.

The two image files **flask_restx_demo-win-by-id.tar** and **flask_restx_demo-win-by-name.tar** should be the same. I'm testing them both anyway.

<!--------------------------------------------------------------------------------->
<h4 style="color:teal;">
  <a id="load-run-windows-image-id">flask_restx_demo-win-by-id.tar</a>
</h4>

❶ Start clean. Remove any existing related containers and images.

❷ To load an image file, use:
 
```
F:\>docker load --input E:\docker-images\flask_restx_demo-win-by-id.tar
```

The loaded image has the same *Id* with the original image's: **1bbe6c6752a2** -- please see the screen capture below:

![031-03-load-win-image-by-id-on-windows.png](https://behainguyen.files.wordpress.com/2022/07/031-03-load-win-image-by-id-on-windows.png)

Since the loaded image does not have an *image name* assigned, we have to run it via its *image Id*.

❸ Run the loaded image by its *Id*: **1bbe6c6752a2**

```
F:\>docker run --publish 8000:8000 --rm 1bbe6c6752a2
```

We run it in none detached mode, that is, without option **-d**, so that we can see the output on command line screen:

![031-04-run-win-image-by-id-on-windows.png](https://behainguyen.files.wordpress.com/2022/07/031-04-run-win-image-by-id-on-windows.png)

❹ We can access the *container* via the following URLs:

Swagger UI URL:

```
http://localhost:8000/api/v1/ui
```

API URL:

```
http://localhost:8000/api/v1/trees
```

<!--------------------------------------------------------------------------------->
<h4 style="color:teal;">
  <a id="load-run-windows-image-tag">flask_restx_demo-win-by-name.tar</a>
</h4>

❶ Start clean. Stop and remove previous test container.

❷ Remove any existing related images.

❸ To load:

```
F:\>docker load --input E:\docker-images\flask_restx_demo-win-by-name.tar
```

This time, the loaded image has both **REPOSITORY** and **TAG** properties defined:

![031-05-load-win-image-by-tag-on-windows.png](https://behainguyen.files.wordpress.com/2022/07/031-05-load-win-image-by-tag-on-windows.png)

❹ Run the loaded image with a different port to the previous run **--publish 9010:8000**: 

```
F:\>docker run --publish 9010:8000 --rm flask-restx-demo
```

❺ As before, we can access the *container* via the following URLs, please note the **port**:

```
http://localhost:9010/api/v1/ui
http://localhost:9010/api/v1/trees
```

<!--------------------------------------------------------------------------------->
<h3 style="color:teal;">
  <a id="load-run-linux-arm64-image">Load and run linux/arm64 image on Synology DS218</a>
</h3>

Recall from section <a href="#build-save-linux-arm64-images">Build and Save linux/arm64 images</a>, the image file has been saved to **E:\docker-images\flask-restx-demo-arm64.tar**.

❶ On the *Synology DS218* box, start the *Docker daemon* if not already started:

```
$ sudo dockerd &
```

❷ Start clean. On the *Synology DS218* box, remove all related containers and images.

❸ Copy **E:\docker-images\flask-restx-demo-arm64.tar** to *Synology DS218* box's **$HOME/Test/**.

❹ Load the image file with:

```
behai@omphalos-nas-01:~/Test$ sudo docker load --input flask-restx-demo-arm64.tar
```

The image loads successfully, please see verifications in the screen capture below:

![031-06-load-linux-arm64-on-ds218.png](https://behainguyen.files.wordpress.com/2022/07/031-06-load-linux-arm64-on-ds218.png)

❺ Run the loaded image with:

```
behai@omphalos-nas-01:~/Test$ sudo docker run --network=host -v "/run/docker.sock:/var/run/docker.sock" --rm flask-restx-demo-arm64
```

It runs successfully:

![031-07-run-linux-arm64-on-ds218.png](https://behainguyen.files.wordpress.com/2022/07/031-07-run-linux-arm64-on-ds218.png)

❻ As before, we can access the *container* via the following URLs from *Windows 10 Pro*:

```
http://omphalos-nas-01:8000/api/v1/ui
http://omphalos-nas-01:8000/api/v1/trees
```

**Please note**, the repo now includes a test *HTML* page using *JQuery* **test_client_app\jquery-ajax\TreeAPIClient.html**, just copy it to a web site or a virtual web directory, and run it from there, for **API URL** use **http://omphalos-nas-01:8000/api/v1/trees**.

<p>✿✿✿</p>

I do enjoy learning and blogging about this feature of *Docker*, I find this feature very useful... Thank you for reading, and I hope you find the info in this post useful also.