Pular para o conteúdo principal

EBS Persistent Storage

orka'i provisions Kubernetes PersistentVolumeClaims (PVCs) for application volumes, managed databases, and the in-cluster registry. By default, PVCs use whatever StorageClass the cluster marks as default — on local dev that is usually local-path (node-local disk, not durable across node loss).

To use AWS EBS (durable block storage), you install the EBS CSI driver on your cluster, create a StorageClass (for example gp3), and tell orka'i which class to use. orka'i never calls the EC2 API directly; the CSI driver provisions and attaches volumes when PVCs are created.

This works on Amazon EKS and self-managed K3s on EC2. You do not need EKS specifically — any Kubernetes cluster whose worker nodes are EC2 instances in AWS can use EBS through the same CSI stack.

How it works

orka'i API → PVC (storageClassName: gp3) → EBS CSI driver → EBS volume → pod mount
  1. orka'i creates a PVC with storageClassName set from the deploy target config.
  2. The AWS EBS CSI driver (ebs.csi.aws.com) provisions an EBS volume in the same region.
  3. Kubernetes schedules the pod on a node in the volume's availability zone and attaches the disk.

Prerequisites

RequirementNotes
EC2 worker nodesEBS volumes attach to EC2 instances in the same AWS region
EBS CSI driveraws-ebs-csi-driver — EKS addon or Helm on K3s
IAM permissionsCSI controller needs CreateVolume, AttachVolume, DetachVolume, DeleteVolume, etc.
StorageClasse.g. gp3 with allowVolumeExpansion: true
orka'i migrationDeploy target config column (included in recent releases)

Not applicable: local dev K3s in Docker (make docker-up) — nodes are not EC2-backed, so EBS cannot attach. Use the cluster default (local-path) for development.

Step 1 — Install the AWS EBS CSI driver

Choose the path that matches your cluster.

Amazon EKS

Install the managed addon (replace cluster name and region):

aws eks create-addon \
--cluster-name my-cluster \
--addon-name aws-ebs-csi-driver \
--region us-east-1

Configure IAM Roles for Service Accounts (IRSA) so the CSI controller can manage EBS volumes. AWS documents the exact trust policy and IAM policy for the ebs-csi-controller-sa service account in the EBS CSI driver docs.

K3s on EC2

Install the driver with Helm on a cluster that already has worker nodes on EC2:

helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
helm repo update

helm upgrade --install aws-ebs-csi-driver aws-ebs-csi-driver/aws-ebs-csi-driver \
--namespace kube-system \
--set controller.serviceAccount.create=true \
--set controller.serviceAccount.name=ebs-csi-controller-sa

Grant IAM permissions via the EC2 instance profile attached to each node (or IRSA if your K3s cluster has OIDC configured). The node role needs the permissions listed in the AWS EBS CSI driver IAM policy.

Verify the controller is running:

kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver

Step 2 — Create a StorageClass

Apply a StorageClass that uses the EBS CSI provisioner. This example creates gp3 with encryption and volume expansion enabled:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
type: gp3
encrypted: "true"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

Save as gp3-storageclass.yaml and apply:

kubectl apply -f gp3-storageclass.yaml

WaitForFirstConsumer delays provisioning until a pod is scheduled, which helps place the volume in the correct availability zone.

You can omit the default-class annotation if you prefer to set the class only in orka'i (see Step 3).

List StorageClasses to confirm:

kubectl get storageclass

Step 3 — Configure orka'i

orka'i reads the default StorageClass from the deploy target config in Postgres. After running migrations, set default_storage_class on your default target:

UPDATE deploy_targets
SET config = jsonb_set(
COALESCE(config, '{}'::jsonb),
'{default_storage_class}',
'"gp3"'
)
WHERE is_default = true;

Or replace the whole config object:

UPDATE deploy_targets
SET config = '{"default_storage_class": "gp3"}'::jsonb
WHERE id = '00000000-0000-4000-8000-000000000001';

Restart the orka'i API (and worker, if running) so bootstrap reloads the target config:

# however you run orka'i in your environment, e.g.
systemctl restart orkai-api

When default_storage_class is empty, orka'i omits storageClassName on PVCs and the cluster default applies — same behavior as before this feature.

What gets EBS-backed

Once configured, new PVCs created by orka'i use the configured class:

WorkloadPVC name pattern
App volume{k8s-name}-{volume-name}
Managed database{k8s-name}-data
In-cluster registryregistry-data (namespace orkai-system)

Existing PVCs are not retroactively changed. Only newly created claims pick up the StorageClass.

Step 4 — Verify

Create an app volume from the UI (Project → App → Volumes), save, and redeploy. Then inspect the PVC:

kubectl get pvc -A
kubectl describe pvc <pvc-name> -n <namespace>

You should see:

  • StorageClass: gp3
  • Status: Bound
  • A VolumeHandle pointing at an EBS volume ID (vol-…)

In the AWS console, confirm an EBS volume exists in the same region and AZ as the scheduled pod.

Admin → Infrastructure → Volumes in orka'i also shows storage_class on each PVC.

Volume expansion

If the StorageClass has allowVolumeExpansion: true (recommended), you can grow PVCs from Admin → Infrastructure → Volumes or by increasing the size on an app volume and redeploying. EBS supports online expansion when the CSI driver and StorageClass allow it.

Size decreases are not supported by Kubernetes or EBS.

Operational notes

TopicImplication
Access modeorka'i uses ReadWriteOnce only — one node per volume
Multi-replica appsEach replica needs its own volume, or use EFS for shared storage
Unmount vs deleteUnmounting from an app keeps the PVC; delete it from Admin → Volumes when no longer needed
AZ placementRWO EBS is AZ-scoped; pods must schedule in the volume's AZ. WaitForFirstConsumer helps
Reclaim policyControlled by the StorageClass (Delete vs Retain). Delete removes the EBS volume when the PVC is deleted

Troubleshooting

PVC stays Pending

  • CSI driver pods not running: kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver
  • IAM permissions missing on the CSI service account (EKS IRSA) or node instance role (K3s)
  • No StorageClass named gp3 (or whatever you configured in orka'i)
  • Insufficient EBS quota in the AWS account

Pod cannot mount volume

  • Pod scheduled in a different AZ than the EBS volume
  • Node lacks permission to attach volumes (ec2:AttachVolume)

orka'i still uses local-path

  • Deploy target config not set or API not restarted after the SQL update
  • Check: SELECT config FROM deploy_targets WHERE is_default = true;
  • PVC was created before config was applied — delete and recreate (data loss unless you snapshot first)

Other cloud providers

The same orka'i mechanism applies to any CSI-backed StorageClass — only the class name and cluster prerequisites change:

ProviderExample StorageClassCSI provisioner
AWS EBSgp3ebs.csi.aws.com
GCP Persistent Diskpd-ssdpd.csi.storage.gke.io
Azure Diskmanaged-csidisk.csi.azure.com

Set default_storage_class in the deploy target config to the class name defined in your cluster.

  • App volumes: Project → App → Volumes tab
  • Cluster-wide PVC list: Admin → Infrastructure → Volumes
  • Local development uses node-local storage; EBS requires EC2-backed nodes in AWS