# Kubernetes

Tigris is S3-compatible, so any Kubernetes workload that uses S3 works with Tigris. There are two ways to connect:

| Approach                                                  | Use when                                       | How it works                                      |
| --------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------- |
| [**Environment variables**](#environment-variables)       | Your app uses an S3 SDK (boto3, AWS SDK, etc.) | Store credentials in a Secret, inject as env vars |
| [**Filesystem mount (CSI-S3)**](#filesystem-mount-csi-s3) | Your app reads/writes files from disk          | Mount a Tigris bucket as a PersistentVolume       |

## Environment variables[​](#environment-variables "Direct link to Environment variables")

Store your Tigris credentials in a Kubernetes Secret and inject them into your Deployment as environment variables. This is the most common approach.

### Create a bucket and access key[​](#create-a-bucket-and-access-key "Direct link to Create a bucket and access key")

1. Create a Tigris bucket at [storage.new](https://storage.new).
2. Create an access key in the [dashboard](https://console.storage.dev). Give it editor permissions on your bucket and copy the credentials.

### Create a Secret[​](#create-a-secret "Direct link to Create a Secret")

```
# secret-tigris-key-mybucket.yaml

apiVersion: v1

kind: Secret

metadata:

  name: tigris-key-mybucket

type: Opaque

stringData:

  AWS_ACCESS_KEY_ID: tid_*

  AWS_SECRET_ACCESS_KEY: tsec_*

  AWS_ENDPOINT_URL_S3: https://t3.storage.dev

  AWS_ENDPOINT_URL_IAM: https://iam.storage.dev

  AWS_REGION: auto

  BUCKET_NAME: mybucket
```

```
kubectl apply -f secret-tigris-key-mybucket.yaml
```

### Attach the Secret to your Deployment[​](#attach-the-secret-to-your-deployment "Direct link to Attach the Secret to your Deployment")

Reference the Secret in your container spec using `envFrom`:

```
# deployment-myapp.yaml

# inside the spec field of a apps/v1 Deployment

containers:

  - name: web

    image: myuser/myimage

    envFrom:

      - secretRef:

          name: tigris-key-mybucket
```

```
kubectl apply -f deployment-myapp.yaml
```

Your application can now use any S3 SDK to read and write objects in Tigris.

## Filesystem mount (CSI-S3)[​](#filesystem-mount-csi-s3 "Direct link to Filesystem mount (CSI-S3)")

Use [csi-s3](https://github.com/yandex-cloud/k8s-csi-s3) to mount a Tigris bucket as a PersistentVolume. This is useful for workloads that expect a filesystem rather than an S3 API. The driver supports ReadWriteMany access, so multiple Pods across multiple Nodes can use the same bucket.

tip

For workloads that need more control over caching and performance tuning (such as AI/ML training), consider [TigrisFS](/docs/training/tigrisfs/.md) instead. TigrisFS is a Tigris-optimized FUSE filesystem with configurable memory limits, flusher threads, and metadata cache TTLs. It requires manual setup per node rather than a CSI driver, but gives you fine-grained control over I/O behavior.

### Install csi-s3[​](#install-csi-s3 "Direct link to Install csi-s3")

If you don't already have Helm installed:

```
brew install helm
```

Create an access key in the [Tigris dashboard](https://console.storage.dev), then install the csi-s3 Helm chart:

```
helm repo add yandex-s3 https://yandex-cloud.github.io/k8s-csi-s3/charts



helm install csi-s3 yandex-s3/csi-s3 \

  --set secret.accessKey=tid_... \

  --set secret.secretKey=tsec_... \

  --set secret.endpoint=https://t3.storage.dev \

  --set secret.region=auto \

  --set storageClass.name=tigris \

  --namespace=kube-system
```

### Use a dynamically created bucket[​](#use-a-dynamically-created-bucket "Direct link to Use a dynamically created bucket")

Create a PersistentVolumeClaim with the `tigris` StorageClass. Kubernetes will automatically create a new Tigris bucket:

```
apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: infinite-storage

  namespace: default

spec:

  accessModes:

    - ReadWriteMany

    - ReadWriteOnce

  resources:

    requests:

      storage: 5Gi

  storageClassName: tigris
```

Mount it in a Pod or Deployment:

```
apiVersion: v1

kind: Pod

metadata:

  name: tigris-test-nginx

  namespace: default

spec:

  containers:

    - name: www

      image: nginx

      volumeMounts:

        - mountPath: /usr/share/nginx/html

          name: webroot

  volumes:

    - name: webroot

      persistentVolumeClaim:

        claimName: infinite-storage

        readOnly: false
```

The bucket name will match the PersistentVolume name assigned by Kubernetes (e.g. `pvc-836006cd-f687-4819-92b9-6ff0fb908d61`).

### Test the mount[​](#test-the-mount "Direct link to Test the mount")

To verify the volume is working, upload a test file and serve it with nginx. Create an `index.html`:

```
<title>Test!</title>

<h1>Test!</h1>

<p>If you see this, then csi-s3 works!</p>
```

Port-forward the pod:

```
kubectl port-forward pod/tigris-test-nginx 8080:80
```

Open <http://localhost:8080> in your browser. You should see the test page:

![csi-s3 test page served from Tigris](data:image/webp;base64,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)

### Use an existing bucket[​](#use-an-existing-bucket "Direct link to Use an existing bucket")

To mount a bucket that already exists, create both a PersistentVolume and a PersistentVolumeClaim. These must be created at the same time so Kubernetes establishes the bidirectional link between them.

```
apiVersion: v1

kind: PersistentVolume

metadata:

  name: mybucket

spec:

  storageClassName: tigris

  capacity:

    storage: 10Ti

  accessModes:

    - ReadWriteMany

  claimRef:

    namespace: default

    name: mybucket

  csi:

    driver: ru.yandex.s3.csi

    controllerPublishSecretRef:

      name: csi-s3-secret

      namespace: csi-s3

    nodePublishSecretRef:

      name: csi-s3-secret

      namespace: csi-s3

    nodeStageSecretRef:

      name: csi-s3-secret

      namespace: csi-s3

    volumeAttributes:

      capacity: 10Ti

      mounter: geesefs

      options: --memory-limit 1000 --dir-mode 0777 --file-mode 0666

    volumeHandle: mybucket

---

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: mybucket

spec:

  storageClassName: "tigris"

  resources:

    requests:

      storage: 10Ti

  volumeMode: Filesystem

  accessModes:

    - ReadWriteMany

  volumeName: mybucket
```

Then mount it in your Pod or Deployment the same way as above, using `claimName: mybucket`.
