Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 126 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,23 @@ A Kubernetes operator for deploying Valkey, Valkey Clusters and managing its lif

## Description

Valkey Operator is a Kubernetes operator that automates the deployment and management of Valkey, a secure and scalable key management solution. The operator simplifies the process of deploying Valkey on Kubernetes clusters, ensuring that it is configured correctly and operates efficiently. It provides features such as automated installation, configuration management, and lifecycle management of Valkey instances.
Valkey Operator is a Kubernetes operator that automates the deployment and management of Valkey clusters with optional persistent storage support. The operator simplifies the process of deploying Valkey on Kubernetes clusters, ensuring that it is configured correctly and operates efficiently.

### Key Features

- 🚀 **Automated Cluster Management** - Deploy and manage Valkey clusters with configurable shards and replicas
- 💾 **Persistent Storage Support** - Optional PersistentVolume support for data durability
- 🔒 **Security Hardened** - Non-root containers, security contexts, and volume permissions
- 📊 **Metrics Export** - Built-in Prometheus metrics exporter
- 🔄 **High Availability** - Multi-shard clusters with replica support
- ⚙️ **Flexible Configuration** - Resource limits, tolerations, node selectors, and affinity rules

### Storage Modes

The operator supports two storage modes:

- **Ephemeral Storage (Default)** - Uses emptyDir for temporary storage, suitable for caching workloads
- **Persistent Storage** - Uses PersistentVolumeClaims with configurable size and storage class for production workloads

> **⚠️ EARLY DEVELOPMENT NOTICE**
>
Expand Down Expand Up @@ -62,7 +78,115 @@ make deploy IMG=<some-registry>/valkey-operator:tag
You can apply the samples (examples) from the config/sample:

```sh
kubectl apply -k config/samples/
# Deploy with persistent storage (production)
kubectl apply -f config/samples/v1alpha1_valkeycluster.yaml

# OR deploy with ephemeral storage (dev/test)
kubectl apply -f config/samples/v1alpha1_valkeycluster_ephemeral.yaml
```

### Example Configurations

#### Persistent Storage (Production)

```yaml
apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
name: valkey-prod
spec:
shards: 3
replicas: 2
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
storage:
enabled: true
size: "10Gi"
storageClassName: "gp3" # AWS EBS gp3
accessModes:
- ReadWriteOnce
volumePermissions: true # Recommended for persistent storage
```

#### Ephemeral Storage (Dev/Test)

```yaml
apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
name: valkey-dev
spec:
shards: 3
replicas: 1
resources:
requests:
memory: "256Mi"
cpu: "100m"
# storage section omitted - uses emptyDir
```

### Deploying to AWS EKS

1. **Configure AWS credentials and kubectl context:**

```sh
aws eks update-kubeconfig --region us-east-1 --name your-cluster-name
```

2. **Build and push the operator image:**

```sh
# Set your Docker registry
export IMG=<your-dockerhub-username>/valkey-operator:latest

# Build for AMD64 (EKS)
make docker-buildx PLATFORMS=linux/amd64

# Or build and push separately
docker buildx build --platform linux/amd64 -t ${IMG} --push .
```

3. **Install CRDs and deploy the operator:**

```sh
make install
make deploy IMG=${IMG}
```

4. **Create a ValkeyCluster with EBS storage:**

```yaml
apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
name: valkey-eks
spec:
shards: 3
replicas: 2
storage:
enabled: true
size: "20Gi"
storageClassName: "gp3" # EBS gp3 storage class
volumePermissions: true
```

5. **Verify deployment:**

```sh
# Check operator pod
kubectl get pods -n valkey-operator-system

# Check ValkeyCluster status
kubectl get valkeycluster
kubectl describe valkeycluster valkey-eks

# Check pods and PVCs
kubectl get pods,pvc -l app.kubernetes.io/name=valkey
```

> **NOTE**: Ensure that the samples has default values to test it out.
Expand Down
34 changes: 34 additions & 0 deletions api/v1alpha1/valkeycluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,38 @@ type ValkeyClusterSpec struct {
// +kubebuilder:default:={enabled:true}
// +optional
Exporter ExporterSpec `json:"exporter,omitempty"`

// PersistentVolume configuration for data persistence
// +optional
Storage StorageSpec `json:"storage,omitempty"`

// VolumePermissions enables an init container to set proper ownership on the data volume
// Required when using persistent storage with non-root security contexts
// +kubebuilder:default=false
// +optional
VolumePermissions bool `json:"volumePermissions,omitempty"`
}

