You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2017/11/29 03:35:12 UTC

[5/9] mesos git commit: Added ContainerMountInfo to avoid pre_exec_commands for mounts.

Added ContainerMountInfo to avoid pre_exec_commands for mounts.

Added ContainerMountInfo protobuf in ContainerLaunchInfo. It is used
by isolators and MesosContainerizer to describe mounts. Previously,
the additional mounts for each container is specified using
'pre_exec_commands', which is not very flexible and slow (requires a
fork/exec for each mount).

Review: https://reviews.apache.org/r/63200


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/93ecd696
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/93ecd696
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/93ecd696

Branch: refs/heads/master
Commit: 93ecd69655f06ce2420a499d9f9050cc7592d1c3
Parents: c7304a1
Author: Jie Yu <yu...@gmail.com>
Authored: Mon Sep 4 08:30:07 2017 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Tue Nov 28 18:45:38 2017 -0800

----------------------------------------------------------------------
 include/mesos/slave/containerizer.proto         | 28 ++++++
 .../mesos/isolators/docker/volume/isolator.cpp  | 19 ++---
 .../mesos/isolators/filesystem/linux.cpp        | 90 +++++---------------
 .../mesos/isolators/filesystem/linux.hpp        |  4 -
 .../mesos/isolators/filesystem/shared.cpp       |  9 +-
 .../mesos/isolators/gpu/isolator.cpp            | 15 +++-
 .../mesos/isolators/namespaces/pid.cpp          | 14 +--
 .../mesos/isolators/volume/host_path.cpp        | 17 ++--
 .../mesos/isolators/volume/image.cpp            | 15 ++--
 .../mesos/isolators/volume/sandbox_path.cpp     | 23 +++--
 src/slave/containerizer/mesos/launch.cpp        | 20 +++++
 11 files changed, 133 insertions(+), 121 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/include/mesos/slave/containerizer.proto
