DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

How to export existing docker images & Containers

— ny_wk

How to export existing docker images & Containers
🛒 Recommended gear on Amazon

Disclosure: some links above are affiliate links — if you buy through them I may earn a small commission at no extra cost to you. Thanks for supporting the channel!

You know, in our DevOps world, everything is usually about automation, CI/CD pipelines, and registries. Ideally, when you want to move a Docker image from one place to another, you’d just do a docker push to your Docker Registry (be it Docker Hub, AWS ECR, Google GCR, or your own private one) and then a docker pull on the target machine. Simple, elegant, cloud-native. But what if that's not an option? What if you're working in an air-gapped environment, need to share an image with a colleague over a local network without setting up a full registry, or perhaps you're testing an image locally before pushing it to a remote dev environment?

Sometimes, the simple, old-school way is the most effective. This is where exporting your Docker images and even running containers as plain old .tar files comes into play. It's like packing a lunchbox – you take what you need, pack it up, and carry it over. This guide will walk you through how to export existing Docker images and containers, making them portable across different hosts without a registry. We'll cover docker save for images, docker export for containers, and even touch upon docker machine scp for specific transfer scenarios. Chalo, let's dive in!

Exporting Docker Images: The docker save Command Deep Dive

First up, let's talk about docker save. When you hear "exporting Docker images," this is often the command that comes to mind. It's designed to take one or more Docker images and bundle them into a single tar archive. Think of it as taking a snapshot of your image, including all its layers, metadata, and history, just as it exists in your local Docker image cache.

What docker save Actually Does

Unlike simply copying files, docker save intelligently packs all the necessary components of an image. Remember, Docker images are built in layers. When you run docker save, it ensures that all these dependent layers are included in the .tar file. This means when you load it on another machine, Docker can reconstruct the exact same image, preserving its complete build history and original image ID (though the local ID on the new machine might differ if other images use the same layers). This preservation of layers is crucial if you later want to inspect the image history with docker history or troubleshoot its build process.

When to Use docker save to Transfer Docker Images

  • Offline Transfers: The most common use case. If your target machine has no internet access or direct connectivity to a Docker registry, saving images as a tarball is your go-to.
  • Air-gapped Environments: For highly secure setups where external network access is restricted, this is often the only way to get images in.
  • Temporary Sharing: Quickly sharing a specific image version with a colleague for testing or debugging without pushing to a shared registry. Imagine you've built a custom image with a fix; you can just hand over the tar file.
  • Backing Up Images: Creating local backups of critical images before major system changes or upgrades.
  • Moving to a New Host: Migrating images when setting up a new server or developer workstation from scratch.

Step-by-Step: Saving and Loading an Image

Let's get our hands dirty. For this example, we'll use a commonly available image, say, a specific version of Python on Alpine. If you don't have it already, pull it:

docker pull python:2.7.17-alpine3.9

You'll see output similar to this, indicating the image and its layers are being downloaded:

2.7.17-alpine3.9: Pulling from library/python
e7c96db7181b: Already exists
1819f4b92bc2: Already exists
8061b3761cb3: Pull complete
73aebae115de: Pull complete
Digest: sha256:5f6059d78f530c3c59c4842e104ddcfc772a27fb8fac0d900f4d77bcb4621d9b
Status: Downloaded newer image for python:2.7.17-alpine3.9
docker.io/library/python:2.7.17-alpine3.9

Saving the Image to a Tarball

Now, to save this image, you have two primary ways: using output redirection or the -o (output) flag. Both achieve the same result: creating a .tar file.

Method 1: Using Redirection (>)

docker save python:2.7.17-alpine3.9 > my-python-image.tar

This command saves the image named python:2.7.17-alpine3.9 into a file called my-python-image.tar in your current directory. It's concise and works well.

Method 2: Using the -o Flag

docker save -o my-python-image.tar python:2.7.17-alpine3.9

This is often preferred as it's more explicit and readable, especially when combining with other flags. Both methods produce the identical .tar archive.

