Persistent block storage is one of the biggest unlocks of Tanzu Platform 10.4. It makes a new class of workloads practical on Tanzu Platform: one-instance apps, sharded state, write-ahead logs, hot caches, checkpoint-style workloads, file-conversion scratch directories, and other patterns that need durable local storage mounted into the app container.

In Tanzu Platform 10.4, the capability ships built into the Elastic Application Runtime (EAR) tile as the Block Storage Broker. Once the operator enables it, developers get a clear workflow: cf create-service, cf bind-service, cf restage. The result is a real block device mounted in the container, with data that survives restages and restarts.

What the broker actually is

The Block Storage Broker is a service broker that lives inside the Elastic Application Runtime tile. It accepts cf create-service calls, talks to vSphere CNS to provision a First-Class Disk, and arranges for Diego to bind-mount it into your app's container at startup.

From the developer's side it looks identical to any other CF service: create, bind, restage, read your env. Under the hood it's spinning up real cloud disks and attaching them to cell VMs.

Step 1 — Configure the broker in OpsMan

In Tanzu Operations Manager, open the Elastic Application Runtime tile and click App Containers in the left-hand nav. Scroll to the Block storage volume service section and fill in four fields:

Tanzu Operations Manager EAR tile: block storage volume service section showing the checkbox, disk-name prefix, disk pool, and disk size fields
The Block storage volume service section in the Elastic Application Runtime tile's App Containers pane.
  1. Allow block storage volume services (vSphere only) — check this. It's the master switch that wires the broker into Cloud Controller and instructs Diego to mount block volumes into bound containers.
  2. Block storage volume service disk name prefix (vSphere only) — the string used to name the First-Class Disks created in vSphere on the platform's behalf. block is a sensible default; pick something that makes the volumes easy to spot in vCenter for your foundation (for example cdc-block).
  3. Block storage volume service disk pool (vSphere only) — the BOSH disk-pool identifier the broker provisions from. The docs call this the IaaS shape of the disk, not the size; the default is the first pool in the list unless you've defined custom pools.
  4. Block storage volume service disk size in MB (vSphere only) — the default volume size in MB. The documented default is 1024 MB. On my foundation, the exposed developer plan is 10240 (10 GB), which is a practical proof-point size for validating the flow before you decide what plans your app teams actually need.

Click Save, then switch to the Errands pane in the left nav and confirm the Block Storage Broker Errand is set to On. This is the post-deploy errand that registers the broker with Cloud Controller every time you apply changes — leaving it on keeps the broker registration sticky across tile upgrades.

Save again, return to the Installation Dashboard, review pending changes, and click Apply Changes. When Apply Changes finishes, the broker is deployed and registered with Cloud Controller.

Step 2 — Enable service access

The errand registers the broker, but per CF semantics service plans are private by default — meaning developers can't see block-storage in their marketplace until an admin explicitly enables access. One Tanzu cf CLI command from any admin-targeted shell does it:

cf enable-service-access block-storage

That makes the service plan visible to every org on the foundation. To scope it to specific orgs instead, pass -o <org-name> — useful when you want to pilot block storage with one team before opening it up platform-wide.

Verify with:

cf service-access | grep -iE "block|blockstoragebroker"

You should see the plan listed with access: all (or your specific org name):

broker: blockstoragebroker
   service         plan                access
   block-storage   on-demand-10240     all

Step 3 — Verify the marketplace

Switch to any developer-style CF target (any user with access to an org you enabled) and check the marketplace:

cf marketplace -e block-storage

You'll see the on-demand plan with the default size you configured in Step 1:

broker: blockstoragebroker
plans:
   name              description                 free or paid
   on-demand-10240   Block storage volumes       free

The plan name encodes the configured default size in MB (10240 = 10 GB in this example). If you changed the disk-size field in Step 1, the plan name reflects your choice.

Step 4 — Use it (developer)

Before you hand this to an app team, set the expectation clearly: block storage is single-attach by design. It is a great fit for one-instance apps, sharded state, write-ahead logs, hot caches, and checkpoint-style workloads. It is not shared NFS; for multi-instance shared writes, use a managed database or shared filesystem instead.

