mirror of https://github.com/easzlab/kubeasz.git
增加helm部署redis-ha集群
parent
f9d0a49fd6
commit
f39ec34d7d
|
@ -98,7 +98,7 @@ replication:
|
|||
## MariaDB replication user password
|
||||
## ref: https://github.com/bitnami/bitnami-docker-mariadb#setting-up-a-replication-cluster
|
||||
##
|
||||
password: replicator
|
||||
password: R4%forep11CAT0r
|
||||
## Password is ignored if existingSecret is specified.
|
||||
##
|
||||
## Option to force users to specify a password. That is required for 'helm upgrade' to work properly.
|
||||
|
@ -167,7 +167,7 @@ master:
|
|||
- ReadWriteOnce
|
||||
## Persistent Volume size
|
||||
##
|
||||
size: 8Gi
|
||||
size: 5Gi
|
||||
##
|
||||
extraInitContainers: |
|
||||
# - name: do-something
|
||||
|
@ -228,7 +228,7 @@ master:
|
|||
failureThreshold: 3
|
||||
|
||||
slave:
|
||||
replicas: 2
|
||||
replicas: 1
|
||||
|
||||
|
||||
## Mariadb Slave additional pod annotations
|
||||
|
@ -262,7 +262,7 @@ slave:
|
|||
- ReadWriteOnce
|
||||
## Persistent Volume size
|
||||
##
|
||||
size: 8Gi
|
||||
size: 5Gi
|
||||
##
|
||||
extraInitContainers: |
|
||||
# - name: do-something
|
||||
|
@ -324,7 +324,7 @@ slave:
|
|||
failureThreshold: 3
|
||||
|
||||
metrics:
|
||||
enabled: true
|
||||
enabled: false
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: prom/mysqld-exporter
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
## Configure resource requests and limits
|
||||
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
|
||||
##
|
||||
image:
|
||||
repository: redis
|
||||
tag: 5.0.3-alpine
|
||||
pullPolicy: IfNotPresent
|
||||
## replicas number for each component
|
||||
replicas: 2
|
||||
|
||||
## Redis specific configuration options
|
||||
redis:
|
||||
port: 6379
|
||||
masterGroupName: mymaster
|
||||
config:
|
||||
## Additional redis conf options can be added below
|
||||
## For all available options see http://download.redis.io/redis-stable/redis.conf
|
||||
min-slaves-to-write: 1
|
||||
min-slaves-max-lag: 5 # Value in seconds
|
||||
maxmemory: "1g" # Max memory to use for each redis instance. Default is unlimited.
|
||||
maxmemory-policy: "allkeys-lru" # Max memory policy to use for each redis instance. Default is volatile-lru.
|
||||
# Determines if scheduled RDB backups are created. Default is false.
|
||||
# Please note that local (on-disk) RDBs will still be created when re-syncing with a new slave. The only way to prevent this is to enable diskless replication.
|
||||
# save: "900 1"
|
||||
# When enabled, directly sends the RDB over the wire to slaves, without using the disk as intermediate storage. Default is false.
|
||||
repl-diskless-sync: "yes"
|
||||
rdbcompression: "yes"
|
||||
rdbchecksum: "yes"
|
||||
|
||||
## Custom redis.conf files used to override default settings. If this file is
|
||||
## specified then the redis.config above will be ignored.
|
||||
# customConfig: |-
|
||||
# Define configuration here
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: 500Mi
|
||||
cpu: 100m
|
||||
limits:
|
||||
memory: 1100Mi
|
||||
|
||||
## Sentinel specific configuration options
|
||||
sentinel:
|
||||
port: 26379
|
||||
quorum: 1
|
||||
config:
|
||||
## Additional sentinel conf options can be added below. Only options that
|
||||
## are expressed in the format simialar to 'sentinel xxx mymaster xxx' will
|
||||
## be properly templated.
|
||||
## For available options see http://download.redis.io/redis-stable/sentinel.conf
|
||||
down-after-milliseconds: 10000
|
||||
## Failover timeout value in milliseconds
|
||||
failover-timeout: 180000
|
||||
parallel-syncs: 5
|
||||
|
||||
## Custom sentinel.conf files used to override default settings. If this file is
|
||||
## specified then the sentinel.config above will be ignored.
|
||||
# customConfig: |-
|
||||
# Define configuration here
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: 200Mi
|
||||
cpu: 100m
|
||||
limits:
|
||||
memory: 200Mi
|
||||
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
|
||||
## Node labels, affinity, and tolerations for pod assignment
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
|
||||
affinity: |
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
topologyKey: kubernetes.io/hostname
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
topologyKey: failure-domain.beta.kubernetes.io/zone
|
||||
|
||||
podDisruptionBudget: {}
|
||||
# maxUnavailable: 1
|
||||
# minAvailable: 1
|
||||
|
||||
## Configures redis with AUTH (requirepass & masterauth conf params)
|
||||
auth: true
|
||||
redisPassword: redis1234
|
||||
|
||||
## Use existing secret containing "auth" key (ignores redisPassword)
|
||||
# existingSecret:
|
||||
|
||||
persistentVolume:
|
||||
enabled: false
|
||||
## redis-ha data Persistent Volume Storage Class
|
||||
## If defined, storageClassName: <storageClass>
|
||||
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
## If undefined (the default) or set to null, no storageClassName spec is
|
||||
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
## GKE, AWS & OpenStack)
|
||||
##
|
||||
storageClass: "nfs-db"
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
size: 3Gi
|
||||
annotations: {}
|
||||
init:
|
||||
resources: {}
|
|
@ -0,0 +1,20 @@
|
|||
name: redis-ha
|
||||
home: http://redis.io/
|
||||
engine: gotpl
|
||||
keywords:
|
||||
- redis
|
||||
- keyvalue
|
||||
- database
|
||||
version: 3.1.3
|
||||
appVersion: 5.0.3
|
||||
description: Highly available Kubernetes implementation of Redis
|
||||
icon: https://upload.wikimedia.org/wikipedia/en/thumb/6/6b/Redis_Logo.svg/1200px-Redis_Logo.svg.png
|
||||
maintainers:
|
||||
- email: salimsalaues@gmail.com
|
||||
name: ssalaues
|
||||
details:
|
||||
This Helm chart provides a highly available Redis implementation with a master/slave configuration
|
||||
and uses Sentinel sidecars for failover management
|
||||
sources:
|
||||
- https://redis.io/download
|
||||
- https://github.com/scality/Zenko/tree/development/1.0/kubernetes/zenko/charts/redis-ha
|
|
@ -0,0 +1,4 @@
|
|||
approvers:
|
||||
- ssalaues
|
||||
reviewers:
|
||||
- ssalaues
|
|
@ -0,0 +1,117 @@
|
|||
# Redis
|
||||
|
||||
[Redis](http://redis.io/) is an advanced key-value cache and store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets, sorted sets, bitmaps and hyperloglogs.
|
||||
|
||||
## TL;DR;
|
||||
|
||||
```bash
|
||||
$ helm install stable/redis-ha
|
||||
```
|
||||
|
||||
By default this chart install 3 pods total:
|
||||
* one pod containing a redis master and sentinel containers
|
||||
* two pods each containing redis slave and sentinel containers.
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart bootstraps a [Redis](https://redis.io) highly available master/slave statefulset in a [Kubernetes](http://kubernetes.io) cluster using the Helm package manager.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.8+ with Beta APIs enabled
|
||||
- PV provisioner support in the underlying infrastructure
|
||||
|
||||
## Upgrading the Chart
|
||||
|
||||
Please note that there have been a number of changes simplifying the redis management strategy (for better failover and elections) in the 3.x version of this chart. These changes allow the use of official [redis](https://hub.docker.com/_/redis/) images that do not require special RBAC or ServiceAccount roles. As a result when upgrading from version >=2.0.1 to >=3.0.0 of this chart, `Role`, `RoleBinding`, and `ServiceAccount` resources should be deleted manually.
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart
|
||||
|
||||
```bash
|
||||
$ helm install stable/redis-ha
|
||||
```
|
||||
|
||||
The command deploys Redis on the Kubernetes cluster in the default configuration. By default this chart install one master pod containing redis master container and sentinel container along with 2 redis slave pods each containing their own sentinel sidecars. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the deployment:
|
||||
|
||||
```bash
|
||||
$ helm delete <chart-name>
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and deletes the release.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following table lists the configurable parameters of the Redis chart and their default values.
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| -------------------------------- | ----------------------------------------------------- | --------------------------------------------------------- |
|
||||
| `image` | Redis image | `redis` |
|
||||
| `tag` | Redis tag | `5.0.3-alpine` |
|
||||
| `replicas` | Number of redis master/slave pods | `3` |
|
||||
| `redis.port` | Port to access the redis service | `6379` |
|
||||
| `redis.masterGroupName` | Redis convention for naming the cluster group | `mymaster` |
|
||||
| `redis.config` | Any valid redis config options in this section will be applied to each server (see below) | see values.yaml |
|
||||
| `redis.customConfig` | Allows for custom redis.conf files to be applied. If this is used then `redis.config` is ignored | `` |
|
||||
| `redis.resources` | CPU/Memory for master/slave nodes resource requests/limits | `{}` |
|
||||
| `sentinel.port` | Port to access the sentinel service | `26379` |
|
||||
| `sentinel.quorum` | Minimum number of servers necessary to maintain quorum | `2` |
|
||||
| `sentinel.config` | Valid sentinel config options in this section will be applied as config options to each sentinel (see below) | see values.yaml |
|
||||
| `sentinel.customConfig` | Allows for custom sentinel.conf files to be applied. If this is used then `sentinel.config` is ignored | `` |
|
||||
| `sentinel.resources` | CPU/Memory for sentinel node resource requests/limits | `{}` |
|
||||
| `init.resources` | CPU/Memory for init Container node resource requests/limits | `{}`
|
||||
| `auth` | Enables or disables redis AUTH (Requires `redisPassword` to be set) | `false` |
|
||||
| `redisPassword` | A password that configures a `requirepass` and `masterauth` in the conf parameters (Requires `auth: enabled`) | `` |
|
||||
| `existingSecret` | An existing secret containing an `auth` key that configures `requirepass` and `masterauth` in the conf parameters (Requires `auth: enabled`, cannot be used in conjunction with `.Values.redisPassword`) | `` |
|
||||
| `nodeSelector` | Node labels for pod assignment | `{}` |
|
||||
| `tolerations` | Toleration labels for pod assignment | `[]` |
|
||||
| `podAntiAffinity.server` | Antiaffinity for pod assignment of servers, `hard` or `soft` | `Hard node and soft zone anti-affinity` |
|
||||
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
|
||||
```bash
|
||||
$ helm install \
|
||||
--set image=redis \
|
||||
--set tag=5.0.3-alpine \
|
||||
stable/redis-ha
|
||||
```
|
||||
|
||||
The above command sets the Redis server within `default` namespace.
|
||||
|
||||
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
|
||||
|
||||
```bash
|
||||
$ helm install -f values.yaml stable/redis-ha
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
||||
|
||||
## Custom Redis and Sentinel config options
|
||||
|
||||
This chart allows for most redis or sentinel config options to be passed as a key value pair through the `values.yaml` under `redis.config` and `sentinel.config`. See links below for all available options.
|
||||
|
||||
[Example redis.conf](http://download.redis.io/redis-stable/redis.conf)
|
||||
[Example sentinel.conf](http://download.redis.io/redis-stable/sentinel.conf)
|
||||
|
||||
For example `repl-timeout 60` would be added to the `redis.config` section of the `values.yaml` as:
|
||||
|
||||
```yml
|
||||
repl-timeout: "60"
|
||||
```
|
||||
|
||||
Sentinel options supported must be in the the `sentinel <option> <master-group-name> <value>` format. For example, `sentinel down-after-milliseconds 30000` would be added to the `sentinel.config` section of the `values.yaml` as:
|
||||
|
||||
```yml
|
||||
down-after-milliseconds: 30000
|
||||
```
|
||||
|
||||
If more control is needed from either the redis or sentinel config then an entire config can be defined under `redis.customConfig` or `sentinel.customConfig`. Please note that these values will override any configuration options under their respective section. For example, if you define `sentinel.customConfig` then the `sentinel.config` is ignored.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
Redis can be accessed via port {{ .Values.redis.port }} and Sentinel can be accessed via port {{ .Values.sentinel.port }} on the following DNS name from within your cluster:
|
||||
{{ template "redis-ha.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
|
||||
|
||||
To connect to your Redis server:
|
||||
|
||||
{{- if .Values.auth }}
|
||||
1. To retrieve the redis password:
|
||||
echo $(kubectl get secret {{ template "redis-ha.fullname" . }} -o "jsonpath={.data['auth']}" | base64 --decode)
|
||||
|
||||
2. Connect to the Redis master pod that you can use as a client. By default the {{ template "redis-ha.fullname" . }}-server-0 pod is configured as the master:
|
||||
|
||||
kubectl exec -it {{ template "redis-ha.fullname" . }}-server-0 sh -n {{ .Release.Namespace }}
|
||||
|
||||
3. Connect using the Redis CLI (inside container):
|
||||
|
||||
redis-cli -a <REDIS-PASS-FROM-SECRET>
|
||||
{{- else }}
|
||||
1. Run a Redis pod that you can use as a client:
|
||||
|
||||
kubectl exec -it {{ template "redis-ha.fullname" . }}-server-0 sh -n {{ .Release.Namespace }}
|
||||
|
||||
2. Connect using the Redis CLI:
|
||||
|
||||
redis-cli -h {{ template "redis-ha.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
|
||||
{{- end }}
|
|
@ -0,0 +1,53 @@
|
|||
{{/* vim: set filetype=mustache: */}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "redis-ha.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "redis-ha.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
Credit: @technosophos
|
||||
https://github.com/technosophos/common-chart/
|
||||
labels.standard prints the standard Helm labels.
|
||||
The standard labels are frequently used in metadata.
|
||||
*/ -}}
|
||||
{{- define "labels.standard" -}}
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
heritage: {{ .Release.Service | quote }}
|
||||
release: {{ .Release.Name | quote }}
|
||||
chart: {{ template "chartref" . }}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
Credit: @technosophos
|
||||
https://github.com/technosophos/common-chart/
|
||||
chartref prints a chart name and version.
|
||||
It does minimal escaping for use in Kubernetes labels.
|
||||
Example output:
|
||||
zookeeper-1.2.3
|
||||
wordpress-3.2.1_20170219
|
||||
*/ -}}
|
||||
{{- define "chartref" -}}
|
||||
{{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
|
||||
{{- end -}}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{{- if and .Values.auth (not .Values.existingSecret) -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
auth: {{ .Values.redisPassword | b64enc | quote }}
|
||||
{{- end -}}
|
|
@ -0,0 +1,33 @@
|
|||
{{- $fullName := include "redis-ha.fullname" . }}
|
||||
{{- $replicas := int .Values.replicas }}
|
||||
{{- $root := . }}
|
||||
{{- range $i := until $replicas }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullName }}-announce-{{ $i }}
|
||||
labels:
|
||||
{{ include "labels.standard" $root | indent 4 }}
|
||||
annotations:
|
||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||
{{- if $root.Values.serviceAnnotations }}
|
||||
{{ toYaml $root.Values.serviceAnnotations | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
publishNotReadyAddresses: true
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: server
|
||||
port: {{ $root.Values.redis.port }}
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: {{ $root.Values.sentinel.port }}
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
release: {{ $root.Release.Name }}
|
||||
app: {{ include "redis-ha.name" $root }}
|
||||
"statefulset.kubernetes.io/pod-name": {{ $fullName }}-server-{{ $i }}
|
||||
{{- end }}
|
|
@ -0,0 +1,137 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-configmap
|
||||
labels:
|
||||
heritage: {{ .Release.Service }}
|
||||
release: {{ .Release.Name }}
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "redis-ha.fullname" . }}
|
||||
data:
|
||||
redis.conf: |
|
||||
{{- if .Values.redis.customConfig }}
|
||||
{{ .Values.redis.customConfig | indent 4 }}
|
||||
{{- else }}
|
||||
dir "/data"
|
||||
{{- range $key, $value := .Values.redis.config }}
|
||||
{{ $key }} {{ $value }}
|
||||
{{- end }}
|
||||
{{- if .Values.auth }}
|
||||
requirepass replace-default-auth
|
||||
masterauth replace-default-auth
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
sentinel.conf: |
|
||||
{{- if .Values.sentinel.customConfig }}
|
||||
{{ .Values.sentinel.customConfig | indent 4 }}
|
||||
{{- else }}
|
||||
dir "/data"
|
||||
{{- $root := . -}}
|
||||
{{- range $key, $value := .Values.sentinel.config }}
|
||||
sentinel {{ $key }} {{ $root.Values.redis.masterGroupName }} {{ $value }}
|
||||
{{- end }}
|
||||
{{- if .Values.auth }}
|
||||
sentinel auth-pass {{ .Values.redis.masterGroupName }} replace-default-auth
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
init.sh: |
|
||||
HOSTNAME="$(hostname)"
|
||||
INDEX="${HOSTNAME##*-}"
|
||||
MASTER="$(redis-cli -h {{ template "redis-ha.fullname" . }} -p {{ .Values.sentinel.port }} sentinel get-master-addr-by-name {{ .Values.redis.masterGroupName }} | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')"
|
||||
MASTER_GROUP="{{ .Values.redis.masterGroupName }}"
|
||||
QUORUM="{{ .Values.sentinel.quorum }}"
|
||||
REDIS_CONF=/data/conf/redis.conf
|
||||
REDIS_PORT={{ .Values.redis.port }}
|
||||
SENTINEL_CONF=/data/conf/sentinel.conf
|
||||
SENTINEL_PORT={{ .Values.sentinel.port }}
|
||||
SERVICE={{ template "redis-ha.fullname" . }}
|
||||
set -eu
|
||||
|
||||
sentinel_update() {
|
||||
echo "Updating sentinel config"
|
||||
sed -i "1s/^/$(cat sentinel-id)\\n/" "$SENTINEL_CONF"
|
||||
sed -i "2s/^/sentinel monitor $MASTER_GROUP $1 $REDIS_PORT $QUORUM \\n/" "$SENTINEL_CONF"
|
||||
echo "sentinel announce-ip $ANNOUNCE_IP" >> $SENTINEL_CONF
|
||||
echo "sentinel announce-port $SENTINEL_PORT" >> $SENTINEL_CONF
|
||||
}
|
||||
|
||||
redis_update() {
|
||||
echo "Updating redis config"
|
||||
echo "slaveof $1 $REDIS_PORT" >> "$REDIS_CONF"
|
||||
echo "slave-announce-ip $ANNOUNCE_IP" >> $REDIS_CONF
|
||||
echo "slave-announce-port $REDIS_PORT" >> $REDIS_CONF
|
||||
}
|
||||
|
||||
copy_config() {
|
||||
if [ -f "$SENTINEL_CONF" ]; then
|
||||
grep "sentinel myid" "$SENTINEL_CONF" > sentinel-id || true
|
||||
fi
|
||||
cp /readonly-config/redis.conf "$REDIS_CONF"
|
||||
cp /readonly-config/sentinel.conf "$SENTINEL_CONF"
|
||||
}
|
||||
|
||||
setup_defaults() {
|
||||
echo "Setting up defaults"
|
||||
if [ "$INDEX" = "0" ]; then
|
||||
echo "Setting this pod as the default master"
|
||||
sed -i "s/^.*slaveof.*//" "$REDIS_CONF"
|
||||
sentinel_update "$ANNOUNCE_IP"
|
||||
else
|
||||
DEFAULT_MASTER="$(getent hosts "$SERVICE-announce-0" | awk '{ print $1 }')"
|
||||
if [ -z "$DEFAULT_MASTER" ]; then
|
||||
echo "Unable to resolve host"
|
||||
exit 1
|
||||
fi
|
||||
echo "Setting default slave config.."
|
||||
redis_update "$DEFAULT_MASTER"
|
||||
sentinel_update "$DEFAULT_MASTER"
|
||||
fi
|
||||
}
|
||||
|
||||
find_master() {
|
||||
echo "Attempting to find master"
|
||||
if [ "$(redis-cli -h "$MASTER"{{ if .Values.auth }} -a "$AUTH"{{ end }} ping)" != "PONG" ]; then
|
||||
echo "Can't ping master, attempting to force failover"
|
||||
if redis-cli -h "$SERVICE" -p "$SENTINEL_PORT" sentinel failover "$MASTER_GROUP" | grep -q 'NOGOODSLAVE' ; then
|
||||
setup_defaults
|
||||
return 0
|
||||
fi
|
||||
sleep 10
|
||||
MASTER="$(redis-cli -h $SERVICE -p $SENTINEL_PORT sentinel get-master-addr-by-name $MASTER_GROUP | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')"
|
||||
if [ "$MASTER" ]; then
|
||||
sentinel_update "$MASTER"
|
||||
redis_update "$MASTER"
|
||||
else
|
||||
echo "Could not failover, exiting..."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Found reachable master, updating config"
|
||||
sentinel_update "$MASTER"
|
||||
redis_update "$MASTER"
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p /data/conf/
|
||||
|
||||
echo "Initializing config.."
|
||||
copy_config
|
||||
|
||||
ANNOUNCE_IP=$(getent hosts "$SERVICE-announce-$INDEX" | awk '{ print $1 }')
|
||||
if [ -z "$ANNOUNCE_IP" ]; then
|
||||
"Could not resolve the announce ip for this pod"
|
||||
exit 1
|
||||
elif [ "$MASTER" ]; then
|
||||
find_master
|
||||
else
|
||||
setup_defaults
|
||||
fi
|
||||
|
||||
if [ "${AUTH:-}" ]; then
|
||||
echo "Setting auth values"
|
||||
sed -i "s/replace-default-auth/$AUTH/" "$REDIS_CONF" "$SENTINEL_CONF"
|
||||
fi
|
||||
|
||||
echo "Ready..."
|
|
@ -0,0 +1,41 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-probes
|
||||
labels:
|
||||
heritage: {{ .Release.Service }}
|
||||
release: {{ .Release.Name }}
|
||||
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
|
||||
app: {{ template "redis-ha.fullname" . }}
|
||||
data:
|
||||
check-quorum.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
MASTER_GROUP="{{ .Values.redis.masterGroupName }}"
|
||||
SENTINEL_PORT={{ .Values.sentinel.port }}
|
||||
REDIS_PORT={{ .Values.redis.port }}
|
||||
NUM_SLAVES=$(redis-cli -p "$SENTINEL_PORT" sentinel master {{ .Values.redis.masterGroupName }} | awk '/num-slaves/{getline; print}')
|
||||
MIN_SLAVES={{ index .Values.redis.config "min-slaves-to-write" }}
|
||||
|
||||
if [ "$1" = "$SENTINEL_PORT" ]; then
|
||||
if redis-cli -p "$SENTINEL_PORT" sentinel ckquorum "$MASTER_GROUP" | grep -q NOQUORUM ; then
|
||||
echo "ERROR: NOQUORUM. Sentinel quorum check failed, not enough sentinels found"
|
||||
exit 1
|
||||
fi
|
||||
elif [ "$1" = "$REDIS_PORT" ]; then
|
||||
if [ "$MIN_SLAVES" -gt "$NUM_SLAVES" ]; then
|
||||
echo "Could not find enough replicating slaves. Needed $MIN_SLAVES but found $NUM_SLAVES"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
sh /probes/readiness.sh "$1"
|
||||
|
||||
readiness.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
CHECK_SERVER="$(redis-cli -p "$1"{{ if .Values.auth }} -a "$AUTH"{{ end }} ping)"
|
||||
|
||||
if [ "$CHECK_SERVER" != "PONG" ]; then
|
||||
echo "Server check failed with: $CHECK_SERVER"
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,14 @@
|
|||
{{- if .Values.podDisruptionBudget -}}
|
||||
apiVersion: policy/v1beta1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-pdb
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
{{ toYaml .Values.podDisruptionBudget | indent 2 }}
|
||||
{{- end -}}
|
|
@ -0,0 +1,25 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
annotations:
|
||||
{{- if .Values.serviceAnnotations }}
|
||||
{{ toYaml .Values.serviceAnnotations | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: server
|
||||
port: {{ .Values.redis.port }}
|
||||
protocol: TCP
|
||||
targetPort: redis
|
||||
- name: sentinel
|
||||
port: {{ .Values.sentinel.port }}
|
||||
protocol: TCP
|
||||
targetPort: sentinel
|
||||
selector:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "redis-ha.name" . }}
|
|
@ -0,0 +1,183 @@
|
|||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-server
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
serviceName: {{ template "redis-ha.fullname" . }}
|
||||
replicas: {{ .Values.replicas }}
|
||||
podManagementPolicy: OrderedReady
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/init-config: {{ include (print $.Template.BasePath "/redis-ha-configmap.yaml") . | sha256sum }}
|
||||
checksum/probe-config: {{ include (print $.Template.BasePath "/redis-ha-healthchecks.yaml") . | sha256sum }}
|
||||
{{- if .Values.podAnnotations }}
|
||||
{{ toYaml .Values.podAnnotations | indent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
release: {{ .Release.Name }}
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
spec:
|
||||
{{- if .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{ toYaml .Values.nodeSelector | indent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml .Values.tolerations | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ tpl . $ | indent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{ toYaml .Values.securityContext | indent 8 }}
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
resources:
|
||||
{{ toYaml .Values.init.resources | indent 10 }}
|
||||
command:
|
||||
- sh
|
||||
args:
|
||||
- /readonly-config/init.sh
|
||||
{{- if .Values.auth }}
|
||||
env:
|
||||
- name: AUTH
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
{{- if .Values.existingSecret }}
|
||||
name: {{ .Values.existingSecret }}
|
||||
{{- else }}
|
||||
name: {{ template "redis-ha.fullname" . }}
|
||||
{{- end }}
|
||||
key: auth
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /readonly-config
|
||||
readOnly: true
|
||||
- name: data
|
||||
mountPath: /data
|
||||
containers:
|
||||
- name: redis
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- redis-server
|
||||
args:
|
||||
- /data/conf/redis.conf
|
||||
{{- if .Values.auth }}
|
||||
env:
|
||||
- name: AUTH
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
{{- if .Values.existingSecret }}
|
||||
name: {{ .Values.existingSecret }}
|
||||
{{- else }}
|
||||
name: {{ template "redis-ha.fullname" . }}
|
||||
{{- end }}
|
||||
key: auth
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: [ "sh", "/probes/readiness.sh", "{{ .Values.redis.port }}"]
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["sh", "/probes/readiness.sh", "{{ .Values.redis.port }}"]
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{ toYaml .Values.redis.resources | indent 10 }}
|
||||
ports:
|
||||
- name: redis
|
||||
containerPort: {{ .Values.redis.port }}
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: data
|
||||
- mountPath: /probes
|
||||
name: probes
|
||||
- name: sentinel
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- redis-sentinel
|
||||
args:
|
||||
- /data/conf/sentinel.conf
|
||||
{{- if .Values.auth }}
|
||||
env:
|
||||
- name: AUTH
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
{{- if .Values.existingSecret }}
|
||||
name: {{ .Values.existingSecret }}
|
||||
{{- else }}
|
||||
name: {{ template "redis-ha.fullname" . }}
|
||||
{{- end }}
|
||||
key: auth
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: [ "sh", "/probes/readiness.sh", "{{ .Values.sentinel.port }}"]
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["sh", "/probes/readiness.sh", "{{ .Values.sentinel.port }}"]
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{ toYaml .Values.sentinel.resources | indent 10 }}
|
||||
ports:
|
||||
- name: sentinel
|
||||
containerPort: {{ .Values.sentinel.port }}
|
||||
volumeMounts:
|
||||
- mountPath: /data
|
||||
name: data
|
||||
- mountPath: /probes
|
||||
name: probes
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ template "redis-ha.fullname" . }}-configmap
|
||||
- name: probes
|
||||
configMap:
|
||||
name: {{ template "redis-ha.fullname" . }}-probes
|
||||
{{- if .Values.persistentVolume.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
annotations:
|
||||
{{- range $key, $value := .Values.persistentVolume.annotations }}
|
||||
{{ $key }}: {{ $value }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- range .Values.persistentVolume.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistentVolume.size | quote }}
|
||||
{{- if .Values.persistentVolume.storageClass }}
|
||||
{{- if (eq "-" .Values.persistentVolume.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: "{{ .Values.persistentVolume.storageClass }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
|
@ -0,0 +1,36 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-configmap-test
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test-success
|
||||
spec:
|
||||
containers:
|
||||
- name: check-init
|
||||
image: koalaman/shellcheck:v0.5.0
|
||||
args:
|
||||
- --shell=sh
|
||||
- /readonly-config/init.sh
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /readonly-config
|
||||
readOnly: true
|
||||
- name: check-probes
|
||||
image: koalaman/shellcheck:v0.5.0
|
||||
args:
|
||||
- --shell=sh
|
||||
- /probes/check-quorum.sh
|
||||
volumeMounts:
|
||||
- name: probes
|
||||
mountPath: /probes
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ template "redis-ha.fullname" . }}-configmap
|
||||
- name: probes
|
||||
configMap:
|
||||
name: {{ template "redis-ha.fullname" . }}-probes
|
||||
restartPolicy: Never
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: {{ template "redis-ha.fullname" . }}-service-test
|
||||
labels:
|
||||
{{ include "labels.standard" . | indent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": test-success
|
||||
spec:
|
||||
containers:
|
||||
- name: "{{ .Release.Name }}-service-test"
|
||||
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- redis-cli -h {{ template "redis-ha.fullname" . }} -p {{ .Values.redis.port }} info server
|
||||
restartPolicy: Never
|
|
@ -0,0 +1,120 @@
|
|||
## Configure resource requests and limits
|
||||
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
|
||||
##
|
||||
image:
|
||||
repository: redis
|
||||
tag: 5.0.3-alpine
|
||||
pullPolicy: IfNotPresent
|
||||
## replicas number for each component
|
||||
replicas: 3
|
||||
|
||||
## Redis specific configuration options
|
||||
redis:
|
||||
port: 6379
|
||||
masterGroupName: mymaster
|
||||
config:
|
||||
## Additional redis conf options can be added below
|
||||
## For all available options see http://download.redis.io/redis-stable/redis.conf
|
||||
min-slaves-to-write: 1
|
||||
min-slaves-max-lag: 5 # Value in seconds
|
||||
maxmemory: "0" # Max memory to use for each redis instance. Default is unlimited.
|
||||
maxmemory-policy: "volatile-lru" # Max memory policy to use for each redis instance. Default is volatile-lru.
|
||||
# Determines if scheduled RDB backups are created. Default is false.
|
||||
# Please note that local (on-disk) RDBs will still be created when re-syncing with a new slave. The only way to prevent this is to enable diskless replication.
|
||||
save: "900 1"
|
||||
# When enabled, directly sends the RDB over the wire to slaves, without using the disk as intermediate storage. Default is false.
|
||||
repl-diskless-sync: "yes"
|
||||
rdbcompression: "yes"
|
||||
rdbchecksum: "yes"
|
||||
|
||||
## Custom redis.conf files used to override default settings. If this file is
|
||||
## specified then the redis.config above will be ignored.
|
||||
# customConfig: |-
|
||||
# Define configuration here
|
||||
|
||||
resources: {}
|
||||
# requests:
|
||||
# memory: 200Mi
|
||||
# cpu: 100m
|
||||
# limits:
|
||||
# memory: 700Mi
|
||||
|
||||
## Sentinel specific configuration options
|
||||
sentinel:
|
||||
port: 26379
|
||||
quorum: 2
|
||||
config:
|
||||
## Additional sentinel conf options can be added below. Only options that
|
||||
## are expressed in the format simialar to 'sentinel xxx mymaster xxx' will
|
||||
## be properly templated.
|
||||
## For available options see http://download.redis.io/redis-stable/sentinel.conf
|
||||
down-after-milliseconds: 10000
|
||||
## Failover timeout value in milliseconds
|
||||
failover-timeout: 180000
|
||||
parallel-syncs: 5
|
||||
|
||||
## Custom sentinel.conf files used to override default settings. If this file is
|
||||
## specified then the sentinel.config above will be ignored.
|
||||
# customConfig: |-
|
||||
# Define configuration here
|
||||
|
||||
resources: {}
|
||||
# requests:
|
||||
# memory: 200Mi
|
||||
# cpu: 100m
|
||||
# limits:
|
||||
# memory: 200Mi
|
||||
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
fsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
|
||||
## Node labels, affinity, and tolerations for pod assignment
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature
|
||||
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
|
||||
affinity: |
|
||||
podAntiAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
topologyKey: kubernetes.io/hostname
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: {{ template "redis-ha.name" . }}
|
||||
release: {{ .Release.Name }}
|
||||
topologyKey: failure-domain.beta.kubernetes.io/zone
|
||||
|
||||
podDisruptionBudget: {}
|
||||
# maxUnavailable: 1
|
||||
# minAvailable: 1
|
||||
|
||||
## Configures redis with AUTH (requirepass & masterauth conf params)
|
||||
auth: false
|
||||
# redisPassword:
|
||||
|
||||
## Use existing secret containing "auth" key (ignores redisPassword)
|
||||
# existingSecret:
|
||||
|
||||
persistentVolume:
|
||||
enabled: true
|
||||
## redis-ha data Persistent Volume Storage Class
|
||||
## If defined, storageClassName: <storageClass>
|
||||
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
## If undefined (the default) or set to null, no storageClassName spec is
|
||||
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
## GKE, AWS & OpenStack)
|
||||
##
|
||||
# storageClass: "-"
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
size: 10Gi
|
||||
annotations: {}
|
||||
init:
|
||||
resources: {}
|
Loading…
Reference in New Issue