Added doc for the `volume/csi` isolator.

Review: https://reviews.apache.org/r/72845
diff --git a/docs/isolators/csi-volume.md b/docs/isolators/csi-volume.md
new file mode 100644
index 0000000..1b1a635
--- /dev/null
+++ b/docs/isolators/csi-volume.md
@@ -0,0 +1,339 @@
+---
+title: Apache Mesos - CSI Volume Support in Mesos Containerizer
+layout: documentation
+---
+
+# Pre-provisioned CSI Volume Support in Mesos Containerizer
+
+Mesos 1.11.0 adds pre-provisioned CSI volume support to the
+[MesosContainerizer](../mesos-containerizer.md) (a.k.a., the universal
+containerizer) by introducing the new `volume/csi` isolator.
+
+This document describes the motivation and the configuration steps for enabling
+the `volume/csi` 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 CSI Volume Isolator](#configure-csi-volume-isolator)
+  - [Enabling frameworks to use CSI volumes](#enable-frameworks)
+    - [Volume Protobuf](#volume-protobuf)
+    - [Example](#example)
+
+## <a name="motivation"></a>Motivation
+
+[Container Storage Interface](https://github.com/container-storage-interface/spec)
+(CSI) is a specification that defines a common set of APIs for all interactions
+between the storage vendors and the container orchestration platforms. Building
+CSI support allows Mesos to make use of the quickly-growing CSI ecosystem.
+
+We already have a [solution](../csi.md) to support CSI introduced in the Mesos
+1.5.0 release, but that solution has a limitation: it requires CSI plugins to
+implement the [ListVolumes](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#listvolumes)
+and [GetCapacity](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#getcapacity)
+APIs so that the external storage can be modeled as Mesos raw disk resources and
+then offered to frameworks. However there are a lot of 3rd party CSI plugins the
+do not implement those two APIs.
+
+Mesos 1.11.0 provides a more generic way to support 3rd party CSI plugins so
+that Mesos can work with broader external storage ecosystem and we will benefit
+from continued development of the community CSI plugins.
+
+## <a name="how-does-it-work"></a>How does it work?
+
+The `volume/csi` isolator interacts with CSI plugins via the plugin's gRPC
+endpoint.
+
+When a new task with CSI volumes is launched, the `volume/csi` isolator will
+call the CSI plugin to publish the specified CSI volumes onto the agent host
+and then mount them onto the task container. When the task terminates, the
+`volume/csi` isolator will call the CSI plugin to unpublish the specified CSI
+volumes.
+
+Currently the `volume/csi` isolator will only call the CSI plugin's [node service](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#node-service-rpc) but not [controller service](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#controller-service-rpc), that means:
+
+- We only support pre-provisioned CSI volume but not dynamic CSI volumes
+  provisioning, so operators need to create the CSI volumes explicitly and
+  provide the volume info (e.g. volume ID, context, etc.) to frameworks so
+  that frameworks can use the volumes in their tasks.
+
+- We do not support the CSI volumes that require the controller service to
+  publish to a node ([ControllerPublishVolume](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#controllerpublishvolume)) prior to the node service publishing on the node
+  ([NodePublishVolume](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#nodepublishvolume)).
+
+## <a name="configuration"></a>Configuration
+
+To use the `volume/csi` isolator, there are certain actions required by
+operators and framework developers. In this section we list the steps
+required by the operator to configure the `volume/csi` isolator and the steps
+required by framework developers to specify CSI volumes in their tasks.
+
+### <a name="pre-conditions"></a>Pre-conditions
+
+- Explicitly create the CSI volumes that are going to be accessed by Mesos
+  tasks. For some CSI plugins (e.g. [NFS](https://github.com/kubernetes-csi/csi-driver-nfs)),
+  they do not implement the [CreateVolume](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#createvolume)
+  API, so operators do not need to create the volume explicitly in this case.
+
+### <a name="configure-csi-volume-isolator"></a>Configuring the CSI Volume Isolator
+
+In order to configure the `volume/csi` isolator, the operator needs to
+configure the `--isolation` and `--csi_plugin_config_dir` flags at agent
+startup as follows:
+
+```{.console}
+  sudo mesos-agent \
+    --master=<master-IP:master-port> \
+    --work_dir=/var/lib/mesos \
+    --isolation=filesystem/linux,volume/csi \
+    --csi_plugin_config_dir=<directory that contains CSI plugin configuration files>
+```
+
+The `volume/csi` isolator must be specified in the `--isolation` flag at agent
+startup; the `volume/csi` isolator has a dependency on the `filesystem/linux`
+isolator.
+
+The operator needs to put the CSI plugin configuration files under the directory
+specified via the agent flag `--csi_plugin_config_dir`. Each file in this
+directory should contain a JSON object representing a `CSIPluginInfo` object
+which can be either a managed CSI plugin (i.e. the plugin launched by Mesos as
+a standalone container) or an unmanaged CSI plugin (i.e. the plugin launched
+outside of Mesos).
+
+```{.proto}
+message CSIPluginInfo {
+  required string type = 1;
+  optional string name = 2 [default = "default"];
+
+  // A list of container configurations to run managed CSI plugin.
+  repeated CSIPluginContainerInfo containers = 3;
+
+  // The service endpoints of the unmanaged CSI plugin.
+  repeated CSIPluginEndpoint endpoints = 4;
+
+  optional string target_path_root = 5;
+  optional bool target_path_exists = 6;
+}
+
+message CSIPluginContainerInfo {
+  enum Service {
+    UNKNOWN = 0;
+    CONTROLLER_SERVICE = 1;
+    NODE_SERVICE = 2;
+  }
+
+  repeated Service services = 1;
+  optional CommandInfo command = 2;
+  repeated Resource resources = 3;
+  optional ContainerInfo container = 4;
+}
+
+message CSIPluginEndpoint {
+  required CSIPluginContainerInfo.Service csi_service = 1;
+  required string endpoint = 2;
+}
+```
+
+Example of managed CSI plugin:
+```{.json}
+{
+  "type": "org.apache.mesos.csi.managed-plugin",
+  "containers": [
+    {
+      "services": [
+        "NODE_SERVICE"
+      ],
+      "command": {
+        "value": "<path-to-managed-plugin> --endpoint=$CSI_ENDPOINT"
+      },
+      "resources": [
+        {"name": "cpus", "type": "SCALAR", "scalar": {"value": 0.1}},
+        {"name": "mem", "type": "SCALAR", "scalar": {"value": 1024}}
+      ]
+    }
+  ]
+}
+```
+
+Example of unmanaged CSI plugin:
+```{.json}
+{
+  "type": "org.apache.mesos.csi.unmanaged-plugin",
+  "endpoints": [
+    {
+      "csi_service": "NODE_SERVICE",
+      "endpoint": "/var/lib/unmanaged-plugin/csi.sock"
+    }
+  ],
+  "target_path_root": "/mnt/unmanaged-plugin"
+}
+```
+
+### <a name="enable-frameworks"></a>Enabling frameworks to use CSI volumes
+
+#### <a name="volume-protobuf"></a>Volume Protobuf
+
+The `Volume` protobuf message has been updated to support CSI volumes.
+
+```{.proto}
+message Volume {
+  ...
+  required Mode mode = 3;
+  required string container_path = 1;
+
+  message Source {
+    enum Type {
+      UNKNOWN = 0;
+      ...
+      CSI_VOLUME = 5;
+    }
+
+    message CSIVolume {
+      required string plugin_name = 1;
+
+      message VolumeCapability {
+        message BlockVolume {
+        }
+
+        message MountVolume {
+          optional string fs_type = 1;
+          repeated string mount_flags = 2;
+        }
+
+        message AccessMode {
+          enum Mode {
+            UNKNOWN = 0;
+            SINGLE_NODE_WRITER = 1;
+            SINGLE_NODE_READER_ONLY = 2;
+            MULTI_NODE_READER_ONLY = 3;
+            MULTI_NODE_SINGLE_WRITER = 4;
+            MULTI_NODE_MULTI_WRITER = 5;
+          }
+
+          required Mode mode = 1;
+        }
+
+        oneof access_type {
+          BlockVolume block = 1;
+          MountVolume mount = 2;
+        }
+
+        required AccessMode access_mode = 3;
+      }
+
+      // Specifies the parameters used to stage/publish a pre-provisioned volume
+      // on an agent host.
+      message StaticProvisioning {
+        required string volume_id = 1;
+        required VolumeCapability volume_capability = 2;
+        optional bool readonly = 3;
+        map<string, Secret> node_stage_secrets = 4;
+        map<string, Secret> node_publish_secrets = 5;
+        map<string, string> volume_context = 6;
+      }
+
+      optional StaticProvisioning static_provisioning = 2;
+    }
+
+    optional Type type = 1;
+    ...
+    optional CSIVolume csi_volume = 6;
+  }
+
+  optional Source source = 5;
+}
+```
+
+When requesting a CSI volume for a container, the framework developer needs to
+set `Volume` for the container, which includes `mode`, `container_path` and
+`source` fields.
+
+The `source` field specifies where the volume comes from. Framework developers
+need to set the `type` field to `CSI_VOLUME` and specify the `csi_volume` field.
+
+The `csi_volume` field specifies the information of the CSI volume. Framework
+developers need to set the `plugin_name` field to the `type` field of one of the
+CSI plugin configuration files in the directory specified via the agent flag
+`--csi_plugin_config_dir`, and specify the `static_provisioning` field according
+to the information of the pre-provisioned volume. The fields in `static_provisioning`
+map directly onto the fields in the CSI calls [NodeStageVolume](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#nodestagevolume)
+and [NodePublishVolume](https://github.com/container-storage-interface/spec/blob/v1.3.0/spec.md#nodepublishvolume),
+please find more detailed descriptions about those fields in the CSI spec.
+
+How to specify `container_path`:
+
+1. If you are launching a task without a container image and `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 task without a container image and with a
+   relative `container_path`, or launching a task with a container image and an
+   absolute or relative `container_path`, the `volume/csi` 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>Task with rootfs</th>
+    <th>Task 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="example"></a>Example
+
+Launch a task with a CSI volume managed by NFS CSI plugin:
+
+   ```{.json}
+   TaskInfo {
+     ...
+     "command" : {
+       "value": "echo test > volume/file"
+     },
+     "container" : {
+       "type": "MESOS",
+       "volumes" : [
+         {
+           "container_path" : "volume",
+           "mode" : "RW",
+           "source": {
+             "type": "CSI_VOLUME",
+             "csi_volume": {
+               "plugin_name": "nfs.csi.k8s.io",
+               "static_provisioning": {
+                 "volume_id": "foo",
+                 "volume_capability": {
+                   "mount": {},
+                   "access_mode": {
+                     "mode": "MULTI_NODE_MULTI_WRITER"
+                   }
+                 },
+                 "volume_context": {
+                   "server": "192.168.1.100",
+                   "share": "/mnt/data"
+                 }
+               }
+             }
+           }
+         }
+       ]
+     }
+   }
+   ```
+
+**NOTE**: To make the above example work, an NFS server (`192.168.1.100`) needs to
+be setup to export the directory `/mnt/data`.
diff --git a/docs/mesos-containerizer.md b/docs/mesos-containerizer.md
index 3231cb9..c632550 100644
--- a/docs/mesos-containerizer.md
+++ b/docs/mesos-containerizer.md
@@ -59,6 +59,7 @@
 - posix/cpu
 - posix/mem
 - [posix/rlimits](isolators/posix-rlimits.md)
+- [volume/csi](isolators/csi-volume.md)
 - [volume/host_path](container-volume.md#host_path-volume-source)
 - volume/image
 - [volume/sandbox_path](container-volume.md#sandbox_path-volume-source)