Using an External File System (Volume Services)

This topic describes how Pivotal Cloud Foundry (PCF) app developers can read and write to a mounted file system from their apps. In PCF, a volume service provides a volume so your app can read or write to a reliable, non-ephemeral file system.

Note: NFS and SMB volume services are available for Linux cells only. These services are not available for Windows cells.

Prerequisite

Before you can use a volume service with your app, your Cloud Foundry administrator must add a volume service to your deployment. See the Enabling Volume Services topic for more information.

You can run the Cloud Foundry Command Line Interface (cf CLI) cf marketplace command to determine if any volume services are available. See the following example output of the NFS volume service:

$ cf marketplace
service   plans      description
nfs       Existing   Service for connecting to NFS volumes

If no volume service that fits your requirements exists, contact your Cloud Foundry administrator.

Mount an External Filesystem

The sections below describe how to mount an external filesystem to your app.

Create and Bind a Service Instance

To use a volume service deployed by your Cloud Foundry administrator, you must first create an instance of the specific volume service that you need. Follow the instructions below to create this service instance.

Note: For NFS-specific instructions and information, see NFS Volume Service.

  1. In a terminal window, run cf create-service SERVICE-NAME PLAN SERVICE-INSTANCE -c SHARE-JSON to create a service instance. Replace the following with the specified values:

    • SERVICE: The name of the volume service that you want to use.
    • PLAN: The name of the service plan. Service plans are a way for providers to offer varying levels of resources or features for the same service.
    • SERVICE-INSTANCE: A name you provide for your service instance. Use any series of alpha-numeric characters, hyphens, and underscores. You can rename the instance at any time.
    • SHARE-JSON (NFS Only): If you create an instance of the NFS volume service, you must supply an extra parameter, share, by using the -c flag with a JSON string, in-line or in a file. This parameter forwards information to the broker about the NFS server and share required for the service.

    The following example shows creating an instance of the “Existing” NFS service plan, passing an in-line JSON string:

    $ cf create-service nfs Existing nfs_service_instance -c '{"share": "10.10.10.10/export/myshare"}'

  2. Run cf bind-service YOUR-APP SERVICE-NAME -c GID-AND-UID-JSON MOUNT-PATH READ-ONLY-TRUE to bind your service instance to an app. Replace the following with the specified values:

    • YOUR-APP: The name of the PCF app for which you want to use the volume service.
    • SERVICE-NAME: The name of the volume service instance you created in the previous step.
    • GID-AND-UID-JSON (NFS only): If you bind an instance of the NFS volume service, you must supply two extra parameters, gid and uid. You can specify these parameters with the -c flag and a JSON string, in-line or from a file. This parameter specifies the gid and uid to use when mounting the share to the app.
    • MOUNT-PATH (Optional): To mount the volume to a particular path within your app rather than the default path, you supply the mount parameter. Choose a path with a root-level folder that already exists in the container, such as /home, /usr, or /var.

      Note: Do not specify a MOUNT-PATH within the /app directory. For more information, see Mount Path Limitation.

    • READ-ONLY-TRUE (Optional): When you issue the cf bind-service command, Volume Services mounts a read-write file system by default. You can specify a read-only mount by adding "readonly":true to the bind configuration JSON string.

    The following example shows binding my-app to the nfs_service_instance and specifying a read-only volume to be mounted to /var/volume1, passing an in-line JSON string:

    $ cf bind-service my-app nfs_service_instance -c '{"uid":"1000","gid":"1000","mount":"/var/volume1","readonly":true}'
    If you use an LDAP server, you must specify username and password instead of a UID and GID in this command. For example:
    $ cf bind-service my-app nfs_service_instance -c '{"username":"user1000","password":"secret","mount":"/var/volume1","readonly":true}'

  3. Run cf restage YOUR-APP to complete the service binding by restaging your app. Replace YOUR-APP with the name of your app.

    $ cf restage my-app

Access the Volume Service from your App

To access the volume service from your app, you must know which file path to use in your code. You can view the file path in the details of the service binding, which are available from the VCAP_SERVICES environment variable. Follow the steps below.

  1. Run cf env YOUR-APP to view environment variables for your app. Replace YOUR-APP with the name of your app.

    $ cf env my-app
    "VCAP_SERVICES": {
    "nfs": [
      {
        "credentials": {},
        "label": "nfs",
        "name": "nfs_service_instance",
        "plan": "Existing",
        "provider": null,
        "syslog_drain_url": null,
        "tags": [
          "nfs"
        ],
        "volume_mounts": [
          {
            "container_dir": "/var/vcap/data/153e3c4b-1151-4cf7-b311-948dd77fce64",
            "device_type": "shared",
            "mode": "rw"
          }
        ]
      }
    ]
    }
    

  2. Use the properties under volume_mounts for any information your app needs. Refer to the following table:

    Property Description
    container_dir String containing the path to the mounted volume that you bound to your app.
    device_type The NFS volume release. This currently only supports shared devices. A shared device represents a distributed file system that can mount on all app instances simultaneously.
    mode String that informs what type of access your app has to NFS, either read-only, ro, or read and write, rw.

