312 lines
13 KiB
YAML
312 lines
13 KiB
YAML
{{- $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 }}
|