Persisting Data with Docker

In this tutorial we will learn how to persist information (files/libraries) in your Docker image.

Maybe you have noticed that if you run a container and create some persistent items, next time you will run the container you will not find the changes to the Docker image. Example:

$ sudo docker run -i -t fedora /bin/bash
[[email protected] /]$ cd home
[[email protected] home]# touch test.txt
[[email protected] home]# ls

Now if you run again the Docker image:

$ sudo docker run -i -t fedora /bin/bash
[[email protected] /]# cd home
[[email protected] home]# ls

No files found. Let’s see some possible options:

Option 1: Attach to the Container image by its id

When you use Docker run to start a container, it actually creates a new container based on the image you have specified. All you need is capturing the CONTAINER_ID. This is visible from the shell:

$ sudo docker run -i -t fedora /bin/bash
[[email protected] /]# cd home
[[email protected] home]# ls

So in our case it’s 2e7c405391c7. (If you don’t have an interactive shell you can use the docker ps command to get it. See later).

Once that you have exited your container, you can re-attach it with a two steps procedure:

$ sudo docker start 2e7c405391c7 # restart it in the background
$ sudo docker attach 2e7c405391c7 # reattach the terminal & stdin

Great! Now you can check that any change you did to the image will be preserved when you re-attach again to it.

Option 2: Commit changes to create a new Image

Let’s say you want to add a new package to your fedora image. We will run it by executing the following command which installs the ping software on it:

$ sudo docker run fedora apt-get install -y ping

As we don’t have an interactive shell, we will pickup the container id with the following command:

[[email protected] ~]# docker ps
CONTAINER ID    	IMAGE           	COMMAND         	CREATED         	STATUS          	PORTS           	NAMES
2e7c405391c7    	fedora          	"/bin/bash"     	2 minutes ago   	Up 2 minutes                        	prickly_goldstine

Now commit changes to the container:

sudo docker commit 2e7c405391c7 myimage/ping

Then run the container to check that the ping package has been included:

sudo docker run myimage/ping ping

Option 3: Create a Dockerfile

A Dockerfile is a script, composed of several commands listed successively to automatically perform actions on a base image in order to create a custom one. They are used for organizing things and help with deployments by simplifying the process start-to-finish.

Dockerfiles begin with defining an image FROM which the build process starts. Followed by various other methods, commands and arguments (or conditions), in return, provide a new image which is to be used for creating docker containers. The RUN command is the central executing directive for Dockerfiles. It takes a command as its argument and runs it to form the image. Unlike CMD, it actually is used to build the image (forming another layer on top of the previous one which is committed).

So, In an empty directory, create a file called “Dockerfile” with the following contents:

FROM fedora
RUN apt-get install ping

Now build your images by tagging it and specifying the location of the Dockerfile:

docker build --tag="mymod/fedora" --file="/var/fedora/Dockerfile"

Now you can test the newly created Container with:

sudo docker run mymod/fedora ping