Bind with an App Manifest

You can also bind volume services using an app manifest as described in the Services section of the Deploying with App Manifests topic. However, app manifests do not support bind configuration. If you want to bind a volume service using an app manifest, you must specify bind configuration when you create the service instance. The releases that support this are nfs-volume v1.3.1 and later and smb-volume v1.0.0 and later.

Mount Path Limitation

Do not specify a MOUNT-PATH within the /app directory, which is where PAS unpacks the droplet. If you specify a mount inside the /app directory, the app may fail to start and parts of the app droplet may be written to the remote file share. This is because PAS mounts the volume before moving your compiled app into the droplet.

If your app requires the shared volume to be placed within the /app directory, do the following:

  1. Specify a mount volume in a location outside of the /app directory.
  2. Create a symbolic link at app startup time, prior to launching the app. For example:
    cf push my-app -c "ln -s /var/volume1 /app/volume1 && \$HOME/boot.sh"

NFS Volume Service

This section describes how to use the NFS volume service.

Create an NFS Volume Service

Cloud Foundry offers two NFS volume services:

  • nfs: This volume service provides support for NFS volumes using both v3 and v4.x protocols.
    • If you do not specify a version parameter in the create configuration, the protocol version used will be negotiated between client and server at mount time. This usually results in the latest available version being used.
    • If you want to request a specific protocol version, include a version parameter in the create configuration.
    • For read-only mounts, the driver enables attribute caching. This results in fewer attribute RPCs and better performance.
    • When you omit uid and gid or username and password in bind configuration, the driver skips mapfs mounting and performs just the normal kernel mount of the NFS file system without the overhead associated with FUSE mounts.
  • nfs-legacy (deprecated): Although it is deprecated, this volume service is still available due to the difficulty of retiring services. If you use this service, it performs exactly the same mount as the nfs service.

Both services offer a single plan called Existing.

To create an NFS volume service, follow the procedure below that corresponds to your use case.

Create an nfs Service (auto-negotiated version)

You can create a NFS volume service using the Existing plan of the nfs service. Run the following command:

$ cf create-service nfs Existing SERVICE-INSTANCE-NAME -c '{"share":"SERVER/SHARE"}'

Where:

  • SERVICE-INSTANCE-NAME is a name you provide for this NFS volume service instance.
  • SERVER/SHARE is the NFS address of your server and share.

Note: Ensure you omit the : that usually follows the server name in the address.

You can run the cf services command to confirm that your newly-created NFS volume service displays in the output.

Create an nfs Service (explicit version)

You can create a NFS volume service with a specific NFS protocol version using the Existing plan of the nfs service. Run the following command:

$ cf create-service nfs Existing SERVICE-INSTANCE-NAME -c '{"share":"SERVER/SHARE", "version":"NFS-PROTOCOL"}'

Where:

  • SERVICE-INSTANCE-NAME is a name you provide for this NFS volume service instance.
  • SERVER/SHARE is the NFS address of your server and share.
  • VERSION is the NFS protocol you want to use. For example, if you want to use NFSv4, set the version to 4.1. Valid values are 3.0, 4.0, 4.1 or 4.2.

Note: Ensure you omit the : that usually follows the server name in the address.

You can run the cf services command to confirm that your newly-created NFS volume service displays in the output.

Existing nfs-legacy Services:

With the release of NFS Volume Service 1.5.4, the original fuse-based NFS service has been deprecated in favor of the newer kernel-mount based NFS service and will eventually be removed. Existing NFS volume service bindings will now be listed as nfs-legacy. To switch over from nfs-legacy to the newer nfs service, we recommend that you re-create and re-bind your nfs service instances.

With the release of NFS Volume Service 2.0.0, the nfs-legacy service has been rewritten to use the nfs service. To avoid being affected when the nfs-legacy service is retired, re-create and re-bind your service instances using the nfs service.

Deploy and Bind a Sample App

