From 860a00f111a93cecdebf56a53f0fd0e9fa3cc2cc Mon Sep 17 00:00:00 2001 From: juan131 Date: Wed, 29 May 2019 17:38:34 +0200 Subject: [PATCH] [bitnami/etcd] Support auto disaster recovery --- bitnami/etcd/Chart.yaml | 2 +- bitnami/etcd/README.md | 128 +++++++--- bitnami/etcd/templates/NOTES.txt | 37 +-- bitnami/etcd/templates/_helpers.tpl | 39 ++- bitnami/etcd/templates/scripts-configmap.yaml | 156 ++++++++++++ bitnami/etcd/templates/secrets.yaml | 10 +- bitnami/etcd/templates/snapshot-pvc.yaml | 18 ++ bitnami/etcd/templates/statefulset.yaml | 239 ++++++++---------- bitnami/etcd/templates/svc-headless.yaml | 16 +- bitnami/etcd/templates/svc.yaml | 16 +- bitnami/etcd/values-production.yaml | 48 +++- bitnami/etcd/values.yaml | 50 +++- 12 files changed, 537 insertions(+), 222 deletions(-) create mode 100644 bitnami/etcd/templates/scripts-configmap.yaml create mode 100644 bitnami/etcd/templates/snapshot-pvc.yaml diff --git a/bitnami/etcd/Chart.yaml b/bitnami/etcd/Chart.yaml index 69d329d85..cb057586f 100644 --- a/bitnami/etcd/Chart.yaml +++ b/bitnami/etcd/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: etcd -version: 2.3.3 +version: 3.0.0 appVersion: 3.3.13 description: etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines keywords: diff --git a/bitnami/etcd/README.md b/bitnami/etcd/README.md index 5409ca473..c8364e8de 100644 --- a/bitnami/etcd/README.md +++ b/bitnami/etcd/README.md @@ -45,13 +45,13 @@ The command removes all the Kubernetes components associated with the chart and The following tables lists the configurable parameters of the etcd chart and their default values. -| Parameter | Description | Default | +| Parameter | Description | Default | |---------------------------------------|----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------- | | `global.imageRegistry` | Global Docker image registry | `nil` | | `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | | `image.registry` | etcd image registry | `docker.io` | -| `image.repository` | etcd Image name | `bitnami/etcd` | -| `image.tag` | etcd Image tag | `{TAG_NAME}` | +| `image.repository` | etcd image name | `bitnami/etcd` | +| `image.tag` | etcd image tag | `{TAG_NAME}` | | `image.pullPolicy` | etcd image pull policy | `IfNotPresent` | | `image.pullSecrets` | Specify docker-registry secret names as an array | `[]` (does not add image pull secrets to deployed pods) | | `image.debug` | Specify if debug values should be set | `false` | @@ -77,48 +77,53 @@ The following tables lists the configurable parameters of the etcd chart and the | `securityContext.enabled` | Enable security context | `true` | | `securityContext.fsGroup` | Group ID for the container | `1001` | | `securityContext.runAsUser` | User ID for the container | `1001` | -| `service.dnsBase` | Kubernetes service cluster dns base name | svc.cluster.local | +| `service.dnsBase` | Kubernetes service cluster dns base name | `svc.cluster.local` | | `service.type` | Kubernetes Service type | `ClusterIP` | | `service.port` | etcd client port | `2379` | | `service.nodePort` | Port to bind to for NodePort service type (client port) | `nil` | | `service.peerPort` | etcd peer port | `2380` | | `service.peerNodePort` | Port to bind to for NodePort service type (peer port) | `nil` | -| `service.annotations` | Annotations for etcd service | {} | +| `service.annotations` | Annotations for etcd service | `{}` | | `service.loadBalancerIP` | loadBalancerIP if etcd service type is `LoadBalancer` | `nil` | | `persistence.enabled` | Enable persistence using PVC | `true` | | `persistence.storageClass` | PVC Storage Class for etcd volume | `nil` | | `persistence.accessMode` | PVC Access Mode for etcd volume | `ReadWriteOnce` | | `persistence.size` | PVC Storage Request for etcd volume | `8Gi` | | `persistence.annotations` | Annotations for the PVC | `{}` | -| `affinity` | Affinity and AntiAffinity rules for pod assignment | `{}` | -| `nodeSelector` | Node labels for pod assignment | `{}` | -| `tolerations` | Toleration labels for pod assignment | `[]` | | `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | -| `livenessProbe.enabled` | Turn on and off liveness probe | `true` | -| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 10 | -| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | -| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | -| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 2 | -| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | -| `readinessProbe.enabled` | Turn on and off readiness probe | `true` | -| `readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 5 | -| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | -| `readinessProbe.timeoutSeconds` | When the probe times out | 5 | -| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 6 | -| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | 1 | -| `podAnnotations` | Annotations to be added to pods | {} | -| `metrics.enabled` | Enable prometheus to access etcd metrics endpoint | `false` | +| `livenessProbe.enabled` | Turn on and off liveness probe | `true` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `10` | +| `livenessProbe.periodSeconds` | How often to perform the probe | `10` | +| `livenessProbe.timeoutSeconds` | When the probe times out | `5` | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `2` | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | `1` | +| `readinessProbe.enabled` | Turn on and off readiness probe | `true` | +| `readinessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | `15` | +| `readinessProbe.periodSeconds` | How often to perform the probe | `10` | +| `readinessProbe.timeoutSeconds` | When the probe times out | `5` | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | `6` | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed | `1` | +| `podAnnotations` | Annotations to be added to pods | `{}` | +| `nodeAffinity` | Node Affinity rules for pod assignment. The value is evaluated as a template. | `{}` | +| `podAffinity` | Affinity rules for pod assignment. The value is evaluated as a template. | `{}` | +| `podAntiAffinity` | Anti-Affinity rules for pod assignment. Allowed values: `soft` and `hard` | `soft` | +| `nodeSelector` | Node labels for pod assignment. The value is evaluated as a template. | `{}` | +| `tolerations` | Tolerations for pod assignment. The value is evaluated as a template. | `{}` | +| `metrics.enabled` | Enable Prometheus exporter to expose etcd metrics | `false` | | `metrics.podAnnotations` | Annotations for enabling prometheus to access the metrics endpoint | {`prometheus.io/scrape: "true",prometheus.io/port: "2379"`} | - +| `disasterRecovery.enabled` | Enable auto disaster recovery by periodically snapshotting the keyspace | `false` | +| `disasterRecovery.interval` | Interval (in seconds) to save snapshots | `300` | +| `disasterRecovery.size` | PVC Storage Request | `2Gi` | +| `disasterRecovery.storageClassName` | PVC Storage ClassName, choose a storageClassName with ReadWriteMany support | `nfs` | Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, ```console $ helm install --name my-release \ - --set auth.rootPassword=secretpassword bitnami/etcd + --set auth.rbac.rootPassword=secretpassword bitnami/etcd ``` -The above command sets the etcd `etcd` account password to `secretpassword`. Additionally it creates a database named `my-database`. +The above command sets the etcd `root` account password to `secretpassword`. Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, @@ -188,7 +193,7 @@ Bitnami will release a new chart updating its containers if a new version of the In order to use custom configuration parameters, two options are available: - - Using environment variables: etcd allows setting environment variables that map to configuration settings. In order to set extra environment variables, use the `envVarsConfigMap` value to point to a ConfigMap that contains them. Example: +- Using environment variables: etcd allows setting environment variables that map to configuration settings. In order to set extra environment variables, use the `envVarsConfigMap` value to point to a ConfigMap that contains them. Example: ```console $ cat << EOF > /tmp/configurationEnvVars.yaml @@ -203,18 +208,32 @@ data: EOF $ kubectl create -f /tmp/configurationEnvVars.yaml - $ helm install bitnami/etcd --set envVarsConfigMap=etcd-env-vars ``` - - Using a custom etcd.conf.yml: The etcd chart allows mounting a custom etcd.conf.yml file using the `configFileConfigMap` value. Example: +- Using a custom `etcd.conf.yml`: The etcd chart allows mounting a custom etcd.conf.yml file using the `configFileConfigMap` value. Example: ```console $ kubectl create configmap etcd-conf --from-file=etcd.conf.yml - $ helm install bitnami/etcd --set configFileConfigMap=etcd-conf ``` +## Production and horizontal scaling + +The following repo contains the recommended production settings for etcd server in an alternative [values file](values-production.yaml). Please read carefully the comments in the values-production.yaml file to set up your environment. + +```console +$ helm install --name my-release -f ./values-production.yaml bitnami/etcd +``` + +To horizontally scale this chart once it has been deployed: + +```console +$ helm upgrade my-release bitnami/etcd \ + -f ./values-production.yaml + --set statefulset.replicaCount=5 +``` + ## Enable security for etcd ### Configure RBAC @@ -223,11 +242,9 @@ In order to enable [Role-based access control for etcd](https://coreos.com/etcd/ ```console $ helm install --name my-release --set auth.rbac.enabled --set auth.rbac.rootPassword=YOUR-PASSWORD bitnami/etcd - ``` -The previous command will deploy etcd creating a `root` user with its associate `root` role with access to everything. -The rest of users will use the `guest` role and won't have permissions to do anything. +The previous command will deploy etcd creating a `root` user with its associate `root` role with access to everything. The rest of users will use the `guest` role and won't have permissions to do anything. ### Configure certificated for peer communication @@ -235,10 +252,9 @@ In order to enable secure transport between peer nodes deploy the helm chart wit ```console $ helm install --name my-release --set auth.peer.secureTransport=true --set auth.peer.useAutoTLS=true bitnami/etcd - ``` -### Configure certificates for client comminication +### Configure certificates for client communication In order to enable secure transport between client and server you have to create a secret containing the cert and key files and the CA used to sign those client certificates. @@ -252,22 +268,56 @@ Once the secret is created, you can deploy the helm chart with these options: ```console $ helm install --name my-release --set auth.client.secureTransport=true --set auth.client.enableAuthentication=true --set auth.client.existingSecret=etcd-client-certs bitnami/etcd - ``` > Ref: [etcd security model](https://coreos.com/etcd/docs/latest/op-guide/security.html) > > Ref: [Generate self-signed certificagtes for etcd](https://coreos.com/os/docs/latest/generate-self-signed-certificates.html) -## Persistence +## Persistence and Disaster recovery -The [Bitnami etcd](https://github.com/bitnami/bitnami-docker-etcd) image stores the etcd data at the `/bitnami/etcd` path of the container. +### Persistence -Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube. -See the [Configuration](#configuration) section to configure the PVC or to disable persistence. +The [Bitnami etcd](https://github.com/bitnami/bitnami-docker-etcd) image stores the etcd data at the `/bitnami/etcd` path of the container. Persistent Volume Claims are used to keep the data across statefulsets. This is known to work in GCE, AWS, and Minikube. To enable persistence, deploy the helm chart with these options: + +```console +$ helm install --name my-release bitnami/etcd \ + --set persistence.enable=true \ + --set persistence.size=8Gi +``` + +### Disaster recovery + +You can enable auto disaster recovery by periodically snapshotting the keyspace. If the cluster permanently loses more than (N-1)/2 members, it tries to recover the cluster from a previous snapshot. + +```console +$ helm install --name my-release bitnami/etcd \ + --set persistence.enable=true \ + --set disasterRecovery.enabled=true \ + --set disasterRecovery.interval=300 \ + --set disasterRecovery.size=2Gi \ + --set disasterRecovery.storageClassName=nfs +``` + +> **Note**: Disaster recovery feature requires using volumes with ReadWriteMany access mode. For instance, you can use the stable/nfs-server-provisioner chart to provide NFS PVCs: + +```console +$ helm install --name nfs-server-provisioner stable/nfs-server-provisioner \ + --set persistence.enabled=true --set persistence.size=10Gi +``` ## Upgrading +### To 3.0.0 + +Backwards compatibility is not guaranteed. The following notables changes were included: + +- **etcdctl** uses v3 API. +- Adds support for auto disaster recovery. +- Labels are adapted to follow the Helm charts best practices. + +To upgrade from previous charts versions, create a snapshot of the keyspace and restore it in a new etcd cluster. Only v3 API data can be restored. + ### To 1.0.0 Backwards compatibility is not guaranteed unless you modify the labels used on the chart's deployments. diff --git a/bitnami/etcd/templates/NOTES.txt b/bitnami/etcd/templates/NOTES.txt index 512277242..a68827e13 100644 --- a/bitnami/etcd/templates/NOTES.txt +++ b/bitnami/etcd/templates/NOTES.txt @@ -4,7 +4,7 @@ WARNING By specifying "service.type=LoadBalancer" and "allowNoneAuthentication=true" you - have most likely exposed the Redis service externally without any authentication + have most likely exposed the etcd service externally without any authentication mechanism. For security reasons, we strongly suggest that you switch to "ClusterIP" or @@ -23,13 +23,13 @@ etcd can be accessed via port {{ .Values.service.port }} on the following DNS na To set a key run the following command: - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "etcd.name" . }}" -o jsonpath="{.items[0].metadata.name}") - kubectl exec -it $POD_NAME -- etcdctl set /message Hello + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "etcd.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + kubectl exec -it $POD_NAME -c etcd -- etcdctl put /message Hello To get a key run the following command: - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "etcd.name" . }}" -o jsonpath="{.items[0].metadata.name}") - kubectl exec -it $POD_NAME -- etcdctl get /message + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ template "etcd.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + kubectl exec -it $POD_NAME -c etcd -- etcdctl get /message To connect to your etcd server from outside the cluster execute the following commands: @@ -45,40 +45,47 @@ To connect to your etcd server from outside the cluster execute the following co Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "etcd.fullname" . }}' export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "etcd.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo "etcd URL: http://$SERVICE_IP:2379/" + echo "etcd URL: http://$SERVICE_IP:{{ .Values.service.port }}/" {{- else if contains "ClusterIP" .Values.service.type }} - kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "etcd.fullname" . }} 2379:2379 & - echo "etcd URL: http://127.0.0.1:2379" + kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "etcd.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} & + echo "etcd URL: http://127.0.0.1:{{ .Values.service.port }}" {{- end }} +{{- if .Values.auth.rbac.enabled }} - -{{ if .Values.auth.rbac.enabled }} - * As rbac is enabled you should add the flag `-u root:$ETCD_ROOT_PASSWORD` to the etcdctl commands. Export the password with this command: + * As rbac is enabled you should add the flag `--user root:$ETCD_ROOT_PASSWORD` to the etcdctl commands. Use the command below to export the password: export ETCD_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "etcd.fullname" . }} -o jsonpath="{.data.etcd-root-password}" | base64 --decode) -{{ end }} +{{- end }} {{- if .Values.auth.client.secureTransport }} {{- if .Values.auth.client.useAutoTLS }} + * As TLS is enabled you should add the flag `--cert-file {{ template "etcd.dataDir" . }}/fixtures/client/cert.pem --key-file {{ template "etcd.dataDir" .}}/fixtures/client/key.pem` to the etcdctl commands. + {{- else }} + * As TLS is enabled you should add the flag `--cert-file /opt/bitnami/etcd/certs/client/cert.pem --key-file /opt/bitnami/etcd/certs/client/key.pem` to the etcdctl commands. + {{- end }} + * You should also export a proper etcdctl endpoint using the https schema. Eg. export ETCDCTL_ENDPOINTS=https://{{ template "etcd.fullname" . }}-0:{{ .Values.service.port }} {{- end }} -{{ if .Values.auth.client.enableAuthentication }} - * As TLS host authentication is enabled you should add the flag `--ca-file /opt/bitnami/etcd/certs/client/ca.crt` to the etcdctl commands. -{{- end }} +{{- if .Values.auth.client.enableAuthentication }} + * As TLS host authentication is enabled you should add the flag `--ca-file /opt/bitnami/etcd/certs/client/ca.crt` to the etcdctl commands. + +{{- end }} {{- if and (contains "bitnami/" .Values.image.repository) (not (.Values.image.tag | toString | regexFind "-r\\d+$|sha256:")) }} WARNING: Rolling tag detected ({{ .Values.image.repository }}:{{ .Values.image.tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment. +info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/ {{- end }} + +{{ include "etcd.validateValues" . }} diff --git a/bitnami/etcd/templates/_helpers.tpl b/bitnami/etcd/templates/_helpers.tpl index 4bcdccbd5..a4fbc36f3 100644 --- a/bitnami/etcd/templates/_helpers.tpl +++ b/bitnami/etcd/templates/_helpers.tpl @@ -82,9 +82,9 @@ Return the proper etcd data dir Return the proper etcdctl authentication options */}} {{- define "etcd.authOptions" -}} -{{- $rbacOption := "-u root:$ETCD_ROOT_PASSWORD" -}} -{{- $certsOption := " --cert-file $ETCD_CERT_FILE --key-file $ETCD_KEY_FILE" -}} -{{- $caOption := " --ca-file $ETCD_TRUSTED_CA_FILE" -}} +{{- $rbacOption := "--user root:$ETCD_ROOT_PASSWORD" -}} +{{- $certsOption := " --cert=\"$ETCD_CERT_FILE\" --key=\"$ETCD_KEY_FILE\"" -}} +{{- $caOption := " --cacert=\"$ETCD_TRUSTED_CA_FILE\"" -}} {{- if .Values.auth.rbac.enabled -}} {{- printf "%s" $rbacOption -}} {{- end -}} @@ -138,3 +138,36 @@ imagePullSecrets: {{- end }} {{- end -}} {{- end -}} + +{{/* +Compile all warnings into a single message, and call fail. +*/}} +{{- define "etcd.validateValues" -}} +{{- $messages := list -}} +{{- $messages := append $messages (include "etcd.validateValues.disasterRecovery" .) -}} +{{- $messages := append $messages (include "etcd.validateValues.podAntiAffinity" .) -}} +{{- $messages := without $messages "" -}} +{{- $message := join "\n" $messages -}} + +{{- if $message -}} +{{- printf "\nVALUES VALIDATION:\n%s" $message | fail -}} +{{- end -}} +{{- end -}} + +{{/* Validate values of etcd - persistence must be enabled when disasterRecovery is enabled */}} +{{- define "etcd.validateValues.disasterRecovery" -}} +{{- if and .Values.disasterRecovery.enabled (not .Values.persistence.enabled) -}} +etcd: disasterRecovery + Persistence must be enabled when disasterRecovery is enabled!! + Please enable persistence (--set persistence.enabled=true) +{{- end -}} +{{- end -}} + +{{/* Validate values of etcd - must provide a valid podAntiAffinity ("soft" or "hard") */}} +{{- define "etcd.validateValues.podAntiAffinity" -}} +{{- if and (ne .Values.podAntiAffinity "soft") (ne .Values.podAntiAffinity "hard") -}} +etcd: mode + Invalid podAntiAffinity selected. Valid values are "soft" and + "hard". Please set a valid mode (--set podAntiAffinity="xxxx") +{{- end -}} +{{- end -}} diff --git a/bitnami/etcd/templates/scripts-configmap.yaml b/bitnami/etcd/templates/scripts-configmap.yaml new file mode 100644 index 000000000..ee0f4f484 --- /dev/null +++ b/bitnami/etcd/templates/scripts-configmap.yaml @@ -0,0 +1,156 @@ +{{- $replicaCount := int .Values.statefulset.replicaCount }} +{{- $clientPort := int .Values.service.port }} +{{- $peerPort := int .Values.service.peerPort }} +{{- $etcdAuthOptions := include "etcd.authOptions" . }} +{{- $etcdDataDir := include "etcd.dataDir" . }} +{{- $etcdFullname := include "etcd.fullname" . }} +{{- $releaseNamespace := .Release.Namespace }} +{{- $etcdHeadlessServiceName := printf "%s-%s" $etcdFullname "headless" }} +{{- $dnsBase := .Values.service.dnsBase }} +{{- $etcdPeerProtocol := include "etcd.peerProtocol" . }} +{{- $etcdClientProtocol := include "etcd.clientProtocol" . }} +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + name: {{ template "etcd.fullname" . }}-scripts +data: + setup.sh: |- + #!/bin/bash + + set -o errexit + set -o pipefail + set -o nounset + + # Constants + HOSTNAME="$(hostname -s)" + AUTH_OPTIONS="{{ $etcdAuthOptions }}" + ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" + # Remove the last comma "," introduced in the string + export ETCDCTL_ENDPOINTS="${ETCDCTL_ENDPOINTS::-1}" + + # Functions + ## Store member id for later member replacement + store_member_id() { + while ! etcdctl $AUTH_OPTIONS member list >/dev/null 2>&1; do sleep 1; done + etcdctl $AUTH_OPTIONS member list | grep "$HOSTNAME" | awk '{ print $1}' | awk -F "," '{ print $1}' > "$ETCD_DATA_DIR/member_id" + exit 0 + } + ## Configure RBAC + configure_rbac() { + # When there's more than one replica, we can assume the 1st member + # to be created is "{{ $etcdFullname }}-0" since a statefulset is used + if [[ -n "$ETCD_ROOT_PASSWORD" ]] && [[ "$HOSTNAME" == "{{ $etcdFullname }}-0" ]]; then + echo "==> Configuring RBAC authentication!" + etcd > /dev/null 2>&1 & + ETCD_PID=$! + while ! etcdctl member list >/dev/null 2>&1; do sleep 1; done + echo "$ETCD_ROOT_PASSWORD" | etcdctl user add root --interactive=false + etcdctl auth enable + kill "$ETCD_PID" + sleep 5 + fi + } + + if [[ ! -d "$ETCD_DATA_DIR" ]]; then + echo "==> Creating data dir..." + mkdir -p "$ETCD_DATA_DIR" + echo "==> There is no data at all. Initializing a new member of the cluster..." + store_member_id & + configure_rbac + else + echo "==> Detected data from previous deployments..." + if ! etcdctl $AUTH_OPTIONS endpoint status >/dev/null 2>&1; then + echo "==> Cluster not responding!!" +{{- if .Values.disasterRecovery.enabled }} + if [[ -f "/snapshots/db" ]]; then + echo "==> Restoring etcd cluster from snapshot..." + rm -rf $ETCD_DATA_DIR + etcdctl snapshot restore /snapshots/db \ + --name $ETCD_NAME \ + --data-dir $ETCD_DATA_DIR \ + --initial-cluster $ETCD_INITIAL_CLUSTER \ + --initial-cluster-token $ETCD_INITIAL_CLUSTER_TOKEN \ + --initial-advertise-peer-urls $ETCD_INITIAL_ADVERTISE_PEER_URLS + store_member_id & + else + echo "==> There was no snapshot to perform data recovery!!" + exit 1 + fi +{{- else }} + exit 1 +{{- end }} + elif [[ -d "$ETCD_DATA_DIR/member/snap" ]] && [[ -f "$ETCD_DATA_DIR/member_id" ]]; then + echo "==> Updating member in existing cluster..." + etcdctl $AUTH_OPTIONS member update "$(cat "$ETCD_DATA_DIR/member_id")" --peer-urls="{{ $etcdPeerProtocol }}://${HOSTNAME}.{{ $etcdHeadlessServiceName }}.{{ .Release.Namespace }}.{{ $dnsBase }}:{{ $peerPort }}" + else + echo "==> Adding new member to existing cluster..." + etcdctl $AUTH_OPTIONS member add "$HOSTNAME" --peer-urls="{{ $etcdPeerProtocol }}://${HOSTNAME}.{{ $etcdHeadlessServiceName }}.{{ .Release.Namespace }}.{{ $dnsBase }}:{{ $peerPort }}" | grep "^ETCD_" > "$ETCD_DATA_DIR/new_member_envs" + sed -ie 's/^/export /' "$ETCD_DATA_DIR/new_member_envs" + echo "==> Loading env vars of existing cluster..." + source "$ETCD_DATA_DIR/new_member_envs" + store_member_id & + fi + fi + + {{- if .Values.configFileConfigMap }} + exec etcd --config-file /opt/bitnami/etcd/conf/etcd.conf.yml + {{- else }} + exec etcd + {{- end }} + prestop-hook.sh: |- + #!/bin/bash + + set -o errexit + set -o pipefail + set -o nounset + + # Constants + HOSTNAME="$(hostname -s)" + AUTH_OPTIONS="{{ $etcdAuthOptions }}" + ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" + # Remove the last comma "," introduced in the string + export ETCDCTL_ENDPOINTS="${ETCDCTL_ENDPOINTS::-1}" + + etcdctl $AUTH_OPTIONS member remove "$(cat "$ETCD_DATA_DIR/member_id")" && rm -rf $ETCD_DATA_DIR/* + probes.sh: |- + #!/bin/bash + + set -o errexit + set -o pipefail + set -o nounset + + # Constants + AUTH_OPTIONS="{{ $etcdAuthOptions }}" + ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" + # Remove the last comma "," introduced in the string + export ETCDCTL_ENDPOINTS="${ETCDCTL_ENDPOINTS::-1}" + + etcdctl $AUTH_OPTIONS endpoint status >/dev/null 2>&1 +{{- if .Values.disasterRecovery.enabled }} + sidecar.sh: |- + #!/bin/bash + + set -o errexit + set -o pipefail + set -o nounset + + # Constants + AUTH_OPTIONS="{{ $etcdAuthOptions }}" + ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" + # Remove the last comma "," introduced in the string + export ETCDCTL_ENDPOINTS="${ETCDCTL_ENDPOINTS::-1}" + + mkdir -p "/snapshots" + while true; do + if etcdctl $AUTH_OPTIONS endpoint status >/dev/null 2>&1; then + echo "Snapshotting the keyspace..." + etcdctl $AUTH_OPTIONS snapshot save "/snapshots/db" + fi + sleep {{ default "600" .Values.disasterRecovery.interval }} + done +{{- end }} diff --git a/bitnami/etcd/templates/secrets.yaml b/bitnami/etcd/templates/secrets.yaml index f25a96126..7ee1c0ce1 100644 --- a/bitnami/etcd/templates/secrets.yaml +++ b/bitnami/etcd/templates/secrets.yaml @@ -4,10 +4,10 @@ kind: Secret metadata: name: {{ template "etcd.fullname" . }} labels: - app: {{ template "etcd.name" . }} - chart: {{ template "etcd.chart" . }} - release: {{ .Release.Name | quote }} - heritage: {{ .Release.Service | quote }} + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} type: Opaque data: {{- if .Values.auth.rbac.rootPassword }} @@ -15,4 +15,4 @@ data: {{ else }} etcd-root-password: {{ randAlphaNum 10 | b64enc | quote }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/bitnami/etcd/templates/snapshot-pvc.yaml b/bitnami/etcd/templates/snapshot-pvc.yaml new file mode 100644 index 000000000..bcd77bd95 --- /dev/null +++ b/bitnami/etcd/templates/snapshot-pvc.yaml @@ -0,0 +1,18 @@ +{{- if .Values.disasterRecovery.enabled -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "etcd.fullname" . }}-snapshot + labels: + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ .Values.disasterRecovery.size | quote }} + storageClassName: nfs +{{- end -}} diff --git a/bitnami/etcd/templates/statefulset.yaml b/bitnami/etcd/templates/statefulset.yaml index 6d6cbd07b..cc16077a3 100644 --- a/bitnami/etcd/templates/statefulset.yaml +++ b/bitnami/etcd/templates/statefulset.yaml @@ -1,17 +1,17 @@ apiVersion: apps/v1beta2 kind: StatefulSet metadata: - name: "{{ template "etcd.fullname" . }}" + name: {{ template "etcd.fullname" . }} labels: - app: {{ template "etcd.name" . }} - chart: {{ template "etcd.chart" . }} - release: {{ .Release.Name | quote }} - heritage: {{ .Release.Service | quote }} + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} spec: selector: matchLabels: - app: {{ template "etcd.name" . }} - release: "{{ .Release.Name }}" + app.kubernetes.io/name: {{ template "etcd.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} serviceName: {{ template "etcd.fullname" . }}-headless podManagementPolicy: {{ .Values.statefulset.podManagementPolicy }} replicas: {{ .Values.statefulset.replicaCount }} @@ -27,10 +27,10 @@ spec: metadata: name: "{{ template "etcd.fullname" . }}" labels: - app: {{ template "etcd.name" . }} - chart: {{ template "etcd.chart" . }} - release: {{ .Release.Name | quote }} - heritage: {{ .Release.Service | quote }} + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} {{- if or .Values.podAnnotations .Values.metrics.enabled }} annotations: {{- if .Values.podAnnotations }} @@ -47,17 +47,37 @@ spec: fsGroup: {{ .Values.securityContext.fsGroup }} runAsUser: {{ .Values.securityContext.runAsUser }} {{- end }} - {{- if .Values.affinity }} affinity: -{{ toYaml .Values.affinity | indent 8 }} + {{- with .Values.nodeAffinity }} + nodeAffinity: {{ tpl (toYaml .) $ | nindent 8 }} + {{- end }} + {{- with .Values.podAffinity }} + podAffinity: {{ tpl (toYaml .) $ | nindent 8 }} + {{- end }} + {{- if eq .Values.podAntiAffinity "hard" }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: "kubernetes.io/hostname" + labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "etcd.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- else if eq .Values.podAntiAffinity "soft" }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: "kubernetes.io/hostname" + labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "etcd.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: {{ tpl (toYaml .) $ | nindent 8 }} {{- end }} - {{- if .Values.nodeSelector }} - nodeSelector: -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- end }} - {{- if .Values.tolerations }} - tolerations: -{{ toYaml .Values.tolerations | indent 8 }} + {{- with .Values.tolerations }} + tolerations: {{ tpl (toYaml .) $ | nindent 8 }} {{- end }} containers: # Variables to populate static cluster @@ -70,76 +90,16 @@ spec: {{- $dnsBase := .Values.service.dnsBase }} {{- $etcdPeerProtocol := include "etcd.peerProtocol" . }} {{- $etcdClientProtocol := include "etcd.clientProtocol" . }} - - name: "{{ template "etcd.fullname" . }}" + - name: etcd image: "{{ template "etcd.image" . }}" imagePullPolicy: "{{ .Values.image.pullPolicy }}" command: - - bash - - -ec - - | - HOSTNAME=$(hostname -s) - ID=${HOSTNAME:(-1)} - echo "==> The ID of the host is $ID" - DATA_DIR={{ template "etcd.dataDir" . }} - - AUTH_OPTIONS="{{ template "etcd.authOptions" . }}" - - ## Store member id for later member replacement - store_member_id() { - while ! etcdctl ${AUTH_OPTIONS} member list &>/dev/null; do sleep 1; done - etcdctl ${AUTH_OPTIONS} member list | grep `hostname -s` | awk '{ print $1}' | awk -F ":" '{ print $1}' > ${DATA_DIR}/member_id - exit 0 - } - - ## Create data dir if not exists - if [ ! -d "${DATA_DIR}" ]; then - echo "==> Creating data dir..." - mkdir -p "${DATA_DIR}" - ## Setting up new cluster - echo "==> There is no data at all. Creating new cluster" - export ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" - store_member_id & - if [ -n "${ETCD_ROOT_PASSWORD}" ] && [ "${HOSTNAME}" == "{{ $etcdFullname }}-0" ]; then - echo "==> Configuring RBAC authentication!" - etcd > /dev/null 2>&1 & - ETCD_PID=$! - while ! etcdctl member list &>/dev/null; do sleep 1; done - echo "${ETCD_ROOT_PASSWORD}" | etcdctl user add root - etcdctl auth enable - etcdctl ${AUTH_OPTIONS} role revoke guest -path '/*' --readwrite - kill "${ETCD_PID}" - sleep 5 - fi - else - ## Re-joining failed node - if [ -d "${DATA_DIR}/member/snap" ]; then - echo "==> Data exists. Re-joining etcd member" - member_id=$(cat "${DATA_DIR}/member_id") - if [ "${HOSTNAME}" != "{{ $etcdFullname }}-0" ]; then - echo "==> Updating member in existing cluster." - export ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" - etcdctl ${AUTH_OPTIONS} member update ${member_id} {{ $etcdPeerProtocol }}://`hostname -s`.{{ $etcdHeadlessServiceName }}.{{ .Release.Namespace }}.{{ $dnsBase }}:{{ $peerPort }} - fi - ## Adding new member to the cluster - else - echo "==> Adding member to existing cluster." - export ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" - - etcdctl ${AUTH_OPTIONS} member add `hostname -s` {{ $etcdPeerProtocol }}://`hostname -s`.{{ $etcdHeadlessServiceName }}.{{ .Release.Namespace }}.{{ $dnsBase }}:{{ $peerPort }} | grep "^ETCD_" > ${DATA_DIR}/new_member_envs - sed -ie 's/^/export /' /bitnami/etcd/data/new_member_envs - - echo "==> Loading env vars of existing cluster" - source "${DATA_DIR}/new_member_envs" - - store_member_id & - fi - fi - - {{- if .Values.configFileConfigMap }} - exec /opt/bitnami/etcd/bin/etcd --config-file /opt/bitnami/etcd/conf/etcd.conf.yml - {{ else }} - exec /opt/bitnami/etcd/bin/etcd - {{- end }} + - /scripts/setup.sh + lifecycle: + preStop: + exec: + command: + - /scripts/prestop-hook.sh resources: {{ toYaml .Values.resources | indent 10 }} {{- if .Values.envVarsConfigMap }} @@ -166,6 +126,8 @@ spec: valueFrom: fieldRef: fieldPath: metadata.name + - name: ETCDCTL_API + value: "3" - name: ETCD_NAME value: "$(MY_POD_NAME)" - name: ETCD_DATA_DIR @@ -195,13 +157,7 @@ spec: ## RBAC authentication - name: ALLOW_NONE_AUTHENTICATION - {{- if .Values.auth.rbac.enabled }} - value: "no" - {{- else if .Values.allowNoneAuthentication }} - value: "yes" - {{- else }} - value: "no" - {{- end }} + value: {{ ternary "yes" "no" (or .Values.auth.rbac.enabled .Values.allowNoneAuthentication) | quote }} {{- if .Values.auth.rbac.enabled }} - name: ETCD_ROOT_PASSWORD valueFrom: @@ -246,29 +202,14 @@ spec: ports: - name: client - containerPort: {{ .Values.service.port }} + containerPort: 2379 - name: peer - containerPort: {{ .Values.service.port }} - lifecycle: - preStop: - exec: - command: - - "/bin/sh" - - "-ec" - - | - AUTH_OPTIONS="{{ template "etcd.authOptions" . }}" - DATA_DIR={{ template "etcd.dataDir" . }} - MEMBER_ID=$(etcdctl member list | grep name=`hostname -s` | awk {'print $1'} | awk -F ":" {'print $1'}) - export ETCDCTL_ENDPOINTS="{{range $i, $e := until $replicaCount }}{{ $etcdClientProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.{{ $releaseNamespace }}.{{ $dnsBase }}:{{ $clientPort }},{{ end }}" - echo "==> Removing $MEMBER_ID from etcd cluster" - etcdctl ${AUTH_OPTIONS} member remove $MEMBER_ID - if [ $? -eq 0 ]; then - rm -rf ${DATA_DIR}/* - fi + containerPort: 2380 {{- if .Values.livenessProbe.enabled }} livenessProbe: - tcpSocket: - port: client + exec: + command: + - /scripts/probes.sh initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.livenessProbe.periodSeconds }} timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} @@ -277,8 +218,9 @@ spec: {{- end }} {{- if .Values.readinessProbe.enabled }} readinessProbe: - tcpSocket: - port: client + exec: + command: + - /scripts/probes.sh initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.readinessProbe.periodSeconds }} timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} @@ -286,42 +228,79 @@ spec: failureThreshold: {{ .Values.readinessProbe.failureThreshold }} {{- end }} volumeMounts: - {{- if .Values.persistence.enabled }} + - name: scripts + mountPath: /scripts - name: data mountPath: /bitnami/etcd - {{ end }} - {{ if .Values.configFileConfigMap }} + {{- if .Values.disasterRecovery.enabled }} + - name: snapshot-volume + mountPath: /snapshots + {{- end }} + {{- if .Values.configFileConfigMap }} - name: etcd-config mountPath: /opt/bitnami/etcd/conf/ - {{ end }} - {{ if or .Values.auth.client.enableAuthentication (and .Values.auth.client.secureTransport (not .Values.auth.client.useAutoTLS ) ) }} + {{- end }} + {{- if or .Values.auth.client.enableAuthentication (and .Values.auth.client.secureTransport (not .Values.auth.client.useAutoTLS ) ) }} - name: etcd-client-certs mountPath: /opt/bitnami/etcd/certs/client/ readOnly: true - {{ end }} - {{ if or .Values.auth.peer.enableAuthentication (and .Values.auth.peer.secureTransport (not .Values.auth.peer.useAutoTLS ) ) }} + {{- end }} + {{- if or .Values.auth.peer.enableAuthentication (and .Values.auth.peer.secureTransport (not .Values.auth.peer.useAutoTLS ) ) }} - name: etcd-peer-certs mountPath: /opt/bitnami/etcd/certs/peer/ readOnly: true - {{ end }} + {{- end }} + {{- if .Values.disasterRecovery.enabled }} + - name: snapshotter-sidecar + image: "{{ template "etcd.image" . }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + command: + - /scripts/sidecar.sh + env: + - name: ETCDCTL_API + value: "3" + {{- if .Values.auth.rbac.enabled }} + - name: ETCD_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ if .Values.auth.rbac.existingSecret }}{{ .Values.auth.rbac.existingSecret }}{{ else }}{{ template "etcd.fullname" . }}{{ end }} + key: etcd-root-password + {{- end }} + volumeMounts: + - name: scripts + mountPath: /scripts + - name: data + mountPath: /bitnami/etcd + - name: snapshot-volume + mountPath: /snapshots + {{- end }} volumes: - {{ if .Values.configFileConfigMap }} + - name: scripts + configMap: + name: {{ template "etcd.fullname" . }}-scripts + defaultMode: 0755 + {{- if .Values.disasterRecovery.enabled }} + - name: snapshot-volume + persistentVolumeClaim: + claimName: {{ template "etcd.fullname" . }}-snapshot + {{- end }} + {{- if .Values.configFileConfigMap }} - name: etcd-config configMap: name: {{ template "etcd.configFileCM" . }} - {{ end }} - {{ if or .Values.auth.client.enableAuthentication (and .Values.auth.client.secureTransport (not .Values.auth.client.useAutoTLS ) ) }} + {{- end }} + {{- if or .Values.auth.client.enableAuthentication (and .Values.auth.client.secureTransport (not .Values.auth.client.useAutoTLS ) ) }} - name: etcd-client-certs secret: secretName: {{ required "A secret containinig the client certificates is required" .Values.auth.client.existingSecret }} defaultMode: 256 - {{ end }} - {{ if or .Values.auth.peer.enableAuthentication (and .Values.auth.peer.secureTransport (not .Values.auth.peer.useAutoTLS ) ) }} + {{- end }} + {{- if or .Values.auth.peer.enableAuthentication (and .Values.auth.peer.secureTransport (not .Values.auth.peer.useAutoTLS ) ) }} - name: etcd-peer-certs secret: secretName: {{ required "A secret containinig the peer certificates is required" .Values.auth.peer.existingSecret }} defaultMode: 256 - {{ end }} + {{- end }} {{- if .Values.persistence.enabled }} volumeClaimTemplates: - metadata: diff --git a/bitnami/etcd/templates/svc-headless.yaml b/bitnami/etcd/templates/svc-headless.yaml index a68a5b5a5..1fb073ad9 100644 --- a/bitnami/etcd/templates/svc-headless.yaml +++ b/bitnami/etcd/templates/svc-headless.yaml @@ -5,20 +5,20 @@ metadata: annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" labels: - app: {{ template "etcd.name" . }} - chart: {{ template "etcd.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} spec: type: ClusterIP clusterIP: None ports: - name: client - port: 2379 + port: {{ .Values.service.port }} targetPort: client - name: peer - port: 2380 + port: {{ .Values.service.peerPort }} targetPort: peer selector: - app: {{ template "etcd.name" . }} - release: {{ .Release.Name | quote }} + app.kubernetes.io/name: {{ template "etcd.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} diff --git a/bitnami/etcd/templates/svc.yaml b/bitnami/etcd/templates/svc.yaml index 5aa1fe5b1..f38ff1f38 100644 --- a/bitnami/etcd/templates/svc.yaml +++ b/bitnami/etcd/templates/svc.yaml @@ -3,10 +3,10 @@ kind: Service metadata: name: {{ template "etcd.fullname" . }} labels: - app: {{ template "etcd.name" . }} - chart: {{ template "etcd.chart" . }} - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" + app.kubernetes.io/name: {{ template "etcd.name" . }} + helm.sh/chart: {{ template "etcd.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} {{- if .Values.service.annotations }} annotations: {{ toYaml .Values.service.annotations | indent 4 }} @@ -18,17 +18,17 @@ spec: {{- end }} ports: - name: client - port: 2379 + port: {{ .Values.service.port }} targetPort: client {{- if and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort)) }} nodePort: {{ .Values.service.nodePort }} {{- end }} - name: peer - port: 2380 + port: {{ .Values.service.peerPort }} targetPort: peer {{- if and (eq .Values.service.type "NodePort") (not (empty .Values.service.peerNodePort)) }} nodePort: {{ .Values.service.peerNodePort }} {{- end }} selector: - app: {{ template "etcd.name" . }} - release: {{ .Release.Name | quote }} \ No newline at end of file + app.kubernetes.io/name: {{ template "etcd.name" . }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} diff --git a/bitnami/etcd/values-production.yaml b/bitnami/etcd/values-production.yaml index 21609ba28..90bf1e9a5 100644 --- a/bitnami/etcd/values-production.yaml +++ b/bitnami/etcd/values-production.yaml @@ -149,12 +149,6 @@ persistence: size: 8Gi annotations: {} -## Node labels 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 -nodeSelector: {} -tolerations: [] - ## Configure resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## @@ -189,8 +183,50 @@ readinessProbe: ## podAnnotations: {} +## Node Affinity. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature +## +nodeAffinity: {} +## Pod Affinity. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +podAffinity: {} +## Pod AntiAffinity +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +podAntiAffinity: soft + +## Node labels for pod assignment. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector +## +nodeSelector: {} +## Tolerations for pod assignment. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature +## +tolerations: {} + +## Add the corresponding annotations so Prometheus can collect etcd metrics +## metrics: enabled: true podAnnotations: prometheus.io/scrape: "true" prometheus.io/port: "2379" + +## Enable auto disaster recovery by periodically snapshotting the keyspace +## - It creates a sidecar container to periodically snapshotting the keyspace +## - It also creates a ReadWriteMany PVC to store the snapshots +## If the cluster permanently loses more than (N-1)/2 members, it tries to recover +## the cluster from a previous snapshot. +## +disasterRecovery: + enabled: true + ## Interval (in seconds) to save snapshots + ## + interval: 300 + ## PVC Storage Request + ## + size: 2Gi + ## storageClassName, choose a storageClassName with ReadWriteMany support + ## + storageClassName: nfs diff --git a/bitnami/etcd/values.yaml b/bitnami/etcd/values.yaml index d439bf260..0747826f1 100644 --- a/bitnami/etcd/values.yaml +++ b/bitnami/etcd/values.yaml @@ -149,12 +149,6 @@ persistence: size: 8Gi annotations: {} -## Node labels 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 -nodeSelector: {} -tolerations: [] - ## Configure resource requests and limits ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## @@ -178,7 +172,7 @@ livenessProbe: readinessProbe: enabled: false - initialDelaySeconds: 5 + initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 6 @@ -189,8 +183,50 @@ readinessProbe: ## podAnnotations: {} +## Node Affinity. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature +## +nodeAffinity: {} +## Pod Affinity. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +podAffinity: {} +## Pod AntiAffinity +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +podAntiAffinity: soft + +## Node labels for pod assignment. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector +## +nodeSelector: {} +## Tolerations for pod assignment. The value is evaluated as a template. +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature +## +tolerations: {} + +## Add the corresponding annotations so Prometheus can collect etcd metrics +## metrics: enabled: false podAnnotations: prometheus.io/scrape: "true" prometheus.io/port: "2379" + +## Enable auto disaster recovery by periodically snapshotting the keyspace +## - It creates a sidecar container to periodically snapshotting the keyspace +## - It also creates a ReadWriteMany PVC to store the snapshots +## If the cluster permanently loses more than (N-1)/2 members, it tries to recover +## the cluster from a previous snapshot. +## +disasterRecovery: + enabled: false + ## Interval (in seconds) to save snapshots + ## + interval: 300 + ## PVC Storage Request + ## + size: 2Gi + ## storageClassName, choose a storageClassName with ReadWriteMany support + ## + storageClassName: nfs