----------------------------------------------------------------------
diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto
index 0f1e1da..5b4dcdd 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -167,6 +167,30 @@ message ContainerConfig {
 
 
 /**
+ * Describes a single mount for the container.
+ */
+message ContainerMountInfo {
+  // The path to the mount point. It must be an absolute path in the
+  // agent's root filesystem.
+  required string target = 1;
+
+  // The source of the mount. This can be the path to a device, a file
+  // or a directory. The path must be an absolute path in the agent's
+  // root filesystem.
+  optional string source = 2;
+
+  // The type of the filesystem to be mounted.
+  optional string type = 3;
+
+  // Mount flags.
+  optional uint32 flags = 4;
+
+  // Mount options of the filesystem to be used.
+  optional string options = 5;
+}
+
+
+/**
  * Protobuf returned by Isolator::prepare(). The command is executed
  * by the Launcher in the containerized context.
  * Note: Currently, any URIs or Environment in the CommandInfo will be
@@ -210,6 +234,10 @@ message ContainerLaunchInfo {
   // from the task working directory when task defines an image.
   optional string working_directory = 6;
 
+  // The additional mounts for the container. The mounts specified in
+  // this list will be mounted in order.
+  repeated ContainerMountInfo mounts = 17;
+
   // (Linux only) The capabilities requested for the container.
   // The capabilities are set while launching the container.
   optional CapabilityInfo effective_capabilities = 7;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
index ed65568..3e85afb 100644
--- a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <process/collect.hpp>
 #include <process/id.hpp>
 
@@ -40,6 +42,7 @@ using mesos::internal::slave::docker::volume::DriverClient;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
@@ -493,18 +496,10 @@ Future<Option<ContainerLaunchInfo>> DockerVolumeIsolatorProcess::_prepare(
     LOG(INFO) << "Mounting docker volume mount point '" << source
               << "' to '" << target << "' for container " << containerId;
 
-    // Launch mount command as a non-shell subprocess to avoid
-    // injecting arbitrary shell commands (e.g., user defined
-    // 'container_path' in volume can be postfixed with any
-    // unsafe arbitrary commands).
-    CommandInfo* command = launchInfo.add_pre_exec_commands();
-    command->set_shell(false);
-    command->set_value("mount");
-    command->add_arguments("mount");
-    command->add_arguments("-n");
-    command->add_arguments("--rbind");
-    command->add_arguments(source);
-    command->add_arguments(target);
+    ContainerMountInfo* mount = launchInfo.add_mounts();
+    mount->set_source(source);
+    mount->set_target(target);
+    mount->set_flags(MS_BIND | MS_REC);
   }
 
   return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
index faf9490..d97f427 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <list>
 #include <sstream>
 #include <string>
@@ -58,6 +60,7 @@ using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerState;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::Isolator;
 
 namespace mesos {
@@ -347,66 +350,15 @@ Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare(
   ContainerLaunchInfo launchInfo;
   launchInfo.add_clone_namespaces(CLONE_NEWNS);
 
-  // Prepare the commands that will be run in the container's mount
-  // namespace right after forking the executor process. We use these
-  // commands to mount those volumes specified in the container info
-  // so that they don't pollute the host mount namespace.
-  Try<vector<CommandInfo>> commands =
-    getPreExecCommands(containerId, containerConfig);
-
-  if (commands.isError()) {
-    return Failure("Failed to get pre-exec commands: " + commands.error());
-  }
-
-  foreach (const CommandInfo& command, commands.get()) {
-    launchInfo.add_pre_exec_commands()->CopyFrom(command);
-  }
-
-  // Currently, we only need to update resources for top level containers.
-  if (containerId.has_parent()) {
-    return launchInfo;
-  }
-
-  return update(containerId, containerConfig.executor_info().resources())
-    .then([launchInfo]() -> Future<Option<ContainerLaunchInfo>> {
-      return launchInfo;
-    });
-}
-
-
-Try<vector<CommandInfo>> LinuxFilesystemIsolatorProcess::getPreExecCommands(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig)
-{
-  vector<CommandInfo> commands;
+  // Prepare the mounts that will be run in the container's mount
+  // namespace right after forking the executor process so that they
+  // don't pollute the host mount namespace.
 
   // Make sure mounts in the container mount namespace do not
   // propagate back to the host mount namespace.
-  // NOTE: We cannot simply run `mount --make-rslave /`, for more info
-  // please refer to comments in mount.hpp.
-  CommandInfo command;
-  command.set_shell(false);
-  command.set_value(path::join(flags.launcher_dir, "mesos-containerizer"));
-  command.add_arguments("mesos-containerizer");
-  command.add_arguments(MesosContainerizerMount::NAME);
-
-  MesosContainerizerMount::Flags mountFlags;
-  mountFlags.operation = MesosContainerizerMount::MAKE_RSLAVE;
-  mountFlags.path = "/";
-
-  foreachvalue (const flags::Flag& flag, mountFlags) {
-    const Option<string> value = flag.stringify(mountFlags);
-    if (value.isSome()) {
-      command.add_arguments(
-          "--" + flag.effective_name().value + "=" + value.get());
-    }
-  }
-
-  commands.push_back(command);
-
-  if (!containerConfig.has_container_info()) {
-    return commands;
-  }
+  ContainerMountInfo* mount = launchInfo.add_mounts();
+  mount->set_target("/");
+  mount->set_flags(MS_SLAVE | MS_REC);
 
   // Bind mount the sandbox if the container specifies a rootfs.
   if (containerConfig.has_rootfs()) {
@@ -419,24 +371,26 @@ Try<vector<CommandInfo>> LinuxFilesystemIsolatorProcess::getPreExecCommands(
     // comments in 'provisioner/backend.hpp' for details.
     Try<Nothing> mkdir = os::mkdir(sandbox);
     if (mkdir.isError()) {
-      return Error(
+      return Failure(
           "Failed to create sandbox mount point at '" +
           sandbox + "': " + mkdir.error());
     }
 
-    CommandInfo command;
-    command.set_shell(false);
-    command.set_value("mount");
-    command.add_arguments("mount");
-    command.add_arguments("-n");
-    command.add_arguments("--rbind");
-    command.add_arguments(containerConfig.directory());
-    command.add_arguments(sandbox);
+    mount = launchInfo.add_mounts();
+    mount->set_source(containerConfig.directory());
+    mount->set_target(sandbox);
+    mount->set_flags(MS_BIND | MS_REC);
+  }
 
-    commands.push_back(command);
+  // Currently, we only need to update resources for top level containers.
+  if (containerId.has_parent()) {
+    return launchInfo;
   }
 
-  return commands;
+  return update(containerId, containerConfig.executor_info().resources())
+    .then([launchInfo]() -> Future<Option<ContainerLaunchInfo>> {
+      return launchInfo;
+    });
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp b/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
index c7fbda5..6584d1e 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
@@ -66,10 +66,6 @@ public:
 private:
   LinuxFilesystemIsolatorProcess(const Flags& flags);
 
-  Try<std::vector<CommandInfo>> getPreExecCommands(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig);
-
   const Flags flags;
 
   struct Info

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp b/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
index ccd3da2..118f398 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <set>
 
 #include <process/id.hpp>
@@ -35,6 +37,7 @@ using std::string;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
@@ -209,8 +212,10 @@ Future<Option<ContainerLaunchInfo>> SharedFilesystemIsolatorProcess::prepare(
       }
     }
 
-    launchInfo.add_pre_exec_commands()->set_value(
-        "mount -n --bind " + hostPath + " " + volume.container_path());
+    ContainerMountInfo* mount = launchInfo.add_mounts();
+    mount->set_source(hostPath);
+    mount->set_target(volume.container_path());
+    mount->set_flags(MS_BIND | MS_REC);
   }
 
   return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
index 4d6f640..7b66426 100644
--- a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
@@ -16,6 +16,8 @@
 
 #include <stdint.h>
 
+#include <sys/mount.h>
+
 // This header include must be enclosed in an `extern "C"` block to
 // workaround a bug in glibc <= 2.12 (see MESOS-7378).
 //
@@ -65,6 +67,7 @@ using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
@@ -400,9 +403,15 @@ Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::_prepare(
           " '" + target + "': " + mkdir.error());
     }
 
-    launchInfo.add_pre_exec_commands()->set_value(
-      "mount --no-mtab --rbind --read-only " +
-      volume.HOST_PATH() + " " + target);
+    ContainerMountInfo* mount = launchInfo.add_mounts();
+    mount->set_source(volume.HOST_PATH());
+    mount->set_target(target);
+    mount->set_flags(MS_RDONLY | MS_BIND | MS_REC);
+
+    // NOTE: MS_REMOUNT is needed to make a bind mount read only.
+    mount = launchInfo.add_mounts();
+    mount->set_target(target);
+    mount->set_flags(MS_RDONLY | MS_REMOUNT | MS_BIND | MS_REC);
   }
 
   return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
index 42bc2e1..4f8253b 100644
--- a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
+++ b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <process/id.hpp>
 
 #include <stout/strings.hpp>
@@ -29,6 +31,7 @@ using process::Owned;
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::Isolator;
 
 namespace mesos {
@@ -121,17 +124,18 @@ Future<Option<ContainerLaunchInfo>> NamespacesPidIsolatorProcess::prepare(
   // Mount /proc with standard options for the container's pid
   // namespace to show the container's pids (and other /proc files),
   // not the parent's. This technique was taken from unshare.c in
-  // utils-linux for --mount-proc. We use the -n flag so the mount is
-  // not added to the mtab where it will not be correctly removed when
-  // the namespace terminates.
+  // utils-linux for --mount-proc.
   //
   // NOTE: 'filesystem/linux' isolator will make sure mounts in the
   // child mount namespace will not be propagated back to the host
   // mount namespace.
   //
   // TOOD(jieyu): Consider unmount the existing /proc.
-  launchInfo.add_pre_exec_commands()->set_value(
-      "mount -n -t proc proc /proc -o nosuid,noexec,nodev");
+  ContainerMountInfo* mount = launchInfo.add_mounts();
+  mount->set_source("proc");
+  mount->set_target("/proc");
+  mount->set_type("proc");
+  mount->set_flags(MS_NOSUID | MS_NODEV | MS_NOEXEC);
 
   return launchInfo;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/volume/host_path.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/host_path.cpp b/src/slave/containerizer/mesos/isolators/volume/host_path.cpp
index 949510a..241a7f6 100644
--- a/src/slave/containerizer/mesos/isolators/volume/host_path.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/host_path.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <glog/logging.h>
 
 #include <process/id.hpp>
@@ -41,6 +43,7 @@ using process::Owned;
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::Isolator;
 
 namespace mesos {
@@ -241,16 +244,10 @@ Future<Option<ContainerLaunchInfo>> VolumeHostPathIsolatorProcess::prepare(
     }
 
     // TODO(jieyu): Consider the mode in the volume.
-    CommandInfo command;
-    command.set_shell(false);
-    command.set_value("mount");
-    command.add_arguments("mount");
-    command.add_arguments("-n");
-    command.add_arguments("--rbind");
-    command.add_arguments(hostPath.get());
-    command.add_arguments(mountPoint);
-
-    launchInfo.add_pre_exec_commands()->CopyFrom(command);
+    ContainerMountInfo* mount = launchInfo.add_mounts();
+    mount->set_source(hostPath.get());
+    mount->set_target(mountPoint);
+    mount->set_flags(MS_BIND | MS_REC);
   }
 
   return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/volume/image.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/image.cpp b/src/slave/containerizer/mesos/isolators/volume/image.cpp
index 35966aa..15e242d 100644
--- a/src/slave/containerizer/mesos/isolators/volume/image.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/image.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <list>
 #include <string>
 #include <vector>
@@ -49,6 +51,7 @@ using process::Shared;
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::Isolator;
 
 namespace mesos {
@@ -229,14 +232,10 @@ Future<Option<ContainerLaunchInfo>> VolumeImageIsolatorProcess::_prepare(
           "Provisioned rootfs '" + source + "' does not exist");
     }
 
-    CommandInfo* command = launchInfo.add_pre_exec_commands();
-    command->set_shell(false);
-    command->set_value("mount");
-    command->add_arguments("mount");
-    command->add_arguments("-n");
-    command->add_arguments("--rbind");
-    command->add_arguments(source);
-    command->add_arguments(target);
+    ContainerMountInfo* mount = launchInfo.add_mounts();
+    mount->set_source(source);
+    mount->set_target(target);
+    mount->set_flags(MS_BIND | MS_REC);
   }
 
   return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
index ee5ea3d..d8e41c4 100644
--- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
@@ -14,6 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <sys/mount.h>
+
 #include <glog/logging.h>
 
 #include <process/future.hpp>
@@ -33,6 +35,10 @@
 
 #include "common/validation.hpp"
 
+#ifdef __linux__
+#include "linux/fs.hpp"
+#endif // __linux__
+
 #include "slave/containerizer/mesos/isolators/volume/sandbox_path.hpp"
 
 using std::list;
@@ -46,6 +52,7 @@ using process::Owned;
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
+using mesos::slave::ContainerMountInfo;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
@@ -357,24 +364,22 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare(
     }
 
     if (bindMountSupported) {
+#ifdef __linux__
       LOG(INFO) << "Mounting SANDBOX_PATH volume from "
                 << "'" << source << "' to '" << target << "' "
                 << "for container " << containerId;
 
-      CommandInfo* command = launchInfo.add_pre_exec_commands();
-      command->set_shell(false);
-      command->set_value("mount");
-      command->add_arguments("mount");
-      command->add_arguments("-n");
-      command->add_arguments("--rbind");
-      command->add_arguments(source);
-      command->add_arguments(target);
+      ContainerMountInfo* mount = launchInfo.add_mounts();
+      mount->set_source(source);
+      mount->set_target(target);
+      mount->set_flags(MS_BIND | MS_REC);
+#endif // __linux__
     } else {
       LOG(INFO) << "Linking SANDBOX_PATH volume from "
                 << "'" << source << "' to '" << target << "' "
                 << "for container " << containerId;
 
-      Try<Nothing> symlink = fs::symlink(source, target);
+      Try<Nothing> symlink = ::fs::symlink(source, target);
       if (symlink.isError()) {
         return Failure(
             "Failed to symlink '" + source + "' -> '" + target + "'"

http://git-wip-us.apache.org/repos/asf/mesos/blob/93ecd696/src/slave/containerizer/mesos/launch.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp
index b1584ff..e61c185 100644
--- a/src/slave/containerizer/mesos/launch.cpp
+++ b/src/slave/containerizer/mesos/launch.cpp
@@ -73,6 +73,7 @@ using mesos::internal::capabilities::ProcessCapabilities;
 #endif // __linux__
 
 using mesos::slave::ContainerLaunchInfo;
+using mesos::slave::ContainerMountInfo;
 
 namespace mesos {
 namespace internal {
@@ -421,6 +422,25 @@ int MesosContainerizerLaunch::execute()
   }
 #endif // __WINDOWS__
 
+#ifdef __linux__
+  foreach (const ContainerMountInfo& mount, launchInfo.mounts()) {
+    Try<Nothing> mnt = fs::mount(
+        (mount.has_source() ? Option<string>(mount.source()) : None()),
+        mount.target(),
+        (mount.has_type() ? Option<string>(mount.type()) : None()),
+        (mount.has_flags() ? mount.flags() : 0),
+        (mount.has_options() ? Option<string>(mount.options()) : None()));
+
+    if (mnt.isError()) {
+      cerr << "Failed to prepare mount '" << JSON::protobuf(mount)
+           << "': " << mnt.error() << endl;
+      exitWithStatus(EXIT_FAILURE);
+    }
+
+    cout << "Prepared mount '" << JSON::protobuf(mount) << "'" << endl;
+  }
+#endif // __linux__
+
   // Run additional preparation commands. These are run as the same
   // user and with the environment as the agent.
   foreach (const CommandInfo& command, launchInfo.pre_exec_commands()) {