First Commit
This commit is contained in:
63
templates/NOTES.txt
Normal file
63
templates/NOTES.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
Native Redis Cluster deployed: {{ .Values.cluster.shards }} writable shards,
|
||||
{{ .Values.cluster.replicasPerShard }} replica(s) per shard,
|
||||
{{ include "redis-cluster.nodeCount" . }} total Redis instances.
|
||||
|
||||
Every shard's persistent members have REQUIRED hostname anti-affinity. A shard
|
||||
cannot place two copies on one Kubernetes worker.
|
||||
|
||||
{{- if .Values.auth.enabled }}
|
||||
|
||||
Get the password:
|
||||
|
||||
kubectl get secret -n {{ .Release.Namespace }} {{ include "redis-cluster.secretName" . }} \
|
||||
-o jsonpath='{.data.{{ include "redis-cluster.secretKey" . }}}' | base64 -d
|
||||
{{- end }}
|
||||
{{- if .Values.redisInsight.enabled }}
|
||||
|
||||
RedisInsight:
|
||||
{{- if .Values.redisInsight.ingress.enabled }}
|
||||
{{ ternary "https" "http" .Values.redisInsight.ingress.tls.enabled }}://{{ .Values.redisInsight.ingress.host }}
|
||||
{{- else }}
|
||||
kubectl port-forward -n {{ .Release.Namespace }} service/{{ include "redis-cluster.redisInsightName" . }} 5540:80
|
||||
http://127.0.0.1:5540
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
Cluster-aware client startup endpoint:
|
||||
|
||||
{{ include "redis-cluster.fullname" . }}.{{ .Release.Namespace }}.svc:{{ .Values.redis.port }}
|
||||
{{- if .Values.externalAccess.enabled }}
|
||||
|
||||
External cluster-aware client startup endpoint:
|
||||
|
||||
kubectl get service -n {{ .Release.Namespace }} \
|
||||
{{ include "redis-cluster.fullname" . }}-external \
|
||||
-o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}'
|
||||
|
||||
Use that returned address on port {{ .Values.externalAccess.port }}.
|
||||
|
||||
The external bootstrap LoadBalancer is discovery only. Redis advertises one
|
||||
dynamic LoadBalancer VIP per member on the same port, so MOVED/ASK redirects
|
||||
remain routable from outside Kubernetes without fixed addresses or port fan-out.
|
||||
{{- end }}
|
||||
|
||||
Check all 16384 slots and primary/replica assignments:
|
||||
|
||||
kubectl exec -n {{ .Release.Namespace }} \
|
||||
{{ include "redis-cluster.fullname" . }}-s0-n0-0 -c redis -- \
|
||||
redis-cli --cluster check 127.0.0.1:{{ .Values.redis.port }}
|
||||
|
||||
Do not use a standalone or Sentinel client. The client must support Redis
|
||||
Cluster redirects and connect to the per-node hostnames returned in the slot map.
|
||||
|
||||
StatefulSets use updateStrategy=OnDelete so independent members cannot all roll
|
||||
at once. Follow the one-member-at-a-time upgrade procedure in README.md.
|
||||
|
||||
{{- if .Values.metrics.enabled }}
|
||||
|
||||
Metrics: http://<pod>:{{ .Values.metrics.port }}/metrics (redis_exporter).
|
||||
{{- if not .Values.metrics.serviceMonitor.enabled }}
|
||||
Set metrics.serviceMonitor.enabled=true (plus the correct selector labels) when
|
||||
using Prometheus Operator.
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
154
templates/_helpers.tpl
Normal file
154
templates/_helpers.tpl
Normal file
@@ -0,0 +1,154 @@
|
||||
{{/* Chart name */}}
|
||||
{{- define "redis-cluster.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Fully qualified app name */}}
|
||||
{{- define "redis-cluster.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 -}}
|
||||
|
||||
{{/* Chart label */}}
|
||||
{{- define "redis-cluster.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Common labels */}}
|
||||
{{- define "redis-cluster.labels" -}}
|
||||
helm.sh/chart: {{ include "redis-cluster.chart" . }}
|
||||
{{ include "redis-cluster.selectorLabels" . }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Selector labels */}}
|
||||
{{- define "redis-cluster.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "redis-cluster.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Headless service DNS name. Deliberately stop at .svc: the cluster DNS suffix is
|
||||
not necessarily cluster.local, and Kubernetes expands this portable name using
|
||||
the pod's search domains.
|
||||
*/}}
|
||||
{{- define "redis-cluster.headlessFqdn" -}}
|
||||
{{ include "redis-cluster.fullname" . }}-headless.{{ .Release.Namespace }}.svc
|
||||
{{- end -}}
|
||||
|
||||
{{/* Service account name */}}
|
||||
{{- define "redis-cluster.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{- default (include "redis-cluster.fullname" .) .Values.serviceAccount.name -}}
|
||||
{{- else -}}
|
||||
{{- default "default" .Values.serviceAccount.name -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Secret name holding the password */}}
|
||||
{{- define "redis-cluster.secretName" -}}
|
||||
{{- if .Values.auth.existingSecret -}}
|
||||
{{- .Values.auth.existingSecret -}}
|
||||
{{- else -}}
|
||||
{{- include "redis-cluster.fullname" . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Secret key holding the password */}}
|
||||
{{- define "redis-cluster.secretKey" -}}
|
||||
{{- if .Values.auth.existingSecret -}}
|
||||
{{- .Values.auth.existingSecretKey -}}
|
||||
{{- else -}}
|
||||
redis-password
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Password: explicit value wins; otherwise reuse the one already in the cluster
|
||||
(so upgrades don't rotate it); otherwise generate.
|
||||
*/}}
|
||||
{{- define "redis-cluster.password" -}}
|
||||
{{- if .Values.auth.password -}}
|
||||
{{- .Values.auth.password -}}
|
||||
{{- else -}}
|
||||
{{- $existing := lookup "v1" "Secret" .Release.Namespace (include "redis-cluster.fullname" .) -}}
|
||||
{{- if and $existing $existing.data (index $existing.data "redis-password") -}}
|
||||
{{- index $existing.data "redis-password" | b64dec -}}
|
||||
{{- else -}}
|
||||
{{- randAlphaNum 24 -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Total Redis nodes: shards * (one primary + replicas per shard). */}}
|
||||
{{- define "redis-cluster.nodeCount" -}}
|
||||
{{- mul (int .Values.cluster.shards) (add (int .Values.cluster.replicasPerShard) 1) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Balanced bootstrap Service used by cluster-aware clients. */}}
|
||||
{{- define "redis-cluster.bootstrapServiceName" -}}
|
||||
{{- if .Values.externalAccess.enabled -}}
|
||||
{{- printf "%s-external" (include "redis-cluster.fullname" .) -}}
|
||||
{{- else -}}
|
||||
{{- include "redis-cluster.fullname" . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* RedisInsight resource name. */}}
|
||||
{{- define "redis-cluster.redisInsightName" -}}
|
||||
{{- printf "%s-insight" (include "redis-cluster.fullname" .) | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* RedisInsight labels deliberately do not match the Redis pod selector. */}}
|
||||
{{- define "redis-cluster.redisInsightLabels" -}}
|
||||
helm.sh/chart: {{ include "redis-cluster.chart" . }}
|
||||
app.kubernetes.io/name: redisinsight
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: insight
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "redis-cluster.redisInsightSelectorLabels" -}}
|
||||
app.kubernetes.io/name: redisinsight
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: insight
|
||||
{{- end -}}
|
||||
|
||||
{{/* Environment shared by Redis lifecycle scripts. */}}
|
||||
{{- define "redis-cluster.commonEnv" -}}
|
||||
- name: STS_NAME
|
||||
value: {{ include "redis-cluster.fullname" . | quote }}
|
||||
- name: HEADLESS_SERVICE
|
||||
value: {{ include "redis-cluster.headlessFqdn" . | quote }}
|
||||
- name: NODE_COUNT
|
||||
value: {{ include "redis-cluster.nodeCount" . | quote }}
|
||||
- name: SHARD_COUNT
|
||||
value: {{ .Values.cluster.shards | quote }}
|
||||
- name: REPLICAS_PER_SHARD
|
||||
value: {{ .Values.cluster.replicasPerShard | quote }}
|
||||
- name: REDIS_PORT
|
||||
value: {{ .Values.redis.port | quote }}
|
||||
- name: CLUSTER_BUS_PORT
|
||||
value: {{ .Values.cluster.busPort | quote }}
|
||||
{{- if .Values.auth.enabled }}
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "redis-cluster.secretName" . }}
|
||||
key: {{ include "redis-cluster.secretKey" . }}
|
||||
- name: REDISCLI_AUTH
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "redis-cluster.secretName" . }}
|
||||
key: {{ include "redis-cluster.secretKey" . }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
381
templates/configmap.yaml
Normal file
381
templates/configmap.yaml
Normal file
@@ -0,0 +1,381 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
data:
|
||||
redis.conf: |
|
||||
port {{ .Values.redis.port }}
|
||||
dir /data
|
||||
appendonly yes
|
||||
appendfsync everysec
|
||||
save ""
|
||||
protected-mode no
|
||||
tcp-keepalive 60
|
||||
repl-diskless-sync yes
|
||||
replica-read-only yes
|
||||
cluster-enabled yes
|
||||
cluster-config-file nodes.conf
|
||||
cluster-port {{ .Values.cluster.busPort }}
|
||||
cluster-node-timeout {{ .Values.cluster.nodeTimeoutMilliseconds }}
|
||||
cluster-require-full-coverage {{ ternary "yes" "no" .Values.cluster.requireFullCoverage }}
|
||||
cluster-allow-reads-when-down {{ ternary "yes" "no" .Values.cluster.allowReadsWhenDown }}
|
||||
cluster-migration-barrier {{ .Values.cluster.migrationBarrier }}
|
||||
cluster-preferred-endpoint-type hostname
|
||||
{{- if .Values.redis.maxmemory }}
|
||||
maxmemory {{ .Values.redis.maxmemory }}
|
||||
maxmemory-policy {{ .Values.redis.maxmemoryPolicy }}
|
||||
{{- end }}
|
||||
{{- with .Values.redis.extraConfig }}
|
||||
{{- . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
start-redis.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
POD_FQDN="$(hostname).${HEADLESS_SERVICE}"
|
||||
if [ "$EXTERNAL_ACCESS_ENABLED" = "true" ]; then
|
||||
ANNOUNCE_HOSTNAME="$(cat /external-endpoint/hostname)"
|
||||
fi
|
||||
/scripts/repair-node-addresses.sh
|
||||
CONF=/etc/redis-runtime/redis.conf
|
||||
cp /etc/redis-ro/redis.conf "$CONF"
|
||||
{
|
||||
echo "cluster-announce-hostname $ANNOUNCE_HOSTNAME"
|
||||
echo "cluster-announce-human-nodename $(hostname)"
|
||||
echo "cluster-announce-port $ANNOUNCE_PORT"
|
||||
echo "cluster-announce-bus-port $CLUSTER_BUS_PORT"
|
||||
if [ -n "${REDIS_PASSWORD:-}" ]; then
|
||||
echo "requirepass $REDIS_PASSWORD"
|
||||
echo "masterauth $REDIS_PASSWORD"
|
||||
fi
|
||||
} >> "$CONF"
|
||||
|
||||
# Only the designated coordinator attempts first-time cluster creation.
|
||||
# The bootstrap runs beside Redis because every node must be listening
|
||||
# before CLUSTER MEET can form the topology.
|
||||
if [ "$POD_FQDN" = "$COORDINATOR_HOST" ]; then
|
||||
/scripts/bootstrap-cluster.sh &
|
||||
/scripts/reconcile-topology.sh &
|
||||
fi
|
||||
|
||||
exec redis-server "$CONF"
|
||||
|
||||
discover-external-endpoint.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
token_file=/var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
ca_file=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||
api="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}"
|
||||
url="${api}/api/v1/namespaces/${POD_NAMESPACE}/services/${EXTERNAL_SERVICE_NAME}"
|
||||
|
||||
while :; do
|
||||
response="$(curl --fail --silent --show-error --cacert "$ca_file" \
|
||||
-H "Authorization: Bearer $(cat "$token_file")" "$url" 2>/dev/null || true)"
|
||||
endpoint="$(printf '%s\n' "$response" |
|
||||
sed -n 's/.*"ip":[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)"
|
||||
if [ -z "$endpoint" ]; then
|
||||
endpoint="$(printf '%s\n' "$response" |
|
||||
sed -n 's/.*"hostname":[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)"
|
||||
fi
|
||||
if [ -n "$endpoint" ]; then
|
||||
printf '%s\n' "$endpoint" > /external-endpoint/hostname
|
||||
echo "Discovered external endpoint $endpoint for $EXTERNAL_SERVICE_NAME"
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for LoadBalancer endpoint on $EXTERNAL_SERVICE_NAME"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
start-redisinsight.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
RI_REDIS_HOST="$(cat /bootstrap-endpoint/hostname)"
|
||||
export RI_REDIS_HOST
|
||||
echo "Starting RedisInsight with discovered Redis bootstrap endpoint $RI_REDIS_HOST"
|
||||
exec "$@"
|
||||
|
||||
repair-node-addresses.sh: |
|
||||
#!/bin/sh
|
||||
set -u
|
||||
# nodes.conf persists node IDs and membership on the PVC, but its cluster
|
||||
# bus endpoints include pod IPs. Refresh those IPs using each member's
|
||||
# unique human nodename before Redis starts so a full reschedule recovers
|
||||
# independently of the client endpoint Redis advertises.
|
||||
nodes=/data/nodes.conf
|
||||
[ -s "$nodes" ] || exit 0
|
||||
|
||||
resolve_host() {
|
||||
host=$1
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
getent hosts "$host" 2>/dev/null | awk 'NR == 1 { print $1 }'
|
||||
else
|
||||
nslookup "$host" 2>/dev/null |
|
||||
awk '/^Address: / && $2 !~ /#/ { address=$2 } END { print address }'
|
||||
fi
|
||||
}
|
||||
|
||||
while :; do
|
||||
resolved=0
|
||||
old_ifs=$IFS; IFS=','
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
[ -n "$(resolve_host "$host")" ] && resolved=$((resolved + 1))
|
||||
done
|
||||
IFS=$old_ifs
|
||||
[ "$resolved" = "$NODE_COUNT" ] && break
|
||||
echo "Waiting for all $NODE_COUNT persisted member hostnames to resolve ($resolved ready)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
old_ifs=$IFS; IFS=','
|
||||
for assignment in $NODE_ADDRESS_ASSIGNMENTS; do
|
||||
pod_name=${assignment%%=*}
|
||||
internal_host=${assignment#*=}
|
||||
ip="$(resolve_host "$internal_host")"
|
||||
[ -n "$ip" ] || continue
|
||||
awk -v target="$pod_name" -v new_ip="$ip" '
|
||||
{
|
||||
metadata_count = split($2, metadata, ",")
|
||||
nodename = ""
|
||||
for (i = 3; i <= metadata_count; i++) {
|
||||
split(metadata[i], auxiliary, "=")
|
||||
if (auxiliary[1] == "nodename") nodename = auxiliary[2]
|
||||
}
|
||||
if (nodename == target) {
|
||||
split(metadata[1], bus, "@")
|
||||
split(bus[1], endpoint, ":")
|
||||
suffix = substr($2, length(metadata[1]) + 1)
|
||||
$2 = new_ip ":" endpoint[2] "@" bus[2] suffix
|
||||
}
|
||||
print
|
||||
}
|
||||
' "$nodes" > "${nodes}.new" && mv "${nodes}.new" "$nodes"
|
||||
done
|
||||
IFS=$old_ifs
|
||||
|
||||
bootstrap-cluster.sh: |
|
||||
#!/bin/sh
|
||||
set -u
|
||||
|
||||
cli() {
|
||||
redis-cli --no-auth-warning "$@"
|
||||
}
|
||||
|
||||
resolve_host() {
|
||||
host=$1
|
||||
if command -v getent >/dev/null 2>&1; then
|
||||
getent hosts "$host" 2>/dev/null | awk 'NR == 1 { print $1 }'
|
||||
else
|
||||
nslookup "$host" 2>/dev/null |
|
||||
awk '/^Address: / && $2 !~ /#/ { address=$2 } END { print address }'
|
||||
fi
|
||||
}
|
||||
|
||||
node_value() {
|
||||
host=$1 field=$2
|
||||
cli -h "$host" -p "$REDIS_PORT" cluster info 2>/dev/null |
|
||||
tr -d '\r' | awk -F: -v field="$field" '$1 == field { print $2 }'
|
||||
}
|
||||
|
||||
echo "Redis Cluster bootstrap coordinator: $COORDINATOR_HOST"
|
||||
while :; do
|
||||
all_ready=true
|
||||
old_ifs=$IFS; IFS=','
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
if [ "$(cli -h "$host" -p "$REDIS_PORT" ping 2>/dev/null)" != PONG ]; then
|
||||
all_ready=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$old_ifs
|
||||
$all_ready && break
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ "$(node_value "$COORDINATOR_HOST" cluster_state)" = ok ]; then
|
||||
echo "Redis Cluster already healthy; bootstrap is a no-op"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Never overwrite a partially configured or previously initialized
|
||||
# cluster. That state needs repair, not a destructive second bootstrap.
|
||||
pristine=true
|
||||
old_ifs=$IFS; IFS=','
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
known="$(node_value "$host" cluster_known_nodes)"
|
||||
assigned="$(node_value "$host" cluster_slots_assigned)"
|
||||
if [ "$known" != 1 ] || [ "$assigned" != 0 ]; then
|
||||
pristine=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$old_ifs
|
||||
if ! $pristine; then
|
||||
echo "Cluster has existing membership or slots but is not healthy; refusing to reinitialize it" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Creating a ${SHARD_COUNT}-shard cluster from ${NODE_COUNT} pristine nodes"
|
||||
old_ifs=$IFS; IFS=','
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
[ "$host" = "$COORDINATOR_HOST" ] && continue
|
||||
ip="$(resolve_host "$host")"
|
||||
if [ -z "$ip" ]; then
|
||||
echo "Could not resolve $host" >&2
|
||||
exit 1
|
||||
fi
|
||||
cli -h "$COORDINATOR_HOST" -p "$REDIS_PORT" \
|
||||
cluster meet "$ip" "$REDIS_PORT" "$CLUSTER_BUS_PORT" >/dev/null || exit 1
|
||||
done
|
||||
IFS=$old_ifs
|
||||
|
||||
# Wait until every node has learned the complete membership before roles
|
||||
# are assigned. This avoids CLUSTER REPLICATE racing gossip propagation.
|
||||
while :; do
|
||||
complete=true
|
||||
old_ifs=$IFS; IFS=','
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
[ "$(node_value "$host" cluster_known_nodes)" = "$NODE_COUNT" ] || complete=false
|
||||
done
|
||||
IFS=$old_ifs
|
||||
$complete && break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
shard=0
|
||||
old_ifs=$IFS; IFS=','
|
||||
for primary in $PRIMARY_HOSTS; do
|
||||
start=$((16384 * shard / SHARD_COUNT))
|
||||
end=$((16384 * (shard + 1) / SHARD_COUNT - 1))
|
||||
echo "Assigning slots $start-$end to shard $shard ($primary)"
|
||||
cli -h "$primary" -p "$REDIS_PORT" cluster addslotsrange "$start" "$end" >/dev/null || exit 1
|
||||
shard=$((shard + 1))
|
||||
done
|
||||
IFS=$old_ifs
|
||||
|
||||
old_ifs=$IFS; IFS=','
|
||||
for assignment in $REPLICA_ASSIGNMENTS; do
|
||||
replica=${assignment%%=*}
|
||||
primary=${assignment#*=}
|
||||
primary_id="$(cli -h "$primary" -p "$REDIS_PORT" cluster myid 2>/dev/null | tr -d '\r')"
|
||||
[ -n "$primary_id" ] || exit 1
|
||||
echo "Attaching $replica as a replica of $primary"
|
||||
cli -h "$replica" -p "$REDIS_PORT" cluster replicate "$primary_id" >/dev/null || exit 1
|
||||
done
|
||||
IFS=$old_ifs
|
||||
|
||||
# Do not declare success merely because slots are covered. Wait for every
|
||||
# intended replica relationship and for every member to see a healthy
|
||||
# cluster, which prevents an early restart from racing topology gossip.
|
||||
while :; do
|
||||
converged=true
|
||||
old_ifs=$IFS; IFS=','
|
||||
for assignment in $REPLICA_ASSIGNMENTS; do
|
||||
replica=${assignment%%=*}
|
||||
role="$(cli -h "$replica" -p "$REDIS_PORT" role 2>/dev/null | head -n1)"
|
||||
[ "$role" = slave ] || converged=false
|
||||
done
|
||||
for host in $ALL_NODE_HOSTS; do
|
||||
[ "$(node_value "$host" cluster_state)" = ok ] || converged=false
|
||||
done
|
||||
IFS=$old_ifs
|
||||
$converged && break
|
||||
sleep 1
|
||||
done
|
||||
echo "Redis Cluster created: all 16384 slots covered"
|
||||
|
||||
reconcile-topology.sh: |
|
||||
#!/bin/sh
|
||||
set -u
|
||||
# Redis correctly promotes replicas but does not automatically fail back.
|
||||
# Restore the canonical member-0 primaries after a failed worker returns,
|
||||
# keeping the three current primaries distributed across workers.
|
||||
cli() { redis-cli --no-auth-warning "$@"; }
|
||||
cluster_state() {
|
||||
cli -h "$COORDINATOR_HOST" -p "$REDIS_PORT" cluster info 2>/dev/null |
|
||||
tr -d '\r' | awk -F: '$1 == "cluster_state" { print $2 }'
|
||||
}
|
||||
|
||||
while :; do
|
||||
[ -f /etc/redis-runtime/terminating ] && exit 0
|
||||
if [ "$(cluster_state)" = ok ]; then
|
||||
old_ifs=$IFS; IFS=','
|
||||
for primary_identity in $PRIMARY_HOSTS; do
|
||||
role="$(cli -h "$primary_identity" -p "$REDIS_PORT" role 2>/dev/null | head -n1)"
|
||||
if [ "$role" = slave ]; then
|
||||
link="$(cli -h "$primary_identity" -p "$REDIS_PORT" info replication 2>/dev/null |
|
||||
tr -d '\r' | awk -F: '$1 == "master_link_status" { print $2 }')"
|
||||
if [ "$link" = up ]; then
|
||||
echo "Restoring canonical primary role to $primary_identity"
|
||||
cli -h "$primary_identity" -p "$REDIS_PORT" cluster failover >/dev/null 2>&1 || true
|
||||
i=0
|
||||
while [ "$i" -lt 20 ]; do
|
||||
role="$(cli -h "$primary_identity" -p "$REDIS_PORT" role 2>/dev/null | head -n1)"
|
||||
[ "$role" = master ] && break
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
while [ "$(cluster_state)" != ok ]; do sleep 1; done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
IFS=$old_ifs
|
||||
fi
|
||||
sleep 30
|
||||
done
|
||||
|
||||
startup-redis.sh: |
|
||||
#!/bin/sh
|
||||
[ "$(redis-cli -t 3 -p "$REDIS_PORT" --no-auth-warning ping 2>/dev/null)" = PONG ]
|
||||
|
||||
liveness-redis.sh: |
|
||||
#!/bin/sh
|
||||
resp="$(redis-cli -t 3 -p "$REDIS_PORT" --no-auth-warning ping 2>&1 || true)"
|
||||
case "$resp" in
|
||||
PONG|*LOADING*|*CLUSTERDOWN*) exit 0 ;;
|
||||
*) echo "$resp"; exit 1 ;;
|
||||
esac
|
||||
|
||||
readiness-redis.sh: |
|
||||
#!/bin/sh
|
||||
[ "$(redis-cli -t 3 -p "$REDIS_PORT" --no-auth-warning ping 2>/dev/null)" = PONG ] || exit 1
|
||||
state="$(redis-cli -t 3 -p "$REDIS_PORT" --no-auth-warning cluster info 2>/dev/null |
|
||||
tr -d '\r' | awk -F: '$1 == "cluster_state" { print $2 }')"
|
||||
[ "$state" = ok ] || { echo "cluster_state=$state"; exit 1; }
|
||||
|
||||
prestop-redis.sh: |
|
||||
#!/bin/sh
|
||||
# During an intentional restart, ask a healthy replica to take over first.
|
||||
# Replica identities remain on a different Kubernetes node because shard
|
||||
# anti-affinity is tied to persistent member identity, not current role.
|
||||
: > /etc/redis-runtime/terminating
|
||||
role="$(redis-cli -p "$REDIS_PORT" --no-auth-warning role 2>/dev/null | head -n1 || true)"
|
||||
[ "$role" = master ] || exit 0
|
||||
node_id="$(redis-cli -p "$REDIS_PORT" --no-auth-warning cluster myid 2>/dev/null | tr -d '\r')"
|
||||
[ -n "$node_id" ] || exit 0
|
||||
endpoint="$(redis-cli -p "$REDIS_PORT" --no-auth-warning cluster replicas "$node_id" 2>/dev/null |
|
||||
awk '$3 !~ /fail/ && $8 == "connected" { print $2; exit }')"
|
||||
[ -n "$endpoint" ] || exit 0
|
||||
address=${endpoint%%@*}
|
||||
metadata=${endpoint#*,}
|
||||
if [ "$metadata" != "$endpoint" ] && [ -n "$metadata" ]; then
|
||||
replica_host=$metadata
|
||||
else
|
||||
replica_host=${address%:*}
|
||||
fi
|
||||
replica_port=${address##*:}
|
||||
echo "Requesting graceful failover to $replica_host:$replica_port"
|
||||
redis-cli -h "$replica_host" -p "$replica_port" --no-auth-warning cluster failover >/dev/null 2>&1 || exit 0
|
||||
i=0
|
||||
while [ "$i" -lt 15 ]; do
|
||||
role="$(redis-cli -p "$REDIS_PORT" --no-auth-warning role 2>/dev/null | head -n1 || true)"
|
||||
[ "$role" != master ] && exit 0
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
exit 0
|
||||
37
templates/external-endpoint-rbac.yaml
Normal file
37
templates/external-endpoint-rbac.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
{{- if .Values.externalAccess.enabled }}
|
||||
{{- $fullname := include "redis-cluster.fullname" . }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ $fullname }}-endpoint-reader
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services"]
|
||||
verbs: ["get"]
|
||||
resourceNames:
|
||||
- {{ $fullname }}-external
|
||||
{{- range $shard := until (int .Values.cluster.shards) }}
|
||||
{{- range $member := until (int (add (int $.Values.cluster.replicasPerShard) 1)) }}
|
||||
- {{ printf "%s-s%d-n%d-x" $fullname $shard $member | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ $fullname }}-endpoint-reader
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "redis-cluster.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ $fullname }}-endpoint-reader
|
||||
{{- end }}
|
||||
51
templates/networkpolicy.yaml
Normal file
51
templates/networkpolicy.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
{{- if .Values.networkPolicy.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
# Intra-release traffic: client protocol is also used for replication and
|
||||
# key migration; the cluster bus carries gossip and failover elections.
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 14 }}
|
||||
ports:
|
||||
- port: {{ .Values.redis.port }}
|
||||
- port: {{ .Values.cluster.busPort }}
|
||||
# Client traffic.
|
||||
{{- if .Values.networkPolicy.allowExternal }}
|
||||
- ports:
|
||||
- port: {{ .Values.redis.port }}
|
||||
{{- else if .Values.networkPolicy.extraIngress }}
|
||||
- from:
|
||||
{{- toYaml .Values.networkPolicy.extraIngress | nindent 8 }}
|
||||
ports:
|
||||
- port: {{ .Values.redis.port }}
|
||||
{{- end }}
|
||||
{{- if .Values.metrics.enabled }}
|
||||
# Metrics scraping.
|
||||
{{- if .Values.networkPolicy.metricsFromNamespaces }}
|
||||
- from:
|
||||
{{- range .Values.networkPolicy.metricsFromNamespaces }}
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: {{ . }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- port: {{ .Values.metrics.port }}
|
||||
{{- else }}
|
||||
- ports:
|
||||
- port: {{ .Values.metrics.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
14
templates/pdb.yaml
Normal file
14
templates/pdb.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
{{- if .Values.podDisruptionBudget.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 6 }}
|
||||
{{- end }}
|
||||
87
templates/redisinsight-istio.yaml
Normal file
87
templates/redisinsight-istio.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
{{- if and .Values.redisInsight.enabled .Values.redisInsight.ingress.enabled }}
|
||||
{{- if not .Values.redisInsight.ingress.host }}
|
||||
{{- fail "redisInsight.ingress.host is required when RedisInsight ingress is enabled" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.redisInsight.ingress.tls.enabled (not .Values.redisInsight.ingress.tls.credentialName) }}
|
||||
{{- fail "redisInsight.ingress.tls.credentialName is required when TLS is enabled" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.redisInsight.ingress.tls.certificate.create (not .Values.redisInsight.ingress.tls.enabled) }}
|
||||
{{- fail "redisInsight.ingress.tls.enabled must be true when certificate.create is true" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.redisInsight.ingress.tls.certificate.create (not .Values.redisInsight.ingress.tls.certificate.issuerName) }}
|
||||
{{- fail "redisInsight.ingress.tls.certificate.issuerName is required when certificate.create is true" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.redisInsight.ingress.tls.enabled .Values.redisInsight.ingress.tls.certificate.create }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}-tls
|
||||
namespace: {{ default .Release.Namespace .Values.redisInsight.ingress.tls.certificate.secretNamespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ .Values.redisInsight.ingress.tls.credentialName }}
|
||||
issuerRef:
|
||||
name: {{ .Values.redisInsight.ingress.tls.certificate.issuerName }}
|
||||
kind: {{ .Values.redisInsight.ingress.tls.certificate.issuerKind }}
|
||||
commonName: {{ .Values.redisInsight.ingress.host | quote }}
|
||||
dnsNames:
|
||||
- {{ .Values.redisInsight.ingress.host | quote }}
|
||||
---
|
||||
{{- end }}
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
spec:
|
||||
selector:
|
||||
{{- toYaml .Values.redisInsight.ingress.gatewaySelector | nindent 4 }}
|
||||
servers:
|
||||
- port:
|
||||
number: 80
|
||||
name: http
|
||||
protocol: HTTP
|
||||
hosts:
|
||||
- {{ .Values.redisInsight.ingress.host | quote }}
|
||||
{{- if .Values.redisInsight.ingress.tls.enabled }}
|
||||
tls:
|
||||
httpsRedirect: true
|
||||
{{- end }}
|
||||
{{- if .Values.redisInsight.ingress.tls.enabled }}
|
||||
- port:
|
||||
number: 443
|
||||
name: https
|
||||
protocol: HTTPS
|
||||
hosts:
|
||||
- {{ .Values.redisInsight.ingress.host | quote }}
|
||||
tls:
|
||||
mode: SIMPLE
|
||||
credentialName: {{ .Values.redisInsight.ingress.tls.credentialName }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
spec:
|
||||
hosts:
|
||||
- {{ .Values.redisInsight.ingress.host | quote }}
|
||||
gateways:
|
||||
- {{ include "redis-cluster.redisInsightName" . }}
|
||||
http:
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /
|
||||
timeout: {{ .Values.redisInsight.ingress.requestTimeout }}
|
||||
route:
|
||||
- destination:
|
||||
host: {{ include "redis-cluster.redisInsightName" . }}
|
||||
port:
|
||||
number: 80
|
||||
{{- end }}
|
||||
220
templates/redisinsight.yaml
Normal file
220
templates/redisinsight.yaml
Normal file
@@ -0,0 +1,220 @@
|
||||
{{- if .Values.redisInsight.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
selector:
|
||||
{{- include "redis-cluster.redisInsightSelectorLabels" . | nindent 4 }}
|
||||
{{- if .Values.redisInsight.persistence.enabled }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
{{- with .Values.redisInsight.persistence.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- toYaml .Values.redisInsight.persistence.accessModes | nindent 4 }}
|
||||
{{- with .Values.redisInsight.persistence.storageClass }}
|
||||
storageClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.redisInsight.persistence.size }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.redisInsightName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightLabels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
# RedisInsight stores its connection database under /data. Recreate avoids
|
||||
# two pods contending for the same ReadWriteOnce volume during an upgrade.
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.redisInsightSelectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "redis-cluster.redisInsightSelectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
sidecar.istio.io/inject: "false"
|
||||
{{- with .Values.redisInsight.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if and .Values.externalAccess.enabled (not .Values.redisInsight.connection.host) }}
|
||||
serviceAccountName: {{ include "redis-cluster.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- end }}
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
fsGroupChangePolicy: OnRootMismatch
|
||||
{{- if and .Values.externalAccess.enabled (not .Values.redisInsight.connection.host) }}
|
||||
initContainers:
|
||||
- name: discover-bootstrap-endpoint
|
||||
image: "{{ .Values.externalAccess.endpointDiscovery.image.repository }}:{{ .Values.externalAccess.endpointDiscovery.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.externalAccess.endpointDiscovery.image.pullPolicy }}
|
||||
command: ["/bin/sh", "/scripts/discover-external-endpoint.sh"]
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
env:
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: EXTERNAL_SERVICE_NAME
|
||||
value: {{ include "redis-cluster.bootstrapServiceName" . | quote }}
|
||||
resources:
|
||||
{{- toYaml .Values.externalAccess.endpointDiscovery.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: scripts
|
||||
mountPath: /scripts
|
||||
readOnly: true
|
||||
- name: bootstrap-endpoint
|
||||
mountPath: /external-endpoint
|
||||
- name: kube-api-access
|
||||
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: redisinsight
|
||||
image: "{{ .Values.redisInsight.image.repository }}:{{ .Values.redisInsight.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.redisInsight.image.pullPolicy }}
|
||||
{{- if and .Values.externalAccess.enabled (not .Values.redisInsight.connection.host) }}
|
||||
# Preserve the image CMD as arguments; this wrapper only injects the
|
||||
# dynamically discovered LoadBalancer endpoint before exec.
|
||||
command: ["/scripts/start-redisinsight.sh"]
|
||||
{{- end }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
env:
|
||||
- name: RI_APP_HOST
|
||||
value: "0.0.0.0"
|
||||
- name: RI_APP_PORT
|
||||
value: {{ .Values.redisInsight.port | quote }}
|
||||
# These variables register a connection inside RedisInsight only;
|
||||
# they do not alter the Redis cluster or its Kubernetes resources.
|
||||
- name: RI_REDIS_HOST
|
||||
value: {{ default (include "redis-cluster.bootstrapServiceName" .) .Values.redisInsight.connection.host | quote }}
|
||||
- name: RI_REDIS_PORT
|
||||
value: {{ default (ternary .Values.externalAccess.port .Values.redis.port .Values.externalAccess.enabled) .Values.redisInsight.connection.port | quote }}
|
||||
- name: RI_REDIS_ALIAS
|
||||
value: {{ .Values.redisInsight.connection.alias | quote }}
|
||||
- name: RI_REDIS_TLS
|
||||
value: {{ .Values.redisInsight.connection.tls | quote }}
|
||||
{{- if .Values.auth.enabled }}
|
||||
- name: RI_REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "redis-cluster.secretName" . }}
|
||||
key: {{ include "redis-cluster.secretKey" . }}
|
||||
{{- end }}
|
||||
- name: RI_STDOUT_LOGGER
|
||||
value: "true"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.redisInsight.port }}
|
||||
protocol: TCP
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /api/health/
|
||||
port: http
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 60
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/health/
|
||||
port: http
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/health/
|
||||
port: http
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 5
|
||||
resources:
|
||||
{{- toYaml .Values.redisInsight.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
{{- if and .Values.externalAccess.enabled (not .Values.redisInsight.connection.host) }}
|
||||
- name: scripts
|
||||
mountPath: /scripts
|
||||
readOnly: true
|
||||
- name: bootstrap-endpoint
|
||||
mountPath: /bootstrap-endpoint
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: data
|
||||
{{- if .Values.redisInsight.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "redis-cluster.redisInsightName" . }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- if and .Values.externalAccess.enabled (not .Values.redisInsight.connection.host) }}
|
||||
- name: scripts
|
||||
configMap:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
defaultMode: 0555
|
||||
- name: bootstrap-endpoint
|
||||
emptyDir: {}
|
||||
- name: kube-api-access
|
||||
projected:
|
||||
defaultMode: 0444
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
path: token
|
||||
expirationSeconds: 3600
|
||||
- configMap:
|
||||
name: kube-root-ca.crt
|
||||
items:
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
{{- end }}
|
||||
{{- with .Values.redisInsight.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.redisInsight.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
12
templates/secret.yaml
Normal file
12
templates/secret.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
{{- if and .Values.auth.enabled (not .Values.auth.existingSecret) }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
redis-password: {{ include "redis-cluster.password" . | b64enc | quote }}
|
||||
{{- end }}
|
||||
75
templates/service-external.yaml
Normal file
75
templates/service-external.yaml
Normal file
@@ -0,0 +1,75 @@
|
||||
{{- if .Values.externalAccess.enabled }}
|
||||
{{- $root := . }}
|
||||
{{- $fullname := include "redis-cluster.fullname" . }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullname }}-external
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
redis-cluster.external-role: bootstrap
|
||||
{{- with .Values.externalAccess.bootstrap.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: {{ .Values.externalAccess.externalTrafficPolicy }}
|
||||
allocateLoadBalancerNodePorts: {{ .Values.externalAccess.allocateLoadBalancerNodePorts }}
|
||||
{{- with .Values.externalAccess.loadBalancerClass }}
|
||||
loadBalancerClass: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.externalAccess.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
- name: tcp-redis
|
||||
port: {{ .Values.externalAccess.port }}
|
||||
targetPort: tcp-redis
|
||||
appProtocol: redis
|
||||
{{- range $shard := until (int .Values.cluster.shards) }}
|
||||
{{- range $member := until (int (add (int $.Values.cluster.replicasPerShard) 1)) }}
|
||||
{{- $memberName := printf "%s-s%d-n%d" $fullname $shard $member | trunc 63 | trimSuffix "-" }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $memberName }}-x
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" $root | nindent 4 }}
|
||||
redis-cluster.external-role: member
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
{{- with $.Values.externalAccess.memberServices.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: {{ $.Values.externalAccess.externalTrafficPolicy }}
|
||||
allocateLoadBalancerNodePorts: {{ $.Values.externalAccess.allocateLoadBalancerNodePorts }}
|
||||
{{- with $.Values.externalAccess.loadBalancerClass }}
|
||||
loadBalancerClass: {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- with $.Values.externalAccess.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 4 }}
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
ports:
|
||||
- name: tcp-redis
|
||||
port: {{ $.Values.externalAccess.port }}
|
||||
targetPort: tcp-redis
|
||||
appProtocol: redis
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
22
templates/service-headless.yaml
Normal file
22
templates/service-headless.yaml
Normal file
@@ -0,0 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}-headless
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
clusterIP: None
|
||||
# Pods must resolve each other during bootstrap, before they are Ready.
|
||||
publishNotReadyAddresses: true
|
||||
selector:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
- name: tcp-redis
|
||||
port: {{ .Values.redis.port }}
|
||||
targetPort: tcp-redis
|
||||
appProtocol: redis
|
||||
- name: tcp-cluster
|
||||
port: {{ .Values.cluster.busPort }}
|
||||
targetPort: tcp-cluster
|
||||
appProtocol: redis
|
||||
24
templates/service.yaml
Normal file
24
templates/service.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
{{/* Any node is a valid startup node. Cluster-aware clients fetch the slot map
|
||||
and then connect directly to the stable per-member hostnames Redis advertises. */}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
- name: tcp-redis
|
||||
port: {{ .Values.redis.port }}
|
||||
targetPort: tcp-redis
|
||||
appProtocol: redis
|
||||
{{- if .Values.metrics.enabled }}
|
||||
- name: http-metrics
|
||||
port: {{ .Values.metrics.port }}
|
||||
targetPort: http-metrics
|
||||
appProtocol: http
|
||||
{{- end }}
|
||||
14
templates/serviceaccount.yaml
Normal file
14
templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: false
|
||||
{{- end }}
|
||||
20
templates/servicemonitor.yaml
Normal file
20
templates/servicemonitor.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "redis-cluster.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" . | nindent 4 }}
|
||||
{{- with .Values.metrics.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" . | nindent 6 }}
|
||||
endpoints:
|
||||
- port: http-metrics
|
||||
interval: {{ .Values.metrics.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }}
|
||||
{{- end }}
|
||||
311
templates/statefulset.yaml
Normal file
311
templates/statefulset.yaml
Normal file
@@ -0,0 +1,311 @@
|
||||
{{- $root := . -}}
|
||||
{{- $fullname := include "redis-cluster.fullname" . -}}
|
||||
{{- if gt (len $fullname) 53 -}}
|
||||
{{- fail (printf "release fullname %q is too long; use fullnameOverride with at most 53 characters" $fullname) -}}
|
||||
{{- end -}}
|
||||
{{- if ge (int .Values.cluster.replicasPerShard) (int .Values.cluster.shards) -}}
|
||||
{{- fail "cluster.replicasPerShard must be lower than cluster.shards so crossed placement never puts a shard replica with its own primary" -}}
|
||||
{{- end -}}
|
||||
{{- $headless := include "redis-cluster.headlessFqdn" . -}}
|
||||
{{- $nodeCount := include "redis-cluster.nodeCount" . -}}
|
||||
{{- $allHosts := list -}}
|
||||
{{- $primaryHosts := list -}}
|
||||
{{- $assignments := list -}}
|
||||
{{- $addressAssignments := list -}}
|
||||
{{- range $shard := until (int .Values.cluster.shards) -}}
|
||||
{{- range $member := until (int (add (int $.Values.cluster.replicasPerShard) 1)) -}}
|
||||
{{- $memberName := printf "%s-s%d-n%d" $fullname $shard $member | trunc 63 | trimSuffix "-" -}}
|
||||
{{- $podName := printf "%s-0" $memberName -}}
|
||||
{{- $host := printf "%s-0.%s" $memberName $headless -}}
|
||||
{{- $allHosts = append $allHosts $host -}}
|
||||
{{- $addressAssignments = append $addressAssignments (printf "%s=%s" $podName $host) -}}
|
||||
{{- if eq $member 0 -}}
|
||||
{{- $primaryHosts = append $primaryHosts $host -}}
|
||||
{{- else -}}
|
||||
{{- $primaryName := printf "%s-s%d-n0" $fullname $shard | trunc 63 | trimSuffix "-" -}}
|
||||
{{- $primaryHost := printf "%s-0.%s" $primaryName $headless -}}
|
||||
{{- $assignments = append $assignments (printf "%s=%s" $host $primaryHost) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $coordinator := first $primaryHosts -}}
|
||||
{{- range $shard := until (int .Values.cluster.shards) }}
|
||||
{{- range $member := until (int (add (int $.Values.cluster.replicasPerShard) 1)) }}
|
||||
{{- $memberName := printf "%s-s%d-n%d" $fullname $shard $member | trunc 63 | trimSuffix "-" }}
|
||||
{{- $memberIndex := add (mul $shard (add (int $.Values.cluster.replicasPerShard) 1)) $member }}
|
||||
{{- $announceHostname := printf "%s-0.%s" $memberName $headless }}
|
||||
{{- $externalServiceName := printf "%s-x" $memberName }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ $memberName }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "redis-cluster.labels" $root | nindent 4 }}
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
spec:
|
||||
serviceName: {{ $fullname }}-headless
|
||||
replicas: 1
|
||||
podManagementPolicy: Parallel
|
||||
# Separate one-member StatefulSets would otherwise all roll concurrently.
|
||||
# OnDelete makes upgrades explicit and safe; see README.md.
|
||||
updateStrategy:
|
||||
type: OnDelete
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 6 }}
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 8 }}
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
{{- with $.Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") $root | sha256sum }}
|
||||
{{- if not $.Values.istio.injectSidecar }}
|
||||
sidecar.istio.io/inject: "false"
|
||||
{{- else }}
|
||||
proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
|
||||
{{- end }}
|
||||
{{- with $.Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "redis-cluster.serviceAccountName" $root }}
|
||||
automountServiceAccountToken: false
|
||||
terminationGracePeriodSeconds: {{ $.Values.terminationGracePeriodSeconds }}
|
||||
{{- with $.Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.priorityClassName }}
|
||||
priorityClassName: {{ . }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml $.Values.podSecurityContext | nindent 8 }}
|
||||
affinity:
|
||||
{{- if gt $member 0 }}
|
||||
# Cross replicas onto the worker holding another shard's canonical
|
||||
# primary. For 3x1 this produces A:P0+R2, B:P1+R0, C:P2+R1.
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 18 }}
|
||||
redis-cluster.shard: {{ mod (add $shard $member) (int $.Values.cluster.shards) | quote }}
|
||||
redis-cluster.member: "0"
|
||||
topologyKey: kubernetes.io/hostname
|
||||
{{- end }}
|
||||
podAntiAffinity:
|
||||
# Hard invariants: copies of one shard never share a worker, and
|
||||
# equivalent member identities are spread across workers. In the
|
||||
# canonical topology, this permits at most one primary per worker.
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 18 }}
|
||||
redis-cluster.shard: {{ $shard | quote }}
|
||||
topologyKey: kubernetes.io/hostname
|
||||
- labelSelector:
|
||||
matchLabels:
|
||||
{{- include "redis-cluster.selectorLabels" $root | nindent 18 }}
|
||||
redis-cluster.member: {{ $member | quote }}
|
||||
topologyKey: kubernetes.io/hostname
|
||||
{{- with $.Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if $.Values.externalAccess.enabled }}
|
||||
initContainers:
|
||||
- name: discover-external-endpoint
|
||||
image: "{{ $.Values.externalAccess.endpointDiscovery.image.repository }}:{{ $.Values.externalAccess.endpointDiscovery.image.tag }}"
|
||||
imagePullPolicy: {{ $.Values.externalAccess.endpointDiscovery.image.pullPolicy }}
|
||||
command: ["/bin/sh", "/scripts/discover-external-endpoint.sh"]
|
||||
securityContext:
|
||||
{{- toYaml $.Values.containerSecurityContext | nindent 12 }}
|
||||
env:
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: EXTERNAL_SERVICE_NAME
|
||||
value: {{ $externalServiceName | quote }}
|
||||
resources:
|
||||
{{- toYaml $.Values.externalAccess.endpointDiscovery.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: scripts
|
||||
mountPath: /scripts
|
||||
- name: external-endpoint
|
||||
mountPath: /external-endpoint
|
||||
- name: kube-api-access
|
||||
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: redis
|
||||
image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag }}"
|
||||
imagePullPolicy: {{ $.Values.image.pullPolicy }}
|
||||
command: ["/bin/sh", "/scripts/start-redis.sh"]
|
||||
securityContext:
|
||||
{{- toYaml $.Values.containerSecurityContext | nindent 12 }}
|
||||
env:
|
||||
{{- include "redis-cluster.commonEnv" $root | nindent 12 }}
|
||||
- name: COORDINATOR_HOST
|
||||
value: {{ $coordinator | quote }}
|
||||
- name: ALL_NODE_HOSTS
|
||||
value: {{ join "," $allHosts | quote }}
|
||||
- name: PRIMARY_HOSTS
|
||||
value: {{ join "," $primaryHosts | quote }}
|
||||
- name: REPLICA_ASSIGNMENTS
|
||||
value: {{ join "," $assignments | quote }}
|
||||
- name: NODE_ADDRESS_ASSIGNMENTS
|
||||
value: {{ join "," $addressAssignments | quote }}
|
||||
- name: ANNOUNCE_HOSTNAME
|
||||
value: {{ $announceHostname | quote }}
|
||||
- name: ANNOUNCE_PORT
|
||||
value: {{ ternary $.Values.externalAccess.port $.Values.redis.port $.Values.externalAccess.enabled | quote }}
|
||||
- name: EXTERNAL_ACCESS_ENABLED
|
||||
value: {{ $.Values.externalAccess.enabled | quote }}
|
||||
ports:
|
||||
- name: tcp-redis
|
||||
containerPort: {{ $.Values.redis.port }}
|
||||
- name: tcp-cluster
|
||||
containerPort: {{ $.Values.cluster.busPort }}
|
||||
startupProbe:
|
||||
exec:
|
||||
command: ["/bin/sh", "/scripts/startup-redis.sh"]
|
||||
initialDelaySeconds: {{ $.Values.probes.redis.startup.initialDelaySeconds }}
|
||||
periodSeconds: {{ $.Values.probes.redis.startup.periodSeconds }}
|
||||
timeoutSeconds: {{ $.Values.probes.redis.startup.timeoutSeconds }}
|
||||
failureThreshold: {{ $.Values.probes.redis.startup.failureThreshold }}
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["/bin/sh", "/scripts/liveness-redis.sh"]
|
||||
periodSeconds: {{ $.Values.probes.redis.liveness.periodSeconds }}
|
||||
timeoutSeconds: {{ $.Values.probes.redis.liveness.timeoutSeconds }}
|
||||
failureThreshold: {{ $.Values.probes.redis.liveness.failureThreshold }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["/bin/sh", "/scripts/readiness-redis.sh"]
|
||||
periodSeconds: {{ $.Values.probes.redis.readiness.periodSeconds }}
|
||||
timeoutSeconds: {{ $.Values.probes.redis.readiness.timeoutSeconds }}
|
||||
failureThreshold: {{ $.Values.probes.redis.readiness.failureThreshold }}
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["/bin/sh", "/scripts/prestop-redis.sh"]
|
||||
resources:
|
||||
{{- toYaml $.Values.redis.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
- name: scripts
|
||||
mountPath: /scripts
|
||||
- name: config
|
||||
mountPath: /etc/redis-ro
|
||||
- name: redis-runtime
|
||||
mountPath: /etc/redis-runtime
|
||||
{{- if $.Values.externalAccess.enabled }}
|
||||
- name: external-endpoint
|
||||
mountPath: /external-endpoint
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- if $.Values.metrics.enabled }}
|
||||
- name: metrics
|
||||
image: "{{ $.Values.metrics.image.repository }}:{{ $.Values.metrics.image.tag }}"
|
||||
imagePullPolicy: {{ $.Values.metrics.image.pullPolicy }}
|
||||
securityContext:
|
||||
{{- toYaml $.Values.containerSecurityContext | nindent 12 }}
|
||||
env:
|
||||
- name: REDIS_ADDR
|
||||
value: "redis://localhost:{{ $.Values.redis.port }}"
|
||||
{{- if $.Values.auth.enabled }}
|
||||
- name: REDIS_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "redis-cluster.secretName" $root }}
|
||||
key: {{ include "redis-cluster.secretKey" $root }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http-metrics
|
||||
containerPort: {{ $.Values.metrics.port }}
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: http-metrics
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: http-metrics
|
||||
periodSeconds: 15
|
||||
resources:
|
||||
{{- toYaml $.Values.metrics.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: scripts
|
||||
configMap:
|
||||
name: {{ $fullname }}
|
||||
defaultMode: 0555
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ $fullname }}
|
||||
items:
|
||||
- key: redis.conf
|
||||
path: redis.conf
|
||||
- name: redis-runtime
|
||||
emptyDir: {}
|
||||
{{- if $.Values.externalAccess.enabled }}
|
||||
- name: external-endpoint
|
||||
emptyDir: {}
|
||||
- name: kube-api-access
|
||||
projected:
|
||||
defaultMode: 0444
|
||||
sources:
|
||||
- serviceAccountToken:
|
||||
path: token
|
||||
expirationSeconds: 3600
|
||||
- configMap:
|
||||
name: kube-root-ca.crt
|
||||
items:
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
{{- end }}
|
||||
{{- if not $.Values.persistence.enabled }}
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- if $.Values.persistence.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
{{- with $.Values.persistence.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- toYaml $.Values.persistence.accessModes | nindent 10 }}
|
||||
{{- with $.Values.persistence.storageClass }}
|
||||
storageClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ $.Values.persistence.size }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
Reference in New Issue
Block a user