Skip to content

Object storage

Every organization with a Kubernetes cluster holds one bucket. Public Research organizations have none. The bucket is the durable store for datasets, checkpoints and outputs. It outlives every cluster. It is reachable from every site and from outside the platform through an S3 compatible endpoint. One access key pair opens it. The platform writes that pair into every Kubernetes cluster of the organization as the Secret nc-storage in the default namespace. The console's Storage page shows the same pair on request.

The bucket

The platform creates the bucket at the organization's first Kubernetes cluster. The name is assigned by the platform (nc- and 16 hex characters). The Storage page shows the bucket under Object storage on every cluster of the organization, with the endpoint, the bucket's name and the access key ID. An organization whose clusters predate object storage and whose Storage page shows no Object storage block asks support.

The bucket belongs to the organization. Nothing about it is per cluster: every Kubernetes cluster of the organization, on every site, reaches the same bucket with the same pair. The bucket survives cluster deletion. Deleting the organization's last cluster does not delete it.

Slurm clusters and VM clusters receive no Secret (below).

The credential

One access key pair per organization: an access key ID and a secret access key. Every member of the organization shares it. There are no per member credentials, no per cluster credentials and no prefix scoping. The pair grants read and write on the whole bucket.

The Secret nc-storage

The platform writes the pair into every Kubernetes cluster of the organization as the Secret nc-storage in the default namespace, within minutes of a cluster's creation and again at every rotate. The Secret carries five keys, named so that the common S3 clients read them with no mapping:

Key Value
AWS_ACCESS_KEY_ID the access key ID
AWS_SECRET_ACCESS_KEY the secret access key
AWS_ENDPOINT_URL the S3 compatible endpoint
AWS_DEFAULT_REGION auto
NC_BUCKET the bucket's name

The Secret is platform managed (label app.kubernetes.io/managed-by: nationalcompute-station). An edit to it is overwritten at the next push. Deleting it revokes nothing. The platform writes it again at the next rotate. The Secret exists in the default namespace only. A pod in another namespace cannot reference it. Copy it into that namespace yourself. A copy does not follow a rotate.

The Storage page shows the Secret's state on the picked cluster: present once the write landed, pending with a short reason while it has not, and Kubernetes clusters only on a Slurm or VM cluster. The platform retries a pending write after five minutes at first and then at growing intervals up to six hours. A Secret that stays pending is a support matter.

Show and Rotate on the Storage page

Show credentials displays the pair. Each display is recorded in your organization's activity trail with the member who asked. Rotate credentials replaces it (below). Both are console actions. No API token and no agent tool can show or rotate the pair.

Using the bucket from a pod

envFrom the Secret. The five variables land in the container's environment. boto3 and the AWS CLI read them as they are: no endpoint flag, no credentials file, no region to choose.

apiVersion: batch/v1
kind: Job
metadata:
  name: bucket-smoke
spec:
  backoffLimit: 0
  ttlSecondsAfterFinished: 120
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: aws
          image: public.ecr.aws/aws-cli/aws-cli:2.38.5
          envFrom:
            - secretRef:
                name: nc-storage
          env:
            # the endpoint does not implement the default checksum mode
            # of current AWS CLI and boto3 releases
            - { name: AWS_REQUEST_CHECKSUM_CALCULATION, value: when_required }
            - { name: AWS_RESPONSE_CHECKSUM_VALIDATION, value: when_required }
          command: ["sh", "-c"]
          args:
            - |
              echo hello > /tmp/hello
              aws s3 cp /tmp/hello "s3://$NC_BUCKET/smoke/hello"
              aws s3 ls "s3://$NC_BUCKET/smoke/"

The Job requests no GPUs, so it runs at once on the cluster CPU worker and never touches the market. A GPU job uses the same envFrom block.

The same round trip in Python:

import os
import boto3

s3 = boto3.client("s3")  # endpoint, region and keys come from the environment
bucket = os.environ["NC_BUCKET"]
s3.put_object(Bucket=bucket, Key="smoke/hello", Body=b"hello\n")
print(s3.get_object(Bucket=bucket, Key="smoke/hello")["Body"].read())

The two checksum variables in the Job apply to boto3 as well. An older client release that does not read AWS_ENDPOINT_URL takes the endpoint explicitly: --endpoint-url "$AWS_ENDPOINT_URL" on the AWS CLI, endpoint_url=os.environ["AWS_ENDPOINT_URL"] on a boto3 client. Multipart uploads work as on any S3 endpoint. An object is currently at most 5 TiB. A key accepts one write per second. A second write to the same key within that second fails. Give concurrent writers their own keys.

The pair works from anywhere on the internet with any S3 client: a laptop, a VM node, a Slurm login node, a Marshall workspace. Set the five variables from the Storage page's Show credentials and the same commands run.

The starter recipes use the same envFrom block, with optional: true so the files run on a cluster without the Secret: object storage recipes.

Rotation

Rotate credentials on the Storage page replaces the whole pair. Both halves change: the access key ID and the secret access key. The platform writes the new pair into every Kubernetes cluster of the organization and shows it once.

  • The old pair keeps working for ten minutes after the rotate, then stops. Every copy you saved stops working with it at that point.
  • The Secret nc-storage is updated in every Kubernetes cluster of the organization within seconds. A cluster the write cannot reach reads pending on the Storage page and receives the pair when the platform's retry lands.
  • A pod that loaded the Secret through envFrom keeps the old pair until it restarts. Kubernetes injects the environment at container start and never updates it. Restart the consuming pods within the ten minutes after a rotate. A pod that starts in the seconds between the rotate and the update on its cluster loads the old pair too. A volume mount of the Secret refreshes on its own within about a minute.

Rotate when a member leaves the organization and after any suspected exposure of the pair. Member removal revokes that member's tokens and sign in. It does not change the bucket pair. A departed member may hold a copy. The activity trail records who pressed Show on the console. It is not a record of who holds the pair: any member, workload or agent account in a cluster reads the Secret without a record.

The soft cap

Each bucket carries a soft cap, currently 2 TiB. Usage is sampled hourly. The Storage page shows the bytes and objects held against the cap. Over the cap the page shows a warning and asks you to contact support, who raise the cap on request. Nothing is refused at the cap today: writes continue while the warning shows. The bucket is not billed today.

Reading the bucket by API

GET /api/k8s/storage/bucket with an org API token answers the bucket's facts, its usage against the cap and the Secret's state on each Kubernetes cluster of the organization. It never carries the secret access key (limit price API). On the MCP server the same body is grid_api get /api/k8s/storage/bucket. Show and Rotate have no route and no tool.

What the bucket is not

  • No public access. There is no public URL, no anonymous read and no per object sharing link. Whoever holds the pair reads and writes. Nobody else does.
  • One pair. The pair opens the whole bucket for the whole organization. Scoping by member, by cluster or by prefix does not exist.
  • No versioning and no lifecycle rules. The platform keeps no object versions, sets no expiry rules and takes no backups of the bucket. A deleted object is gone.
  • Kubernetes clusters only. The Secret lands in Kubernetes clusters. Slurm clusters and VM clusters receive nothing. The pair itself works from any machine.
  • No tenant delete. No console action and no route deletes the bucket or revokes its pair. Ask support. A bucket is destroyed only when it is empty.
  • No append and no tail. A write replaces the whole object. A log kept in the bucket reads as of its last upload (logs in the bucket).
  • No POSIX mount. For a filesystem shared by every node of a cluster, ask support for a shared volume.