This week, the PCFDev team released a new version of PCFDev that includes local-volume services out of the box.  This new release of PCFDev gives us an option to get up and running with volume services that is an order of magnitude easier than any of the options we had before. We thought it would be a good time to write a post detailing the steps to try out volume services with your Cloud Foundry applications, now that the post doesn’t need to be quite so long.

1. Install PCFDev

(Time: 30-90 minutes, depending on your internet connection speed, and what you already have installed.)

Instructions for PCFDev installation can be found here.  Installation requires VirtualBox and the Cloud Foundry CLI, and you will need to have (or create) an account on Pivotal Network.  Don’t be deterred.  It’s free and easy.  If you already have PCFDev, make sure that you have version 0.22.0 or later.

Once you have installed PCFDev and successfully started it up, you should see something like this:


Now log in and select the pcfdev-org space:

○ → cf login -a --skip-ssl-validation
API endpoint:

Email> admin


Select an org (or press enter to skip):
1. pcfdev-org
2. system

Org> 1
Targeted org pcfdev-org

Targeted space pcfdev-space

API endpoint: (API version: 2.58.0)
User: admin
Org: pcfdev-org
Space: pcfdev-space

○ →

2. Create a New Volume

(Time: 1 minute)

If you have the right version of PCFDev, then the local-volume service broker should already be installed.  You can tell this by typing

cf marketplace

You should see local-volume in the list of available services:


Use cf create-service to create a new file volume that you can bind to your application:

○ → cf create-service local-volume free-local-disk myvolume
Creating service instance myvolume in org pcfdev-org / space pcfdev-space as admin...

○ →

3. Push an Application

(Time: 5 minutes)

For the purposes of this blog post, we’ll use the “pora” test application that we use in our persi CI pipeline. “Pora” is the persistent version of the Cloud Foundry acceptance test “Dora” application.  It is a simple ‘hello world” app that writes a message into a file, and then reads it back out again.

To get the Pora app, first clone the persi-acceptance-tests github repo:

○ → git clone
Cloning into 'persi-acceptance-tests'...
remote: Counting objects: 228, done.
remote: Compressing objects: 100% (97/97), done.
remote: Total 228 (delta 120), reused 222 (delta 114), pack-reused 0
Receiving objects: 100% (228/228), 39.42 KiB | 0 bytes/s, done.
Resolving deltas: 100% (120/120), done.
Checking connectivity... done.

○ → 

Now change to the pora folder, and push the app to cf with the “no-start” option:

○ → cd persi-acceptance-tests/assets/pora

○ → cf push pora --no-start
Using manifest file /Users/pivotal/workspace/eraseme/persi-acceptance-tests/assets/pora/manifest.yml

Creating app pora in org pcfdev-org / space pcfdev-space as admin...

Creating route

Binding to pora...

Uploading pora...
Uploading app files from: /Users/pivotal/workspace/eraseme/persi-acceptance-tests/assets/pora
Uploading 1K, 2 files
Done uploading
○ →

4. Bind the Service to the Application and Start the App

(Time: 5 minutes)

The cf “bind-service” command makes our new volume available to the Pora application.

○ → cf bind-service pora myvolume
Binding service myvolume to app pora in org pcfdev-org / space pcfdev-space as admin...
TIP: Use 'cf restage pora' to ensure your env variable changes take effect

○ →

Now start the pora application:

○ → cf start pora
Starting app pora in org pcfdev-org / space pcfdev-space as admin...
Downloading go_buildpack...
Downloaded go_buildpack (320.8M)
Creating container
Successfully created container
Downloading app package...
Downloaded app package (1.1K)
-------> Buildpack version 1.7.10
-----> Installing go1.6.3... done
Downloaded [file:///tmp/buildpacks/a62bb8a9fc6ecb01a06f86c020c7a142/dependencies/https___storage.googleapis.com_golang_go1.6.3.linux-amd64.tar.gz]
-----> Running: go install -v -tags cloudfoundry .
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading build artifacts cache...
Uploading droplet...
Uploaded build artifacts cache (81.6M)
Uploaded droplet (2.3M)
Uploading complete
Destroying container
Successfully destroyed container

1 of 1 instances running

App started


App pora was started using this command `pora`

Showing health and status for app pora in org pcfdev-org / space pcfdev-space as admin...

requested state: started
instances: 1/1
usage: 256M x 1 instances
last uploaded: Thu Nov 17 03:20:29 UTC 2016
stack: cflinuxfs2
buildpack: go_buildpack

state since cpu memory disk details
#0 running 2016-11-16 07:38:32 PM 0.0% 0 of 256M 0 of 512M

○ →

Once the app is started, you can use curl with the reported url to make sure it is reachable.  The default endpoint for the application will just report back the instance index for the application:

○ → curl
instance index: 0
○ →

To test the persistence feature, add “/write” to the end of the url.  This will cause the pora app to pull the location of the shared volume from the VCAP_SERVICES environment variable, create a file, write a message into it, and then read the message back out:

○ → curl
Hello Persistent World!
○ →

5. Use Persistent Volumes with Your Own Application

By default, the volume service broker will generate a container mount path for your mounted volume, and it will pass that path into your application via the VCAP_SERVICES environment variable. You can see this when you type “cf env pora” which produces output like this:

  "local-volume": [
    "volume_mounts": [
      "container_path": "/var/vcap/data/0ce3b464-3d4c-45af-9e78-29990d7ddac1",
      "mode": "rw"

In your application, you can parse the VCAP_SERVICES environment variable as json and determine the value of “container_path” to find the location of your shared volume in the container, or simply parse out the path with a regular expression.  You can see an example of this code flow in the Pora application here.

If it isn’t practical to connect to an arbitrary location in your application for some reason, (e.g. the directory is hard coded everywhere, or your code is precompiled, or you are reluctant to change it) then you can also tell the broker to put the volume in a specific location when you bind the application to the service.  To do that, unbind the service, and then rebind it using the -c option.  This will create any necessary directories on the container, and put the volume mount in the specific path you need:

○ → cf unbind-service pora myvolume
Unbinding app pora from service myvolume in org pcfdev-org / space pcfdev-space as admin...
○ → cf bind-service pora myvolume -c '{"mount":"/my/specific/path"}'
Binding service myvolume to app pora in org pcfdev-org / space pcfdev-space as admin...
TIP: Use 'cf restage pora' to ensure your env variable changes take effect
○ →

Type “cf restage pora” to restart the application in this new configuration, and you should observe that the application operates as before, except that it now accesses the shared volume from “/my/specific/path”.  You can also see the new path transmitted to the application by typing “cf env pora”.

6. If You Need to Copy Data

If you need to copy existing data into your new volume in order for your application to use it, you will need to get the data onto the PCFDev host, and then copy it into the source directory that the local-volume service uses to mimic a shared volume.  In a real-world scenario, these steps wouldn’t be necessary because the volume would come from a real shared filesystem that you could mount and copy content to, but the local-volume service is a test service that mimics shared volumes for simple cloudfoundry deployments.

The key that PCFDev uses for scp/ssh is located in ~/.pcfdev/vms/key.pem.  This file must be tweaked to reduce its permissions before it can be used by scp:

○ → chmod 0600 ~/.pcfdev/vms/key.pem
○ →

Now invoke scp to copy your content across to the PCFDev VM.  The example below copies a file named “assets.tar” to the var/vcap/data directory on the VM:

○ → scp -i ~/.pcfdev/vms/key.pem ./assets.tar
assets.tar 100% 10KB 10.0KB/s 00:00
○ →

Now, use “cf dev ssh” to open a ssh session into the vm, and cd to /var/vcap/data.  You should find your file there:

○ → cf dev ssh
Welcome to Ubuntu 14.04.5 LTS (GNU/Linux 3.19.0-74-generic x86_64)

* Documentation:
New release '16.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

vcap@agent-id-pcfdev-0:~$ cd /var/
-bash: cd: /var/ No such file or directory
vcap@agent-id-pcfdev-0:~$ cd /var/vcap/data
vcap@agent-id-pcfdev-0:/var/vcap/data$ ls
assets.tar cloud_controller_ng executor_cache jobs nginx_cc stager tmp uaa voldrivers
bbs executor garden mysql packages sys tps upgrade_preparation_nodes volumes

“ls volumes/local/_volumes” gives us a listing of the volumes that have been created.  If you are following this tutorial, there should be only one directory in there, with a long ugly name.  Move the file into that directory, and then exit the ssh session

vcap@agent-id-pcfdev-0:/var/vcap/data$ ls volumes/local/_volumes/
vcap@agent-id-pcfdev-0:/var/vcap/data$ mv assets.tar volumes/local/_volumes/843f99cc-7638-4a0f-8209-b522928cd443/
vcap@agent-id-pcfdev-0:/var/vcap/data$ exit
○ →

Finally, invoke “cf ssh pora” to open a ssh session into the cloudfoundry app.  This will allow you to verify that the data is available to your application.  If you used the -c option to specify a mount path, you should find your content there.  If not, you will find it under “/var/vcap/data/{some-guid}”:

○ → cf ssh pora
vcap@2bts9kfetl8:~$ ls /my/specific/path/
assets.tar test.txt

7. Where to Find More Information

The best place to reach the CF Diego Persistence team is on our Slack channel here: We’re happy to hear from you with any questions you have, and to help steer you in the right direction.

If you don’t already have an account on CF slack, you can create an account here:

For an introduction to Volume Services in Cloud Foundry, refer to this document:

Or watch our various presentations this year:

CF Summit Frankfurt 2016:

Spring One Platform 2016:

CF Summit Santa Clara 2016:

Julian Hjortshoj

Julian Hjortshoj

Julian is a 12 year veteran of DellEmc, and the current PM of the Cloud Foundry Diego Persistence team.


  1. Ben says:

    This is a cracking article, thank you very much.

    I just used it to provision a local server certificate and private key to an HTTPS server that I wanted to test TCP routes with.

    Best wishes Ben

Leave a Comment

The comments are moderated by EMC and EMC reserves the right to remove any content it deems inappropriate, including but not limited to spam, promotional and offensive comments.

Follow Us on Twitter

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.