diff --git a/bitnami/etcd/.helmignore b/bitnami/etcd/.helmignore new file mode 100644 index 000000000..6b8710a71 --- /dev/null +++ b/bitnami/etcd/.helmignore @@ -0,0 +1 @@ +.git diff --git a/bitnami/etcd/Chart.yaml b/bitnami/etcd/Chart.yaml new file mode 100644 index 000000000..ffde9faf6 --- /dev/null +++ b/bitnami/etcd/Chart.yaml @@ -0,0 +1,18 @@ +name: etcd +version: 0.0.1 +appVersion: 3.3.8 +description: etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines +keywords: +- etcd +- cluster +- database +- cache +- key-value +home: https://coreos.com/etcd/ +sources: +- https://github.com/bitnami/bitnami-docker-etcd +maintainers: +- name: Bitnami + email: containers@bitnami.com +engine: gotpl +icon: https://bitnami.com/assets/stacks/etcd/img/etcd-stack-110x117.png diff --git a/bitnami/etcd/README.md b/bitnami/etcd/README.md new file mode 100644 index 000000000..0c1890add --- /dev/null +++ b/bitnami/etcd/README.md @@ -0,0 +1,178 @@ +# etcd + +[etcd](https://www.etcd.org/) is an object-relational database management system (ORDBMS) with an emphasis on extensibility and on standards-compliance. + +## TL;DR; + +```console +$ helm install bitnami/etcd +``` + +## Introduction + +This chart bootstraps a [etcd](https://github.com/bitnami/bitnami-docker-etcd) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Kubernetes 1.4+ with Beta APIs enabled +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +$ helm install --name my-release bitnami/etcd +``` + +The command deploys etcd on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Configuration + +The following tables lists the configurable parameters of the etcd chart and their default values. + +| Parameter | Description | Default | +|------------------------------------|------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------- | +| `image.registry` | etcd image registry | `docker.io` | +| `image.repository` | etcd Image name | `bitnami/etcd` | +| `image.tag` | etcd Image tag | `{VERSION}` | +| `image.pullPolicy` | etcd image pull policy | `Always` | +| `image.pullSecrets` | Specify image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `image.debug` | Specify if debug values should be set | `false` | +| `updateStrategy` | Update strategy for the stateful set | `RollingUpdate` | +| `podManagementPolicy` | Pod management policy for the stateful set | `OrderedReady` | +| `replicaCount` | Number of etcd nodes | `1` | +| `useConfigmap` | Switch to use the config map for etcd | `false` | +| `allowNoneAuthentication` | Allow to use etcd without configuring RBAC authentication | `true` | +| `auth.rbac.enabled` | Switch to enable the etcd authentication. | `false` | +| `auth.rbac.rootPassword` | Password for the root user | `false` | +| `auth.rbac.existingSecret` | Name of the existing secret containing the root password | `false` | +| `auth.client.secureTransport` | Switch to encrypt client communication using TLS certificates | `false` | +| `auth.client.useAutoTLS` | Switch to automatically create the TLS certificates | `false` | +| `auth.client.enableAuthentication` | Switch to enable host authentication using TLS certificates. Requires existing secret. | `secret` | +| `auth.client.existingSecret` | Name of the existing secret containing cert files for client communication. | `nil` | +| `auth.peer.secureTransport` | Switch to encrypt peer communication using TLS certificates | `false` | +| `auth.peer.useAutoTLS` | Switch to automatically create the TLS certificates | `false` | +| `auth.peer.enableAuthentication` | Switch to enable host authentication using TLS certificates. Requires existing secret. | `false` | +| `auth.peer.existingSecret` | Name of the existing secret containing cert files for peer communication. | `nil` | +| `securityContext.enabled` | Enable security context | `true` | +| `securityContext.fsGroup` | Group ID for the container | `1001` | +| `securityContext.runAsUser` | User ID for the container | `1001` | +| `service.type` | Kubernetes Service type | `ClusterIP` | +| `service.port` | etcd client port | `2379` | +| `service.peerPort` | etcd peer port | `2380` | +| `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 | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Toleration labels for pod assignment | `[]` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `250m` | +| `livenessProbe.enabled` | would you like a livessProbed to be enabled | `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` | would you like a readinessProbe to be enabled | `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 | + +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 +``` + +The above command sets the etcd `etcd` account password to `secretpassword`. Additionally it creates a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```console +$ helm install --name my-release -f values.yaml bitnami/etcd +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## 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 +$ kubectl scale statefulset my-etcd --replicas=5 +``` + +## Enable security for etcd and Zookeeper + +### Configure RBAC + +In order to enable [Role-based access control for etcd](https://coreos.com/etcd/docs/latest/op-guide/authentication.html) you can run the following command: + +```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. + +### Configure certificated for peer communication + +In order to enable secure transport between peer nodes deploy the helm chart with these options: + +```console +$ helm install --name my-release --set auth.peer.secureTransport=true --set auth.peer.useAutoTLS=true bitnami/etcd + +``` + +### Configure certificates for client comminication + +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. + +You can create that secret with this command: + +```console +$ kubectl create secret generic etcd-client-certs --from-file=ca.crt=path/to/ca.crt --from-file=cert.pem=path/to/cert.pem --from-file=key.pem=path/to/key.pem +``` + +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 + +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 deployments. This is known to work in GCE, AWS, and minikube. +See the [Configuration](#configuration) section to configure the PVC or to disable persistence. diff --git a/bitnami/etcd/templates/NOTES.txt b/bitnami/etcd/templates/NOTES.txt new file mode 100644 index 000000000..fc4857d66 --- /dev/null +++ b/bitnami/etcd/templates/NOTES.txt @@ -0,0 +1,75 @@ +{{- if contains .Values.service.type "LoadBalancer" }} +{{- if .Values.allowNoneAuthentication }} +------------------------------------------------------------------------------- + WARNING + + By specifying "service.type=LoadBalancer" and "allowNoneAuthentication=true" you + have most likely exposed the Redis service externally without any authentication + mechanism. + + For security reasons, we strongly suggest that you switch to "ClusterIP" or + "NodePort". As alternative, you can also switch to "usePassword=true" + providing a valid password on "password" parameter. + +------------------------------------------------------------------------------- +{{- end }} +{{- end }} + +** Please be patient while the chart is being deployed ** + +etcd can be accessed via port 2379 on the following DNS name from within your cluster: + + {{ template "etcd.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + +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 + +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 + +To connect to your etcd server from outside the cluster execute the following commands: + +{{- if contains "NodePort" .Values.service.type }} + + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "etcd.fullname" . }}) + +{{- else if contains "LoadBalancer" .Values.service.type }} + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + 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" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + +{{- else if contains "ClusterIP" .Values.service.type }} + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "etcd.name" . }}" -o jsonpath="{.items[0].metadata.name}") + kubectl port-forward --namespace {{ .Release.Namespace }} $POD_NAME 2379:2379 & + +{{- end }} + + +{{ 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: + + export ETCD_ROOT_PASSWORD=${kubectl get secret --namespace {{ .Release.Namespace }} {{ template "etcd.fullname" . }} -o jsonpath="{.data.etcd-root-password}" | base64 --decode)} + +{{ end }} +{{- if .Values.auth.client.secureTransport }} +{{- if .Values.auth.client.useAutoTLS }} + * As TLS secured transport 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 secured transport 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 }} \ No newline at end of file diff --git a/bitnami/etcd/templates/_helpers.tpl b/bitnami/etcd/templates/_helpers.tpl new file mode 100644 index 000000000..c4d8c0194 --- /dev/null +++ b/bitnami/etcd/templates/_helpers.tpl @@ -0,0 +1,66 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "etcd.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 24 -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "etcd.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 24 -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "etcd.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the proper etcd image name +*/}} +{{- define "etcd.image" -}} +{{- $registryName := .Values.image.registry -}} +{{- $tag := .Values.image.tag | toString -}} +{{- printf "%s/%s:%s" $registryName .Values.image.repository $tag -}} +{{- end -}} +{{/* + +{{/* +Return the proper etcd peer protocol +*/}} +{{- define "etcd.peerProtocol" -}} +{{- if .Values.auth.peer.secureTransport -}} +{{- print "https" -}} +{{- else -}} +{{- print "http" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper etcd client protocol +*/}} +{{- define "etcd.clientProtocol" -}} +{{- if .Values.auth.client.secureTransport -}} +{{- print "https" -}} +{{- else -}} +{{- print "http" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the proper etcd data dir +*/}} +{{- define "etcd.dataDir" -}} +{{- if .Values.persistence.enabled -}} +{{- print "/bitnami/etcd/data" -}} +{{- else -}} +{{- print "/opt/bitnami/etcd/data" -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/bitnami/etcd/templates/configmap.yaml b/bitnami/etcd/templates/configmap.yaml new file mode 100644 index 000000000..cbe95fb00 --- /dev/null +++ b/bitnami/etcd/templates/configmap.yaml @@ -0,0 +1,108 @@ +{{- if .Values.useConfigmap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "etcd.fullname" . }}-configuration + labels: + app: "{{ template "etcd.name" . }}" + chart: {{ template "etcd.chart" . }} + release: {{ .Release.Name | quote }} + heritage: {{ .Release.Service | quote }} +data: + etcd.conf.yml: |- + # This is the configuration file for the etcd server. + # Human-readable name for this member. + name: 'default' + # Path to the data directory. + data-dir: + # Path to the dedicated wal directory. + wal-dir: + # Number of committed transactions to trigger a snapshot to disk. + snapshot-count: 10000 + # Time (in milliseconds) of a heartbeat interval. + heartbeat-interval: 100 + # Time (in milliseconds) for an election to timeout. + election-timeout: 1000 + # Raise alarms when backend size exceeds the given quota. 0 means use the + # default quota. + quota-backend-bytes: 0 + # List of comma separated URLs to listen on for peer traffic. + listen-peer-urls: http://0.0.0.0:2380 + # List of comma separated URLs to listen on for client traffic. + listen-client-urls: http://0.0.0.0:2379 + # Maximum number of snapshot files to retain (0 is unlimited). + max-snapshots: 5 + # Maximum number of wal files to retain (0 is unlimited). + max-wals: 5 + # Comma-separated white list of origins for CORS (cross-origin resource sharing). + cors: + # List of this member's peer URLs to advertise to the rest of the cluster. + # The URLs needed to be a comma-separated list. + initial-advertise-peer-urls: http://localhost:2380 + # List of this member's client URLs to advertise to the public. + # The URLs needed to be a comma-separated list. + advertise-client-urls: http://localhost:2379 + # Discovery URL used to bootstrap the cluster. + discovery: + # Valid values include 'exit', 'proxy' + discovery-fallback: 'proxy' + # HTTP proxy to use for traffic to discovery service. + discovery-proxy: + # DNS domain used to bootstrap initial cluster. + discovery-srv: + # Initial cluster configuration for bootstrapping. + initial-cluster: + # Initial cluster token for the etcd cluster during bootstrap. + initial-cluster-token: 'etcd-cluster' + # Initial cluster state ('new' or 'existing'). + initial-cluster-state: 'new' + # Reject reconfiguration requests that would cause quorum loss. + strict-reconfig-check: false + # Accept etcd V2 client requests + enable-v2: true + # Enable runtime profiling data via HTTP server + enable-pprof: true + # Valid values include 'on', 'readonly', 'off' + proxy: 'off' + # Time (in milliseconds) an endpoint will be held in a failed state. + proxy-failure-wait: 5000 + # Time (in milliseconds) of the endpoints refresh interval. + proxy-refresh-interval: 30000 + # Time (in milliseconds) for a dial to timeout. + proxy-dial-timeout: 1000 + # Time (in milliseconds) for a write to timeout. + proxy-write-timeout: 5000 + # Time (in milliseconds) for a read to timeout. + proxy-read-timeout: 0 + client-transport-security: + # Path to the client server TLS cert file. + cert-file: + # Path to the client server TLS key file. + key-file: + # Enable client cert authentication. + client-cert-auth: false + # Path to the client server TLS trusted CA cert file. + trusted-ca-file: + # Client TLS using generated certificates + auto-tls: false + peer-transport-security: + # Path to the peer server TLS cert file. + cert-file: + # Path to the peer server TLS key file. + key-file: + # Enable peer client cert authentication. + peer-client-cert-auth: false + # Path to the peer server TLS trusted CA cert file. + trusted-ca-file: + # Peer TLS using generated certificates. + auto-tls: false + # Enable debug-level logging for etcd. + debug: false + logger: zap + # Specify 'stdout' or 'stderr' to skip journald logging even when running under systemd. + log-outputs: [stderr] + # Force to create a new one member cluster. + force-new-cluster: false + auto-compaction-mode: periodic + auto-compaction-retention: "1" +{{- end -}} \ No newline at end of file diff --git a/bitnami/etcd/templates/secrets.yaml b/bitnami/etcd/templates/secrets.yaml new file mode 100644 index 000000000..f25a96126 --- /dev/null +++ b/bitnami/etcd/templates/secrets.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.auth.rbac.enabled (not .Values.auth.rbac.existingSecret) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "etcd.fullname" . }} + labels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: {{ .Release.Name | quote }} + heritage: {{ .Release.Service | quote }} +type: Opaque +data: + {{- if .Values.auth.rbac.rootPassword }} + etcd-root-password: {{ .Values.auth.rbac.rootPassword | b64enc | quote }} + {{ else }} + etcd-root-password: {{ randAlphaNum 10 | b64enc | quote }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/bitnami/etcd/templates/statefulset.yaml b/bitnami/etcd/templates/statefulset.yaml new file mode 100644 index 000000000..9796fc8de --- /dev/null +++ b/bitnami/etcd/templates/statefulset.yaml @@ -0,0 +1,357 @@ +apiVersion: apps/v1beta2 +kind: StatefulSet +metadata: + name: "{{ template "etcd.fullname" . }}" + labels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: {{ .Release.Name | quote }} + heritage: {{ .Release.Service | quote }} +spec: + serviceName: {{ template "etcd.fullname" . }}-headless + podManagementPolicy: {{ .Values.podManagementPolicy }} + replicas: {{ .Values.replicaCount }} + updateStrategy: + type: {{ .Values.updateStratey }} + selector: + matchLabels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: {{ .Release.Name | quote }} + heritage: {{ .Release.Service | quote }} + template: + metadata: + name: "{{ template "etcd.fullname" . }}" + labels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: {{ .Release.Name | quote }} + heritage: {{ .Release.Service | quote }} + spec: + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end}} + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + containers: + # Variables to populate static cluster + {{- $replicaCount := int .Values.replicaCount }} + {{- $clientPort := int .Values.service.port }} + {{- $peerPort := int .Values.service.peerPort }} + {{- $etcdFullname := include "etcd.fullname" . }} + {{- $etcdHeadlessServiceName := printf "%s-%s" $etcdFullname "headless" }} + {{- $etcdPeerProtocol := include "etcd.peerProtocol" . }} + {{- $etcdClientProtocol := include "etcd.clientProtocol" . }} + - name: "{{ template "etcd.fullname" . }}" + 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="" + if [ ! -z "$ETCD_ROOT_PASSWORD" ]; then + echo "==> Setting RBAC options for command line..." + AUTH_OPTIONS+="-u root:${ETCD_ROOT_PASSWORD}" + fi + if [ ! -z "$ETCD_CERT_FILE" ] && [ ! -z "$ETCD_KEY_FILE" ]; then + echo "==> Setting cert and key options for command line..." + AUTH_OPTIONS+=" --cert-file $ETCD_CERT_FILE --key-file $ETCD_KEY_FILE" + fi + if [ ! -z "$ETCD_TRUSTED_CA_FILE" ]; then + echo "==> Setting trusted ca file option for command line..." + AUTH_OPTIONS+=" --ca-file $ETCD_TRUSTED_CA_FILE" + fi + + ## 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} + fi + + ## Re-joining failed node + if [ -d '${DATA_DIR}/member/' ]; then + echo "==> Data exists. Re-joining etcd member" + member_id=$(cat ${DATA_DIR}/member_id) + + echo "==> Updating member in existing cluster." + export ETCDCTL_ENDPOINTS="{{ $etcdClientProtocol }}://{{ $etcdFullname }}-0.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $clientPort }}" + etcdctl ${AUTH_OPTIONS} member update ${member_id} {{ $etcdPeerProtocol }}://`hostname -s`.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $peerPort }} + + ## Adding new member to the cluster + elif [ "${ID}" -ge {{ $replicaCount }} ]; then + echo "==> Adding member to existing cluster." + export ETCDCTL_ENDPOINTS="{{ $etcdClientProtocol }}://{{ $etcdFullname }}-0.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $clientPort }}" + + echo "==> Adding new member" + etcdctl ${AUTH_OPTIONS} member add `hostname -s` {{ $etcdPeerProtocol }}://`hostname -s`.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $peerPort }} | grep "^ETCD_" > ${DATA_DIR}/new_member_envs + + echo "==> Loading env vars of existing cluster" + source ${DATA_DIR}/new_member_envs + + store_member_id & + + ## Setting up new cluster + else + echo "==> There is no data at all. Creating new cluster" + + store_member_id & + + if [ ! -z "$ETCD_ROOT_PASSWORD" ] && [ `hostname -s` == '{{ $etcdFullname }}-0' ]; then + echo "==> Configuring RBAC authentication!" + etcd > /dev/null 2>&1 & + ETCD_PID=$! + sleep 5 + echo "$ETCD_ROOT_PASSWORD" | etcdctl user add root + etcdctl auth enable + etcdctl -u root:"$ETCD_ROOT_PASSWORD" role revoke guest -path '/*' --readwrite + kill $ETCD_PID + sleep 5 + fi + fi + + {{- if .Values.useConfigmap }} + exec /opt/bitnami/etcd/bin/etcd --config-file /opt/bitnami/etcd/conf/etcd.conf.yml + {{ else }} + exec /opt/bitnami/etcd/bin/etcd + {{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + env: + {{- if .Values.image.debug }} + - name: BASH_DEBUG + value: "1" + - name: NAMI_DEBUG + value: "1" + - name: NAMI_LOG_LEVEL + value: "trace8" + {{- end }} + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + + ## Basic configuration + - name: ETCD_NAME + value: "$(MY_POD_NAME)" + - name: ETCD_DATA_DIR + value: {{ template "etcd.dataDir" . }} + - name: ETCD_ADVERTISE_CLIENT_URLS + value: "{{ $etcdClientProtocol }}://$(MY_POD_NAME):{{ .Values.service.port }}" + - name: ETCD_LISTEN_CLIENT_URLS + value: "{{ $etcdClientProtocol }}://0.0.0.0:{{ .Values.service.port }}" + - name: ETCD_INITIAL_ADVERTISE_PEER_URLS + value: "{{ $etcdPeerProtocol }}://$(MY_POD_NAME):{{ .Values.service.peerPort }}" + - name: ETCD_LISTEN_PEER_URLS + value: "{{ $etcdPeerProtocol }}://0.0.0.0:{{ .Values.service.peerPort }}" + + ## Clustering configuration + {{- if gt $replicaCount 1 }} + - name: ETCD_INITIAL_CLUSTER_TOKEN + value: "etcd-cluster-k8s" + - name: ETCD_INITIAL_CLUSTER_STATE + value: "new" + - name: ETCD_INITIAL_CLUSTER + value: {{range $i, $e := until $replicaCount }}{{ $etcdFullname }}-{{ $e }}={{ $etcdPeerProtocol }}://{{ $etcdFullname }}-{{ $e }}.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $peerPort }},{{ end }} + {{- end }} + + ## RBAC authentication + - name: ALLOW_NONE_AUTHENTICATION + {{- if .Values.auth.rbac.enabled }} + value: "no" + {{- else if .Values.allowNoneAuthentication }} + value: "yes" + {{- else }} + value: "no" + {{- end }} + {{- if .Values.auth.rbac.enabled }} + - name: ETCD_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ if .Values.auth.existingSecret }}{{ .Values.auth.existingSecret }}{{ else }}{{ template "etcd.fullname" . }}{{ end }} + key: etcd-root-password + {{- end }} + + ## Client-to-server communication + {{- if and .Values.auth.client.secureTransport .Values.auth.client.useAutoTLS }} + - name: ETCD_AUTO_TLS + value: "true" + {{- else if .Values.auth.client.secureTransport }} + - name: ETCD_CERT_FILE + value: "/opt/bitnami/etcd/certs/client/cert.pem" + - name: ETCD_KEY_FILE + value: "/opt/bitnami/etcd/certs/client/key.pem" + {{- if .Values.auth.client.enableAuthentication }} + - name: ETCD_CLIENT_CERT_AUTH + value: "true" + - name: ETCD_TRUSTED_CA_FILE + value: "/opt/bitnami/etcd/certs/client/ca.crt" + {{- end }} + {{- end }} + + ## Peer-to-peer communication + {{- if and .Values.auth.peer.secureTransport .Values.auth.peer.useAutoTLS }} + - name: ETCD_PEER_AUTO_TLS + value: "true" + {{- else if .Values.auth.peer.secureTransport }} + - name: ETCD_PEER_CERT_FILE + value: "/opt/bitnami/etcd/certs/peer/cert.pem" + - name: ETCD_PEER_KEY_FILE + value: "/opt/bitnami/etcd/certs/peer/key.pem" + {{- if .Values.auth.peer.enableAuthentication }} + - name: ETCD_PEER_CLIENT_CERT_AUTH + value: "true" + - name: ETCD_PEER_TRUSTED_CA_FILE + value: "/opt/bitnami/etcd/certs/peer/ca.crt" + {{- end }} + {{- end }} + + ports: + - name: client + containerPort: {{ .Values.service.port }} + - name: peer + containerPort: {{ .Values.service.port }} + lifecycle: + preStop: + exec: + command: + - "/bin/sh" + - "-ec" + - | + AUTH_OPTIONS="" + if [ ! -z "$ETCD_ROOT_PASSWORD" ]; then + echo "==> Setting RBAC options for command line..." + AUTH_OPTIONS+="-u root:${ETCD_ROOT_PASSWORD}" + fi + if [ ! -z "$ETCD_CERT_FILE" ] && [ ! -z "$ETCD_KEY_FILE" ]; then + echo "==> Setting cert and key options for command line..." + AUTH_OPTIONS+=" --cert-file $ETCD_CERT_FILE --key-file $ETCD_KEY_FILE" + fi + if [ ! -z "$ETCD_TRUSTED_CA_FILE" ]; then + echo "==> Setting trusted ca file option for command line..." + AUTH_OPTIONS+=" --ca-file $ETCD_TRUSTED_CA_FILE" + fi + DATA_DIR={{ template "etcd.dataDir" . }} + MEMBER_ID=$(etcdctl member list | grep name=`hostname -s` | awk {'print $1'} | awk -F ":" {'print $1'}) + export ETCDCTL_ENDPOINTS="{{ $etcdClientProtocol }}://{{ $etcdFullname }}-0.{{ $etcdHeadlessServiceName }}.default.svc.cluster.local:{{ $clientPort }}" + echo "==> Removing $MEMBER_ID from etcd cluster" + etcdctl ${AUTH_OPTIONS} member remove $MEMBER_ID + if [ $? -eq 0 ]; then + rm -rf ${DATA_DIR}/* + fi + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: client + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: client + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + volumeMounts: + {{- if .Values.persistence.enabled }} + - name: data + mountPath: /bitnami/etcd + {{ end }} + {{ if .Values.useConfigmap }} + - 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 ) ) }} + - 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 ) ) }} + - name: etcd-peer-certs + mountPath: /opt/bitnami/etcd/certs/peer/ + readOnly: true + {{ end }} + volumes: + {{ if .Values.useConfigmap }} + - name: etcd-config + configMap: + name: {{ template "etcd.fullname" . }}-configuration + {{ 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 ) ) }} + - name: etcd-peer-certs + secret: + secretName: {{ required "A secret containinig the peer certificates is required" .Values.auth.peer.existingSecret }} + defaultMode: 256 + {{ end }} +{{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + annotations: + {{- range $key, $value := .Values.persistence.annotations }} + {{ $key }}: {{ $value }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" + {{- end }} + {{- end }} +{{- else }} + - name: data + emptyDir: {} +{{- end }} + + diff --git a/bitnami/etcd/templates/svc-headless.yaml b/bitnami/etcd/templates/svc-headless.yaml new file mode 100644 index 000000000..691f43df3 --- /dev/null +++ b/bitnami/etcd/templates/svc-headless.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "etcd.fullname" . }}-headless + annotations: + service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" + labels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: ClusterIP + clusterIP: None + ports: + - name: client + port: 2379 + targetPort: client + - name: peer + port: 2380 + targetPort: peer + selector: + app: {{ template "etcd.name" . }} + release: "{{ .Release.Name }}" diff --git a/bitnami/etcd/templates/svc.yaml b/bitnami/etcd/templates/svc.yaml new file mode 100644 index 000000000..dfde124ac --- /dev/null +++ b/bitnami/etcd/templates/svc.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "etcd.fullname" . }} + labels: + app: {{ template "etcd.name" . }} + chart: {{ template "etcd.chart" . }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + type: {{ .Values.service.type }} + ports: + - name: client + port: 2379 + targetPort: client + - name: peer + port: 2380 + targetPort: peer + selector: + app: {{ template "etcd.name" . }} + release: {{ .Release.Name | quote }} \ No newline at end of file diff --git a/bitnami/etcd/values-production.yaml b/bitnami/etcd/values-production.yaml new file mode 100644 index 000000000..2b7d7c9e4 --- /dev/null +++ b/bitnami/etcd/values-production.yaml @@ -0,0 +1,138 @@ +## Bitnami etcd image version +## ref: https://hub.docker.com/r/bitnami/etcd/tags/ +## +image: + registry: docker.io + repository: bitnami/etcd + tag: 3.3.8 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistrKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + debug: false + +updateStrategy: RollingUpdate +podManagementPolicy: OrderedReady +replicaCount: 3 + +## Take into account that if you use a config map you need to provide the whole configuration +## as the env vars defined in the statefulset.yaml will not be applied +## +useConfigmap: false + +## etcd docker image available customizations +## https://github.com/bitnami/bitnami-docker-etcd#configuration +## +## Allow to use etcd without configuring RBAC authentication +allowNoneAuthentication: true + + +## Authentication parameteres +## https://github.com/bitnami/bitnami-docker-etcd#security +## +auth: + rbac: + enabled: true + ## etcd root user password. The root user is always `root`. + # rootPassword: + ## Name of the existing secret containing credentials for the root user. + # existingSecret: + + client: + ## Switch to encrypt client communication using TLS certificates + secureTransport: true + ## Switch to automatically create the TLS certificates + useAutoTLS: false + ## Switch to enable host authentication using TLS certificates. Requires existing secret. + enableAuthentication: true + ## Name of the existing secret containing cert files for client communication. + # existingSecret: + + peer: + ## Switch to encrypt client communication using TLS certificates + secureTransport: true + ## Switch to automatically create the TLS certificates + useAutoTLS: true + ## Switch to enable host authentication using TLS certificates. Requires existing secret. + enableAuthentication: false + ## Name of the existing secret containing cert files for client communication. + # existingSecret: + + +## Kubernetes Security Context +## https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + runAsUser: 1001 + +## Kubernetes configuration +## For minikube, set this to NodePort, elsewhere use LoadBalancer +## +service: + type: ClusterIP + port: 2379 + peerPort: 2380 + +## etcd data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: false + # storageClass: "-" + accessModes: + - ReadWriteOnce + 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/ +## +resources: +# limits: +# cpu: 200m +# memory: 1Gi +# requests: +# memory: 256Mi +# cpu: 250m + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +livenessProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 2 + successThreshold: 1 + +readinessProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 \ No newline at end of file diff --git a/bitnami/etcd/values.yaml b/bitnami/etcd/values.yaml new file mode 100644 index 000000000..035a4948f --- /dev/null +++ b/bitnami/etcd/values.yaml @@ -0,0 +1,138 @@ +## Bitnami etcd image version +## ref: https://hub.docker.com/r/bitnami/etcd/tags/ +## +image: + registry: docker.io + repository: bitnami/etcd + tag: 3.3.8 + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images + ## + pullPolicy: Always + + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # pullSecrets: + # - myRegistrKeySecretName + + ## Set to true if you would like to see extra information on logs + ## It turns BASH and NAMI debugging in minideb + ## ref: https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging + debug: false + +updateStrategy: RollingUpdate +podManagementPolicy: OrderedReady +replicaCount: 1 + +## Take into account that if you use a config map you need to provide the whole configuration +## as the env vars defined in the statefulset.yaml will not be applied +## +useConfigmap: false + +## etcd docker image available customizations +## https://github.com/bitnami/bitnami-docker-etcd#configuration +## +## Allow to use etcd without configuring RBAC authentication +allowNoneAuthentication: true + + +## Authentication parameteres +## https://github.com/bitnami/bitnami-docker-etcd#security +## +auth: + rbac: + enabled: true + ## etcd root user password. The root user is always `root`. + # rootPassword: + ## Name of the existing secret containing credentials for the root user. + # existingSecret: + + client: + ## Switch to encrypt client communication using TLS certificates + secureTransport: false + ## Switch to automatically create the TLS certificates + useAutoTLS: false + ## Switch to enable host authentication using TLS certificates. Requires existing secret. + enableAuthentication: false + ## Name of the existing secret containing cert files for client communication. + # existingSecret: + + peer: + ## Switch to encrypt client communication using TLS certificates + secureTransport: false + ## Switch to automatically create the TLS certificates + useAutoTLS: false + ## Switch to enable host authentication using TLS certificates. Requires existing secret. + enableAuthentication: false + ## Name of the existing secret containing cert files for client communication. + # existingSecret: + + +## Kubernetes Security Context +## https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +## +securityContext: + enabled: true + fsGroup: 1001 + runAsUser: 1001 + +## Kubernetes configuration +## For minikube, set this to NodePort, elsewhere use LoadBalancer +## +service: + type: ClusterIP + port: 2379 + peerPort: 2380 + +## etcd data Persistent Volume Storage Class +## If defined, storageClassName: +## If set to "-", storageClassName: "", which disables dynamic provisioning +## If undefined (the default) or set to null, no storageClassName spec is +## set, choosing the default provisioner. (gp2 on AWS, standard on +## GKE, AWS & OpenStack) +## +persistence: + enabled: false + # storageClass: "-" + accessModes: + - ReadWriteOnce + 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/ +## +resources: +# limits: +# cpu: 200m +# memory: 1Gi +# requests: +# memory: 256Mi +# cpu: 250m + +## Configure extra options for liveness and readiness probes +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes) +livenessProbe: + enabled: false + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 2 + successThreshold: 1 + +readinessProbe: + enabled: false + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 \ No newline at end of file