Docker Level 3, Task 4: Moving Images Between Hosts Without a Registry¶
Today's task was about a very practical, real-world scenario: transferring a Docker image from one server to another without using a central Docker Registry. This is a crucial skill for working in environments with network restrictions (like air-gapped systems) or for simple, one-off transfers where setting up a registry would be overkill.
The process taught me the save, copy, load workflow. More importantly, it turned into a great lesson on Linux file permissions, as I ran into a classic "Permission denied" error that I had to diagnose and solve. This document is my detailed, first-person account of that entire successful journey.
Table of Contents¶
- The Task
- My Step-by-Step Solution
- My Troubleshooting Journey: The
scpPermission Problem - Why Did I Do This? (The "What & Why")
- Deep Dive: Manual Image Transfer vs. Using a Registry
- Common Pitfalls
- Exploring the Commands Used
The Task¶
My objective was to move a custom Docker image named demo:nautilus from App Server 1 to App Server 3. The steps were:
1. On App Server 1, save the demo:nautilus image into a .tar archive file.
2. Securely transfer this archive file to App Server 3.
3. On App Server 3, load the image from the archive, ensuring it retained its original name and tag.
My Step-by-Step Solution¶
The solution involved a three-phase process across two servers, including a critical troubleshooting step.
Phase 1: Saving the Image (on App Server 1)¶
First, I needed to package the image into a single, transferable file.
1. I connected to App Server 1: ssh tony@stapp01.
2. I confirmed the demo:nautilus image existed using sudo docker images.
3. I used the docker save command to create the archive in the /tmp directory. Because Docker operations require elevated privileges, I used sudo.
sudo docker save -o /tmp/demo_nautilus.tar demo:nautilus
Phase 2: Transferring the Image (from App Server 1)¶
This is where I hit a roadblock and had to apply a fix.
1. The Failure: I initially tried to copy the file to App Server 3 using scp:
scp /tmp/demo_nautilus.tar banner@stapp03:/home/banner/
Permission denied. I quickly realized that because I created the file with sudo, it was owned by root, and my regular tony user had no permission to read it.
- The Solution: I fixed this by changing the ownership of the archive file to my current user.
sudo chown tony:tony /tmp/demo_nautilus.tar - With the permissions fixed, I re-ran the
scpcommand, and it worked perfectly.
Phase 3: Loading the Image (on App Server 3)¶
The final step was to unpack the archive on the destination server.
1. I connected to App Server 3: ssh banner@stapp03.
2. I used the docker load command to import the image from the .tar file that was now in my home directory.
sudo docker load -i /home/banner/demo_nautilus.tar
Phase 4: Verification¶
The final and most important step was to confirm that the image was successfully loaded on App Server 3.
sudo docker images
demo:nautilus image in the list, with the exact same Image ID as it had on the source server. This was the definitive proof of success.
My Troubleshooting Journey: The scp Permission Problem¶
This task was a perfect lesson in how Docker operations and standard Linux permissions interact.
* The Conflict:
1. docker save needs sudo, so the output file (demo_nautilus.tar) was owned by the root user.
2. scp was run as the regular user tony.
3. The tony user tried to read the root-owned file, and the operating system correctly denied permission.
* The Lesson: This highlighted a fundamental Linux security principle. Just because a file is in a shared directory like /tmp doesn't mean everyone can read it. Ownership and permissions are always enforced.
* The Fix (chown): The chown (change owner) command was the key. By running sudo chown tony:tony ..., I, as an administrator, changed the owner of the file from root to tony. After that, the tony user had full rights to the file, and the scp command could read it without any issues.
Why Did I Do This? (The "What & Why")¶
- docker save: This command is the key to the offline transfer workflow. It serializes a Docker image, including all of its layers, tags, and metadata, into a single .tar archive. It's like creating a self-contained backup of the image.
- docker load: This is the inverse command to docker save. It reads a .tar archive created by docker save, unpacks all the layers and metadata, and loads them into the local Docker image cache. Crucially, it restores the image with its original name and tag.
- Offline Image Transfer: This entire process is the standard method for moving Docker images in environments without access to a Docker Registry. This is common in secure or "air-gapped" networks where servers have no internet connectivity.
Deep Dive: Manual Image Transfer vs. Using a Registry¶
This task showed me the manual way to move images. It's important to understand how this compares to the standard registry-based workflow (docker push / docker pull).
| Feature | Manual (save/load) |
Registry (push/pull) |
|---|---|---|
| Use Case | Offline environments, air-gapped networks, quick one-off transfers. | The standard for all development and production workflows. |
| Efficiency | Inefficient. Transfers the entire image as a single, large file every time. | Highly Efficient. The registry is layer-aware. It only transfers the specific layers that the destination machine doesn't already have. This is much faster and saves bandwidth. |
| Scalability | Poor. Manually copying a file to 100 servers is not feasible. | Excellent. 100 servers can all pull from a central registry in parallel. |
| Security | As secure as your file transfer method (scp is very secure). |
Very secure. Registries have robust authentication and authorization controls. |
| Best For | Emergency transfers or environments with no network access. | Almost every other situation. |
Common Pitfalls¶
- Permissions on the Archive: As I discovered, the file created by sudo docker save will be owned by root, leading to Permission denied errors with scp if not corrected with chown.
- Forgetting Flags: Forgetting the -o (output) flag on docker save will cause it to write to standard output (your terminal), which is not what you want. Similarly, forgetting the -i (input) flag on docker load will cause it to wait for input from the terminal.
- docker export vs. docker save: There is another command, docker export, which also creates a .tar file. However, export creates an archive of a container's filesystem, not the image's layers. You cannot use docker load on an exported file. You must use docker save.
Exploring the Commands Used¶
- sudo docker save -o [output_file] [image:tag]: Saves a Docker image to a .tar archive. The -o flag is for the output file path.
- sudo chown [user]:[group] [file]: The standard Linux command to change the owner of a file. I used it to fix my permissions issue.
- scp [source_file] [user]@[host]:[destination_path]: Securely copies a file to a remote host over SSH.
- sudo docker load -i [input_file]: Loads a Docker image from a .tar archive. The -i flag is for the input file path.
- sudo docker images: Lists all the Docker images stored on the local server, which I used to verify the presence of the image on both the source and destination servers.