A small tip: You can save multiple images into a single tarball by listing them: docker save -o all-my-images.tar image1:tag image2:tag. Docker will intelligently pack all unique layers and metadata into one archive. Very handy for backing up related images!

Verifying the Saved Image File

Once the command completes, you should have a new .tar file. You can check its size using du -h:

du -h my-python-image.tar

You'll likely see something like 75M my-python-image.tar. This confirms the file was created and has content.

Transferring the Tarball to Another Host

Now that you have the .tar file, you can transfer it to your target machine using any standard file transfer utility:

  • scp: Securely copy over SSH. This is one of the most common methods. Example: scp my-python-image.tar user@remote_host:/path/to/destination/
  • rsync: Efficiently copy and synchronize files, especially useful for large files or if you need to resume transfers. Example: rsync -P my-python-image.tar user@remote_host:/path/to/destination/
  • Shared Network Drive: If you're in an office network, a shared drive is often the easiest, provided security policies allow.
  • USB Drive: For truly air-gapped or offline transfers, the good old USB stick still works like a charm!

Loading the Image on the Target Machine

Once the .tar file is on the target machine, navigate to its location and use the docker load command. Similar to saving, you can use input redirection or the -i (input) flag.

Method 1: Using Redirection (<)

docker load < my-python-image.tar

Method 2: Using the -i Flag

docker load -i my-python-image.tar

Docker will then extract the image layers and metadata, importing them into the local Docker image cache. You'll see progress indicators as layers are extracted. The image, with all its history, will be recreated locally.

Verifying the Loaded Image

To confirm the image has been successfully loaded, list your local Docker images:

docker images

or

docker image list

You should see your python:2.7.17-alpine3.9 image listed with its correct tag, image ID, and size. Ab, dekho, the image is now ready to use on the new host!

Potential Pitfalls with docker save:

  • Disk Space: Tarballs can be large, especially for complex images with many layers or large base images. Ensure both source and target machines have enough disk space.
  • Image Name/Tag: Always use the exact image name and tag when saving. Misspellings will result in errors ("No such image").
  • File Corruption: During transfer, especially over unreliable networks, the .tar file might get corrupted. Verify checksums (like MD5 or SHA256) after transfer if you're paranoid or it's a critical image.

Exporting Docker Containers: Understanding docker export

Now, let's switch gears and talk about docker export. This command is fundamentally different from docker save, and this distinction is super important for any DevOps engineer to grasp. While docker save deals with images (the blueprint), docker export deals with containers (a running instance of that blueprint, potentially with changes).

What docker export Actually Does

docker export takes a *running or stopped container* and creates a new filesystem tarball. This tarball represents the *current state of the container's root filesystem*. What does that mean? It means any files you've added, modified, or deleted *inside* that specific container instance since it started will be included. However, and this is a big "however," it *does not* export image layers, history, or any volumes attached to the container. It's a flat filesystem snapshot, similar to a VM disk image, but specifically for the container's mutable layer.

When to Use docker export for Container Backup or Migration

  • Creating a Base Image from a Modified Container: If you've tinkered extensively inside a running container, installed software, or configured it manually, and you want to save that exact state as a *new* image (without its history) to serve as a new base for other containers.
  • Container Forensics/Debugging: Exporting a problematic container's filesystem for later analysis on another machine without keeping the container running. This lets you inspect its exact state at the time of export.
  • "Squashing" Images: Effectively flattens all layers into a single layer, which can sometimes result in a smaller image, but you lose all historical context. This can be useful for reducing image size for deployment if history isn't critical.
  • Migrating a Specific Container State: If you need to move a container's working state to another host as a fresh image, for instance, a temporary testing environment.

Step-by-Step: Exporting and Importing a Container

For this walkthrough, let's grab a simple Alpine image and run a container from it. We'll make a small change inside to demonstrate that the export captures the *container's* state.

docker pull alpine

Now, let's run an instance in detached mode (`-d`) and give it a name (`--name`) so we can easily reference it. We'll also use `-it` for interactive capabilities if we needed to shell into it.

