Skip to content

Container Object Storage Interface (COSI)

The Ceph COSI driver provisions buckets for object storage. This document instructs on enabling the driver and consuming a bucket from a sample application.

Note

The Ceph COSI driver is currently in experimental mode.

Prerequisites

COSI requires: 1. A running Rook object store 2. COSI controller

Deploy the COSI controller with these commands:

kubectl apply -k github.com/kubernetes-sigs/container-object-storage-interface-api
kubectl apply -k github.com/kubernetes-sigs/container-object-storage-interface-controller

Ceph COSI Driver

The Ceph COSI driver will be started when the CephCOSIDriver CR is created and when the first CephObjectStore is created.

1
2
3
4
5
6
7
apiVersion: ceph.rook.io/v1
kind: CephCOSIDriver
metadata:
  name: ceph-cosi-driver
  namespace: rook-ceph
spec:
  deploymentStrategy: "Auto"
cd deploy/examples/cosi
kubectl create -f cephcosidriver.yaml

The driver is created in the same namespace as Rook operator.

Admin Operations

Create a Ceph Object Store User

Create a CephObjectStoreUser to be used by the COSI driver for provisioning buckets.

apiVersion: ceph.rook.io/v1
kind: CephObjectStoreUser
metadata:
  name: cosi
  namespace: rook-ceph
spec:
  displayName: "cosi user"
  store: my-store
  capabilities:
    bucket: "*"
    user: "*"
kubectl create -f cosi-user.yaml

Above step will be automated in future by the Rook operator.

Create a BucketClass and BucketAccessClass

The BucketClass and BucketAccessClass are CRDs defined by COSI. The BucketClass defines the storage class for the bucket. The BucketAccessClass defines the access class for the bucket. The BucketClass and BucketAccessClass are defined as below:

kind: BucketClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
  name: sample-bcc
driverName: ceph.objectstorage.k8s.io
deletionPolicy: Delete
parameters:
  objectStoreUserSecretName: rook-ceph-object-user-my-store-cosi
  objectStoreUserSecretNamespace: rook-ceph
---
kind: BucketAccessClass
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
  name: sample-bac
driverName: ceph.objectstorage.k8s.io
authenticationType: KEY
parameters:
  objectStoreUserSecretName: rook-ceph-object-user-my-store-cosi
  objectStoreUserSecretNamespace: rook-ceph
kubectl create -f bucketclass.yaml -f bucketaccessclass.yaml

The objectStoreUserSecretName and objectStoreUserSecretNamespace are the name and namespace of the CephObjectStoreUser created in the previous step.

User Operations

Create a Bucket

To create a bucket, use the BucketClass to pointing the required object store and then define BucketClaim request as below:

1
2
3
4
5
6
7
8
9
kind: BucketClaim
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
  name: sample-bc
  namespace: default # any namespace can be used
spec:
  bucketClassName: sample-bcc
  protocols:
    - s3
kubectl create -f bucketclaim.yaml

Bucket Access

Define access to the bucket by creating the BucketAccess resource:

kind: BucketAccess
apiVersion: objectstorage.k8s.io/v1alpha1
metadata:
  name: sample-access
  namespace: default # any namespace can be used
spec:
  bucketAccessClassName: sample-bac
  bucketClaimName: sample-bc
  protocol: s3
  # Change to the name of the secret where access details are stored
  credentialsSecretName: sample-secret-name
kubectl create -f bucketaccess.yaml

The secret will be created which contains the access details for the bucket in JSON format in the namespace of BucketAccess:

kubectl get secret sample-secret-name -o yaml
{
  "metadata": {
    "name": "bc-81733d1a-ac7a-4759-96f3-fbcc07c0cee9",
    "creationTimestamp": null
  },
  "spec": {
    "bucketName": "sample-bcc1fc94b04-6011-45e0-a3d8-b6a093055783",
    "authenticationType": "KEY",
    "secretS3": {
      "endpoint": "http://rook-ceph-rgw-my-store.rook-ceph.svc:80",
      "region": "us-east",
      "accessKeyID": "LI2LES8QMR9GB5SZLB02",
      "accessSecretKey": "s0WAmcn8N1eIBgNV0mjCwZWQmJiCF4B0SAzbhYCL"
    },
    "secretAzure": null,
    "protocols": [
      "s3"
    ]
  }
}

Consuming the Bucket via secret

To access the bucket from an application pod, mount the secret for accessing the bucket:

  volumes:
  - name: cosi-secrets
    secret:
      #  Set the name of the secret from the BucketAccess
      secretName: sample-secret-name
  spec:
    containers:
    - name: sample-app
      volumeMounts:
      - name: cosi-secrets
        mountPath: /data/cosi

The Secret will be mounted in the pod in the path: /data/cosi/BucketInfo. The app must parse the JSON object to load the bucket connection details.

Another approach is the json data can be parsed by the application to access the bucket via init container. Following is a sample init container which parses the json data and creates a file with the access details:

set -e

jsonfile=%s

if [ -d "$jsonfile" ]; then
    export ENDPOINT=$(jq -r '.spec.secretS3.endpoint' $jsonfile)
    export BUCKET=$(jq -r '.spec.bucketName' $jsonfile)
    export AWS_ACCESS_KEY_ID=$(jq -r '.spec.secretS3.accessKeyID' $jsonfile)
    export AWS_SECRET_ACCESS_KEY=$(jq -r '.spec.secretS3.accessSecretKey' $jsonfile)
fi
else
    echo "Error: $jsonfile does not exist"
    exit 1
fi
apiVersion: v1
kind: Pod
metadata:
  name: sample-app
  namespace: rook-ceph
spec:
  containers:
  - name: sample-app
    image: busybox
    command: ["/bin/sh", "-c", "sleep 3600"]
    volumeMounts:
    - name: cosi-secrets
      mountPath: /data/cosi
  initContainers:
  - name: init-cosi
    image: busybox
    command: ["/bin/sh", "-c", "setup-aws-credentials /data/cosi/BucketInfo/credentials"]
    volumeMounts:
    - name: cosi-secrets
      mountPath: /data/cosi
  volumes:
  - name: cosi-secrets
    secret:
      #  Set the name of the secret from the BucketAccess
      secretName: sample-secret-name