As part of the Nimble Linux Toolkit 2.0 we're introducing a plug-in for Docker. Please be aware that the software is still in beta and what the examples outlined below are subject to change without notice. Docker is a widely popular container system used to build, ship and run applications anywhere. We announced the Nimble Docker Volume plug-in on our corporate blog, my personal blog talks about the container paradigm shift and the impact of containers. This post will go into even greater technical detail of our implementation.

 

We plan to support Docker Datacenter, which include Docker CS (commercially supported) Engine which is suitable for production use. We're also ensuring support for the latest 'main' release train as we appreciate that the tinkerers out there want to take advantage of all the new features. Examples below uses Docker 1.12.1, differences between that version and the Docker CS Engine are discussed in the Availability Options section.

 

Nimble Linux Toolkit 2.0

The NLT 2.0 is delivered as a multi-platform binary installer. We're currently targeting to have it readily available for the most popular Linux distributions at launch through InfoSight. NLT requires that the Nimble arrays are running at least NimbleOS 3.3 or above. Once NLT is installed, all you have to do is add your Nimble Storage array to your host and start the "Docker-Driver". NLT depends on a number of system utilities such as open-iscsi, multipathd and the sg3 utilities. The install process will be outlined in the documentation at release.

 

Add your Nimble Storage array:

# nltadm --group --add --ip-address 192.168.10.64 --username admin --password admin

Done


Start the "Docker-Driver":

# nltadm --start Docker-Driver

Done

# nltadm --status

Service Name         Service Status

--------------------+--------------

Connection-Manager          RUNNING

Docker-Driver               RUNNING

 

For Docker to "pickup" the new volume plug-in. Docker needs to be restarted.

# systemctl restart docker

 

The state of NLT is saved across reboots, once everything is installed and running, so there's no need to start anything manually after a reboot. Also, an important tidbit is that there's no configuration necessary on the array except making sure IP connectivity is established between the Docker host and array, both for the management interface and data interfaces. That said, only iSCSI will be supported in the initial release.

 

Create your first Docker Volume on Nimble Storage

Our plug-in is overloaded with features. We've worked diligently to ensure the Docker admin will get the full Nimble experience while provisioning Docker Volumes. All volume option flags are available to glance over from the CLI. Let's have a look:

 

$ docker volume create --driver nimble -o help

Nimble Storage Docker Volume Driver: Create Help

Create or Clone a Nimble Storage backed Docker Volume or Import an existing Nimble Volume or Clone of a Snapshot into Docker.

 

Create options:

  -o sizeInGiB=X          X is the size of volume specified in GiB

  -o size=X               X is the size of volume specified in GiB (short form of sizeInGiB)

  -o fsOwner=X            X is the user id and group id that should own the root directory of the filesystem, in the form of [userId:groupId]

  -o fsMode=X             X is 1 to 4 octal digits that represent the file mode to be applied to the root directory of the filesystem

  -o description=X        X is the text to be added to volume description (optional)

  -o perfPolicy=X         X is the name of the performance policy (optional)

  -o pool=X               X is the name of pool in which to place the volume (optional)

  -o folder=X             X is the name of folder in which to place the volume (optional)

  -o encryption           indicates that the volume should be encrypted (optional, dedupe and encryption are mutually exclusive)

  -o thick                indicates that the volume should be thick provisioned (optional, dedupe and thick are mutually exclusive)

  -o dedupe               indicates that the volume should be deduplicated (optional, requires perfPolicy option to be set)

 

Clone options:

  -o cloneOf=X            X is the name of Docker Volume to create a clone of

 

Import Volume options:

  -o importVol=X          X is the name of the Nimble Volume to import

  -o pool=X               X is the name of the pool in which the volume to be imported resides (optional)

  -o folder=X             X is the name of the folder in which the volume to be imported resides (optional)

  -o forceImport          forces the import of the volume.  Note that overwrites application metadata (optional)

 

Import Clone of Snapshot options:

  -o importCloneOfSnap=X  X is the name of the Nimble Volume and Nimble Snapshot to clone and import, in for form of [volName:snapName]

  -o pool=X               X is the name of the pool in which the volume to be imported resides (optional)

  -o folder=X             X is the name of the folder in which the volume to be imported resides (optional)

 

Performance Policies: Exchange 2003 data store, SQL Server Logs, Windows File Server, Other Workloads, Exchange 2007 data store,

                      Exchange 2010 data store, Exchange log, SQL Server, SQL Server 2012, SharePoint, Oracle OLTP, DockerDefault

 

In an effort not to overwhelm users with all these flags, we've picked a sensible set of defaults for all options underneath the "Create options" column. The stock defaults may be overridden in the plug-in configuration file: /opt/NimbleStorage/etc/docker-driver.conf (requires NLT restart) if desired. That said, creating a new volume is as simple as:

 

$ docker volume create --driver nimble --name demo-vol1

demo-vol1

$ docker volume ls

DRIVER            VOLUME NAME

nimble            demo-vol1


The volume is now ready for use by a container. But before that, let's inspect our new volume:

$ docker volume inspect demo-vol1

[

    {

        "Name": "demo-vol1",

        "Driver": "nimble",

        "Mountpoint": "",

        "Status": {

            "ApplicationCategory": "Virtual Server",

            "Blocksize": 4096,

            "CachePinned": false,

            "CachingEnabled": true,

            "Connections": 0,

            "DedupeEnabled": false,

            "Description": "Docker knows this volume as demo-vol1.",

            "EncryptionCipher": "none",

            "Group": "nimgrp-dev2",

            "ID": "0633cfd76905aa2a500000000000000000000000a4",

            "LimitVolPercentOfSize": 100,

            "PerfPolicy": "DockerDefault",

            "Pool": "default",

            "Serial": "9e1b8cac258070856c9ce90039fd6536",

            "SnapUsageMiB": 0,

            "ThinlyProvisioned": true,

            "VolSizeMiB": 10240,

            "VolUsageMiB": 0,

            "VolumeCollection": "",

            "VolumeName": "demo-vol1.docker"

        },

        "Labels": {},

        "Scope": "global"

    }

]