docker run -it --detach --name my-alpine-container alpine

Verify that your container is running:

docker ps

You should see something like:

CONTAINER ID   IMAGE     COMMAND    CREATED          STATUS          PORTS     NAMES
35f34fabfa84   alpine    "/bin/sh"  14 seconds ago   Up 8 seconds    alpine-t

Note down your container ID or name (my-alpine-container in this case).

Making a Change Inside the Container (Optional, but good for demonstration)

Let's pretend we installed some package or created a file inside this container. This change will be captured by `docker export`.

docker exec -it my-alpine-container sh -c "echo 'Hello from inside the container!' > /tmp/hello.txt && apk add --no-cache curl"

This command enters the container, creates a file `/tmp/hello.txt`, and installs `curl`. Now, the container's filesystem state is different from its original Alpine image. The `apk add` ensures `curl` is permanently part of the container's filesystem.

Exporting the Container to a Tarball

Now, we'll export the `my-alpine-container`. Again, you can use output redirection or the `-o` flag.

Method 1: Using Redirection (>)

docker export my-alpine-container > my-exported-container.tar

Method 2: Using the -o Flag

docker export -o my-exported-container.tar my-alpine-container

After running this, you'll have a `my-exported-container.tar` file. Check its size with `du -h` to see its footprint.

Transferring the Tarball

Just like with `docker save`, you can use `scp`, `rsync`, or any other method to move `my-exported-container.tar` to your target machine.

Importing the Container as an Image on the Target Machine

This is where another crucial difference lies. You don't use `docker load` for `docker export` output. Instead, you use docker import.

docker import creates a *new image* from the exported container's filesystem. You can also apply a tag directly during import. This new image will be a single layer containing the exported filesystem.

docker import my-exported-container.tar my-new-alpine-image:latest

You can also use redirection, which is common in scripting pipelines:

cat my-exported-container.tar | docker import - my-new-alpine-image:latest

The hyphen `'-'` tells `docker import` to read from `stdin`.

Verifying the Imported Image and its State

Check if the new image exists:

docker images

You should see `my-new-alpine-image:latest` in your list. Now, let's verify that the changes we made inside the container (like creating `/tmp/hello.txt` and installing `curl`) were preserved in this new image:

docker run --rm my-new-alpine-image:latest cat /tmp/hello.txt

And you should see: `Hello from inside the container!`

Also, check for curl:

docker run --rm my-new-alpine-image:latest which curl

This should output `/usr/bin/curl`, confirming `curl` was installed and the container's state was accurately exported and imported. This shows that the exact filesystem state, including modifications, was captured.

Major Pitfalls with docker export:

  • No Layer History: You lose all original image layers and build history. The imported image is a single, flat layer. This can make debugging, auditing, or understanding its origin harder, as you can't trace back the `dockerfile` commands.
  • No Volumes: This is probably the most common gotcha. If your container was using volumes (either bind mounts or Docker volumes), the *contents of those volumes are NOT included* in the `docker export` tarball. You need to back up and restore volumes separately. For example, using docker cp or backing up the volume's host path.
  • Container Metadata Lost: Things like original entrypoints, commands, environment variables, exposed ports defined in the Dockerfile might not be perfectly preserved or would need to be re-specified when you run a container from the imported image. You can add them during `docker import` with flags like `--change "ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"` but it's not always straightforward.

Seamless Transfers with docker machine scp

While `scp` and `rsync` are universal tools, if you're managing remote Docker hosts using Docker Machine, there's an even more convenient way to transfer files: docker-machine scp. This command simplifies the process by handling SSH credentials and host addressing for you. It's particularly useful when dealing with hosts on cloud providers like AWS EC2, DigitalOcean, or Azure that you provisioned with Docker Machine.

How docker machine scp Works for Docker Transfers

Docker Machine, for those not familiar, allows you to provision and manage Docker hosts (virtual machines) on various platforms. When you create a machine using `docker-machine create`, it sets up SSH access, including keys and configurations. `docker-machine scp` leverages this pre-configured SSH connection to securely copy files between your local machine and the remote Docker Machine, or even between two Docker Machines, without you having to manually manage SSH keys or host IP addresses. It basically wraps the standard `scp` command with Docker Machine's intelligence.