type StorageSpec struct {
// Enable persistent storage for Valkey data
// +kubebuilder:default=false
// +optional
Enabled bool `json:"enabled,omitempty"`

// StorageClassName is the name of the StorageClass to use for PersistentVolumeClaims
// If not specified, the default StorageClass will be used
// +optional
StorageClassName *string `json:"storageClassName,omitempty"`

// Size of the persistent volume claim
// +kubebuilder:default="1Gi"
// +optional
Size string `json:"size,omitempty"`

// AccessModes contains the desired access modes for the volume
// +kubebuilder:default={"ReadWriteOnce"}
// +optional
AccessModes []corev1.PersistentVolumeAccessMode `json:"accessModes,omitempty"`
}

type ExporterSpec struct {
Expand Down Expand Up @@ -154,6 +186,8 @@ const (
ReasonSlotsUnassigned = "SlotsUnassigned"
ReasonPrimaryLost = "PrimaryLost"
ReasonNoSlots = "NoSlotsAvailable"
ReasonVolumeExpanding = "VolumeExpanding"
ReasonVolumeExpanded = "VolumeExpanded"
)

// +kubebuilder:object:root=true
Expand Down
26 changes: 26 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions config/crd/bases/valkey.io_valkeyclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,31 @@ spec:
format: int32
minimum: 1
type: integer
storage:
description: PersistentVolume configuration for data persistence
properties:
accessModes:
default:
- ReadWriteOnce
description: AccessModes contains the desired access modes for
the volume
items:
type: string
type: array
enabled:
default: false
description: Enable persistent storage for Valkey data
type: boolean
size:
default: 1Gi
description: Size of the persistent volume claim
type: string
storageClassName:
description: |-
StorageClassName is the name of the StorageClass to use for PersistentVolumeClaims
If not specified, the default StorageClass will be used
type: string
type: object
tolerations:
description: Tolerations to apply to the pods
items:
Expand Down Expand Up @@ -1164,6 +1189,12 @@ spec:
type: string
type: object
type: array
volumePermissions:
default: false
description: |-
VolumePermissions enables an init container to set proper ownership on the data volume
Required when using persistent storage with non-root security contexts
type: boolean
type: object
status:
default:
Expand Down
2 changes: 1 addition & 1 deletion config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ spec:
args:
- --leader-elect
- --health-probe-bind-address=:8081
image: controller:latest
image: umarriswan/valkey-operator:latest
name: manager
ports: []
securityContext:
Expand Down
10 changes: 10 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ rules:
- ""
resources:
- configmaps
- persistentvolumeclaims
- services
verbs:
- create
Expand All @@ -29,6 +30,7 @@ rules:
- apps
resources:
- deployments
- statefulsets
verbs:
- create
- delete
Expand All @@ -44,6 +46,14 @@ rules:
verbs:
- create
- patch
- apiGroups:
- storage.k8s.io
resources:
- storageclasses
verbs:
- get
- list
- watch
- apiGroups:
- valkey.io
resources:
Expand Down
1 change: 1 addition & 0 deletions config/samples/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Append samples of your project ##
resources:
- v1alpha1_valkeycluster.yaml
- v1alpha1_valkeycluster_ephemeral.yaml
# +kubebuilder:scaffold:manifestskustomizesamples
8 changes: 8 additions & 0 deletions config/samples/v1alpha1_valkeycluster.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ spec:
limits:
memory: "512Mi"
cpu: "500m"
storage:
enabled: true
size: "2Gi"
# storageClassName: standard # Uncomment to specify a StorageClass
accessModes:
- ReadWriteOnce
# Enable init container to fix volume permissions (recommended for persistent storage)
volumePermissions: true
21 changes: 21 additions & 0 deletions config/samples/v1alpha1_valkeycluster_ephemeral.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: valkey.io/v1alpha1
kind: ValkeyCluster
metadata:
name: valkeycluster-ephemeral
spec:
shards: 3
replicas: 1
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
# Storage section omitted - uses ephemeral storage (emptyDir)
# This is suitable for:
# - Development/testing environments
# - Cache-only workloads where data loss is acceptable
# - Temporary clusters
#
# Note: Data will be lost when pods are deleted or restarted
Loading