Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Persistence to Redis pods #68

Merged
merged 8 commits into from
Jul 18, 2018
Merged
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION := 0.3.0
VERSION := 0.4.0

# Name of this service/application
SERVICE_NAME := redis-operator
Expand Down Expand Up @@ -144,6 +144,6 @@ endif

# Generate kubernetes code for types..
.PHONY: update-codegen
update-codegen: build
update-codegen: docker-build
@echo ">> Generating code for Kubernetes CRD types..."
docker run --rm -v $(PWD):/go/src/github.com/spotahome/redis-operator/ $(REPOSITORY)-dev /bin/bash -c '$(UPDATE_CODEGEN_CMD)'
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ helm install --name redisfailover charts/redisoperator
## Usage
Once the operator is deployed inside a Kubernetes cluster, a new API will be accesible, so you'll be able to create, update and delete redisfailovers.

In order to deploy a new redis-failover a [specification](example/redisfailover.yaml) has to be created:
In order to deploy a new redis-failover a [specification](example/redisfailover/all-options.yaml) has to be created:
```
kubectl create -f https://raw.githubusercontent.com/spotahome/redis-operator/master/example/redisfailover.yaml
kubectl create -f https://raw.githubusercontent.com/spotahome/redis-operator/master/redisfailover/all-options.yaml
```

This redis-failover will be managed by the operator, resulting in the following elements created inside Kubernetes:
Expand All @@ -51,6 +51,13 @@ This redis-failover will be managed by the operator, resulting in the following

**NOTE**: `NAME` is the named provided when creating the RedisFailover.

### Persistance
The operator has the ability of add persistance to Redis data. By default an `emptyDir` will be used, so the data is not saved.

In order to have persistance, a PersistentVolumeClaim usage is allowed. The full [PVC definition has to be added](example/redisfailover/persistant-storage.yaml) to the Redis Failover Spec under the `Storage` section.

**IMPORTANT**: By default, the persistent volume claims will be deleted when the Redis Failover is. If this is not the expected usage, a `keepAfterDeletion` flag can be added under the `storage` section of Redis. [An example is given](example/redisfailover/persistant-storage-no-pvc-deletion.yaml).

