Persistent storage for containers

Containers are designed to be transient; they run for a while and then disappear. Anything inside the container disappears with it, including files and data created during the container's run. This isn't always what we want, of course. If you're running a database inside a container, for example, you usually want that data to persist when the container goes away.

There are two ways of persisting data in a container: the first is to mount a directory from the host machine inside the container, known as a host-mounted volume, and the second is to use what's called a Docker volume. We'll look at both of these in the following sections.

Host-mounted volumes

If you want a container to be able to access files on the host machine's filesystem (such as application code that you're working on and that you want to test, for example), the easiest way to do that is to mount a directory from the host on the container. The following example shows how to do this (docker_mount.pp):

docker::run { 'mount_test':
  image   => 'library/alpine',
  volumes => ['/tmp/container_data:/mnt/data'],
  command => '/bin/sh -c "echo Hello, world >/mnt/data/hello.txt"',
}

The volumes attribute specifies an array of volumes to attach to the container. If the volume is of the form HOST_PATH:CONTAINER_PATH, Docker will assume you want to mount the directory HOST_PATH on the container. The path inside the container will be CONTAINER_PATH. Any files which already exist in the mounted directory will be accessible to the container, and anything the container writes to the directory will still be available once the container has stopped.

If you apply this example manifest, the container will mount the host machine's /tmp/container_data/ directory (this will be created if it doesn't exist) as /mnt/data/ in the container.

The command attribute tells the container to write the string Hello, world to the file /mnt/data/hello.txt.

Run the following command to apply this manifest:

sudo puppet apply /vagrant/examples/docker_mount.pp

The container will start, write the data, and then exit. If all has gone well, you'll see that the file /tmp/container_data/hello.txt is now present and contains the data written by the container:

cat /tmp/container_data/hello.txt
Hello, world

Host-mounted volumes are very useful when a container needs to access or share data with applications running on the host machine. For example, you could use a host-mounted volume with a container which runs syntax checks, lint, or continuous integration tests on your source code directory.

However, containers using host-mounted volumes are not portable, and they rely on a specific directory being present on the host machine. You can't specify a host-mounted volume in a Dockerfile, so you can't publish a container which relies on one. While host-mounted volumes can be useful for testing and development, a better solution in production is to use Docker volumes.

Docker volumes

A more portable way of adding persistent storage to containers is to use a Docker volume. This is a persistent data object which lives in Docker's storage area, and can be attached to one or more containers.

The following example shows how to use docker::run to start a container with a Docker volume (docker_volume.pp):

docker::run { 'volume_test':
  image   => 'library/alpine',
  volumes => ['pbg-volume:/mnt/volume'],
  command => '/bin/sh -c "echo Hello from inside a Docker volume >/mnt/volume/index.html"',
}

Tip

The volumes attribute is a little different from the previous example. It has the form VOLUME_NAME:CONTAINER_PATH, which tells Docker that this is not a host-mounted volume, but a Docker volume named VOLUME_NAME. If the value before the colon is a path, Docker assumes you want to mount that path from the host machine, but, otherwise, it assumes you want to mount a Docker volume with the specified name.

As in the previous example, the container's command argument writes a message to a file on the mounted volume.

If you apply this manifest, once the container has exited, you can see that the volume is still present by running the following command:

sudo docker volume ls
DRIVER              VOLUME NAME
local               pbg-volume

A Docker volume is a good way to store data that you need to keep even when the container is not running (a database, for example). It's also a good way to make data available to containers without having to load it into each container every time it starts.

In the website example earlier in the chapter, instead of each container checking out its own copy of the Git repo, you could check out the repo into a Docker volume and then have each container mount this volume when it starts.

Let's test that idea with the following manifest (docker_volume2.pp):

docker::run { 'volume_test2':
  image   => 'nginx:alpine',
  volumes => ['pbg-volume:/usr/share/nginx/html'],
  ports   => ['80:80'],
}

This is the same nginx container we used earlier in the chapter, which serves whatever is in its /usr/share/nginx/html directory as a website.

The volumes attribute tells the container to mount the pbg-volume volume on /usr/share/nginx/html.

Run the following commands to apply this manifest:

sudo docker stop pbg-nginx
sudo puppet apply /vagrant/examples/docker_volume2.pp

If everything works as we expect, we should be able to browse to the following URL on the local machine:

http://localhost:8080/

We should also then see the following text:

Hello from inside a Docker volume

This is a very powerful feature of containers. They can read, write, and modify data created by other containers, maintain persistent storage of their own, and share data with other running containers, all by using volumes.

A common pattern for running applications in Docker is to use multiple, communicating containers, each providing a single specific service. For example, a web application might use an Nginx container to serve an application to users, while storing its session data in a MySQL container mounting a persistent volume. It could also use a linked Redis container as an in-memory, key-value store.

Apart from sharing data via volumes, though, how do these containers actually communicate over the network? We'll see the answer to that in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.42.129