When to Use docker machine scp

  • When you have Docker Machine managed hosts (e.g., development VMs, cloud instances). This is its specific niche.
  • To easily transfer image tarballs (created with docker save) to a remote Docker Machine for loading.
  • To copy configuration files, application code, or any other data to or from a remote Docker Machine.

Step-by-Step: Using docker machine scp

Let's assume you have a remote Docker Machine named `remote-dev-machine`. If not, you'd create one first. For example, using the VirtualBox driver:

docker-machine create --driver virtualbox remote-dev-machine

(Replace `virtualbox` with your desired driver like `aws`, `digitalocean`, etc., and ensure you have the necessary credentials configured.)

Ensure your local Docker environment is pointing to this machine if you want to perform Docker commands directly on it, although for `scp` it's not strictly necessary:

eval $(docker-machine env remote-dev-machine)

And switch back to your local Docker daemon when done:

eval $(docker-machine env -u)

1. Save Your Image Locally

First, save the Docker image on your local machine using docker save, as discussed earlier. For instance, if you have an application image:

docker save -o my-app-image.tar my-application:latest

2. Copy the Image Tarball to the Remote Machine

Now, use docker-machine scp. The syntax is similar to standard `scp` but you specify the machine name directly:

docker-machine scp ./my-app-image.tar remote-dev-machine:/home/ubuntu/

This command copies `my-app-image.tar` from your current local directory to the `/home/ubuntu/` directory on your `remote-dev-machine`. Docker Machine handles all the SSH authentication magic for you, using the keys it generated when creating the machine.

You can also copy from the remote machine to local, or machine to machine:

  • Remote to Local: docker-machine scp remote-dev-machine:/home/ubuntu/some-log.txt ./
  • Machine to Machine: docker-machine scp machine1:/path/to/file machine2:/path/to/destination/ (Requires both machines to be managed by the same Docker Machine instance.)

3. Load the Image on the Remote Machine

Once the file is transferred, you need to execute the `docker load` command on the remote machine. You can do this by SSHing into the machine using `docker-machine ssh` and running the command there:

docker-machine ssh remote-dev-machine sudo docker load -i /home/ubuntu/my-app-image.tar

