Dynamic provisioning¶
Secrets¶
After acquiring service account keys, create 2 secrets (we'll call them csi-gcs-secret-mounter and csi-gcs-secret-creator in the following example):
kubectl create secret generic csi-gcs-secret-mounter --from-file=key=<PATH_TO_SERVICE_ACCOUNT_KEY_1>
kubectl create secret generic csi-gcs-secret-creator --from-file=key=<PATH_TO_SERVICE_ACCOUNT_KEY_2> --from-literal=projectId=csi-gcs
Usage¶
Let's run another example application!
kubectl apply -k "github.com/ofek/csi-gcs/examples/dynamic?ref=v0.9.0"
Confirm it's working by running
kubectl get pods,sc,pv,pvc
You should see something like
NAME READY STATUS RESTARTS AGE
pod/csi-gcs-test-5f677df9f9-qd8nt 2/2 Running 0 100s
NAME PROVISIONER AGE
storageclass.storage.k8s.io/csi-gcs gcs.csi.ofek.dev 100s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-906ed812-2c06-4eaa-a80e-7115e8ffd653 5Gi RWO Delete Bound default/csi-gcs-pvc csi-gcs 98s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/csi-gcs-pvc Bound pvc-906ed812-2c06-4eaa-a80e-7115e8ffd653 5Gi RWO csi-gcs 100s
Note the pod name, in this case csi-gcs-test-5f677df9f9-qd8nt. The pod in the example deployment has 2 containers: a writer and a reader.
Now create some data!
kubectl exec csi-gcs-test-5f677df9f9-qd8nt -c writer -- /bin/sh -c "echo Hello from Google Cloud Storage! > /data/test.txt"
Let's read what we just put in the bucket
$ kubectl exec csi-gcs-test-5f677df9f9-qd8nt -c reader -it -- /bin/sh
/ # ls -lh /data
total 1K
-rw-r--r-- 1 root root 33 May 26 21:23 test.txt
/ # cat /data/test.txt
Hello from Google Cloud Storage!
Notice that while the writer container's permission is completely governed by the mounter's service account key, the reader container is further restricted to read-only access
/ # touch /data/forbidden.txt
touch: /data/forbidden.txt: Read-only file system
To clean up everything, run the following commands
kubectl delete -f "https://github.com/ofek/csi-gcs/blob/v0.9.0/examples/dynamic/deployment.yaml"
kubectl delete -f "https://github.com/ofek/csi-gcs/blob/v0.9.0/examples/dynamic/pvc.yaml"
kubectl delete -f "https://github.com/ofek/csi-gcs/blob/v0.9.0/examples/dynamic/sc.yaml"
kubectl delete -k "github.com/ofek/csi-gcs/deploy/overlays/stable?ref=v0.9.0"
kubectl delete secret csi-gcs-secret-creator
kubectl delete secret csi-gcs-secret-mounter
Note
Cleanup is necessarily verbose until this is resolved.
Driver options¶
StorageClass is the resource type that enables dynamic provisioning.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: <STORAGE_CLASS_NAME>
provisioner: gcs.csi.ofek.dev
reclaimPolicy: Delete
parameters: ...
Storage Class Parameters¶
| Annotation | Description |
|---|---|
csi.storage.k8s.io/node-publish-secret-name | The name of the secret allowed to mount created buckets |
csi.storage.k8s.io/node-publish-secret-namespace | The namespace of the secret allowed to mount created buckets |
csi.storage.k8s.io/provisioner-secret-name | The name of the secret allowed to create buckets |
csi.storage.k8s.io/provisioner-secret-namespace | The namespace of the secret allowed to create buckets |
csi.storage.k8s.io/controller-expand-secret-name | The name of the secret allowed to expand bucket capacity |
csi.storage.k8s.io/controller-expand-secret-namespace | The namespace of the secret allowed to expand bucket capacity |
gcs.csi.ofek.dev/project-id | The project to create the buckets in. If not specified, projectId will be looked up in the provisioner's secret |
gcs.csi.ofek.dev/location | The location to create buckets at (default US multi-region) |
gcs.csi.ofek.dev/kms-key-id | (optional) KMS encryption key ID. (projects/my-pet-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key) |
gcs.csi.ofek.dev/max-retry-sleep | The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries. |
Tip
You may omit the secret definition and let the code automatically detect the service account key using standard heuristics.
Persistent Volume Claim Parameters¶
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations: ...
| Annotation | Description |
|---|---|
gcs.csi.ofek.dev/project-id | The project to create the buckets in. If not specified, projectId will be looked up in the provisioner's secret |
gcs.csi.ofek.dev/location | The location to create buckets at (default US multi-region) |
gcs.csi.ofek.dev/bucket | The name for the new bucket |
gcs.csi.ofek.dev/kms-key-id | (optional) KMS encryption key ID. (projects/my-pet-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key) |
gcs.csi.ofek.dev/max-retry-sleep | The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries. |
Persistent buckets¶
In our example, the dynamically created buckets are deleted during cleanup. If you want the buckets to not be ephemeral, you can set reclaimPolicy to Retain.
Extra flags¶
You can pass flags to gcsfuse. They will be forwarded to PersistentVolumeClaim.spec.csi.volumeAttributes.
The following flags are supported (ordered by precedence):
-
PersistentVolumeClaim.metadata.annotations
apiVersion: v1 kind: PersistentVolumeClaim metadata: annotations: gcs.csi.ofek.dev/gid: "63147" gcs.csi.ofek.dev/dir-mode: "0775" gcs.csi.ofek.dev/file-mode: "0664"Option Type Description gcs.csi.ofek.dev/dir-modeOctal Integer Permission bits for directories. (default: 0775) gcs.csi.ofek.dev/file-modeOctal Integer Permission bits for files. (default: 0664) gcs.csi.ofek.dev/gidInteger GID owner of all inodes. (default: 63147) gcs.csi.ofek.dev/uidInteger UID owner of all inodes. (default: -1) gcs.csi.ofek.dev/implicit-dirsFlag Implicitly define directories based on content. gcs.csi.ofek.dev/billing-projectText Project to use for billing when accessing requester pays buckets. gcs.csi.ofek.dev/limit-bytes-per-secInteger Bandwidth limit for reading data, measured over a 30-second window. The default is -1 (no limit). gcs.csi.ofek.dev/limit-ops-per-secInteger Operations per second limit, measured over a 30-second window. The default is 5. Use -1 for no limit. gcs.csi.ofek.dev/stat-cache-ttlText How long to cache StatObject results and inode attributes e.g. 1h.gcs.csi.ofek.dev/type-cache-ttlText How long to cache name -> file/dir mappings in directory inodes e.g. 1h.gcs.csi.ofek.dev/fuse-mount-optionsText[] Additional comma-separated system-specific mount options. Be careful! gcs.csi.ofek.dev/max-retry-sleepInteger The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries. -
StorageClass.parameters
apiVersion: storage.k8s.io/v1 kind: StorageClass parameters: gid: "63147" dirMode: "0775" fileMode: "0664"Option Type Description dirModeOctal Integer Permission bits for directories. (default: 0775) fileModeOctal Integer Permission bits for files. (default: 0664) gidInteger GID owner of all inodes. (default: 63147) uidInteger UID owner of all inodes. (default: -1) implicitDirsFlag Implicitly define directories based on content. billingProjectText Project to use for billing when accessing requester pays buckets. limitBytesPerSecInteger Bandwidth limit for reading data, measured over a 30-second window. The default is -1 (no limit). limitOpsPerSecInteger Operations per second limit, measured over a 30-second window. The default is 5. Use -1 for no limit. statCacheTTLText How long to cache StatObject results and inode attributes e.g. 1h.typeCacheTTLText How long to cache name -> file/dir mappings in directory inodes e.g. 1h.fuseMountOptionsText[] Additional comma-separated system-specific mount options. Be careful! maxRetrySleepInteger The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries. -
StorageClass.mountOptions
apiVersion: storage.k8s.io/v1 kind: StorageClass mountOptions: - --gid=63147 - --dir-mode=0775 - --file-mode=0664Option Type Description dir-modeOctal Integer Permission bits for directories. (default: 0775) file-modeOctal Integer Permission bits for files. (default: 0664) gidInteger GID owner of all inodes. (default: 63147) uidInteger UID owner of all inodes. (default: -1) implicit-dirsFlag Implicitly define directories based on content. billing-projectText Project to use for billing when accessing requester pays buckets. limit-bytes-per-secInteger Bandwidth limit for reading data, measured over a 30-second window. The default is -1 (no limit). limit-ops-per-secInteger Operations per second limit, measured over a 30-second window. The default is 5. Use -1 for no limit. stat-cache-ttlText How long to cache StatObject results and inode attributes e.g. 1h.type-cache-ttlText How long to cache name -> file/dir mappings in directory inodes e.g. 1h.fuse-mount-optionText Additional system-specific mount option. Be careful! max-retry-sleepInteger The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries. -
StorageClass.parameters."csi.storage.k8s.io/provisioner-secret-name"
Option Type Description dirModeOctal Integer Permission bits for directories, in octal. (default: 0775) fileModeOctal Integer Permission bits for files, in octal. (default: 0664) gidInteger GID owner of all inodes. (default: 63147) uidInteger UID owner of all inodes. (default: -1) implicitDirsFlag Implicitly define directories based on content. billingProjectText Project to use for billing when accessing requester pays buckets. limitBytesPerSecInteger Bandwidth limit for reading data, measured over a 30-second window. The default is -1 (no limit). limitOpsPerSecInteger Operations per second limit, measured over a 30-second window. The default is 5. Use -1 for no limit. statCacheTTLText How long to cache StatObject results and inode attributes e.g. 1h.typeCacheTTLText How long to cache name -> file/dir mappings in directory inodes e.g. 1h.fuseMountOptionsText[] Additional comma-separated system-specific mount options. Be careful! maxRetrySleepInteger The maximum duration allowed to sleep in a retry loop with exponential backoff for failed requests to GCS backend. Once the backoff duration exceeds this limit, the retry stops. The default is 1 minute. A value of 0 disables retries.
Permission¶
In order to access anything stored in GCS, you will need service accounts with appropriate IAM roles. You will usually assign the role roles/storage.admin.
The easiest way to create service account keys, if you don't yet have any, is to run:
gcloud iam service-accounts list
to find the email of a desired service account, then run:
gcloud iam service-accounts keys create <FILE_NAME>.json --iam-account <EMAIL>
to create a key file.
Mounter¶
The Node Plugin is the component that is actually mounting and serving buckets to pods. If writes are needed, you will usually select roles/storage.objectAdmin scoped to the desired buckets.
Creator¶
The Controller Plugin is the component that is in charge of creating buckets. The service account will need the storage.buckets.create Cloud IAM permission.