cf create-service block-storage on-demand-10240 my-disk
cf bind-service my-app my-disk
cf restage my-app

One thing to know about that last command: restage, not restart. Diego attaches the volume during the staging cycle, so a fresh cf restage is what picks up the new mount.

Step 5 — What your app sees

Inside the container, your app reads VCAP_SERVICES and finds:

{
  "block-storage": [{
    "name": "my-disk",
    "instance_name": "my-disk",
    "label": "block-storage",
    "plan": "on-demand-10240",
    "tags": ["block-storage"],
    "credentials": {},
    "volume_mounts": [{
      "container_dir": "/var/vcap/data/<binding-guid>",
      "device_type": "dedicated",
      "mode": "rw"
    }]
  }]
}

The container_dir is your mount point. Read and write it like a local filesystem — the data persists across restages and restarts.

In a fresh proof run, the broker and Cloud Controller pieces behaved exactly this way: the app was bound to a block-storage service instance, the service plan was on-demand-10240, and cf env showed a dedicated read-write mount under /var/vcap/data/<service-guid>. After a restart, the app came back on a different container and the write counter kept incrementing on the same mounted path.

Block storage proof app showing a mounted volume, persistent write count, service name, mount path, and recent writes across containers
The proof app after restart: request 1 and 2 landed on one container, request 3 and 4 landed on a different container, and the counter persisted through the block storage mount.

A quick Python sanity check, deployable as a Flask app:

import os, json, time
import flask

VCAP = json.loads(os.environ["VCAP_SERVICES"])
MOUNT = VCAP["block-storage"][0]["volume_mounts"][0]["container_dir"]

app = flask.Flask(__name__)

@app.route("/")
def index():
    log = os.path.join(MOUNT, "boots.log")
    with open(log, "a") as f:
        f.write(f"{time.time()}\n")
    with open(log) as f:
        return f"This container has booted {len(f.readlines())} times.\n"

cf push it, hit the route a few times, then cf restage and watch the counter keep climbing from the mounted volume.

Operator tips worth knowing

A few rollout details are worth calling out:

  • Restage to mount the volume. Diego attaches the disk when an app's container is being created, so after cf bind-service run cf restage to bring up new instances with the mount in place.
  • Validate with a tiny app before broad rollout. Push a single-instance app, create and bind a disk, restage, write a counter file under the reported container_dir, then restart the app and confirm the counter keeps climbing from the same mounted path.
  • Org quotas. Block storage instances count against your org's total_service_instances quota. Raise that limit proactively when you roll out broadly: cf update-org-quota <quota> --total-service-instances 50.
  • Disk pool and size choices. The disk pool field in Step 1 maps to a vSphere CNS disk-pool resource defined in BOSH and controls the IaaS shape of the disk. The configured size in MB drives both the plan name (on-demand-<size>) and the provisioned volume size, so set it to the most common size you expect to hand out.
  • Plan backup and recovery separately. Block storage gives the app a persistent device; it is not a backup. Coordinate volume protection and recovery with your vSphere and storage teams.

Where block storage shines

Block storage is the right fit when your app has local-disk semantics — one-instance apps, sharded state, write-ahead logs, hot caches, checkpoint-style workloads, file-conversion staging, or anything else that wants a real filesystem mounted in the container.

For multi-instance shared state, reach for a managed database (Postgres, MySQL on Tanzu) or a shared filesystem (NFS broker). For long-term archival, object storage is the better fit. Tanzu Platform ships brokers for all of those alongside block storage — pick the one that matches the access pattern.

TL;DR

One OpsMan section, an errand toggle, one cf enable-service-access, and three developer commands — that's the whole pipeline to give your platform stateful-workload support.

# Operator (one-time)
# 1. OpsMan: Elastic Application Runtime tile → App Containers → Block storage volume service
#    - Enable the checkbox
#    - Set disk-name prefix, disk pool, default size
# 2. OpsMan: Errands → Block Storage Broker Errand → On
# 3. Apply Changes
# 4. cf enable-service-access block-storage

# Developer
cf create-service block-storage on-demand-10240 my-disk
cf bind-service my-app my-disk
cf restage my-app