blob: 2dbd0441a924c9360c1d6432bcc36febe925268b [file] [log] [blame] [view]
---
title: Apache Mesos - Docker Volume Support in Mesos Containerizer
layout: documentation
---
# Docker Volume Support in Mesos Containerizer
Mesos 1.0 adds Docker volume support to the
[MesosContainerizer](mesos-containerizer.md) (a.k.a., the unified containerizer)
by introducing the new `docker/volume` isolator.
This document describes the motivation, overall architecture, configuration
steps for enabling Docker volume isolator, and required framework changes.
## Table of Contents
- [Motivation](#motivation)
- [How does it work?](#how-does-it-work)
- [Configuration](#configuration)
- [Pre-conditions](#pre-conditions)
- [Configuring Docker Volume Isolator](#configure-Docker-volume-isolator)
- [Enabling frameworks to use Docker volumes](#enable-frameworks)
- [Volume Protobuf](#volume-protobuf)
- [Examples](#examples)
- [Limitations](#limitations)
- [Test it out!](#test-it-out)
## <a name="motivation"></a>Motivation
The integration of external storage in Mesos is an attractive feature. The
Mesos [persistent volume](persistent-volume.md) primitives allow stateful
services to persist data on an agent's local storage. However, the amount of
storage capacity that can be directly attached to a single agent is
limited---certain applications (e.g., databases) would like to access more data
than can easily be attached to a single node. Using external storage can
also simplify data migration between agents/containers, and can make backups and
disaster recovery easier.
The [Docker Volume Driver
API](https://github.com/Docker/Docker/blob/master/docs/extend/plugins_volume.md)
defines an interface between the container runtime and external storage systems.
It has been widely adopted. There are Docker volume plugins for a variety of
storage drivers, such as [Convoy](https://github.com/rancher/convoy),
[Flocker](https://docs.clusterhq.com/en/latest/Docker-integration/),
[GlusterFS](https://github.com/calavera/Docker-volume-glusterfs), and
[REX-Ray](https://github.com/emccode/rexray). Each plugin typically supports a
variety of external storage systems, such as Amazon EBS, OpenStack Cinder, etc.
Therefore, introducing support for external storage in Mesos through the
`docker/volume` isolator provides Mesos with tremendous flexibility to
orchestrate containers on a wide variety of external storage technologies.
## <a name="how-does-it-work"></a>How does it work?
![Docker Volume Isolator Architecture](images/docker-volume-isolator.png)
The `docker/volume` isolator interacts with Docker volume plugins using
[dvdcli](https://github.com/emccode/dvdcli), an open-source command line tool
from EMC.
When a new task with Docker volumes is launched, the `docker/volume` isolator
will invoke [dvdcli](https://github.com/emccode/dvdcli) to mount the
corresponding Docker volume onto the host and then onto the container.
When the task finishes or is killed, the `docker/volume` isolator will invoke
[dvdcli](https://github.com/emccode/dvdcli) to unmount the corresponding Docker
volume.
The detailed workflow for the `docker/volume` isolator is as follows:
1. A framework specifies external volumes in `ContainerInfo` when launching a
task.
2. The master sends the launch task message to the agent.
3. The agent receives the message and asks all isolators (including the
`docker/volume` isolator) to prepare for the container with the
`ContainerInfo`.
4. The isolator invokes [dvdcli](https://github.com/emccode/dvdcli) to mount the
corresponding external volume to a mount point on the host.
5. The agent launches the container and bind-mounts the volume into the
container.
6. The bind-mounted volume inside the container will be unmounted from the
container automatically when the container finishes, as the container is in
its own mount namespace.
7. The agent invokes isolator cleanup which invokes
[dvdcli](https://github.com/emccode/dvdcli) to unmount all mount points for
the container.
## <a name="configuration"></a>Configuration
To use the `docker/volume` isolator, there are certain actions required by
operators and framework developers. In this section we list the steps required
by the operator to configure `docker/volume` isolator and the steps required by
framework developers to specify the Docker volumes.
### <a name="pre-conditions"></a>Pre-conditions
- Install `dvdcli` version
[0.1.0](https://github.com/emccode/dvdcli/releases/tag/v0.1.0) on each agent.
- Install the [Docker volume
plugin](https://github.com/Docker/Docker/blob/master/docs/extend/plugins.md#volume-plugins)
on each agent.
- Explicitly create the Docker volumes that are going to be accessed by Mesos
tasks. If this is not done, volumes will be implicitly created by
[dvdcli](https://github.com/emccode/dvdcli) but the volumes may not fit into
framework resource requirement well.
### <a name="configure-Docker-volume-isolator"></a>Configuring Docker Volume Isolator
In order to configure the `docker/volume` isolator, the operator needs to
configure two flags at agent startup as follows:
```{.console}
sudo mesos-agent \
--master=<master IP> \
--ip=<agent IP> \
--work_dir=/var/lib/mesos \
--isolation=filesystem/linux,docker/volume \
--docker_volume_checkpoint_dir=<mount info checkpoint path>
```
The `docker/volume` isolator must be specified in the `--isolation` flag at
agent startup; the `docker/volume` isolator has a dependency on the
`filesystem/linux` isolator.
The `--docker_volume_checkpoint_dir` is an optional flag with a default value of
`/var/run/mesos/isolators/docker/volume`. The `docker/volume` isolator will
checkpoint all Docker volume mount point information under
`--docker_volume_checkpoint_dir` for recovery. The checkpoint information under
the default `--docker_volume_checkpoint_dir` will be cleaned up after agent
restart. Therefore, it is recommended to set `--docker_volume_checkpoint_dir` to
a directory which will survive agent restart.
### <a name="enable-frameworks"></a>Enabling frameworks to use Docker volumes
#### <a name="volume-protobuf"></a>Volume Protobuf
The `Volume` protobuf message has been updated to support Docker volumes.
```{.proto}
message Volume {
...
required string container_path = 1;
message Source {
enum Type {
UNKNOWN = 0;
DOCKER_VOLUME = 1;
}
message DockerVolume {
optional string driver = 1;
required string name = 2;
optional Parameters driver_options = 3;
}
optional Type type = 1;
optional DockerVolume docker_volume = 2;
}
optional Source source = 5;
}
```
When requesting a Docker volume for a container, the framework developer needs to
set `Volume` for the container, which includes `mode`, `container_path` and
`source`.
The `source` field specifies where the volume comes from. Framework developers need to
specify the `type`, Docker volume `driver`, `name` and `options`. At present,
only the `DOCKER_VOLUME` type is supported; we plan to add support for more
types of volumes in the future.
How to specify `container_path`:
1. If you are launching a Mesos container `without rootfs`. If `container_path`
is an absolute path, you need to make sure the absolute path exists on your
host root file system as the container shares the host root file system;
otherwise, the task will fail.
2. For other cases like launching a Mesos container `without rootfs` and
`container_path` is a relative path, or launching a task `with rootfs` and
`container_path` is an absolute path, or launching a task `with rootfs` and
`container_path` as a relative path, the isolator will help create the
`container_path` as the mount point.
The following table summarizes the above rules for `container_path`:
<table class="table table-striped">
<tr>
<th></th>
<th>Container with rootfs</th>
<th>Container without rootfs</th>
</tr>
<tr>
<td>Absolute container_path</td>
<td>No need to exist</td>
<td>Must exist</td>
</tr>
<tr>
<td>Relative container_path</td>
<td>No need to exist</td>
<td>No need to exist</td>
</tr>
</table>
#### <a name="examples"></a>Examples
1. Launch a task with one Docker volume using the default command executor.
```{.json}
TaskInfo {
...
"command" : ...,
"container" : {
"volumes" : [
{
"container_path" : "/mnt/volume",
"mode" : "RW",
"source" : {
"type" : "DOCKER_VOLUME",
"docker_volume" : {
"driver" : "rexray",
"name" : "myvolume"
}
}
}
]
}
}
```
2. Launch a task with two Docker volumes using the default command executor.
```{.json}
TaskInfo {
...
"command" : ...,
"container" : {
"volumes" : [
{
"container_path" : "volume1",
"mode" : "RW",
"source" : {
"type" : "DOCKER_VOLUME",
"docker_volume" : {
"driver" : "rexray",
"name" : "volume1"
}
}
},
{
"container_path" : "volume2",
"mode" : "RW",
"source" : {
"type" : "DOCKER_VOLUME",
"docker_volume" : {
"driver" : "rexray",
"name" : "volume2",
"driver_options" : {
"parameter" : [{
"key" : <key>,
"value" : <value>
}, {
"key" : <key>,
"value" : <value>
}]
}
}
}
}
]
}
}
```
**NOTE**: The task launch will be failed if one container uses multiple Docker
volumes with the same `driver` and `name`.
## <a name="limitations"></a>Limitations
Using the same Docker volume in both the
[DockerContainerizer](docker-containerizer.md) and the MesosContainerizer
simultaneously is **strongly discouraged**, because the MesosContainerizer has its
own reference counting to decide when to unmount a Docker volume. Otherwise, it
would be problematic if a Docker volume is unmounted by MesosContainerizer but
the DockerContainerizer is still using it.
## <a name="test-it-out"></a>Test it out!
This section presents examples for launching containers with Docker volumes.
The following example is using [convoy](https://github.com/rancher/convoy/)
as the Docker volume driver.
Start the Mesos master.
```{.console}
$ sudo mesos-master --work_dir=/tmp/mesos/master
```
Start the Mesos agent.
```{.console}
$ sudo mesos-agent \
--master=<MASTER_IP>:5050 \
--isolation=docker/volume,docker/runtime,filesystem/linux \
--work_dir=/tmp/mesos/agent \
--image_providers=docker \
--executor_environment_variables="{}"
```
Create a volume named as `myvolume` with
[convoy](https://github.com/rancher/convoy/).
```{.console}
$ convoy create myvolume
```
Prepare a volume json file named as `myvolume.json` with following content.
```
[{
"container_path":"\/tmp\/myvolume",
"mode":"RW",
"source":
{
"docker_volume":
{
"driver":"convoy",
"name":"myvolume"
},
"type":"DOCKER_VOLUME"
}
}]
```
Now, use Mesos CLI (i.e., mesos-execute) to launch a Docker container with
`--volumes=<path>/myvolume.json` option.
```{.console}
$ sudo mesos-execute \
--master=<MASTER_IP>:5050 \
--name=test \
--docker_image=ubuntu:14.04 \
--command="touch /tmp/myvolume/myfile" \
--volumes=<path>/myvolume.json
```
Create another task to verify the file `myfile` was created successfully.
```{.console}
$ sudo mesos-execute \
--master=<MASTER_IP>:5050 \
--name=test \
--docker_image=ubuntu:14.04 \
--command="ls /tmp/myvolume" \
--volumes=<path>/myvolume.json
```
Check the [sandbox
](https://github.com/apache/mesos/blob/master/docs/sandbox.md#where-is-the-sandbox)
for the second task to check the file `myfile` was created successfully.
```{.console}
$ cat stdout
Received SUBSCRIBED event
Subscribed executor on mesos002
Received LAUNCH event
Starting task test
Forked command at 27288
sh -c 'ls /tmp/myvolume/'
lost+found
myfile
Command exited with status 0 (pid: 27288)
```