S3-Compatible Object Storage on Kubernetes
A Kubernetes operator for Garage - distributed, self-hosted object storage with multi-cluster federation.
helm install garage-operator oci://ghcr.io/rajsinghtech/charts/garage-operator \
--namespace garage-operator-system \
--create-namespaceFirst, create an admin token secret for the operator to manage Garage resources:
kubectl create secret generic garage-admin-token \
--from-literal=admin-token=$(openssl rand -hex 32)Create a 3-node Garage cluster:
apiVersion: garage.rajsingh.info/v1alpha1
kind: GarageCluster
metadata:
name: garage
spec:
replicas: 3
zone: us-east-1
replication:
factor: 3
storage:
data:
size: 100Gi
network:
rpcBindPort: 3901
service:
type: ClusterIP
admin:
enabled: true
bindPort: 3903
adminTokenSecretRef:
name: garage-admin-token
key: admin-tokenWait for the cluster to be ready:
kubectl wait --for=condition=Ready garagecluster/garage --timeout=300sCreate a bucket:
apiVersion: garage.rajsingh.info/v1alpha1
kind: GarageBucket
metadata:
name: my-bucket
spec:
clusterRef:
name: garage
quotas:
maxSize: 10GiCreate access credentials:
apiVersion: garage.rajsingh.info/v1alpha1
kind: GarageKey
metadata:
name: my-key
spec:
clusterRef:
name: garage
bucketPermissions:
- bucketRef: my-bucket
read: true
write: trueGet S3 credentials:
kubectl get secret my-key -o jsonpath='{.data.access-key-id}' | base64 -d && echo
kubectl get secret my-key -o jsonpath='{.data.secret-access-key}' | base64 -d && echo
kubectl get secret my-key -o jsonpath='{.data.endpoint}' | base64 -d && echoGateway clusters handle S3 API requests without storing data. They connect to a storage cluster and scale independently, ideal for edge deployments or handling high request volumes.
apiVersion: garage.rajsingh.info/v1alpha1
kind: GarageCluster
metadata:
name: garage-gateway
spec:
replicas: 5
gateway: true
connectTo:
clusterRef:
name: garage # Reference to storage cluster
replication:
factor: 3 # Must match storage cluster
admin:
enabled: true
adminTokenSecretRef:
name: garage-admin-token
key: admin-tokenKey differences from storage clusters:
- Creates a Deployment instead of StatefulSet (no PVCs needed)
- Registers pods as gateway nodes in the layout (capacity=null)
- Requires
connectToto reference a storage cluster - Lightweight and horizontally scalable
For cross-namespace or external storage clusters, use rpcSecretRef and adminApiEndpoint:
connectTo:
rpcSecretRef:
name: garage-rpc-secret
key: rpc-secret
adminApiEndpoint: "http://garage.storage-namespace.svc.cluster.local:3903"
adminTokenSecretRef:
name: storage-admin-token
key: admin-tokenThe operator includes an optional COSI (Container Object Storage Interface) driver that provides Kubernetes-native object storage provisioning.
-
Install the COSI CRDs:
for crd in bucketclaims bucketaccesses bucketclasses bucketaccessclasses buckets; do kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/container-object-storage-interface/main/client/config/crd/objectstorage.k8s.io_${crd}.yaml" done
-
Deploy the COSI controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/container-object-storage-interface/main/deploy/controller/controller.yaml
-
Install the operator with COSI enabled:
helm install garage-operator oci://ghcr.io/rajsinghtech/charts/garage-operator \ --namespace garage-operator-system \ --create-namespace \ --set cosi.enabled=true
-
Create a BucketClass:
apiVersion: objectstorage.k8s.io/v1alpha2 kind: BucketClass metadata: name: garage-standard spec: driverName: garage.rajsingh.info deletionPolicy: Delete parameters: clusterRef: garage clusterNamespace: garage-operator-system
-
Create a BucketAccessClass:
apiVersion: objectstorage.k8s.io/v1alpha2 kind: BucketAccessClass metadata: name: garage-readwrite spec: driverName: garage.rajsingh.info authenticationType: Key parameters: clusterRef: garage clusterNamespace: garage-operator-system
-
Request a bucket:
apiVersion: objectstorage.k8s.io/v1alpha2 kind: BucketClaim metadata: name: my-bucket spec: bucketClassName: garage-standard protocols: - S3
-
Request access credentials:
apiVersion: objectstorage.k8s.io/v1alpha2 kind: BucketAccess metadata: name: my-bucket-access spec: bucketAccessClassName: garage-readwrite bucketClaimName: my-bucket credentialsSecretName: my-bucket-creds protocol: S3
-
Use the credentials in your application:
env: - name: S3_ENDPOINT valueFrom: secretKeyRef: name: my-bucket-creds key: COSI_S3_ENDPOINT - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: name: my-bucket-creds key: COSI_S3_ACCESS_KEY_ID - name: AWS_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: my-bucket-creds key: COSI_S3_ACCESS_SECRET_KEY
- Only S3 protocol is supported
- Only Key authentication is supported (no IAM)
- Bucket deletion requires the bucket to be empty first
- Helm Chart - Installation and configuration
- Garage Docs - Garage project documentation
make dev-up # Start kind cluster with operator
make dev-test # Apply test resources
make dev-status # View cluster status
make dev-logs # Stream operator logs
make dev-down # Tear down