### Connection
In order to connect to the redis-failover and use it, a [Sentinel-ready](https://redis.io/topics/sentinel-clients) library has to be used. This will connect through the Sentinel service to the Redis node working as a master.
The connection parameters are the following:
Expand Down
9 changes: 8 additions & 1 deletion api/redisfailover/v1alpha2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type RedisSettings struct {
Image string `json:"image,omitempty"`
Version string `json:"version,omitempty"`
ConfigMap string `json:"configMap,omitempty"`
DataVolume corev1.Volume `json:"dataVolume,omitempty"`
Storage RedisStorage `json:"storage,omitempty"`
}

// SentinelSettings defines the specification of the sentinel cluster
Expand All @@ -65,6 +65,13 @@ type CPUAndMem struct {
Memory string `json:"memory"`
}

// RedisStorage defines the structure used to store the Redis Data
type RedisStorage struct {
KeepAfterDeletion bool `json:"keepAfterDeletion,omitempty"`
EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"`
PersistentVolumeClaim *corev1.PersistentVolumeClaim `json:"persistentVolumeClaim,omitempty"`
}

// RedisFailoverStatus has the status of the cluster
type RedisFailoverStatus struct {
Phase Phase `json:"phase"`
Expand Down
36 changes: 35 additions & 1 deletion api/redisfailover/v1alpha2/zz_generated.deepcopy.go

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

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ spec:
exporter: false # Optional. False by default. Adds a redis-exporter container to export metrics.
exporterImage: oliver006/redis_exporter # Optional. oliver006/redis_exporter by default.
exporterVersion: v0.11.3 # Optional. v0.11.3 by default.
dataVolume:
name: redis-data
emptyDir: {}
storage:
emptyDir: {} # Optional. emptyDir by default.

File renamed without changes.
21 changes: 21 additions & 0 deletions example/redisfailover/persistant-storage-no-pvc-deletion.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: storage.spotahome.com/v1alpha2
kind: RedisFailover
metadata:
name: redisfailover-persistant-keep
spec:
sentinel:
replicas: 3
redis:
replicas: 3
storage:
keepAfterDeletion: true
persistentVolumeClaim:
metadata:
name: redisfailover-persistant-keep-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

20 changes: 20 additions & 0 deletions example/redisfailover/persistant-storage.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: storage.spotahome.com/v1alpha2
kind: RedisFailover
metadata:
name: redisfailover-persistant
spec:
sentinel:
replicas: 3
redis:
replicas: 3
storage:
persistentVolumeClaim:
metadata:
name: redisfailover-persistant-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

69 changes: 57 additions & 12 deletions operator/redisfailover/service/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import (
"github.com/spotahome/redis-operator/operator/redisfailover/util"
)

const (
redisConfigurationVolumeName = "redis-config"
redisStorageVolumeName = "redis-data"
)

func generateSentinelService(rf *redisfailoverv1alpha2.RedisFailover, labels map[string]string, ownerRefs []metav1.OwnerReference) *corev1.Service {
name := GetSentinelName(rf)
namespace := rf.Namespace
Expand Down Expand Up @@ -205,6 +210,16 @@ func generateRedisStatefulSet(rf *redisfailoverv1alpha2.RedisFailover, labels ma
},
}

if rf.Spec.Redis.Storage.PersistentVolumeClaim != nil {
if !rf.Spec.Redis.Storage.KeepAfterDeletion {
// Set an owner reference so the persistent volumes are deleted when the RF is
rf.Spec.Redis.Storage.PersistentVolumeClaim.OwnerReferences = ownerRefs
}
ss.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{
*rf.Spec.Redis.Storage.PersistentVolumeClaim,
}
}

if rf.Spec.Redis.Exporter {
exporter := createRedisExporterContainer(rf)
ss.Spec.Template.Spec.Containers = append(ss.Spec.Template.Spec.Containers, exporter)
Expand Down Expand Up @@ -523,17 +538,13 @@ func getRedisExporterImage(rf *redisfailoverv1alpha2.RedisFailover) string {
func getRedisVolumeMounts(rf *redisfailoverv1alpha2.RedisFailover) []corev1.VolumeMount {
volumeMounts := []corev1.VolumeMount{
{
Name: "redis-config",
Name: redisConfigurationVolumeName,
MountPath: "/redis",
},
}

// check if data volume is set, if set, mount to /data
if rf.Spec.Redis.DataVolume.Name != "" {
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Name: rf.Spec.Redis.DataVolume.Name,
{
Name: getRedisDataVolumeName(rf),
MountPath: "/data",
})
},
}

return volumeMounts
Expand All @@ -544,7 +555,7 @@ func getRedisVolumes(rf *redisfailoverv1alpha2.RedisFailover) []corev1.Volume {

volumes := []corev1.Volume{
{
Name: "redis-config",
Name: redisConfigurationVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Expand All @@ -555,10 +566,44 @@ func getRedisVolumes(rf *redisfailoverv1alpha2.RedisFailover) []corev1.Volume {
},
}

// check if data volume is set, if not set skip it
if rf.Spec.Redis.DataVolume.Name != "" {
volumes = append(volumes, rf.Spec.Redis.DataVolume)
dataVolume := getRedisDataVolume(rf)
if dataVolume != nil {
volumes = append(volumes, *dataVolume)
}

return volumes
}

func getRedisDataVolume(rf *redisfailoverv1alpha2.RedisFailover) *corev1.Volume {
// This will find the volumed desired by the user. If no volume defined
// an EmptyDir will be used by default
switch {
case rf.Spec.Redis.Storage.PersistentVolumeClaim != nil:
return nil
case rf.Spec.Redis.Storage.EmptyDir != nil:
return &corev1.Volume{
Name: redisStorageVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: rf.Spec.Redis.Storage.EmptyDir,
},
}
default:
return &corev1.Volume{
Name: redisStorageVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
}
}
}

func getRedisDataVolumeName(rf *redisfailoverv1alpha2.RedisFailover) string {
switch {
case rf.Spec.Redis.Storage.PersistentVolumeClaim != nil:
return rf.Spec.Redis.Storage.PersistentVolumeClaim.Name
case rf.Spec.Redis.Storage.EmptyDir != nil:
return redisStorageVolumeName
default:
return redisStorageVolumeName
}
}
Loading