Now, let's run a container with the new volume:

$ docker run --rm -it -v demo-vol1:/data busybox sh

/ # df -h | grep /data

/dev/mapper/mpathb       10.0G     32.2M     10.0G   0% /data


An important aspect of the semantics is that volumes are not mounted on the Docker host unless a container requests it. When the container exits, the filesystem is unmounted, the DM device torn down and the Initiator Group is removed from the volume on the array. The process happens in reverse when a mount is requested by Docker.


Compose your first Application with Persistent Storage

The previous 'Hello World' example does not have many practical use cases other than making sure everything works. For this example, we'll use Docker Compose to deploy Drupal, a popular Open Source CMS using the LAMP stack. Drupal is an interesting example because both the webserver and the database requires persistent storage. The next example will then illustrate how we are able to clone a production instance and run it side by side.

 

Here's our base docker-compose.yml file:

version: "2"

services:

  web:

    image: drupal:8.1.8-apache

    ports:

    - "8080:80"

    volumes:

    - www-data:/var/www/html/sites/default

 

  db:

    image: mysql:5.7.14

    volumes:

    - mysql-data:/var/lib/mysql

    environment:

      MYSQL_DATABASE: drupaldb

      MYSQL_USER: db

      MYSQL_PASSWORD: secret

      MYSQL_ROOT_PASSWORD: donotuse

 

volumes:

  www-data:

    driver: nimble

    driver_opts:

      sizeInGiB: 10

      fsOwner: "33:33"

      perfPolicy: "Windows File Server"

      description: "This is my Drupal assets and configuration"

 

  mysql-data:

    driver: nimble

    driver_opts:

      sizeInGiB: 1

      fsOwner: "999:999"

      perfPolicy: "default"

      description: "This my MySQL database volume"

 

What we see here are two containers being deployed, web and db, and they have a volume each with slightly different characteristics. Let's go ahead and deploy:

$ docker-compose up

Creating volume "drupal_mysql-data" with nimble driver

Creating volume "drupal_www-data" with nimble driver

Creating drupal_web_1

Creating drupal_db_1

Attaching to drupal_db_1, drupal_web_1

...

 

There should now be a webserver listening on port 8080 on the host where the containers have been deployed. As we step through the setup wizard, we need to pay attention to the database setup screen. Docker Compose creates a private overlay network between the webserver and database.  Both nodes can reach each other with their respective container names defined in the docker-compose.yml file.

drupal-setup.png

Drupal is now ready for use!

 

Clone your Application

As we are bringing premium data management features to Docker, I wanted to walk through a simple example of how to make a zero-copy clone of the example above.

 

We need a new Docker Compose file, so I created a new directory called 'clone' and made these few edits for docker-compose.yml:

version: "2"

services:

  web:

    image: drupal:8.1.8-apache

    ports:

    # If we intend to run the clone on the same host on the

    # default bridge, we need to change port mapping

    - "8081:80"

    volumes:

    # We don't need to change the volume name as

    # docker-compose prefix the names for you

    - www-data:/var/www/html/sites/default

 

  db:

    image: mysql:5.7.14

    volumes:

    - mysql-data:/var/lib/mysql

    # Since the database is already setup, no need for

    # environment variables

 

volumes:

  www-data:

    driver: nimble

    driver_opts:

      # All parameters will be inherited by the clone, we only

      # need to specify the source volume

      cloneOf: drupal_www-data

      description: "This is my cloned Drupal assets and configuration"

 

  mysql-data:

    driver: nimble

    driver_opts:

      cloneOf: drupal_mysql-data

      description: "This my cloned MySQL database volume"

 

To bring up the cloned environment, simply do this:

$ docker-compose up

Creating volume "clone_mysql-data" with nimble driver

Creating volume "clone_www-data" with nimble driver

Creating clone_web_1

Creating clone_db_1

Attaching to clone_web_1, clone_db_1

...

 

The clone is now available on port 8081, completely separated from the production instance. Since YAML data structures are simple to manipulate programmatically, it would be trivial to incorporate cloning in an automated workflow to spin up clones on demand that allow every developer or designer to essentially have a personal clone of a production copy.

 

More examples will be available at release, such as containerizing a non-containerized workload by cloning snapshots.

 

Availability Options

We will support Docker UCP and CS Engine,  that are part of Docker Datacenter, to allow high-availability for your stateful containers in a production environment. We also support the new SwarmKit in Docker 1.12.1. We're closely working with Docker to ensure we will fully support Distributed Application Bundle (.dab) files once DAB files will support volumes through Docker Compose. We do support the new mount syntax with 'docker service' and you may run your containers without the Docker Compose component using the Nimble Storage Docker Volume plug-in.

 

Conclusion

If you're faced with the challenge of running highly-available stateful containers with Docker and realizing that storage is a non-trivial problem to solve, you should explore our solution as we genuinely believe we're solving a real problem. Our arrays integrate seamlessly in any infrastructure, traditional IT shops, DevOps shops or via Direct Connect to your public cloud. InfoSight keeps your storage environment humming and your time could be spent focusing on higher business objectives.

 

So, tell me, what are your containerizing today?