This command connects to `remote-dev-machine`, executes `sudo docker load -i /home/ubuntu/my-app-image.tar`, and then exits the SSH session. The `sudo` might be necessary depending on how Docker is set up on your remote machine (if the user doesn't have permissions to access the Docker socket directly).

4. Verify on the Remote Machine

Finally, confirm the image is loaded on the remote machine:

docker-machine ssh remote-dev-machine docker images

You should see `my-application:latest` listed there. Simple, right? This method is super convenient if your workflow heavily relies on Docker Machine for managing remote development or testing environments.

Docker Save vs. Docker Export: Choosing the Right Tool

The distinction between docker save and docker export is a common point of confusion for many, but it's crucial for effective Docker management. Let's consolidate their differences clearly, so you never get stuck:

Feature docker save (for Images) docker export (for Containers)
What it targets Docker images – the immutable blueprints of your applications. Docker containers (running or stopped) – live instances with their modified state.
What it includes Image layers, all metadata, history, tags. The full "blueprint" with its complete lineage. The current filesystem contents of the container's rootfs. A flat snapshot of its state.
Output Format A tar archive containing JSON manifest and all individual layer tarballs. A single tar archive representing a flattened filesystem.
Command to import/load docker load – to put the image back into the Docker cache. docker import – to create a new image from the container's filesystem.
Preserves history Yes, all build history and layers are preserved. You can see `docker history`. No, history is lost. The imported image is a single, flat layer. `docker history` will show only one layer.
Includes volumes N/A (images themselves don't contain volume data; volumes are attached to containers). No, attached volumes are explicitly excluded. You must back them up separately.
Typical Use Cases Transferring images between hosts (offline, air-gapped), backing up images, sharing specific image versions for reproducible builds. Creating a new base image from a modified container, forensic analysis of a container's state, "squashing" layers for a smaller final image, migrating a specific container's operational state.
Size Potentially larger due to including all distinct layers and metadata. Often smaller, as it's a flattened filesystem without redundant layers or history.

Dekho, the thumb rule is: If you want to move the *blueprint* (the image, with its full lineage and layered structure), use docker save. If you want to move the *current state of a running instance* (the container's modified filesystem, as a fresh, flat image), use docker export, keeping in mind its limitations regarding history and volumes. Don't mix them up, varna problem ho sakti hai!

Advanced Tips & Best Practices for Docker Transfers

Beyond the basics, there are a few considerations that can make your Docker image and container transfer process smoother, more robust, and secure. Ek senior engineer ki tarah, tumhe yeh sab pata hona chahiye!

1. Handling Docker Volumes and Data Persistence

As we discussed, docker export *does not* include data stored in volumes. This is a critical point. If your container relies on persistent data (e.g., a database, application logs, user uploads), you absolutely *must* handle volume backup and restoration separately. Here are a few ways:

  • docker cp: For bind mounts or named volumes, you can often copy data directly from the volume path within the container to a host directory before exporting. Example: docker cp my-container:/path/to/data /local/backup/path. This creates a host-side copy of the volume content.
  • Data Volume Containers: A common pattern involves dedicated "data containers" that simply hold volumes. You can then use tools like tar or rsync directly on the host to backup these volumes' contents from their host mount points.
  • Cloud-Specific Solutions: If your volumes are backed by cloud providers (e.g., AWS EBS, Azure Disks, Google Persistent Disks), leverage their native snapshotting and migration features, which are often more robust for production data.
  • Database Dumps: For databases, the most robust approach is usually to perform a logical backup (e.g., `pg_dump` for PostgreSQL, `mysqldump` for MySQL) from within the container and restore the data into a fresh database instance on the target host. This ensures data consistency.

Always have a clear strategy for data persistence independent of your image/container transfer method. Data is king, remember that!

2. Verifying Integrity of Tarballs

Especially when transferring large files or over unreliable networks, a tarball can get corrupted during transit. To ensure the integrity of your transferred file, generate a checksum (like MD5 or SHA256) on the source machine and verify it on the target machine. This small step can save you hours of debugging mysterious "image corrupted" or "tar file invalid" errors.

On Source (after saving/exporting):

sha256sum my-python-image.tar > my-python-image.tar.sha256

Then, transfer both `my-python-image.tar` and `my-python-image.tar.sha256` to the destination.

On Target (after transfer):

sha256sum -c my-python-image.tar.sha256

If the file is intact, it will report "OK". If corrupted, it will flag an error, allowing you to re-transfer. Yeh toh pakka karna chahiye!

3. Security Considerations During Transfers

When transferring sensitive images or container data, be mindful of the channel and destination:

  • Use Secure Protocols: Always prefer `scp` or `rsync` over SSH for network transfers. These encrypt the data in transit. Avoid plain FTP or HTTP unless absolutely necessary and the data is non-sensitive or already encrypted end-to-end.
  • Access Control: Ensure the target directory on the remote host has appropriate permissions. Only authorized users should be able to read or modify your tarballs.
  • Image Vulnerabilities: Even if transferring offline, remember that the image itself might contain vulnerabilities. Always scan your images before and after transfer with tools like Trivy or Clair. A transferred image is not automatically a secure image.

4. Automation and Scripting for Efficiency

If you regularly perform these transfers, especially in a development or testing workflow, consider scripting the process. A simple shell script can:

  • Take image name/tag and target host as input.
  • Perform `docker save`.
  • Generate checksum.
  • scp the tarball and checksum to the remote host.
  • SSH into remote host and `docker load`.
  • Verify checksum on remote.
  • Clean up local tarball.

This reduces manual errors, standardizes your workflow, and saves time. Automation hi toh DevOps ka mantra hai!

5. When to Still Use a Registry

While these tarball methods are great for specific, often isolated scenarios, don't ditch Docker registries entirely. For production environments, continuous integration, and large-scale deployments, Docker registries are indispensable and remain the recommended best practice. They offer:

  • Version Control: Centralized management and versioning of image tags.
  • Access Control: Fine-grained permissions for pushing/pulling images by teams and users.
  • Scanning & Security: Many registries integrate vulnerability scanning and policy enforcement.
  • Scalability & Reliability: Designed for high availability and performance, crucial for CI/CD.
  • Ecosystem Integration: Seamlessly integrates with CI/CD pipelines, orchestrators like Kubernetes, and cloud services.

Use offline transfers strategically, but keep your primary workflow registry-centric when possible for robustness and maintainability. (Related reading: Best Practices for Docker Registry Management)

6. Alternative Tools (Brief Mention)

For more advanced image manipulation and transfer scenarios (like copying images directly between different registry types or formats without pulling locally), tools like skopeo exist. skopeo is a powerful command-line utility that can copy container images between various storage mechanisms, including Docker registries, local storage, and even different image formats. It's often used in more complex, heterogeneous container environments.

skopeo copy docker://registry.access.redhat.com/ubi8/ubi:latest docker-archive:ubi8-ubi-latest.tar

This is beyond the scope of basic transfers, but good to know it's there for when your needs evolve. (Related reading: Advanced Docker Image Management with Skopeo)

Key Takeaways

  • docker save exports Docker images (blueprints) with their full layer history and metadata into a .tar file, perfect for offline transfers.
  • docker load is the command used to import images that were created with docker save.
  • docker export exports a Docker container's current filesystem state as a flat .tar file, which is useful for creating new base images or forensic analysis, but it loses layer history and excludes volumes.
  • docker import is the corresponding command to create a new image from a .tar file generated by docker export.
  • docker machine scp provides a convenient way to transfer files (like image tarballs) to and from Docker Machine-managed remote hosts, handling SSH credentials automatically for a smoother workflow.
  • Always handle Docker volumes separately when using docker export, as their contents are not included in the tarball and require independent backup strategies.
  • Verify the integrity of transferred tarballs using checksums (e.g., SHA256) to prevent corruption during network transfer and ensure a successful load/import.
  • While these offline transfer methods are incredibly useful for specific scenarios, Docker registries remain the best practice for production and large-scale, automated environments.

Frequently Asked Questions

What's the main difference between docker save and docker export?

The main difference is what they target and what they preserve: docker save exports an entire Docker image, including all its layers, build history, and metadata, into a tarball. This is like saving the complete blueprint of your application. In contrast, docker export exports the filesystem snapshot of a specific Docker container instance at its current state, flattening all layers into one, losing the image's history, and explicitly excluding any associated volumes. It's like saving the current state of a modified machine, not its original design or all its prior repair logs.

Can I transfer multiple Docker images with docker save in one go?

Yes, absolutely! You can specify multiple image names and tags as arguments to the docker save command, and it will bundle all of them into a single .tar archive. For example: docker save -o my-images.tar image1:tag image2:tag image3:tag. When this combined tarball is loaded with docker load on the target machine, all included images will be imported into the local Docker image cache.

Does docker export include the data from attached volumes?

No, docker export explicitly *does not* include the data stored in Docker volumes (neither named volumes nor bind mounts). It only captures the contents of the container's root filesystem. If your container uses persistent data, you must back up and restore those volumes separately using methods like docker cp, host-level backups of volume mount points, or database-specific dump/restore utilities before relying solely on a docker export for migration.

There you have it, folks! Now you're equipped with the knowledge to handle Docker images and containers like a pro, even when the registry isn't an option. Whether it's for offline work, local sharing, or just understanding the internals better, these commands are invaluable in a DevOps toolkit.

If you found this guide useful, make sure to check out the original video on @explorenystream for a visual walkthrough and more awesome DevOps content. Don't forget to subscribe for more deep dives!