This section describes how to deploy a sample app and bind it to the NFS volume service.

  1. Clone the github repo and push the pora test app:

    1. cd ~/workspace
    2. git clone https://github.com/cloudfoundry/persi-acceptance-tests.git
    3. cd ~/workspace/persi-acceptance-tests/assets/pora
    4. cf push pora --no-start
  2. To bind the service to your app, run the following command:

    $ cf bind-service pora SERVICE-INSTANCE-NAME -c '{"uid":"UID","gid":"GID"}'
    

    Where:

    • SERVICE-INSTANCE-NAME: The name of the volume service instance you created previously.
    • UID and GID: The gid and uid to use when mounting the share to the app. The NFS driver uses these values in the following ways:

      • When sending traffic to the NFS server, the NFS driver translates the app user id and group id to the UID and GID values.
      • When returning attributes from the NFS server, the NFS driver translates the UID and GID back to the running user uid and default gid.

      This allows you to interact with your NFS server as a specific user while allowing Cloud Foundry to run your app as an arbitrary user.

    • Optional paramenters:

      • mount: Use this option to specify the path at which volumes mount to the app container. The default is an arbitrarily-named folder in /var/vcap/data. You may need to modify this value if your app has specific requirements. For example:

        cf bind-service pora myVolume -c '{"uid":"0","gid":"0","mount":"/var/path"}'
        
      • readonly: When you issue the cf bind-service command, Volume Services mounts a read-write file system by default. You can specify a read-only mount by adding "readonly":true to the bind configuration JSON string.

  3. Start the app:

    $ cf start pora
    
  4. Use the following curl command to confirm the app is running. The command returns an instance index for your app.

    $ curl http://pora.YOUR-CF-DOMAIN.com
    
  5. Use the following curl command to confirm the app can access the shared volume. The command writes a file to the share and then reads it back out again.

    $ curl http://pora.YOUR-CF-DOMAIN.com/write
    

Additional Information

This section provides additional information about using the NFS Volume Service.

Binding with LDAP Credentials

If your Cloud Foundry deployment has LDAP enabled, you can bind using LDAP credentials.

To bind an app to your volume using LDAP credentials, specify username and password instead of uid and gid. See the following example:

$ cf bind-service pora myVolume -c '{"username":"USERNAME","password":"PASSWORD"}'

Note: If your LDAP server password changes, you must re-bind your app to the service and restage. If you do not, your app will fail during restart or scaling. This is because user credentials are stored as part of the service binding and checked whenever an app is placed on a cell.

Specifying Bind Parameters During Service Instance Creation

As of nfs-volume-release v1.3.1, you can specify bind parameters in advance, when you create a service instance. Use this option if you bind the service to your app in an app manifest, where bind configuration is not supported.

File Locking with flock() and lockf()/fcntl()

Apps that use file locking through unix system calls such as flock() and fcntl() or script commands such as flock may use the nfs service. The nfs-legacy service uses a fuse mounting process that does not enforce locks across Diego cells.

SMB Volume Service

This section describes how to use an SMB (Server Message Block) volume service.

Create an SMB Volume Service

Cloud Foundry offers one SMB volume service:

  • smb: This volume service provides support for existing SMB shares.

The service offers a single plan called Existing.

To create an SMB volume service, follow the procedure below.

Create with smb Service

You can create an SMB volume service using the Existing plan of the smb service. Run the following command:

$ cf create-service smb Existing SERVICE-INSTANCE-NAME -c '{"share":"//SERVER/SHARE"}'

Where:

  • SERVICE-INSTANCE-NAME is a name you provide for this SMB volume service instance.
  • //SERVER/SHARE is the SMB address of your server and share.

You can run the cf services command to confirm that your newly-created SMB volume service displays in the output.

Deploy and Bind a Sample App

This section describes how to deploy a sample app and bind it to the SMB volume service.

  1. Clone the github repo and push the pora test app:

    1. cd ~/workspace
    2. git clone https://github.com/cloudfoundry/persi-acceptance-tests.git
    3. cd ~/workspace/persi-acceptance-tests/assets/pora
    4. cf push pora --no-start
  2. To bind the service to your app, run the following command:

    $ cf bind-service pora SERVICE-INSTANCE-NAME -c '{"username":"USERNAME","password":"PASSWORD"}'
    

    Where:

    • SERVICE-INSTANCE-NAME: The name of the volume service instance you created previously.
    • USERNAME and PASSWORD: The username and password to use when mounting the share to the app. This allows you to interact with your SMB server as a specific user while allowing Cloud Foundry to run your app as an arbitrary user.
    • Optional parameters:

      • mount: Use this option to specify the path at which volumes mount to the app container. The default is an arbitrarily-named folder in /var/vcap/data. You may need to modify this value if your app has specific requirements. For example:

        cf bind-service pora myVolume -c '{"username":"some-user","password":"some-password","mount":"/var/path"}'
        
      • readonly: When you issue the cf bind-service command, Volume Services mounts a read-write file system by default. You can specify a read-only mount by adding "readonly":true to the bind configuration JSON string.

      • domain: In case if your user is in windows domain you can specify domain parameter.

  3. Start the app:

    $ cf start pora
    
  4. Use the following curl command to confirm the app is running. The command returns an instance index for your app.

    $ curl http://pora.YOUR-CF-DOMAIN.com
    
  5. Use the following curl command to confirm the app can access the shared volume. The command writes a file to the share and then reads it back out again.

    $ curl http://pora.YOUR-CF-DOMAIN.com/write
    
Create a pull request or raise an issue on the source for this page in GitHub