Save the current state of docker image and export to another server

Viewed 5728

I am new to docker and containers. I followed the below steps to migrate my postgres database running on a docker container:

docker save -o <path for generated tar file> <image name>
scp root@192.10.1.5:/images/gpdb.tar root@192.10.2.5:/images

In the destination server (192.10.2.5):

docker load -i /images/gpdb.tar

But, when I login to the docker image, the database is not there. How do I save the docker image with all database tables and data.

4 Answers

There's no database because the docker save and docker commit commands don't save the container volumes...

Here's a script to do just that:

https://github.com/ricardobranco777/docker-volumes.sh

# Stop the container 
docker stop $CONTAINER
# Create a new image
docker commit $CONTAINER $CONTAINER
# Save and load image to another host
docker save $CONTAINER | ssh $USER@$HOST docker load 

# Save the volumes (use ".tar.gz" if you want compression)
docker-volumes.sh $CONTAINER save $CONTAINER-volumes.tar

# Copy image and volumes to another host
scp $CONTAINER.tar $CONTAINER-volumes.tar $USER@$HOST:

### On the other host:

# Create container with the same options used by the previous container
docker create --name $CONTAINER [<PREVIOUS CONTAINER OPTIONS>] $CONTAINER

# Load the volumes
docker-volumes.sh $CONTAINER load $CONTAINER-volumes.tar

# Start container
docker start $CONTAINER

Trying to move a container like this is not a best practice. It may take some setup to get your container into the right state, though.

The important detail is that all data that could change and needs to be persisted needs to be stored outside the container. While Docker endorses named volumes for this, using a native filesystem path is IME easier to maintain and move around. You need to know where inside the container the data goes (it's usually well-documented) but then you can run commands like

docker run -v /data/mysql:/var/lib/mysql/data ... mysql

Now you can do whatever you want with the container, even docker rm it, but just so long as /data/mysql on your host is intact your data is fine. That also means you can use an ordinary scp to copy the data to some other host and docker run the same container there, which is the more typical migration path.

If you're building and running custom images, there are a couple of things to check:

  • You really should be using some sort of Docker registry, whether that's Docker Hub, something your cloud provider offers, something third-party, or something self-hosted. docker save to move images around is a last resort that's rarely needed.

  • The images themselves should be built from Dockerfiles and, like the rest of your application, be checked into source control. Ideally you have an automated build system (continuous integration) running docker build && docker push for you. Never use docker commit or docker export: they are a recipe for getting different versions of software on different systems and not remembering how you got there.

  • Your application should minimize the amount of data it stores locally. Best case is to store everything in an external database, and then you can just point at the database; if local file storage is really unavoidable try to contain it all in a single directory that's not within your application's source tree.

  • Locally you should be freely able to docker stop; docker rm; docker run the same container and not lose data. Test this before you need to do a cross-host migration.

If you can structure your application so that all of its data is in an external database, consider running the database on a dedicated host with extremely good backup procedures. If you've done everything up to here, you can have a massive coordinated hard disk failure and lose all of your Docker hosts, and not actually have lost anything (because you can docker build the images from source again, and docker run the containers, and the data is off-host).

Your container was based on image when start, but after start, all changes will not affect image.

So all your changes including database if made on the runtime of container need to be commit to form a new docker image before save.

Something like follows, see here

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Then save the new image to tar, and do what you wanted.

commit the current state to the image

docker commit currentcontainer newimage

save image as a tar file

docker save newimage > /tmp/newimage.tar

load the container from the image

docker load < /tmp/newimage.tar
Related