From dc80617f6f5ce0c97200f6d21db7f37ee16c30eb Mon Sep 17 00:00:00 2001 From: Rudro Debnath <56835340+Rudro-25@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:01:21 +0600 Subject: [PATCH] Add ZooKeeper Ops Request Docs (#711) Signed-off-by: Rudro-25 --- .../zookeeper/monitoring/builtin-prom-zk.yaml | 23 + .../zookeeper/monitoring/prom-config.yaml | 68 ++ .../zookeeper/monitoring/prom-zk.yaml | 23 + .../zookeeper/reconfiguration/new-secret.yaml | 8 + .../sample-zk-configuration.yaml | 18 + .../zookeeper/reconfiguration/secret.yaml | 8 + .../zkops-apply-reconfiguration.yaml | 13 + .../zkops-reconfiguration.yaml | 12 + .../reconfigure-tls/zkops-remove.yaml | 11 + .../reconfigure-tls/zkops-rotate.yaml | 11 + .../reconfigure-tls/zookeeper-add-tls.yaml | 23 + .../reconfigure-tls/zookeeper-issuer.yaml | 8 + .../reconfigure-tls/zookeeper-new-issuer.yaml | 8 + .../zookeeper-update-tls-issuer.yaml | 14 + .../zookeeper/reconfigure-tls/zookeeper.yaml | 16 + .../zookeeper/scaling/zk-hscale-down-ops.yaml | 11 + .../zookeeper/scaling/zk-hscale-up-ops.yaml | 11 + .../examples/zookeeper/scaling/zk-vscale.yaml | 20 + .../examples/zookeeper/scaling/zookeeper.yaml | 17 + .../zookeeper/tls/zookeeper-issuer.yaml | 8 + .../examples/zookeeper/tls/zookeeper-tls.yaml | 22 + .../zkops-volume-exp-offline.yaml | 12 + .../zkops-volume-exp-online.yaml | 12 + .../zookeeper/volume-expansion/zookeeper.yaml | 17 + docs/guides/zookeeper/monitoring/_index.md | 10 + docs/guides/zookeeper/monitoring/overview.md | 81 ++ .../monitoring/using-builtin-prometheus.md | 370 ++++++ .../monitoring/using-prometheus-operator.md | 357 ++++++ .../zookeeper/reconfigure-tls/_index.md | 10 + .../zookeeper/reconfigure-tls/overview.md | 54 + .../reconfigure-tls/reconfigure-tls.md | 1014 +++++++++++++++++ docs/guides/zookeeper/reconfigure/_index.md | 10 + docs/guides/zookeeper/reconfigure/overview.md | 54 + .../zookeeper/reconfigure/reconfigure.md | 529 +++++++++ docs/guides/zookeeper/restart/restart.md | 1 - docs/guides/zookeeper/scaling/_index.md | 10 + .../scaling/horizontal-scaling/_index.md | 10 + .../horizontal-scaling/horizontal-scaling.md | 419 +++++++ .../scaling/horizontal-scaling/overview.md | 54 + .../scaling/vertical-scaling/_index.md | 10 + .../scaling/vertical-scaling/overview.md | 54 + .../vertical-scaling/vertical-scaling.md | 293 +++++ docs/guides/zookeeper/tls/_index.md | 10 + docs/guides/zookeeper/tls/configure-ssl.md | 268 +++++ docs/guides/zookeeper/tls/overview.md | 70 ++ .../zookeeper/volume-expansion/_index.md | 10 + .../zookeeper/volume-expansion/overview.md | 56 + .../volume-expansion/volume-expansion.md | 386 +++++++ .../zookeeper/zk-horizontal-scaling.svg | 3 + .../zookeeper/zk-reconfigure-tls.svg | 3 + .../zookeeper/zk-reconfigure.svg | 3 + .../zookeeper/zk-version-update.svg | 2 +- .../zookeeper/zk-vertical-scaling.svg | 4 + .../zookeeper/zk-volume-expansion.svg | 3 + .../zookeeper/zk-builtin-prom-target.png | Bin 0 -> 129554 bytes docs/images/zookeeper/zk-tls.svg | 4 + .../images/zookeeper/zookeeper-prometheus.png | Bin 0 -> 114166 bytes 57 files changed, 4554 insertions(+), 2 deletions(-) create mode 100644 docs/examples/zookeeper/monitoring/builtin-prom-zk.yaml create mode 100644 docs/examples/zookeeper/monitoring/prom-config.yaml create mode 100644 docs/examples/zookeeper/monitoring/prom-zk.yaml create mode 100644 docs/examples/zookeeper/reconfiguration/new-secret.yaml create mode 100644 docs/examples/zookeeper/reconfiguration/sample-zk-configuration.yaml create mode 100644 docs/examples/zookeeper/reconfiguration/secret.yaml create mode 100644 docs/examples/zookeeper/reconfiguration/zkops-apply-reconfiguration.yaml create mode 100644 docs/examples/zookeeper/reconfiguration/zkops-reconfiguration.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zkops-remove.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zkops-rotate.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zookeeper-add-tls.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zookeeper-issuer.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zookeeper-new-issuer.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zookeeper-update-tls-issuer.yaml create mode 100644 docs/examples/zookeeper/reconfigure-tls/zookeeper.yaml create mode 100644 docs/examples/zookeeper/scaling/zk-hscale-down-ops.yaml create mode 100644 docs/examples/zookeeper/scaling/zk-hscale-up-ops.yaml create mode 100644 docs/examples/zookeeper/scaling/zk-vscale.yaml create mode 100644 docs/examples/zookeeper/scaling/zookeeper.yaml create mode 100644 docs/examples/zookeeper/tls/zookeeper-issuer.yaml create mode 100644 docs/examples/zookeeper/tls/zookeeper-tls.yaml create mode 100644 docs/examples/zookeeper/volume-expansion/zkops-volume-exp-offline.yaml create mode 100644 docs/examples/zookeeper/volume-expansion/zkops-volume-exp-online.yaml create mode 100644 docs/examples/zookeeper/volume-expansion/zookeeper.yaml create mode 100644 docs/guides/zookeeper/monitoring/_index.md create mode 100644 docs/guides/zookeeper/monitoring/overview.md create mode 100644 docs/guides/zookeeper/monitoring/using-builtin-prometheus.md create mode 100644 docs/guides/zookeeper/monitoring/using-prometheus-operator.md create mode 100644 docs/guides/zookeeper/reconfigure-tls/_index.md create mode 100644 docs/guides/zookeeper/reconfigure-tls/overview.md create mode 100644 docs/guides/zookeeper/reconfigure-tls/reconfigure-tls.md create mode 100644 docs/guides/zookeeper/reconfigure/_index.md create mode 100644 docs/guides/zookeeper/reconfigure/overview.md create mode 100644 docs/guides/zookeeper/reconfigure/reconfigure.md create mode 100644 docs/guides/zookeeper/scaling/_index.md create mode 100644 docs/guides/zookeeper/scaling/horizontal-scaling/_index.md create mode 100644 docs/guides/zookeeper/scaling/horizontal-scaling/horizontal-scaling.md create mode 100644 docs/guides/zookeeper/scaling/horizontal-scaling/overview.md create mode 100644 docs/guides/zookeeper/scaling/vertical-scaling/_index.md create mode 100644 docs/guides/zookeeper/scaling/vertical-scaling/overview.md create mode 100644 docs/guides/zookeeper/scaling/vertical-scaling/vertical-scaling.md create mode 100644 docs/guides/zookeeper/tls/_index.md create mode 100644 docs/guides/zookeeper/tls/configure-ssl.md create mode 100644 docs/guides/zookeeper/tls/overview.md create mode 100644 docs/guides/zookeeper/volume-expansion/_index.md create mode 100644 docs/guides/zookeeper/volume-expansion/overview.md create mode 100644 docs/guides/zookeeper/volume-expansion/volume-expansion.md create mode 100644 docs/images/day-2-operation/zookeeper/zk-horizontal-scaling.svg create mode 100644 docs/images/day-2-operation/zookeeper/zk-reconfigure-tls.svg create mode 100644 docs/images/day-2-operation/zookeeper/zk-reconfigure.svg create mode 100644 docs/images/day-2-operation/zookeeper/zk-vertical-scaling.svg create mode 100644 docs/images/day-2-operation/zookeeper/zk-volume-expansion.svg create mode 100644 docs/images/zookeeper/zk-builtin-prom-target.png create mode 100644 docs/images/zookeeper/zk-tls.svg create mode 100644 docs/images/zookeeper/zookeeper-prometheus.png diff --git a/docs/examples/zookeeper/monitoring/builtin-prom-zk.yaml b/docs/examples/zookeeper/monitoring/builtin-prom-zk.yaml new file mode 100644 index 0000000000..d3b61d559b --- /dev/null +++ b/docs/examples/zookeeper/monitoring/builtin-prom-zk.yaml @@ -0,0 +1,23 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zookeeper-builtin-prom + namespace: demo +spec: + version: 3.8.3 + replicas: 3 + storage: + resources: + requests: + storage: "100Mi" + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut + monitor: + agent: prometheus.io/builtin + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s \ No newline at end of file diff --git a/docs/examples/zookeeper/monitoring/prom-config.yaml b/docs/examples/zookeeper/monitoring/prom-config.yaml new file mode 100644 index 0000000000..45aee6317a --- /dev/null +++ b/docs/examples/zookeeper/monitoring/prom-config.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + app: prometheus-demo + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubedb-databases' + honor_labels: true + scheme: http + kubernetes_sd_configs: + - role: endpoints + # by default Prometheus server select all Kubernetes services as possible target. + # relabel_config is used to filter only desired endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape","prometheus.io/path" and "prometheus.io/port" anootations + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_port] + separator: ; + regex: true;(.*) + action: keep + # currently KubeDB supported databases uses only "http" scheme to export metrics. so, drop any service that uses "https" scheme. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: https + # only keep the stats services created by KubeDB for monitoring purpose which has "-stats" suffix + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*-stats) + action: keep + # service created by KubeDB will have "app.kubernetes.io/name" and "app.kubernetes.io/instance" annotations. keep only those services that have these annotations. + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + separator: ; + regex: (.*) + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + # read the port from "prometheus.io/port: " annotation and update scraping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scraped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as a label to the scraped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace + # add stats service's labels to the scraped metrics + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) diff --git a/docs/examples/zookeeper/monitoring/prom-zk.yaml b/docs/examples/zookeeper/monitoring/prom-zk.yaml new file mode 100644 index 0000000000..de720d8b12 --- /dev/null +++ b/docs/examples/zookeeper/monitoring/prom-zk.yaml @@ -0,0 +1,23 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zookeeper + namespace: demo +spec: + version: 3.8.3 + replicas: 3 + storage: + resources: + requests: + storage: "100Mi" + storageClassName: longhorn + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfiguration/new-secret.yaml b/docs/examples/zookeeper/reconfiguration/new-secret.yaml new file mode 100644 index 0000000000..78b7ef3694 --- /dev/null +++ b/docs/examples/zookeeper/reconfiguration/new-secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +stringData: + zoo.cfg: | + maxClientCnxns=100 +kind: Secret +metadata: + name: zk-new-configuration + namespace: demo \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfiguration/sample-zk-configuration.yaml b/docs/examples/zookeeper/reconfiguration/sample-zk-configuration.yaml new file mode 100644 index 0000000000..0f929f28ff --- /dev/null +++ b/docs/examples/zookeeper/reconfiguration/sample-zk-configuration.yaml @@ -0,0 +1,18 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + configSecret: + name: zk-configuration + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfiguration/secret.yaml b/docs/examples/zookeeper/reconfiguration/secret.yaml new file mode 100644 index 0000000000..3db7af1c97 --- /dev/null +++ b/docs/examples/zookeeper/reconfiguration/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +stringData: + zoo.cfg: | + maxClientCnxns=70 +kind: Secret +metadata: + name: zk-configuration + namespace: demo \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfiguration/zkops-apply-reconfiguration.yaml b/docs/examples/zookeeper/reconfiguration/zkops-apply-reconfiguration.yaml new file mode 100644 index 0000000000..d7ef3c52d3 --- /dev/null +++ b/docs/examples/zookeeper/reconfiguration/zkops-apply-reconfiguration.yaml @@ -0,0 +1,13 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-reconfig-apply + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: zk-quickstart + configuration: + applyConfig: + zoo.cfg: | + maxClientCnxns=90 \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfiguration/zkops-reconfiguration.yaml b/docs/examples/zookeeper/reconfiguration/zkops-reconfiguration.yaml new file mode 100644 index 0000000000..844046ce08 --- /dev/null +++ b/docs/examples/zookeeper/reconfiguration/zkops-reconfiguration.yaml @@ -0,0 +1,12 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-reconfig + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: zk-quickstart + configuration: + configSecret: + name: zk-new-configuration \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zkops-remove.yaml b/docs/examples/zookeeper/reconfigure-tls/zkops-remove.yaml new file mode 100644 index 0000000000..714c89ae57 --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zkops-remove.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-remove + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + remove: true \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zkops-rotate.yaml b/docs/examples/zookeeper/reconfigure-tls/zkops-rotate.yaml new file mode 100644 index 0000000000..16d11432f4 --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zkops-rotate.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-rotate + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + rotateCertificates: true \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zookeeper-add-tls.yaml b/docs/examples/zookeeper/reconfigure-tls/zookeeper-add-tls.yaml new file mode 100644 index 0000000000..36542f5c2d --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zookeeper-add-tls.yaml @@ -0,0 +1,23 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-add-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + issuerRef: + name: zookeeper-ca-issuer + kind: Issuer + apiGroup: "cert-manager.io" + certificates: + - alias: client + subject: + organizations: + - zookeeper + organizationalUnits: + - client + timeout: 5m + apply: IfReady \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zookeeper-issuer.yaml b/docs/examples/zookeeper/reconfigure-tls/zookeeper-issuer.yaml new file mode 100644 index 0000000000..5d0f5284be --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zookeeper-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zk-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-ca \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zookeeper-new-issuer.yaml b/docs/examples/zookeeper/reconfigure-tls/zookeeper-new-issuer.yaml new file mode 100644 index 0000000000..f411e6c0f6 --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zookeeper-new-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zk-new-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-new-ca \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zookeeper-update-tls-issuer.yaml b/docs/examples/zookeeper/reconfigure-tls/zookeeper-update-tls-issuer.yaml new file mode 100644 index 0000000000..425f2eea92 --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zookeeper-update-tls-issuer.yaml @@ -0,0 +1,14 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-update-issuer + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + issuerRef: + name: zk-new-issuer + kind: Issuer + apiGroup: "cert-manager.io" \ No newline at end of file diff --git a/docs/examples/zookeeper/reconfigure-tls/zookeeper.yaml b/docs/examples/zookeeper/reconfigure-tls/zookeeper.yaml new file mode 100644 index 0000000000..c121a2d2fd --- /dev/null +++ b/docs/examples/zookeeper/reconfigure-tls/zookeeper.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" \ No newline at end of file diff --git a/docs/examples/zookeeper/scaling/zk-hscale-down-ops.yaml b/docs/examples/zookeeper/scaling/zk-hscale-down-ops.yaml new file mode 100644 index 0000000000..6edf303de8 --- /dev/null +++ b/docs/examples/zookeeper/scaling/zk-hscale-down-ops.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: horizontal-scale-down + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: zk-quickstart + horizontalScaling: + replicas: 3 diff --git a/docs/examples/zookeeper/scaling/zk-hscale-up-ops.yaml b/docs/examples/zookeeper/scaling/zk-hscale-up-ops.yaml new file mode 100644 index 0000000000..ea07c7d983 --- /dev/null +++ b/docs/examples/zookeeper/scaling/zk-hscale-up-ops.yaml @@ -0,0 +1,11 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: horizontal-scale-up + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: zk-quickstart + horizontalScaling: + replicas: 5 \ No newline at end of file diff --git a/docs/examples/zookeeper/scaling/zk-vscale.yaml b/docs/examples/zookeeper/scaling/zk-vscale.yaml new file mode 100644 index 0000000000..654b1bbe4c --- /dev/null +++ b/docs/examples/zookeeper/scaling/zk-vscale.yaml @@ -0,0 +1,20 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: vscale + namespace: demo +spec: + databaseRef: + name: zk-quickstart + type: VerticalScaling + verticalScaling: + node: + resources: + limits: + cpu: 1 + memory: 2Gi + requests: + cpu: 1 + memory: 2Gi + timeout: 5m + apply: IfReady diff --git a/docs/examples/zookeeper/scaling/zookeeper.yaml b/docs/examples/zookeeper/scaling/zookeeper.yaml new file mode 100644 index 0000000000..d996a50c86 --- /dev/null +++ b/docs/examples/zookeeper/scaling/zookeeper.yaml @@ -0,0 +1,17 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 4 + storage: + resources: + requests: + storage: "1Gi" + storageClassName: "standard" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" diff --git a/docs/examples/zookeeper/tls/zookeeper-issuer.yaml b/docs/examples/zookeeper/tls/zookeeper-issuer.yaml new file mode 100644 index 0000000000..cee750e080 --- /dev/null +++ b/docs/examples/zookeeper/tls/zookeeper-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zookeeper-ca-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-ca \ No newline at end of file diff --git a/docs/examples/zookeeper/tls/zookeeper-tls.yaml b/docs/examples/zookeeper/tls/zookeeper-tls.yaml new file mode 100644 index 0000000000..eafa468bb7 --- /dev/null +++ b/docs/examples/zookeeper/tls/zookeeper-tls.yaml @@ -0,0 +1,22 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + enableSSL: true + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: zookeeper-ca-issuer + adminServerPort: 8080 + replicas: 5 + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" \ No newline at end of file diff --git a/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-offline.yaml b/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-offline.yaml new file mode 100644 index 0000000000..da8cb7f8a9 --- /dev/null +++ b/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-offline.yaml @@ -0,0 +1,12 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-offline-volume-expansion + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: zk-quickstart + volumeExpansion: + mode: "Offline" + node: 2Gi diff --git a/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-online.yaml b/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-online.yaml new file mode 100644 index 0000000000..ef287faa14 --- /dev/null +++ b/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-online.yaml @@ -0,0 +1,12 @@ +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-online-volume-expansion + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: zk-quickstart + volumeExpansion: + mode: "Online" + node: 2Gi diff --git a/docs/examples/zookeeper/volume-expansion/zookeeper.yaml b/docs/examples/zookeeper/volume-expansion/zookeeper.yaml new file mode 100644 index 0000000000..7e8f26ca62 --- /dev/null +++ b/docs/examples/zookeeper/volume-expansion/zookeeper.yaml @@ -0,0 +1,17 @@ +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + storageClassName: "standard" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" \ No newline at end of file diff --git a/docs/guides/zookeeper/monitoring/_index.md b/docs/guides/zookeeper/monitoring/_index.md new file mode 100644 index 0000000000..90c043fcb8 --- /dev/null +++ b/docs/guides/zookeeper/monitoring/_index.md @@ -0,0 +1,10 @@ +--- +title: Monitoring ZooKeeper +menu: + docs_{{ .version }}: + identifier: zk-monitoring-guides + name: Monitoring + parent: zk-zookeeper-guides + weight: 110 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/zookeeper/monitoring/overview.md b/docs/guides/zookeeper/monitoring/overview.md new file mode 100644 index 0000000000..be14f20d04 --- /dev/null +++ b/docs/guides/zookeeper/monitoring/overview.md @@ -0,0 +1,81 @@ +--- +title: ZooKeeper Monitoring Overview +description: ZooKeeper Monitoring Overview +menu: + docs_{{ .version }}: + identifier: zk-monitoring-overview + name: Overview + parent: zk-monitoring-guides + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring ZooKeeper with KubeDB + +KubeDB has native support for monitoring via [Prometheus](https://prometheus.io/). You can use builtin [Prometheus](https://github.com/prometheus/prometheus) scraper or [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) to monitor KubeDB managed databases. This tutorial will show you how database monitoring works with KubeDB and how to configure Database crd to enable monitoring. + +## Overview + +KubeDB uses Prometheus [exporter](https://prometheus.io/docs/instrumenting/exporters/#databases) images to export Prometheus metrics for respective databases. Following diagram shows the logical flow of database monitoring with KubeDB. + +

+  Database Monitoring Flow +

+ +When a user creates a database crd with `spec.monitor` section configured, KubeDB operator provisions the respective database and injects an exporter image as sidecar to the database pod. It also creates a dedicated stats service with name `{database-crd-name}-stats` for monitoring. Prometheus server can scrape metrics using this stats service. + +## Configure Monitoring + +In order to enable monitoring for a database, you have to configure `spec.monitor` section. KubeDB provides following options to configure `spec.monitor` section: + +| Field | Type | Uses | +| -------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `spec.monitor.agent` | `Required` | Type of the monitoring agent that will be used to monitor this database. It can be `prometheus.io/builtin` or `prometheus.io/operator`. | +| `spec.monitor.prometheus.exporter.port` | `Optional` | Port number where the exporter side car will serve metrics. | +| `spec.monitor.prometheus.exporter.args` | `Optional` | Arguments to pass to the exporter sidecar. | +| `spec.monitor.prometheus.exporter.env` | `Optional` | List of environment variables to set in the exporter sidecar container. | +| `spec.monitor.prometheus.exporter.resources` | `Optional` | Resources required by exporter sidecar container. | +| `spec.monitor.prometheus.exporter.securityContext` | `Optional` | Security options the exporter should run with. | +| `spec.monitor.prometheus.serviceMonitor.labels` | `Optional` | Labels for `ServiceMonitor` crd. | +| `spec.monitor.prometheus.serviceMonitor.interval` | `Optional` | Interval at which metrics should be scraped. | + +## Sample Configuration + +A sample YAML for ZooKeeper crd with `spec.monitor` section configured to enable monitoring with [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) is shown below. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zookeeper + namespace: demo +spec: + version: 3.8.3 + replicas: 3 + storage: + resources: + requests: + storage: "100Mi" + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s +``` + +Here, we have specified that we are going to monitor this server using Prometheus operator through `spec.monitor.agent: prometheus.io/operator`. KubeDB will create a `ServiceMonitor` crd in databases namespace and this `ServiceMonitor` will have `release: prometheus` label. + + +## Next Steps + +- Learn how to monitor ZooKeeper database with KubeDB using [builtin-Prometheus](/docs/guides/zookeeper/monitoring/using-builtin-prometheus.md) +- Learn how to monitor ZooKeeper database with KubeDB using [Prometheus operator](/docs/guides/zookeeper/monitoring/using-prometheus-operator.md). diff --git a/docs/guides/zookeeper/monitoring/using-builtin-prometheus.md b/docs/guides/zookeeper/monitoring/using-builtin-prometheus.md new file mode 100644 index 0000000000..6746c0a8a8 --- /dev/null +++ b/docs/guides/zookeeper/monitoring/using-builtin-prometheus.md @@ -0,0 +1,370 @@ +--- +title: Monitor ZooKeeper using Builtin Prometheus Discovery +menu: + docs_{{ .version }}: + identifier: zk-using-builtin-prometheus-monitoring + name: Builtin Prometheus + parent: zk-monitoring-guides + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring ZooKeeper with builtin Prometheus + +This tutorial will show you how to monitor ZooKeeper database using builtin [Prometheus](https://github.com/prometheus/prometheus) scraper. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +- If you are not familiar with how to configure Prometheus to scrape metrics from various Kubernetes resources, please read the tutorial from [here](https://github.com/appscode/third-party-tools/tree/master/monitoring/prometheus/builtin). + +- To learn how Prometheus monitoring works with KubeDB in general, please visit [here](/docs/guides/zookeeper/monitoring/overview.md). + +- To keep Prometheus resources isolated, we are going to use a separate namespace called `monitoring` to deploy respective monitoring resources. We are going to deploy database in `demo` namespace. + + ```bash + $ kubectl create ns monitoring + namespace/monitoring created + + $ kubectl create ns demo + namespace/demo created + ``` + +> Note: YAML files used in this tutorial are stored in [docs/examples/zookeeper](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/zookeeper) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Deploy ZooKeeper with Monitoring Enabled + +At first, let's deploy an ZooKeeper database with monitoring enabled. Below is the ZooKeeper object that we are going to create. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zookeeper-builtin-prom + namespace: demo +spec: + version: 3.8.3 + replicas: 3 + storage: + resources: + requests: + storage: "100Mi" + storageClassName: standard + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut + monitor: + agent: prometheus.io/builtin + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s +``` + +Here, + +- `spec.monitor.agent: prometheus.io/builtin` specifies that we are going to monitor this server using builtin Prometheus scraper. + +Let's create the ZooKeeper crd we have shown above. + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/monitoring/builtin-prom-zk.yaml +zookeeper.kubedb.com/zookeeper-builtin-prom created +``` + +Now, wait for the database to go into `Running` state. + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zookeeper-builtin-prom 3.8.3 Ready 129m +``` + +KubeDB will create a separate stats service with name `{ZooKeeper crd name}-stats` for monitoring purpose. + +```bash +$ kubectl get svc -n demo --selector="app.kubernetes.io/instance=zookeeper-builtin-prom" +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +zookeeper-builtin-prom ClusterIP 10.43.115.171 2181/TCP 129m +zookeeper-builtin-prom-admin-server ClusterIP 10.43.55.7 8080/TCP 129m +zookeeper-builtin-prom-pods ClusterIP None 2181/TCP,2888/TCP,3888/TCP 129m +zookeeper-builtin-prom-stats ClusterIP 10.43.211.84 7000/TCP 129m +``` + +Here, `zookeeper-builtin-prom-stats` service has been created for monitoring purpose. Let's describe the service. + +```bash +$ kubectl describe svc -n demo zookeeper-builtin-prom-stats +Name: zookeeper-builtin-prom-stats +Namespace: demo +Labels: app.kubernetes.io/component=database + app.kubernetes.io/instance=zookeeper-builtin-prom + app.kubernetes.io/managed-by=kubedb.com + app.kubernetes.io/name=zookeepers.kubedb.com + kubedb.com/role=stats +Annotations: monitoring.appscode.com/agent: prometheus.io/builtin + prometheus.io/path: /metrics + prometheus.io/port: 7000 + prometheus.io/scrape: true +Selector: app.kubernetes.io/instance=zookeeper-builtin-prom,app.kubernetes.io/managed-by=kubedb.com,app.kubernetes.io/name=zookeepers.kubedb.com +Type: ClusterIP +IP Family Policy: SingleStack +IP Families: IPv4 +IP: 10.43.211.84 +IPs: 10.43.211.84 +Port: metrics 7000/TCP +TargetPort: metrics/TCP +Endpoints: 10.42.0.124:7000,10.42.0.126:7000,10.42.0.128:7000 +Session Affinity: None +Events: +``` + +You can see that the service contains following annotations. + +```bash +prometheus.io/path: /metrics +prometheus.io/port: 7000 +prometheus.io/scrape: true +``` + +The Prometheus server will discover the service endpoint using these specifications and will scrape metrics from the exporter. + +## Configure Prometheus Server + +Now, we have to configure a Prometheus scraping job to scrape the metrics using this service. We are going to configure scraping job similar to this [kubernetes-service-endpoints](https://github.com/appscode/third-party-tools/tree/master/monitoring/prometheus/builtin#kubernetes-service-endpoints) job that scrapes metrics from endpoints of a service. + +Let's configure a Prometheus scraping job to collect metrics from this service. + +```yaml +- job_name: 'kubedb-databases' + honor_labels: true + scheme: http + kubernetes_sd_configs: + - role: endpoints + # by default Prometheus server select all Kubernetes services as possible target. + # relabel_config is used to filter only desired endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape","prometheus.io/path" and "prometheus.io/port" anootations + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_port] + separator: ; + regex: true;(.*) + action: keep + # currently KubeDB supported databases uses only "http" scheme to export metrics. so, drop any service that uses "https" scheme. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: https + # only keep the stats services created by KubeDB for monitoring purpose which has "-stats" suffix + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*-stats) + action: keep + # service created by KubeDB will have "app.kubernetes.io/name" and "app.kubernetes.io/instance" annotations. keep only those services that have these annotations. + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + separator: ; + regex: (.*) + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + # read the port from "prometheus.io/port: " annotation and update scraping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scraped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as a label to the scraped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace + # add stats service's labels to the scraped metrics + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) +``` + +### Configure Existing Prometheus Server + +If you already have a Prometheus server running, you have to add above scraping job in the `ConfigMap` used to configure the Prometheus server. Then, you have to restart it for the updated configuration to take effect. + +>If you don't use a persistent volume for Prometheus storage, you will lose your previously scraped data on restart. + +### Deploy New Prometheus Server + +If you don't have any existing Prometheus server running, you have to deploy one. In this section, we are going to deploy a Prometheus server in `monitoring` namespace to collect metrics using this stats service. + +**Create ConfigMap:** + +At first, create a ConfigMap with the scraping configuration. Bellow, the YAML of ConfigMap that we are going to create in this tutorial. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-config + labels: + app: prometheus-demo + namespace: monitoring +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubedb-databases' + honor_labels: true + scheme: http + kubernetes_sd_configs: + - role: endpoints + # by default Prometheus server select all Kubernetes services as possible target. + # relabel_config is used to filter only desired endpoints + relabel_configs: + # keep only those services that has "prometheus.io/scrape","prometheus.io/path" and "prometheus.io/port" anootations + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape, __meta_kubernetes_service_annotation_prometheus_io_port] + separator: ; + regex: true;(.*) + action: keep + # currently KubeDB supported databases uses only "http" scheme to export metrics. so, drop any service that uses "https" scheme. + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: https + # only keep the stats services created by KubeDB for monitoring purpose which has "-stats" suffix + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*-stats) + action: keep + # service created by KubeDB will have "app.kubernetes.io/name" and "app.kubernetes.io/instance" annotations. keep only those services that have these annotations. + - source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name] + separator: ; + regex: (.*) + action: keep + # read the metric path from "prometheus.io/path: " annotation + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + # read the port from "prometheus.io/port: " annotation and update scraping address accordingly + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + # add service namespace as label to the scraped metrics + - source_labels: [__meta_kubernetes_namespace] + separator: ; + regex: (.*) + target_label: namespace + replacement: $1 + action: replace + # add service name as a label to the scraped metrics + - source_labels: [__meta_kubernetes_service_name] + separator: ; + regex: (.*) + target_label: service + replacement: $1 + action: replace + # add stats service's labels to the scraped metrics + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) +``` + +Let's create above `ConfigMap`, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/monitoring/prom-config.yaml +configmap/prometheus-config created +``` + +**Create RBAC:** + +If you are using an RBAC enabled cluster, you have to give necessary RBAC permissions for Prometheus. Let's create necessary RBAC stuffs for Prometheus, + +```bash +$ kubectl apply -f https://github.com/appscode/third-party-tools/raw/master/monitoring/prometheus/builtin/artifacts/rbac.yaml +clusterrole.rbac.authorization.k8s.io/prometheus created +serviceaccount/prometheus created +clusterrolebinding.rbac.authorization.k8s.io/prometheus created +``` + +>YAML for the RBAC resources created above can be found [here](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/artifacts/rbac.yaml). + +**Deploy Prometheus:** + +Now, we are ready to deploy Prometheus server. We are going to use following [deployment](https://github.com/appscode/third-party-tools/blob/master/monitoring/prometheus/builtin/artifacts/deployment.yaml) to deploy Prometheus server. + +Let's deploy the Prometheus server. + +```bash +$ kubectl apply -f https://github.com/appscode/third-party-tools/raw/master/monitoring/prometheus/builtin/artifacts/deployment.yaml +deployment.apps/prometheus created +``` + +### Verify Monitoring Metrics + +Prometheus server is listening to port `9090`. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access Prometheus dashboard. + +At first, let's check if the Prometheus pod is in `Running` state. + +```bash +$ kubectl get pod -n monitoring -l=app=prometheus +NAME READY STATUS RESTARTS AGE +prometheus-d64b668fb-vg746 1/1 Running 0 28s +``` + +Now, run following command on a separate terminal to forward 9090 port of `prometheus-7bd56c6865-8dlpv` pod, + +```bash +$ kubectl port-forward -n monitoring prometheus-d64b668fb-vg746 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, we can access the dashboard at `localhost:9090`. Open [http://localhost:9090](http://localhost:9090) in your browser. You should see the endpoint of `zookeeper-builtin-prom-stats` service as one of the targets. + +

+  Prometheus Target +

+ +Check the labels marked with red rectangle. These labels confirm that the metrics are coming from `ZooKeeper` database `zookeeper-builtin-prom` through stats service `zookeeper-builtin-prom-stats`. + +Now, you can view the collected metrics and create a graph from homepage of this Prometheus dashboard. You can also use this Prometheus server as data source for [Grafana](https://grafana.com/) and create beautiful dashboard with collected metrics. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run following commands + +```bash +kubectl delete -n demo zk/zookeeper-builtin-prom + +kubectl delete -n monitoring deployment.apps/prometheus + +kubectl delete -n monitoring clusterrole.rbac.authorization.k8s.io/prometheus +kubectl delete -n monitoring serviceaccount/prometheus +kubectl delete -n monitoring clusterrolebinding.rbac.authorization.k8s.io/prometheus + +kubectl delete ns demo +kubectl delete ns monitoring +``` + +## Next Steps + +- Monitor your ZooKeeper database with KubeDB using [`out-of-the-box` Prometheus operator](/docs/guides/zookeeper/monitoring/using-prometheus-operator.md). + +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/zookeeper/monitoring/using-prometheus-operator.md b/docs/guides/zookeeper/monitoring/using-prometheus-operator.md new file mode 100644 index 0000000000..4943bea813 --- /dev/null +++ b/docs/guides/zookeeper/monitoring/using-prometheus-operator.md @@ -0,0 +1,357 @@ +--- +title: Monitor ZooKeeper using Prometheus Operator +menu: + docs_{{ .version }}: + identifier: zk-using-prometheus-operator-monitoring + name: Prometheus Operator + parent: zk-monitoring-guides + weight: 15 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Monitoring ZooKeeper Using Prometheus operator + +[Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) provides simple and Kubernetes native way to deploy and configure Prometheus server. This tutorial will show you how to use Prometheus operator to monitor ZooKeeper database deployed with KubeDB. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- To learn how Prometheus monitoring works with KubeDB in general, please visit [here](/docs/guides/zookeeper/monitoring/overview.md). + +- We need a [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator) instance running. If you don't already have a running instance, you can deploy one using this helm chart [here](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack). + +- To keep Prometheus resources isolated, we are going to use a separate namespace called `monitoring` to deploy the prometheus operator helm chart. We are going to deploy database in `demo` namespace. + + ```bash + $ kubectl create ns monitoring + namespace/monitoring created + + $ kubectl create ns demo + namespace/demo created + ``` + + + +> Note: YAML files used in this tutorial are stored in [docs/examples/ZooKeeper](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/zookeeper) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Find out required labels for ServiceMonitor + +We need to know the labels used to select `ServiceMonitor` by a `Prometheus` crd. We are going to provide these labels in `spec.monitor.prometheus.serviceMonitor.labels` field of ZooKeeper crd so that KubeDB creates `ServiceMonitor` object accordingly. + +At first, let's find out the available Prometheus server in our cluster. + +```bash +$ kubectl get prometheus --all-namespaces +NAMESPACE NAME VERSION DESIRED READY RECONCILED AVAILABLE AGE +monitoring prometheus-kube-prometheus-prometheus v2.54.1 1 1 True True 22h +``` + +> If you don't have any Prometheus server running in your cluster, deploy one following the guide specified in **Before You Begin** section. + +Now, let's view the YAML of the available Prometheus server `prometheus` in `monitoring` namespace. + +```yaml +$ kubectl get prometheus -n monitoring prometheus-kube-prometheus-prometheus -o yaml +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + annotations: + meta.helm.sh/release-name: prometheus + meta.helm.sh/release-namespace: monitoring + creationTimestamp: "2024-11-06T07:39:12Z" + generation: 1 + labels: + app: kube-prometheus-stack-prometheus + app.kubernetes.io/instance: prometheus + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/part-of: kube-prometheus-stack + app.kubernetes.io/version: 65.1.1 + chart: kube-prometheus-stack-65.1.1 + heritage: Helm + release: prometheus + name: prometheus-kube-prometheus-prometheus + namespace: monitoring + resourceVersion: "91198" + uid: 4f52775a-e0f8-4158-aa3e-6a1d558e0ef9 +spec: + alerting: + alertmanagers: + - apiVersion: v2 + name: prometheus-kube-prometheus-alertmanager + namespace: monitoring + pathPrefix: / + port: http-web + automountServiceAccountToken: true + enableAdminAPI: false + evaluationInterval: 30s + externalUrl: http://prometheus-kube-prometheus-prometheus.monitoring:9090 + hostNetwork: false + image: quay.io/prometheus/prometheus:v2.54.1 + listenLocal: false + logFormat: logfmt + logLevel: info + paused: false + podMonitorNamespaceSelector: {} + podMonitorSelector: + matchLabels: + release: prometheus + portName: http-web + probeNamespaceSelector: {} + probeSelector: + matchLabels: + release: prometheus + replicas: 1 + retention: 10d + routePrefix: / + ruleNamespaceSelector: {} + ruleSelector: + matchLabels: + release: prometheus + scrapeConfigNamespaceSelector: {} + scrapeConfigSelector: + matchLabels: + release: prometheus + scrapeInterval: 30s + securityContext: + fsGroup: 2000 + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + serviceAccountName: prometheus-kube-prometheus-prometheus + serviceMonitorNamespaceSelector: {} + serviceMonitorSelector: + matchLabels: + release: prometheus + shards: 1 + tsdb: + outOfOrderTimeWindow: 0s + version: v2.54.1 + walCompression: true +status: + availableReplicas: 1 + conditions: + - lastTransitionTime: "2024-11-07T05:26:29Z" + message: "" + observedGeneration: 1 + reason: "" + status: "True" + type: Available + - lastTransitionTime: "2024-11-07T05:26:29Z" + message: "" + observedGeneration: 1 + reason: "" + status: "True" + type: Reconciled + paused: false + replicas: 1 + selector: app.kubernetes.io/instance=prometheus-kube-prometheus-prometheus,app.kubernetes.io/managed-by=prometheus-operator,app.kubernetes.io/name=prometheus,operator.prometheus.io/name=prometheus-kube-prometheus-prometheus,prometheus=prometheus-kube-prometheus-prometheus + shardStatuses: + - availableReplicas: 1 + replicas: 1 + shardID: "0" + unavailableReplicas: 0 + updatedReplicas: 1 + shards: 1 + unavailableReplicas: 0 + updatedReplicas: 1 +``` + +Notice the `spec.serviceMonitorSelector` section. Here, `release: prometheus` label is used to select `ServiceMonitor` crd. So, we are going to use this label in `spec.monitor.prometheus.serviceMonitor.labels` field of ZooKeeper crd. + +## Deploy ZooKeeper with Monitoring Enabled + +At first, let's deploy an ZooKeeper database with monitoring enabled. Below is the ZooKeeper object that we are going to create. + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zookeeper + namespace: demo +spec: + version: 3.8.3 + replicas: 3 + storage: + resources: + requests: + storage: "100Mi" + storageClassName: longhorn + accessModes: + - ReadWriteOnce + deletionPolicy: WipeOut + monitor: + agent: prometheus.io/operator + prometheus: + serviceMonitor: + labels: + release: prometheus + interval: 10s +``` + +Here, + +- `monitor.agent: prometheus.io/operator` indicates that we are going to monitor this server using Prometheus operator. +- `monitor.prometheus.serviceMonitor.labels` specifies that KubeDB should create `ServiceMonitor` with these labels. +- `monitor.prometheus.interval` indicates that the Prometheus server should scrape metrics from this database with 10 seconds interval. + +Let's create the ZooKeeper object that we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/monitoring/prom-zk.yaml +zookeeper.kubedb.com/zookeeper created +``` + +Now, wait for the database to go into `Running` state. + +```bash +$ kubectl get zk -n demo zookeeper +NAME VERSION STATUS AGE +zookeeper 3.8.3 Ready 34s +``` + +KubeDB will create a separate stats service with name `{ZooKeeper crd name}-stats` for monitoring purpose. + +```bash +$ kubectl get svc -n demo --selector="app.kubernetes.io/instance=zookeeper" +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +zookeeper ClusterIP 10.43.121.151 2181/TCP 26s +zookeeper-admin-server ClusterIP 10.43.28.44 8080/TCP 26s +zookeeper-pods ClusterIP None 2181/TCP,2888/TCP,3888/TCP 26s +zookeeper-stats ClusterIP 10.43.19.32 7000/TCP 26s +``` + +Here, `zookeeper-stats` service has been created for monitoring purpose. + +Let's describe this stats service. + +```yaml +$ kubectl describe svc -n demo zookeeper-stats +Name: zookeeper-stats +Namespace: demo +Labels: app.kubernetes.io/component=database + app.kubernetes.io/instance=zookeeper + app.kubernetes.io/managed-by=kubedb.com + app.kubernetes.io/name=zookeepers.kubedb.com + kubedb.com/role=stats +Annotations: monitoring.appscode.com/agent: prometheus.io/operator +Selector: app.kubernetes.io/instance=zookeeper,app.kubernetes.io/managed-by=kubedb.com,app.kubernetes.io/name=zookeepers.kubedb.com +Type: ClusterIP +IP Family Policy: SingleStack +IP Families: IPv4 +IP: 10.43.19.32 +IPs: 10.43.19.32 +Port: metrics 7000/TCP +TargetPort: metrics/TCP +Endpoints: 10.42.0.100:7000,10.42.0.96:7000,10.42.0.98:7000 +Session Affinity: None +Events: +``` + +Notice the `Labels` and `Port` fields. `ServiceMonitor` will use this information to target its endpoints. + +KubeDB will also create a `ServiceMonitor` crd in `demo` namespace that select the endpoints of `zookeeper-stats` service. Verify that the `ServiceMonitor` crd has been created. + +```bash +$ kubectl get servicemonitor -n demo +NAME AGE +zookeeper-stats 2m40s +``` + +Let's verify that the `ServiceMonitor` has the label that we had specified in `spec.monitor` section of ZooKeeper crd. + +```yaml +$ kubectl get servicemonitor -n demo zookeeper-stats -o yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + creationTimestamp: "2024-11-07T07:20:08Z" + generation: 1 + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: zookeeper + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: zookeepers.kubedb.com + release: prometheus + name: zookeeper-stats + namespace: demo + ownerReferences: + - apiVersion: v1 + blockOwnerDeletion: true + controller: true + kind: Service + name: zookeeper-stats + uid: 5865230f-7e68-452c-90ae-c760fbd694d0 + resourceVersion: "94745" + uid: 404eb867-f01a-4a9a-9646-9008159d5408 +spec: + endpoints: + - honorLabels: true + interval: 10s + path: /metrics + port: metrics + namespaceSelector: + matchNames: + - demo + selector: + matchLabels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: zookeeper + app.kubernetes.io/managed-by: kubedb.com + app.kubernetes.io/name: zookeepers.kubedb.com + kubedb.com/role: stats +``` + +Notice that the `ServiceMonitor` has label `release: prometheus` that we had specified in ZooKeeper crd. + +Also notice that the `ServiceMonitor` has selector which match the labels we have seen in the `zookeeper-stats` service. It also, target the `metrics` port that we have seen in the stats service. + +## Verify Monitoring Metrics + +At first, let's find out the respective Prometheus pod for `prometheus` Prometheus server. + +```bash +$ kubectl get pod -n monitoring -l=app.kubernetes.io/name=prometheus +NAME READY STATUS RESTARTS AGE +prometheus-prometheus-kube-prometheus-prometheus-0 2/2 Running 1 22h +``` + +Prometheus server is listening to port `9090` of `prometheus-prometheus-kube-prometheus-prometheus-0` pod. We are going to use [port forwarding](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) to access Prometheus dashboard. + +Run following command on a separate terminal to forward the port 9090 of `prometheus-prometheus-kube-prometheus-prometheus-0` pod, + +```bash +$ kubectl port-forward -n monitoring prometheus-prometheus-kube-prometheus-prometheus-0 9090 +Forwarding from 127.0.0.1:9090 -> 9090 +Forwarding from [::1]:9090 -> 9090 +``` + +Now, we can access the dashboard at `localhost:9090`. Open [http://localhost:9090](http://localhost:9090) in your browser. You should see `metrics` endpoint of `zookeeper-stats` service as one of the targets. + +

+  Prometheus Target +

+ +Check the `endpoint` and `service` labels marked by the red rectangles. It verifies that the target is our expected database. Now, you can view the collected metrics and create a graph from homepage of this Prometheus dashboard. You can also use this Prometheus server as data source for [Grafana](https://grafana.com/) and create a beautiful dashboard with collected metrics. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run following commands + +```bash +kubectl delete -n demo zk/zookeeper +kubectl delete ns demo +``` + +## Next Steps + +- Monitor your ZooKeeper database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/zookeeper/monitoring/using-builtin-prometheus.md). +- Detail concepts of [ZooKeeper object](/docs/guides/zookeeper/concepts/zookeeper.md). +- Detail concepts of [ZooKeeperVersion object](/docs/guides/zookeeper/concepts/catalog.md). + +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/zookeeper/reconfigure-tls/_index.md b/docs/guides/zookeeper/reconfigure-tls/_index.md new file mode 100644 index 0000000000..5d3b1e62d4 --- /dev/null +++ b/docs/guides/zookeeper/reconfigure-tls/_index.md @@ -0,0 +1,10 @@ +--- +title: Reconfigure TLS/SSL +menu: + docs_{{ .version }}: + identifier: zk-reconfigure-tls + name: Reconfigure TLS/SSL + parent: zk-zookeeper-guides + weight: 46 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/zookeeper/reconfigure-tls/overview.md b/docs/guides/zookeeper/reconfigure-tls/overview.md new file mode 100644 index 0000000000..eefb9fc393 --- /dev/null +++ b/docs/guides/zookeeper/reconfigure-tls/overview.md @@ -0,0 +1,54 @@ +--- +title: Reconfiguring TLS/SSL +menu: + docs_{{ .version }}: + identifier: zk-reconfigure-tls-overview + name: Overview + parent: zk-reconfigure-tls + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfiguring TLS of ZooKeeper + +This guide will give an overview on how KubeDB Ops-manager operator reconfigures TLS configuration i.e. add TLS, remove TLS, update Issuer/Cluster Issuer or Certificates and rotate the Certificates of `ZooKeeper`. + +## Before You Begin + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + +## How Reconfiguring ZooKeeper TLS Configuration Process Works + +The following diagram shows how KubeDB Ops-manager operator reconfigures TLS of a `ZooKeeper`. Open the image in a new tab to see the enlarged version. + +
+  Reconfiguring TLS process of ZooKeeper +
Fig: Reconfiguring TLS process of ZooKeeper
+
+ +The Reconfiguring ZooKeeper TLS process consists of the following steps: + +1. At first, a user creates a `ZooKeeper` Custom Resource Object (CRO). + +2. `KubeDB` Provisioner operator watches the `ZooKeeper` CRO. + +3. When the operator finds a `ZooKeeper` CR, it creates required number of `PetSets` and related necessary stuff like secrets, services, etc. + +4. Then, in order to reconfigure the TLS configuration of the `ZooKeeper` database the user creates a `ZooKeeperOpsRequest` CR with desired information. + +5. `KubeDB` Ops-manager operator watches the `ZooKeeperOpsRequest` CR. + +6. When it finds a `ZooKeeperOpsRequest` CR, it pauses the `ZooKeeper` object which is referred from the `ZooKeeperOpsRequest`. So, the `KubeDB` Provisioner operator doesn't perform any operations on the `ZooKeeper` object during the reconfiguring TLS process. + +7. Then the `KubeDB` Ops-manager operator will add, remove, update or rotate TLS configuration based on the Ops Request yaml. + +8. Then the `KubeDB` Ops-manager operator will restart all the Pods of the database so that they restart with the new TLS configuration defined in the `ZooKeeperOpsRequest` CR. + +9. After the successful reconfiguring of the `ZooKeeper` TLS, the `KubeDB` Ops-manager operator resumes the `ZooKeeper` object so that the `KubeDB` Provisioner operator resumes its usual operations. + +In the [next](/docs/guides/zookeeper/reconfigure-tls/reconfigure-tls.md) docs, we are going to show a step by step guide on reconfiguring TLS configuration of a ZooKeeper database using `ZooKeeperOpsRequest` CRD. \ No newline at end of file diff --git a/docs/guides/zookeeper/reconfigure-tls/reconfigure-tls.md b/docs/guides/zookeeper/reconfigure-tls/reconfigure-tls.md new file mode 100644 index 0000000000..91351d3636 --- /dev/null +++ b/docs/guides/zookeeper/reconfigure-tls/reconfigure-tls.md @@ -0,0 +1,1014 @@ +--- +title: Reconfigure ZooKeeper TLS/SSL Encryption +menu: + docs_{{ .version }}: + identifier: zk-reconfigure-tls-zookeeper + name: Reconfigure ZooKeeper TLS/SSL Encryption + parent: zk-reconfigure-tls + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfigure ZooKeeper TLS/SSL (Transport Encryption) + +KubeDB supports reconfigure i.e. add, remove, update and rotation of TLS/SSL certificates for existing ZooKeeper database via a ZooKeeperOpsRequest. This tutorial will show you how to use KubeDB to reconfigure TLS/SSL encryption. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install [`cert-manger`](https://cert-manager.io/docs/installation/) v1.0.0 or later to your cluster to manage your SSL/TLS certificates. + +- Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + + ```bash + $ kubectl create ns demo + namespace/demo created + ``` + +> Note: YAML files used in this tutorial are stored in [docs/examples/zookeeper](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/zookeeper) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Add TLS to a ZooKeeper database + +Here, We are going to create a ZooKeeper without TLS and then reconfigure the database to use TLS. + +### Deploy ZooKeeper without TLS + +In this section, we are going to deploy a ZooKeeper ensemble without TLS. In the next few sections we will reconfigure TLS using `ZooKeeperOpsRequest` CRD. Below is the YAML of the `ZooKeeper` CR that we are going to create, + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" + +``` + +Let's create the `ZooKeeper` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zookeeper.yaml +zookeeper.kubedb.com/zk-quickstart created +``` + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ watch kubectl get zookeeper -n demo +NAME TYPE VERSION STATUS AGE +zk-quickstart kubedb.com/v1alpha2 3.8.3 Ready 60s +``` + +Now, we can exec one zookeeper broker pod and verify configuration that the TLS is disabled. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ cat ../conf/zoo.cfg +4lw.commands.whitelist=* +dataDir=/data +tickTime=2000 +initLimit=10 +syncLimit=2 +clientPort=2181 +globalOutstandingLimit=1000 +preAllocSize=65536 +snapCount=10000 +commitLogCount=500 +snapSizeLimitInKb=4194304 +maxCnxns=0 +maxClientCnxns=60 +minSessionTimeout=4000 +maxSessionTimeout=40000 +autopurge.snapRetainCount=3 +autopurge.purgeInterval=1 +quorumListenOnAllIPs=false +admin.serverPort=8080 +authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider +reconfigEnabled=true +standaloneEnabled=false +dynamicConfigFile=/data/zoo.cfg.dynamic +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ +``` + +We can verify from the above output that TLS is disabled for this Ensemble. + +### Create Issuer/ ClusterIssuer + +Now, We are going to create an example `Issuer` that will be used to enable SSL/TLS in ZooKeeper. Alternatively, you can follow this [cert-manager tutorial](https://cert-manager.io/docs/configuration/ca/) to create your own `Issuer`. + +- Start off by generating a ca certificates using openssl. + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=ca/O=kubedb" +Generating a RSA private key +................+++++ +........................+++++ +writing new private key to './ca.key' +----- +``` + +- Now we are going to create a ca-secret using the certificate files that we have just generated. + +```bash +$ kubectl create secret tls zookeeper-ca \ + --cert=ca.crt \ + --key=ca.key \ + --namespace=demo +secret/zookeeper-ca created +``` + +Now, Let's create an `Issuer` using the `zookeeper-ca` secret that we have just created. The `YAML` file looks like this: + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zk-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-ca +``` + +Let's apply the `YAML` file: + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zookeeper-issuer.yaml +issuer.cert-manager.io/zk-issuer created +``` + +### Create ZooKeeperOpsRequest + +In order to add TLS to the zookeeper, we have to create a `ZooKeeperOpsRequest` CRO with our created issuer. Below is the YAML of the `ZooKeeperOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-add-tls + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + issuerRef: + name: zookeeper-ca-issuer + kind: Issuer + apiGroup: "cert-manager.io" + certificates: + - alias: client + subject: + organizations: + - zookeeper + organizationalUnits: + - client + timeout: 5m + apply: IfReady +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing reconfigure TLS operation on `zk-quickstart` cluster. +- `spec.type` specifies that we are performing `ReconfigureTLS` on zookeeper. +- `spec.tls.issuerRef` specifies the issuer name, kind and api group. +- `spec.tls.certificates` specifies the certificates. You can learn more about this field from [here](/docs/guides/zookeeper/concepts/zookeeper.md#spectls). + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zookeeper-add-tls.yaml +zookeeperopsrequest.ops.kubedb.com/zkops-add-tls created +``` + +#### Verify TLS Enabled Successfully + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CRO, + +```bash +$ kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zkops-add-tls ReconfigureTLS Successful 4m36s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zkops-add-tls +Name: zkops-add-tls +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-11-04T05:46:18Z + Generation: 1 + Resource Version: 2118117 + UID: aa25e2b8-2583-4757-b3f7-b053fc21819f +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Tls: + Issuer Ref: + API Group: cert-manager.io + Kind: Issuer + Name: zookeeper-ca-issuer + Type: ReconfigureTLS +Status: + Conditions: + Last Transition Time: 2024-11-04T05:46:18Z + Message: ZooKeeper ops-request has started to reconfigure tls for zookeeper nodes + Observed Generation: 1 + Reason: ReconfigureTLS + Status: True + Type: ReconfigureTLS + Last Transition Time: 2024-11-04T05:46:31Z + Message: Successfully synced all certificates + Observed Generation: 1 + Reason: CertificateSynced + Status: True + Type: CertificateSynced + Last Transition Time: 2024-11-04T05:46:26Z + Message: get certificate; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetCertificate + Last Transition Time: 2024-11-04T05:46:26Z + Message: check ready condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: CheckReadyCondition + Last Transition Time: 2024-11-04T05:46:26Z + Message: issuing condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: IssuingCondition + Last Transition Time: 2024-11-04T05:46:36Z + Message: successfully reconciled the ZooKeeper with tls configuration + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-11-04T05:48:56Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-11-04T05:46:41Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T05:46:41Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T05:46:46Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-11-04T05:47:26Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T05:47:26Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T05:48:16Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T05:48:16Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T05:48:56Z + Message: Successfully completed reconfigureTLS for zookeeper. + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: +``` + +Now, Let's exec into a zookeeper ensemble pod and verify the configuration that the TLS is enabled. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ cat ../conf/zoo.cfg +4lw.commands.whitelist=* +dataDir=/data +tickTime=2000 +initLimit=10 +syncLimit=2 +clientPort=2181 +globalOutstandingLimit=1000 +preAllocSize=65536 +snapCount=10000 +commitLogCount=500 +snapSizeLimitInKb=4194304 +maxCnxns=0 +maxClientCnxns=60 +minSessionTimeout=4000 +maxSessionTimeout=40000 +autopurge.snapRetainCount=3 +autopurge.purgeInterval=1 +quorumListenOnAllIPs=false +admin.serverPort=8080 +authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider +reconfigEnabled=true +standaloneEnabled=false +dynamicConfigFile=/data/zoo.cfg.dynamic +secureClientPort=2182 +serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory +authProvider.x509=org.apache.zookeeper.server.auth.X509AuthenticationProvider +ssl.keyStore.location=/var/private/ssl/server.keystore.jks +ssl.keyStore.password=fdjk2dgffqn9 +ssl.trustStore.location=/var/private/ssl/server.truststore.jks +ssl.trustStore.password=fdjk2dgffqn9 +sslQuorum=true +ssl.quorum.keyStore.location=/var/private/ssl/server.keystore.jks +ssl.quorum.keyStore.password=fdjk2dgffqn9 +ssl.quorum.trustStore.location=/var/private/ssl/server.truststore.jks +ssl.quorum.trustStore.password=fdjk2dgffqn9 +ssl.quorum.hostnameVerification=false +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ +``` + +We can see from the above output that, keystore location is `/var/private/ssl/server.keystore.jks` which means that TLS is enabled. + +## Rotate Certificate + +Now we are going to rotate the certificate of this cluster. First let's check the current expiration date of the certificate. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ openssl x509 -in /var/private/ssl/tls.crt -inform PEM -enddate -nameopt RFC2253 -noout +notAfter=Feb 2 12:53:30 2025 GMT +``` + +So, the certificate will expire on this time `Feb 2 12:53:30 2025 GMT`. + +### Create ZooKeeperOpsRequest + +Now we are going to increase it using a ZooKeeperOpsRequest. Below is the yaml of the ops request that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-rotate + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + rotateCertificates: true +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing reconfigure TLS operation on `zk-quickstart`. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our cluster. +- `spec.tls.rotateCertificates` specifies that we want to rotate the certificate of this zookeeper cluster. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zkops-rotate.yaml +zookeeperopsrequest.ops.kubedb.com/zkops-rotate created +``` + +#### Verify Certificate Rotated Successfully + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CRO, + +```bash +$ kubectl get zookeeperopsrequests -n demo zkops-rotate +NAME TYPE STATUS AGE +zkops-rotate ReconfigureTLS Successful 4m4s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zkops-rotate +Name: zkops-rotate +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-11-04T13:10:03Z + Generation: 1 + Resource Version: 2153555 + UID: a1886cd3-784b-4523-936c-a510327d6129 +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Tls: + Rotate Certificates: true + Type: ReconfigureTLS +Status: + Conditions: + Last Transition Time: 2024-11-04T13:10:03Z + Message: ZooKeeper ops-request has started to reconfigure tls for zookeeper nodes + Observed Generation: 1 + Reason: ReconfigureTLS + Status: True + Type: ReconfigureTLS + Last Transition Time: 2024-11-04T13:10:16Z + Message: Successfully synced all certificates + Observed Generation: 1 + Reason: CertificateSynced + Status: True + Type: CertificateSynced + Last Transition Time: 2024-11-04T13:10:11Z + Message: get certificate; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetCertificate + Last Transition Time: 2024-11-04T13:10:11Z + Message: check ready condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: CheckReadyCondition + Last Transition Time: 2024-11-04T13:10:11Z + Message: issuing condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: IssuingCondition + Last Transition Time: 2024-11-04T13:10:22Z + Message: successfully reconciled the ZooKeeper with tls configuration + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-11-04T13:12:42Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-11-04T13:10:27Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:10:27Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:10:32Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-11-04T13:11:07Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:11:07Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:11:52Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:11:52Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:12:42Z + Message: Successfully completed reconfigureTLS for zookeeper. + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 2m57s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/zkops-rotate + Normal Starting 2m57s KubeDB Ops-manager Operator Pausing ZooKeeper database: demo/zk-quickstart + Normal Successful 2m57s KubeDB Ops-manager Operator Successfully paused ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zkops-rotate + Warning get certificate; ConditionStatus:True 2m49s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m49s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m49s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Warning get certificate; ConditionStatus:True 2m49s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m49s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m49s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Normal CertificateSynced 2m49s KubeDB Ops-manager Operator Successfully synced all certificates + Warning get certificate; ConditionStatus:True 2m44s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m44s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m44s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Warning get certificate; ConditionStatus:True 2m44s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m44s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m44s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Normal CertificateSynced 2m44s KubeDB Ops-manager Operator Successfully synced all certificates + Normal UpdatePetSets 2m38s KubeDB Ops-manager Operator successfully reconciled the ZooKeeper with tls configuration + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-0 2m33s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-0 2m33s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning running pod; ConditionStatus:False 2m28s KubeDB Ops-manager Operator running pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-1 113s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-1 113s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-2 68s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-2 68s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Normal RestartNodes 18s KubeDB Ops-manager Operator Successfully restarted all nodes + Normal Starting 18s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 18s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zkops-rotate +``` + +Now, let's check the expiration date of the certificate. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ openssl x509 -in /var/private/ssl/tls.crt -inform PEM -enddate -nameopt RFC2253 -noout +notAfter=Feb 2 13:12:42 2025 GMT +``` + +As we can see from the above output, the certificate has been rotated successfully. + +## Change Issuer/ClusterIssuer + +Now, we are going to change the issuer of this database. + +- Let's create a new ca certificate and key using a different subject `CN=ca-update,O=kubedb-updated`. + +```bash +$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=ca-updated/O=kubedb-updated" +Generating a RSA private key +..............................................................+++++ +......................................................................................+++++ +writing new private key to './ca.key' +----- +``` + +- Now we are going to create a new ca-secret using the certificate files that we have just generated. + +```bash +$ kubectl create secret tls zookeeper-new-ca \ + --cert=ca.crt \ + --key=ca.key \ + --namespace=demo +secret/zookeeper-new-ca created +``` + +Now, Let's create a new `Issuer` using the `mongo-new-ca` secret that we have just created. The `YAML` file looks like this: + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zk-new-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-new-ca +``` + +Let's apply the `YAML` file: + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zookeeper-new-issuer.yaml +issuer.cert-manager.io/zk-new-issuer created +``` + +### Create ZooKeeperOpsRequest + +In order to use the new issuer to issue new certificates, we have to create a `ZooKeeperOpsRequest` CRO with the newly created issuer. Below is the YAML of the `ZooKeeperOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-update-issuer + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + issuerRef: + name: zk-new-issuer + kind: Issuer + apiGroup: "cert-manager.io" +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing reconfigure TLS operation on `zk-quickstart` cluster. +- `spec.type` specifies that we are performing `ReconfigureTLS` on our zookeeper. +- `spec.tls.issuerRef` specifies the issuer name, kind and api group. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zookeeper-update-tls-issuer.yaml +zookeeperpsrequest.ops.kubedb.com/zkops-update-issuer created +``` + +#### Verify Issuer is changed successfully + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CRO, + +```bash +$ kubectl get zookeeperopsrequests -n demo zkops-update-issuer +NAME TYPE STATUS AGE +zkops-update-issuer ReconfigureTLS Successful 8m6s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zkops-update-issuer +Name: zkops-update-issuer +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-11-04T13:27:25Z + Generation: 1 + Resource Version: 2155331 + UID: 399cae54-a6ab-4848-93ff-5dba09a128d7 +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Tls: + Issuer Ref: + API Group: cert-manager.io + Kind: Issuer + Name: zk-new-issuer + Type: ReconfigureTLS +Status: + Conditions: + Last Transition Time: 2024-11-04T13:27:25Z + Message: ZooKeeper ops-request has started to reconfigure tls for zookeeper nodes + Observed Generation: 1 + Reason: ReconfigureTLS + Status: True + Type: ReconfigureTLS + Last Transition Time: 2024-11-04T13:27:35Z + Message: Successfully synced all certificates + Observed Generation: 1 + Reason: CertificateSynced + Status: True + Type: CertificateSynced + Last Transition Time: 2024-11-04T13:27:30Z + Message: get certificate; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetCertificate + Last Transition Time: 2024-11-04T13:27:30Z + Message: check ready condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: CheckReadyCondition + Last Transition Time: 2024-11-04T13:27:30Z + Message: issuing condition; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: IssuingCondition + Last Transition Time: 2024-11-04T13:27:40Z + Message: successfully reconciled the ZooKeeper with tls configuration + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-11-04T13:30:00Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-11-04T13:27:45Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:27:45Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:27:50Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-11-04T13:28:30Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:28:30Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:29:20Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:29:20Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:30:00Z + Message: Successfully completed reconfigureTLS for zookeeper. + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 2m53s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/zkops-update-issuer + Warning get certificate; ConditionStatus:True 2m48s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m48s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m48s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Warning get certificate; ConditionStatus:True 2m48s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m48s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m48s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Normal CertificateSynced 2m48s KubeDB Ops-manager Operator Successfully synced all certificates + Warning get certificate; ConditionStatus:True 2m43s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m43s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m43s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Warning get certificate; ConditionStatus:True 2m43s KubeDB Ops-manager Operator get certificate; ConditionStatus:True + Warning check ready condition; ConditionStatus:True 2m43s KubeDB Ops-manager Operator check ready condition; ConditionStatus:True + Warning issuing condition; ConditionStatus:True 2m43s KubeDB Ops-manager Operator issuing condition; ConditionStatus:True + Normal CertificateSynced 2m43s KubeDB Ops-manager Operator Successfully synced all certificates + Normal UpdatePetSets 2m38s KubeDB Ops-manager Operator successfully reconciled the ZooKeeper with tls configuration + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-0 2m33s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-0 2m33s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning running pod; ConditionStatus:False 2m28s KubeDB Ops-manager Operator running pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-1 108s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-1 108s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-2 58s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-2 58s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Normal RestartNodes 18s KubeDB Ops-manager Operator Successfully restarted all nodes + Normal Starting 18s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 18s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zkops-update-issuer +``` + +Now, Let's exec into a zookeeper node and find out the ca subject to see if it matches the one we have provided. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ keytool -list -v -keystore /var/private/ssl/server.keystore.jks -storepass fdjk2dgffqn9 | grep 'Issuer' +Issuer: O=kubedb-updated, CN=ca-updated +Issuer: O=kubedb-updated, CN=ca-updated +``` + +We can see from the above output that, the subject name matches the subject name of the new ca certificate that we have created. So, the issuer is changed successfully. + +## Remove TLS from the Database + +Now, we are going to remove TLS from this database using a ZooKeeperOpsRequest. + +### Create ZooKeeperOpsRequest + +Below is the YAML of the `ZooKeeperOpsRequest` CRO that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zkops-remove + namespace: demo +spec: + type: ReconfigureTLS + databaseRef: + name: zk-quickstart + tls: + remove: true +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing reconfigure TLS operation on `zk-quickstart` cluster. +- `spec.type` specifies that we are performing `ReconfigureTLS` on ZooKeeper. +- `spec.tls.remove` specifies that we want to remove tls from this cluster. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfigure-tls/zkops-remove.yaml +zookeeperopsrequest.ops.kubedb.com/zkops-remove created +``` + +#### Verify TLS Removed Successfully + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CRO, + +```bash +$ kubectl get zookeeperopsrequest -n demo zkops-remove +NAME TYPE STATUS AGE +zkops-remove ReconfigureTLS Successful 105s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zkops-remove +Name: zkops-remove +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-11-04T13:39:19Z + Generation: 1 + Resource Version: 2156556 + UID: 8f669fe1-169f-4446-9d12-bf959216e2e0 +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Tls: + Remove: true + Type: ReconfigureTLS +Status: + Conditions: + Last Transition Time: 2024-11-04T13:39:19Z + Message: ZooKeeper ops-request has started to reconfigure tls for zookeeper nodes + Observed Generation: 1 + Reason: ReconfigureTLS + Status: True + Type: ReconfigureTLS + Last Transition Time: 2024-11-04T13:39:27Z + Message: successfully reconciled the ZooKeeper with tls configuration + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-11-04T13:41:42Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-11-04T13:39:32Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:39:32Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-11-04T13:39:37Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-11-04T13:40:22Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:40:22Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-11-04T13:41:02Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:41:02Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-11-04T13:41:42Z + Message: Successfully completed reconfigureTLS for zookeeper. + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 2m26s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/zkops-remove + Normal Starting 2m26s KubeDB Ops-manager Operator Pausing ZooKeeper database: demo/zk-quickstart + Normal Successful 2m26s KubeDB Ops-manager Operator Successfully paused ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zkops-remove + Normal UpdatePetSets 2m18s KubeDB Ops-manager Operator successfully reconciled the ZooKeeper with tls configuration + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-0 2m13s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-0 2m13s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning running pod; ConditionStatus:False 2m8s KubeDB Ops-manager Operator running pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-1 83s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-1 83s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-2 43s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-2 43s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Normal RestartNodes 3s KubeDB Ops-manager Operator Successfully restarted all nodes + Normal Starting 3s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 3s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zkops-remove +``` + +Now, Let's exec into one of the broker node and find out that TLS is disabled or not. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ cat ../conf/zoo.cfg +4lw.commands.whitelist=* +dataDir=/data +tickTime=2000 +initLimit=10 +syncLimit=2 +clientPort=2181 +globalOutstandingLimit=1000 +preAllocSize=65536 +snapCount=10000 +commitLogCount=500 +snapSizeLimitInKb=4194304 +maxCnxns=0 +maxClientCnxns=60 +minSessionTimeout=4000 +maxSessionTimeout=40000 +autopurge.snapRetainCount=3 +autopurge.purgeInterval=1 +quorumListenOnAllIPs=false +admin.serverPort=8080 +authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider +reconfigEnabled=true +standaloneEnabled=false +dynamicConfigFile=/data/zoo.cfg.dynamic +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ +``` + +So, we can see from the above that, output that tls is disabled successfully. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete opsrequest zkops-add-tls zkops-remove zkops-rotate zkops-update-issuer +kubectl delete zookeeper -n demo zk-quickstart +kubectl delete issuer -n demo zk-issuer zk-new-issuer +kubectl delete ns demo +``` + +## Next Steps + +- Detail concepts of [ZooKeeper object](/docs/guides/zookeeper/concepts/zookeeper.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/zookeeper/reconfigure/_index.md b/docs/guides/zookeeper/reconfigure/_index.md new file mode 100644 index 0000000000..1fcfbf6768 --- /dev/null +++ b/docs/guides/zookeeper/reconfigure/_index.md @@ -0,0 +1,10 @@ +--- +title: Reconfigure +menu: + docs_{{ .version }}: + identifier: zk-reconfigure + name: Reconfigure + parent: zk-zookeeper-guides + weight: 80 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/zookeeper/reconfigure/overview.md b/docs/guides/zookeeper/reconfigure/overview.md new file mode 100644 index 0000000000..36f508cc1f --- /dev/null +++ b/docs/guides/zookeeper/reconfigure/overview.md @@ -0,0 +1,54 @@ +--- +title: Reconfiguring ZooKeeper +menu: + docs_{{ .version }}: + identifier: zk-reconfigure-overview + name: Overview + parent: zk-reconfigure + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfiguring ZooKeeper + +This guide will give an overview on how KubeDB Ops-manager operator reconfigures `ZooKeeper` cluster. + +## Before You Begin + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + +## How does Reconfiguring ZooKeeper Process Works + +The following diagram shows how KubeDB Ops-manager operator reconfigures `ZooKeeper` database components. Open the image in a new tab to see the enlarged version. + +
+  Reconfiguring process of ZooKeeper +
Fig: Reconfiguring process of ZooKeeper
+
+ +The Reconfiguring ZooKeeper process consists of the following steps: + +1. At first, a user creates a `ZooKeeper` Custom Resource (CR). + +2. `KubeDB` Provisioner operator watches the `ZooKeeper` CR. + +3. When the operator finds a `ZooKeeper` CR, it creates required number of `Petsets` and related necessary stuff like secrets, services, etc. + +4. Then, in order to reconfigure the `ZooKeeper` database the user creates a `ZooKeeperOpsRequest` CR with desired information. + +5. `KubeDB` Ops-manager operator watches the `ZooKeeperOpsRequest` CR. + +6. When it finds a `ZooKeeperOpsRequest` CR, it halts the `ZooKeeper` object which is referred from the `ZooKeeperOpsRequest`. So, the `KubeDB` Provisioner operator doesn't perform any operations on the `ZooKeeper` object during the reconfiguring process. + +7. Then the `KubeDB` Ops-manager operator will replace the existing configuration with the new configuration provided or merge the new configuration with the existing configuration according to the `ZooKeeperOpsRequest` CR. + +8. Then the `KubeDB` Ops-manager operator will restart the related Petset Pods so that they restart with the new configuration defined in the `ZooKeeperOpsRequest` CR. + +9. After the successful reconfiguring of the `ZooKeeper` components, the `KubeDB` Ops-manager operator resumes the `ZooKeeper` object so that the `KubeDB` Provisioner operator resumes its usual operations. + +In the [next](/docs/guides/zookeeper/reconfigure/reconfigure.md) docs, we are going to show a step by step guide on reconfiguring ZooKeeper database components using `ZooKeeperOpsRequest` CRD. \ No newline at end of file diff --git a/docs/guides/zookeeper/reconfigure/reconfigure.md b/docs/guides/zookeeper/reconfigure/reconfigure.md new file mode 100644 index 0000000000..c108938793 --- /dev/null +++ b/docs/guides/zookeeper/reconfigure/reconfigure.md @@ -0,0 +1,529 @@ +--- +title: Reconfigure ZooKeeper Ensemble +menu: + docs_{{ .version }}: + identifier: zk-ensemble-reconfigure + name: Reconfigure Configurations + parent: zk-reconfigure + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Reconfigure ZooKeeper Ensemble + +This guide will show you how to use `KubeDB` Ops-manager operator to reconfigure a ZooKeeper ensemble. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. + +- Install `KubeDB` Provisioner and Ops-manager operator in your cluster following the steps [here](/docs/setup/README.md). + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + - [Reconfigure Overview](/docs/guides/zookeeper/reconfigure/overview.md) + +To keep everything isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> **Note:** YAML files used in this tutorial are stored in [examples](/docs/examples/zookeeper) directory of [kubedb/docs](https://github.com/kubedb/docs) repository. + +Now, we are going to deploy a `ZooKeeper` cluster using a supported version by `KubeDB` operator. Then we are going to apply `ZooKeeperOpsRequest` to reconfigure its configuration. + +### Prepare ZooKeeper Ensemble + +Now, we are going to deploy a `ZooKeeper` cluster with version `3.8.3`. + +### Deploy ZooKeeper Ensemble + +At first, we will create `secret` named zk-configuration containing required configuration settings. + +```yaml +apiVersion: v1 +stringData: + zoo.cfg: | + maxClientCnxns=70 +kind: Secret +metadata: + name: zk-configuration + namespace: demo +``` +Here, `maxClientCnxns` is set to `70`, whereas the default value is `60`. + +Now, we will apply the secret with custom configuration. +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfiguration/secret.yaml +secret/zk-configuration created +``` + +In this section, we are going to create a ZooKeeper object specifying `spec.configSecret` field to apply this custom configuration. Below is the YAML of the `ZooKeeper` CR that we are going to create, + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + configSecret: + name: zk-configuration + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" +``` + +Let's create the `ZooKeeper` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfiguration/sample-zk-configuration.yaml +zookeeper.kubedb.com/zk-quickstart created +``` + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 23s +``` + +Now, we will check if the database has started with the custom configuration we have provided. + +Now, you can exec into the zookeeper pod and find if the custom configuration is there, + +```bash +$ Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ echo conf | nc localhost 2181 +clientPort=2181 +secureClientPort=-1 +dataDir=/data/version-2 +dataDirSize=134218330 +dataLogDir=/data/version-2 +dataLogSize=134218330 +tickTime=2000 +maxClientCnxns=70 +minSessionTimeout=4000 +maxSessionTimeout=40000 +clientPortListenBacklog=-1 +serverId=1 +initLimit=10 +syncLimit=2 +electionAlg=3 +electionPort=3888 +quorumPort=2888 +peerType=0 +membership: +server.1=zk-quickstart-0.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.2=zk-quickstart-1.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.3=zk-quickstart-2.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +version=100000011zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ exit +exit +``` + +As we can see from the configuration of running zookeeper, the value of `maxClientCnxns` has been set to `70`. + +### Reconfigure using new secret + +Now we will reconfigure this database to set `maxClientCnxns` to `100`. + +At first, we will create `secret` named new-configuration containing required configuration settings. + +```yaml +apiVersion: v1 +stringData: + zoo.cfg: | + maxClientCnxns=100 +kind: Secret +metadata: + name: zk-new-configuration + namespace: demo +``` +Here, `maxClientCnxns` is set to `100`. + +Now, we will apply the secret with custom configuration. +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfiguration/new-secret.yaml +secret/zk-new-configuration created +``` + +#### Create ZooKeeperOpsRequest + +Now, we will use this secret to replace the previous secret using a `ZooKeeperOpsRequest` CR. The `ZooKeeperOpsRequest` yaml is given below, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-reconfig + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: zk-quickstart + configuration: + configSecret: + name: zk-new-configuration +``` + +Here, + +- `spec.databaseRef.name` specifies that we are reconfiguring `zk-quickstart` database. +- `spec.type` specifies that we are performing `Reconfigure` on our database. +- `spec.configuration.configSecret.name` specifies the name of the new secret. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfiguration/zkops-reconfiguration.yaml +zookeeperopsrequest.ops.kubedb.com/zk-reconfig created +``` + +#### Verify the new configuration is working + +If everything goes well, `KubeDB` Ops-manager operator will update the `configSecret` of `ZooKeeper` object. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ watch kubectl get zookeeperopsrequest -n demo +Every 2.0s: kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zk-reconfig Reconfigure Successful 1m +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to reconfigure the database. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zk-reconfig +Name: zk-reconfig +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-30T08:27:00Z + Generation: 1 + Resource Version: 1548116 + UID: 4f3daa11-c41b-4079-a8d8-1040931284ef +Spec: + Apply: IfReady + Configuration: + Config Secret: + Name: zk-new-configuration + Database Ref: + Name: zk-quickstart + Type: Reconfigure +Status: + Conditions: + Last Transition Time: 2024-10-30T08:27:00Z + Message: ZooKeeper ops-request has started to reconfigure ZooKeeper nodes + Observed Generation: 1 + Reason: Reconfigure + Status: True + Type: Reconfigure + Last Transition Time: 2024-10-30T08:27:08Z + Message: successfully reconciled the ZooKeeper with new configure + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-10-30T08:29:18Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-10-30T08:27:13Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-10-30T08:27:13Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-10-30T08:27:18Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-10-30T08:27:58Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-10-30T08:27:58Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-10-30T08:28:38Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-10-30T08:28:38Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-10-30T08:29:18Z + Message: Successfully completed reconfigure ZooKeeper + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: +``` + +Now need to check the new configuration we have provided. + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 20s +``` + +Now let’s exec into the zookeeper pod and check the new configuration we have provided. + +```bash +$ Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ echo conf | nc localhost 2181 +clientPort=2181 +secureClientPort=-1 +dataDir=/data/version-2 +dataDirSize=134218330 +dataLogDir=/data/version-2 +dataLogSize=134218330 +tickTime=2000 +maxClientCnxns=100 +minSessionTimeout=4000 +maxSessionTimeout=40000 +clientPortListenBacklog=-1 +serverId=1 +initLimit=10 +syncLimit=2 +electionAlg=3 +electionPort=3888 +quorumPort=2888 +peerType=0 +membership: +server.1=zk-quickstart-0.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.2=zk-quickstart-1.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.3=zk-quickstart-2.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +version=100000011zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ exit +exit +``` + +As we can see from the configuration of running zookeeper, the value of `maxClientCnxns` has been changed from `70` to `100`. So the reconfiguration of the zookeeper is successful. + +### Reconfigure using apply config + +Now we will reconfigure this database again to set `maxClientCnxns` to `90`. This time we won't use a new secret. We will use the `applyConfig` field of the `ZooKeeperOpsRequest`. This will merge the new config in the existing secret. + +#### Create ZooKeeperOpsRequest + +Now, we will use the new configuration in the `data` field in the `ZooKeeperOpsRequest` CR. The `ZooKeeperOpsRequest` yaml is given below, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-reconfig-apply + namespace: demo +spec: + type: Reconfigure + databaseRef: + name: zk-quickstart + configuration: + applyConfig: + zoo.cfg: | + maxClientCnxns=90 +``` + +Here, + +- `spec.databaseRef.name` specifies that we are reconfiguring `zk-quickstart` database. +- `spec.type` specifies that we are performing `Reconfigure` on our database. +- `spec.configuration.applyConfig` specifies the new configuration that will be merged in the existing secret. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/reconfiguration/zkops-apply-reconfiguration.yaml +zookeeperopsrequest.ops.kubedb.com/zk-reconfig-apply created +``` + +#### Verify the new configuration is working + +If everything goes well, `KubeDB` Ops-manager operator will merge this new config with the existing configuration. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ watch kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zk-reconfig-apply Reconfigure Successful 38s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to reconfigure the database. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zk-reconfig-apply +Name: zk-reconfig-apply +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-30T08:27:00Z + Generation: 1 + Resource Version: 1548116 + UID: 4f3daa11-c41b-4079-a8d8-1040931284ef +Spec: + Apply: IfReady + Configuration: + Config Secret: + Name: zk-new-configuration + Database Ref: + Name: zk-quickstart + Type: Reconfigure +Status: + Conditions: + Last Transition Time: 2024-10-30T08:27:00Z + Message: ZooKeeper ops-request has started to reconfigure ZooKeeper nodes + Observed Generation: 1 + Reason: Reconfigure + Status: True + Type: Reconfigure + Last Transition Time: 2024-10-30T08:27:08Z + Message: successfully reconciled the ZooKeeper with new configure + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-10-30T08:29:18Z + Message: Successfully restarted all nodes + Observed Generation: 1 + Reason: RestartNodes + Status: True + Type: RestartNodes + Last Transition Time: 2024-10-30T08:27:13Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-10-30T08:27:13Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-10-30T08:27:18Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-10-30T08:27:58Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-10-30T08:27:58Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-10-30T08:28:38Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-10-30T08:28:38Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Last Transition Time: 2024-10-30T08:29:18Z + Message: Successfully completed reconfigure ZooKeeper + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: +``` + +Now need to check the new configuration we have provided. + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 20s +``` + +Now let’s exec into the zookeeper pod and check the new configuration we have provided. + +```bash +$ Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ echo conf | nc localhost 2181 +clientPort=2181 +secureClientPort=-1 +dataDir=/data/version-2 +dataDirSize=134218330 +dataLogDir=/data/version-2 +dataLogSize=134218330 +tickTime=2000 +maxClientCnxns=90 +minSessionTimeout=4000 +maxSessionTimeout=40000 +clientPortListenBacklog=-1 +serverId=1 +initLimit=10 +syncLimit=2 +electionAlg=3 +electionPort=3888 +quorumPort=2888 +peerType=0 +membership: +server.1=zk-quickstart-0.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.2=zk-quickstart-1.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +server.3=zk-quickstart-2.zk-quickstart-pods.demo.svc.cluster.local:2888:3888:participant;0.0.0.0:2181 +version=100000011zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ exit +exit +``` + +As we can see from the configuration of running zookeeper, the value of `maxClientCnxns` has been changed from `100` to `90`. So, the reconfiguration of the database using the `applyConfig` field is successful. + +## Cleaning Up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete zk -n demo zk-quickstart +kubectl delete zookeeperopsrequest -n demo zk-reconfig zk-reconfig-apply +``` \ No newline at end of file diff --git a/docs/guides/zookeeper/restart/restart.md b/docs/guides/zookeeper/restart/restart.md index 387b837774..583f8b0de2 100644 --- a/docs/guides/zookeeper/restart/restart.md +++ b/docs/guides/zookeeper/restart/restart.md @@ -201,6 +201,5 @@ kubectl delete ns demo ## Next Steps -- Detail concepts of [ZooKeeper object](/docs/guides/zookeeper/concepts/zookeeper.md). - Detail concepts of [ZooKeeper object](/docs/guides/zookeeper/concepts/zookeeper.md). - Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/zookeeper/scaling/_index.md b/docs/guides/zookeeper/scaling/_index.md new file mode 100644 index 0000000000..4e80b1d73f --- /dev/null +++ b/docs/guides/zookeeper/scaling/_index.md @@ -0,0 +1,10 @@ +--- +title: Scaling ZooKeeper +menu: + docs_{{ .version }}: + identifier: zk-scaling + name: Scaling + parent: zk-zookeeper-guides + weight: 60 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/horizontal-scaling/_index.md b/docs/guides/zookeeper/scaling/horizontal-scaling/_index.md new file mode 100644 index 0000000000..edc4bdfa96 --- /dev/null +++ b/docs/guides/zookeeper/scaling/horizontal-scaling/_index.md @@ -0,0 +1,10 @@ +--- +title: Horizontal Scaling +menu: + docs_{{ .version }}: + identifier: zk-horizontal-scaling + name: Horizontal Scaling + parent: zk-scaling + weight: 10 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/horizontal-scaling/horizontal-scaling.md b/docs/guides/zookeeper/scaling/horizontal-scaling/horizontal-scaling.md new file mode 100644 index 0000000000..1caa212db8 --- /dev/null +++ b/docs/guides/zookeeper/scaling/horizontal-scaling/horizontal-scaling.md @@ -0,0 +1,419 @@ +--- +title: Horizontal Scaling ZooKeeper +menu: + docs_{{ .version }}: + identifier: zk-horizontal-scaling-ops + name: Scale Horizontally + parent: zk-horizontal-scaling + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Horizontal Scale ZooKeeper + +This guide will show you how to use `KubeDB` Ops-manager operator to scale the ZooKeeper Cluster. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install `KubeDB` Provisioner and Ops-manager operator in your cluster following the steps [here](/docs/setup/README.md). + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + - [Horizontal Scaling Overview](/docs/guides/zookeeper/scaling/horizontal-scaling/overview.md) + +To keep everything isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> **Note:** YAML files used in this tutorial are stored in [docs/examples/zookeeper](/docs/examples/zookeeper) directory of [kubedb/docs](https://github.com/kubedb/docs) repository. + +## Apply Horizontal Scaling on zookeeper + +Here, we are going to deploy a `ZooKeeper` using a supported version by `KubeDB` operator. Then we are going to apply horizontal scaling on it. + +### Deploy ZooKeeper + +In this section, we are going to deploy a ZooKeeper. We are going to deploy a `ZooKeeper` with version `3.8.3`. Then, in the next section we will scale the zookeeper using `ZooKeeperOpsRequest` CRD. Below is the YAML of the `ZooKeeper` CR that we are going to create, + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + storageClassName: "standard" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" +``` +Let's create the `ZooKeeper` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/scaling/zookeeper.yaml +zookeeper.kubedb.com/zk-quickstart created +``` + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 5m56s +``` + +Let's check the number of replicas this zookeeper has from the ZooKeeper object, number of pods the PetSet have, + +```bash +$ kubectl get zookeeper -n demo zk-quickstart -o json | jq '.spec.replicas' +3 + +$ kubectl get petset -n demo zk-quickstart -o json | jq '.spec.replicas' +3 +``` + +We can see from both command that the zookeeper has 3 replicas. + +We are now ready to apply the `ZooKeeperOpsRequest` CR to scale this zookeeper. + +## Scale Up Replicas + +Here, we are going to scale up the replicas of the zookeeper to meet the desired number of replicas after scaling. + +#### Create ZooKeeperOpsRequest + +In order to scale up the replicas of the zookeeper, we have to create a `ZooKeeperOpsRequest` CR with our desired replicas. Below is the YAML of the `ZooKeeperOpsRequest` CR that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zookeeper-horizontal-scale-up + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: zk-quickstart + horizontalScaling: + replicas: 5 +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing horizontal scaling operation on `zk-quickstart` zookeeper. +- `spec.type` specifies that we are performing `HorizontalScaling` on our zookeeper. +- `spec.horizontalScaling.replicas` specifies the desired replicas after scaling. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/scaling/horizontal-scaling/zk-hscale-up-ops.yaml +zookeeperopsrequest.ops.kubedb.com/zookeeper-horizontal-scale-up created +``` + +#### Verify replicas scaled up successfully + +If everything goes well, `KubeDB` Ops-manager operator will update the replicas of `ZooKeeper` object and related `PetSet`. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ watch kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zookeeper-horizontal-scale-up HorizontalScaling Successful 2m49s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to scale the zookeeper. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zookeeper-horizontal-scale-up +Name: zookeeper-horizontal-scale-up +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-25T13:37:43Z + Generation: 1 + Resource Version: 1198117 + UID: bfa6fb3f-5eb2-456c-8a3e-7a59097add0a +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Horizontal Scaling: + Replicas: 5 + Type: HorizontalScaling +Status: + Conditions: + Last Transition Time: 2024-10-25T13:37:43Z + Message: ZooKeeper ops-request has started to horizontally scaling the nodes + Observed Generation: 1 + Reason: HorizontalScaling + Status: True + Type: HorizontalScaling + Last Transition Time: 2024-10-25T13:38:03Z + Message: Successfully Scaled Up Node + Observed Generation: 1 + Reason: HorizontalScaleUp + Status: True + Type: HorizontalScaleUp + Last Transition Time: 2024-10-25T13:37:48Z + Message: patch petset; ConditionStatus:True; PodName:zk-quickstart-4 + Observed Generation: 1 + Status: True + Type: PatchPetset--zk-quickstart-4 + Last Transition Time: 2024-10-25T13:37:48Z + Message: zk-quickstart already has desired replicas + Observed Generation: 1 + Reason: HorizontalScale + Status: True + Type: HorizontalScale + Last Transition Time: 2024-10-25T13:37:58Z + Message: is pod ready; ConditionStatus:True; PodName:zk-quickstart-4 + Observed Generation: 1 + Status: True + Type: IsPodReady--zk-quickstart-4 + Last Transition Time: 2024-10-25T13:37:58Z + Message: is node healthy; ConditionStatus:True; PodName:zk-quickstart-4 + Observed Generation: 1 + Status: True + Type: IsNodeHealthy--zk-quickstart-4 + Last Transition Time: 2024-10-25T13:38:03Z + Message: Successfully updated ZooKeeper + Observed Generation: 1 + Reason: UpdateDatabase + Status: True + Type: UpdateDatabase + Last Transition Time: 2024-10-25T13:38:03Z + Message: Successfully completed the HorizontalScaling for FerretDB + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 47s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/horizontal-scale-up + Warning patch petset; ConditionStatus:True; PodName:zk-quickstart-4 42s KubeDB Ops-manager Operator patch petset; ConditionStatus:True; PodName:zk-quickstart-4 + Warning is pod ready; ConditionStatus:False; PodName:zk-quickstart-4 37s KubeDB Ops-manager Operator is pod ready; ConditionStatus:False; PodName:zk-quickstart-4 + Warning is pod ready; ConditionStatus:True; PodName:zk-quickstart-4 32s KubeDB Ops-manager Operator is pod ready; ConditionStatus:True; PodName:zk-quickstart-4 + Warning is node healthy; ConditionStatus:True; PodName:zk-quickstart-4 32s KubeDB Ops-manager Operator is node healthy; ConditionStatus:True; PodName:zk-quickstart-4 + Normal HorizontalScaleUp 27s KubeDB Ops-manager Operator Successfully Scaled Up Node + Normal UpdateDatabase 27s KubeDB Ops-manager Operator Successfully updated ZooKeeper + Normal Starting 27s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 27s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: horizontal-scale-up +``` + +Now, we are going to verify the number of replicas this zookeeper has from the Pgpool object, number of pods the PetSet have, + +```bash +$ kubectl get zookeeper -n demo zk-quickstart -o json | jq '.spec.replicas' +5 + +$ kubectl get petset -n demo zk-quickstart -o json | jq '.spec.replicas' +5 +``` +From all the above outputs we can see that the replicas of the zookeeper is `5`. That means we have successfully scaled up the replicas of the ZooKeeper. + + +### Scale Down Replicas + +Here, we are going to scale down the replicas of the zookeeper to meet the desired number of replicas after scaling. + +#### Create ZooKeeperOpsRequest + +In order to scale down the replicas of the zookeeper, we have to create a `ZooKeeperOpsRequest` CR with our desired replicas. Below is the YAML of the `ZooKeeperOpsRequest` CR that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zookeeper-horizontal-scale-down + namespace: demo +spec: + type: HorizontalScaling + databaseRef: + name: zk-quickstart + horizontalScaling: + replicas: 3 + +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing horizontal scaling down operation on `zookeeper` zookeeper. +- `spec.type` specifies that we are performing `HorizontalScaling` on our zookeeper. +- `spec.horizontalScaling.replicas` specifies the desired replicas after scaling. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/scaling/horizontal-scaling/zk-hscale-down-ops.yaml +zookeeperopsrequest.ops.kubedb.com/zookeeper-horizontal-scale-down created +``` + +#### Verify replicas scaled down successfully + +If everything goes well, `KubeDB` Ops-manager operator will update the replicas of `ZooKeeper` object and related `PetSet`. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ watch kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zookeeper-horizontal-scale-down HorizontalScaling Successful 75s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to scale the zookeeper. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zookeeper-horizontal-scale-down +Name: zookeeper-horizontal-scale-down +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-25T13:58:45Z + Generation: 1 + Resource Version: 1199568 + UID: 18b2adbb-9fbd-44fe-a265-e7eb4a292798 +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Horizontal Scaling: + Replicas: 3 + Type: HorizontalScaling +Status: + Conditions: + Last Transition Time: 2024-10-25T13:58:45Z + Message: ZooKeeper ops-request has started to horizontally scaling the nodes + Observed Generation: 1 + Reason: HorizontalScaling + Status: True + Type: HorizontalScaling + Last Transition Time: 2024-10-25T14:00:23Z + Message: Successfully Scaled Down Node + Observed Generation: 1 + Reason: HorizontalScaleDown + Status: True + Type: HorizontalScaleDown + Last Transition Time: 2024-10-25T13:58:53Z + Message: patch petset; ConditionStatus:True; PodName:zk-quickstart-4 + Observed Generation: 1 + Status: True + Type: PatchPetset--zk-quickstart-4 + Last Transition Time: 2024-10-25T13:58:58Z + Message: get pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: GetPod + Last Transition Time: 2024-10-25T13:59:28Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-4 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-4 + Last Transition Time: 2024-10-25T13:59:28Z + Message: delete pvc; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: DeletePvc + Last Transition Time: 2024-10-25T13:59:38Z + Message: patch petset; ConditionStatus:True; PodName:zk-quickstart-3 + Observed Generation: 1 + Status: True + Type: PatchPetset--zk-quickstart-3 + Last Transition Time: 2024-10-25T13:59:38Z + Message: zk-quickstart already has desired replicas + Observed Generation: 1 + Reason: HorizontalScale + Status: True + Type: HorizontalScale + Last Transition Time: 2024-10-25T14:00:13Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-3 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-3 + Last Transition Time: 2024-10-25T14:00:23Z + Message: Successfully updated ZooKeeper + Observed Generation: 1 + Reason: UpdateDatabase + Status: True + Type: UpdateDatabase + Last Transition Time: 2024-10-25T14:00:23Z + Message: Successfully completed the HorizontalScaling for FerretDB + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 3m27s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/horizontal-scale-down + Normal Starting 3m27s KubeDB Ops-manager Operator Pausing ZooKeeper database: demo/zk-quickstart + Normal Successful 3m27s KubeDB Ops-manager Operator Successfully paused ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: horizontal-scale-down + Warning patch petset; ConditionStatus:True; PodName:zk-quickstart-4 3m19s KubeDB Ops-manager Operator patch petset; ConditionStatus:True; PodName:zk-quickstart-4 + Warning get pod; ConditionStatus:False 3m14s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-4 2m44s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-4 + Warning delete pvc; ConditionStatus:True 2m44s KubeDB Ops-manager Operator delete pvc; ConditionStatus:True + Warning get pod; ConditionStatus:False 2m44s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-4 2m39s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-4 + Warning delete pvc; ConditionStatus:True 2m39s KubeDB Ops-manager Operator delete pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-4 2m39s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-4 + Warning patch petset; ConditionStatus:True; PodName:zk-quickstart-3 2m34s KubeDB Ops-manager Operator patch petset; ConditionStatus:True; PodName:zk-quickstart-3 + Warning get pod; ConditionStatus:False 2m29s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-3 119s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-3 + Warning delete pvc; ConditionStatus:True 119s KubeDB Ops-manager Operator delete pvc; ConditionStatus:True + Warning get pod; ConditionStatus:False 119s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-3 114s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-3 + Warning delete pvc; ConditionStatus:True 114s KubeDB Ops-manager Operator delete pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-3 114s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-3 + Normal HorizontalScaleDown 109s KubeDB Ops-manager Operator Successfully Scaled Down Node + Normal UpdateDatabase 109s KubeDB Ops-manager Operator Successfully updated ZooKeeper + Normal Starting 109s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 109s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: horizontal-scale-down +``` + +Now, we are going to verify the number of replicas this zookeeper has from the ZooKeeper object, number of pods the petset have, + +```bash +$ kubectl get zookeeper -n demo zk-quickstart -o json | jq '.spec.replicas' +3 + +$ kubectl get petset -n demo zk-quickstart -o json | jq '.spec.replicas' +3 +``` +From all the above outputs we can see that the replicas of the zookeeper is `3`. That means we have successfully scaled up the replicas of the ZooKeeper. + +## Cleaning Up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete zk -n demo +kubectl delete zookeeperopsrequest -n demo zookeeper-horizontal-scale-down +``` \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/horizontal-scaling/overview.md b/docs/guides/zookeeper/scaling/horizontal-scaling/overview.md new file mode 100644 index 0000000000..4f12b86e16 --- /dev/null +++ b/docs/guides/zookeeper/scaling/horizontal-scaling/overview.md @@ -0,0 +1,54 @@ +--- +title: ZooKeeper Horizontal Scaling Overview +menu: + docs_{{ .version }}: + identifier: zk-horizontal-scaling-overview + name: Overview + parent: zk-horizontal-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# ZooKeeper Horizontal Scaling + +This guide will give an overview on how KubeDB Ops-manager operator scales up or down `ZooKeeper` cluster. + +## Before You Begin + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + +## How Horizontal Scaling Process Works + +The following diagram shows how KubeDB Ops-manager operator scales up or down `ZooKeeper` database components. Open the image in a new tab to see the enlarged version. + +
+  Horizontal scaling process of ZooKeeper +
Fig: Horizontal scaling process of ZooKeeper
+
+ +The Horizontal scaling process consists of the following steps: + +1. At first, a user creates a `ZooKeeper` Custom Resource (CR). + +2. `KubeDB` Provisioner operator watches the `ZooKeeper` CR. + +3. When the operator finds a `ZooKeeper` CR, it creates required number of `PetSets` and related necessary stuff like secrets, services, etc. + +4. Then, in order to scale the `ZooKeeper` cluster, the user creates a `ZooKeeperOpsRequest` CR with desired information. + +5. `KubeDB` Ops-manager operator watches the `ZooKeeperOpsRequest` CR. + +6. When it finds a `ZooKeeperOpsRequest` CR, it halts the `ZooKeeper` object which is referred from the `ZooKeeperOpsRequest`. So, the `KubeDB` Provisioner operator doesn't perform any operations on the `ZooKeeper` object during the horizontal scaling process. + +7. Then the `KubeDB` Ops-manager operator will scale the related PetSet Pods to reach the expected number of replicas defined in the `ZooKeeperOpsRequest` CR. + +8. After the successfully scaling the replicas of the related PetSet Pods, the `KubeDB` Ops-manager operator updates the number of replicas in the `ZooKeeper` object to reflect the updated state. + +9. After the successful scaling of the `ZooKeeper` replicas, the `KubeDB` Ops-manager operator resumes the `ZooKeeper` object so that the `KubeDB` Provisioner operator resumes its usual operations. + +In the [next](/docs/guides/zookeeper/scaling/horizontal-scaling/horizontal-scaling.md) docs, we are going to show a step by step guide on horizontal scaling of ZooKeeper database using `ZooKeeperOpsRequest` CRD. \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/vertical-scaling/_index.md b/docs/guides/zookeeper/scaling/vertical-scaling/_index.md new file mode 100644 index 0000000000..4b0fd3973a --- /dev/null +++ b/docs/guides/zookeeper/scaling/vertical-scaling/_index.md @@ -0,0 +1,10 @@ +--- +title: Vertical Scaling +menu: + docs_{{ .version }}: + identifier: zk-vertical-scaling + name: Vertical Scaling + parent: zk-scaling + weight: 20 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/vertical-scaling/overview.md b/docs/guides/zookeeper/scaling/vertical-scaling/overview.md new file mode 100644 index 0000000000..67d462d379 --- /dev/null +++ b/docs/guides/zookeeper/scaling/vertical-scaling/overview.md @@ -0,0 +1,54 @@ +--- +title: ZooKeeper Vertical Scaling Overview +menu: + docs_{{ .version }}: + identifier: zk-vertical-scaling-overview + name: Overview + parent: zk-vertical-scaling + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# ZooKeeper Vertical Scaling + +This guide will give an overview on how KubeDB Ops-manager operator updates the resources(for example CPU and Memory etc.) of the `ZooKeeper` database. + +## Before You Begin + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + +## How Vertical Scaling Process Works + +The following diagram shows how KubeDB Ops-manager operator updates the resources of the `ZooKeeper` database. Open the image in a new tab to see the enlarged version. + +
+  Vertical scaling process of ZooKeeper +
Fig: Vertical scaling process of ZooKeeper
+
+ +The vertical scaling process consists of the following steps: + +1. At first, a user creates a `ZooKeeper` Custom Resource (CR). + +2. `KubeDB` Provisioner operator watches the `ZooKeeper` CR. + +3. When the operator finds a `ZooKeeper` CR, it creates required number of `Petsets` and related necessary stuff like secrets, services, etc. + +4. Then, in order to update the resources(for example `CPU`, `Memory` etc.) of the `ZooKeeper` database the user creates a `ZooKeeperOpsRequest` CR with desired information. + +5. `KubeDB` Ops-manager operator watches the `ZooKeeperOpsRequest` CR. + +6. When it finds a `ZooKeeperOpsRequest` CR, it halts the `ZooKeeper` object which is referred from the `ZooKeeperOpsRequest`. So, the `KubeDB` Provisioner operator doesn't perform any operations on the `ZooKeeper` object during the vertical scaling process. + +7. Then the `KubeDB` Ops-manager operator will update resources of the Petset Pods to reach desired state. + +8. After the successful update of the resources of the Petset's replica, the `KubeDB` Ops-manager operator updates the `ZooKeeper` object to reflect the updated state. + +9. After the successful update of the `ZooKeeper` resources, the `KubeDB` Ops-manager operator resumes the `ZooKeeper` object so that the `KubeDB` Provisioner operator resumes its usual operations. + +In the [next](/docs/guides/zookeeper/scaling/vertical-scaling/vertical-scaling.md) docs, we are going to show a step by step guide on updating resources of ZooKeeper database using `ZooKeeperOpsRequest` CRD. \ No newline at end of file diff --git a/docs/guides/zookeeper/scaling/vertical-scaling/vertical-scaling.md b/docs/guides/zookeeper/scaling/vertical-scaling/vertical-scaling.md new file mode 100644 index 0000000000..508beb5e07 --- /dev/null +++ b/docs/guides/zookeeper/scaling/vertical-scaling/vertical-scaling.md @@ -0,0 +1,293 @@ +--- +title: Vertical Scaling ZooKeeper +menu: + docs_{{ .version }}: + identifier: zk-vertical-scaling-ops + name: Scale Vertically + parent: zk-vertical-scaling + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Vertical Scale ZooKeeper Standalone + +This guide will show you how to use `KubeDB` Ops-manager operator to update the resources of a ZooKeeper standalone database. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install `KubeDB` Provisioner and Ops-manager operator in your cluster following the steps [here](/docs/setup/README.md). + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + - [Vertical Scaling Overview](/docs/guides/zookeeper/scaling/vertical-scaling/overview.md) + +To keep everything isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> **Note:** YAML files used in this tutorial are stored in [docs/examples/zookeeper](/docs/examples/zookeeper) directory of [kubedb/docs](https://github.com/kubedb/docs) repository. + +## Apply Vertical Scaling on Standalone + +Here, we are going to deploy a `ZooKeeper` standalone using a supported version by `KubeDB` operator. Then we are going to apply vertical scaling on it. + +### Prepare ZooKeeper Standalone Database + +Now, we are going to deploy a `ZooKeeper` standalone database with version `3.8.3`. + +### Deploy ZooKeeper standalone + +In this section, we are going to deploy a ZooKeeper standalone database. Then, in the next section we will update the resources of the database using `ZooKeeperOpsRequest` CRD. Below is the YAML of the `ZooKeeper` CR that we are going to create, + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + storageClassName: "standard" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" + +``` + +Let's create the `ZooKeeper` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/scaling/zookeeper.yaml +zookeeper.kubedb.com/zk-quickstart created +``` + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 5m56s +``` + +Let's check the Pod containers resources, + +```bash +$ kubectl get pod -n demo zk-quickstart-0 -o json | jq '.spec.containers[].resources' +{ + "limits": { + "memory": "1Gi" + }, + "requests": { + "cpu": "500m", + "memory": "1Gi" + } +} +``` + +You can see the Pod has default resources which is assigned by the Kubedb operator. + +We are now ready to apply the `ZooKeeperOpsRequest` CR to update the resources of this database. + +### Vertical Scaling + +Here, we are going to update the resources of the standalone database to meet the desired resources after scaling. + +#### Create ZooKeeperOpsRequest + +In order to update the resources of the database, we have to create a `ZooKeeperOpsRequest` CR with our desired resources. Below is the YAML of the `ZooKeeperOpsRequest` CR that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: vscale + namespace: demo +spec: + databaseRef: + name: zk-quickstart + type: VerticalScaling + verticalScaling: + node: + resources: + limits: + cpu: 1 + memory: 2Gi + requests: + cpu: 1 + memory: 2Gi + timeout: 5m + apply: IfReady +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing vertical scaling operation on `vscale` database. +- `spec.type` specifies that we are performing `VerticalScaling` on our database. +- `spec.VerticalScaling.node` specifies the desired resources after scaling. +- Have a look [here](/docs/guides/zookeeper/concepts/opsrequest.md#spectimeout) on the respective sections to understand the `timeout` & `apply` fields. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/scaling/vertical-scaling/zk-vscale.yaml +zookeeperopsrequest.ops.kubedb.com/vscale created +``` + +#### Verify ZooKeeper Standalone resources updated successfully + +If everything goes well, `KubeDB` Ops-manager operator will update the resources of `ZooKeeper` object and related `Petsets` and `Pods`. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ kubectl get zookeeperopsrequest -n demo +Every 2.0s: kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +vscale VerticalScaling Successful 108s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to scale the database. + +```bash +$ kubectl describe zookeeperopsrequest -n demo vscale +Name: vscale +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-24T11:21:28Z + Generation: 1 + Resource Version: 1151711 + UID: 53ba9aef-cfa6-40f1-a5a8-6055bafb0c7b +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Timeout: 5m + Type: VerticalScaling + Vertical Scaling: + Node: + Resources: + Limits: + Cpu: 1 + Memory: 2Gi + Requests: + Cpu: 1 + Memory: 2Gi +Status: + Conditions: + Last Transition Time: 2024-10-24T11:21:28Z + Message: ZooKeeper ops-request has started to vertically scaling the ZooKeeper nodes + Observed Generation: 1 + Reason: VerticalScaling + Status: True + Type: VerticalScaling + Last Transition Time: 2024-10-24T11:21:31Z + Message: Successfully updated PetSets Resources + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-10-24T11:21:31Z + Message: Successfully Restarted Pods With Resources + Observed Generation: 1 + Reason: RestartPods + Status: False + Type: RestartPods + Last Transition Time: 2024-10-24T11:21:36Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-0 + Last Transition Time: 2024-10-24T11:21:36Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-0 + Last Transition Time: 2024-10-24T11:21:41Z + Message: running pod; ConditionStatus:False + Observed Generation: 1 + Status: False + Type: RunningPod + Last Transition Time: 2024-10-24T11:22:16Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-1 + Last Transition Time: 2024-10-24T11:22:16Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-1 + Last Transition Time: 2024-10-24T11:22:56Z + Message: get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: GetPod--zk-quickstart-2 + Last Transition Time: 2024-10-24T11:22:56Z + Message: evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + Observed Generation: 1 + Status: True + Type: EvictPod--zk-quickstart-2 + Observed Generation: 1 + Phase: Progressing +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 3m24s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/vscale + Normal Starting 3m24s KubeDB Ops-manager Operator Pausing ZooKeeper database: demo/zk-quickstart + Normal Successful 3m24s KubeDB Ops-manager Operator Successfully paused ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: vscale + Normal UpdatePetSets 3m21s KubeDB Ops-manager Operator Successfully updated PetSets Resources + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-0 3m16s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-0 3m16s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-0 + Warning running pod; ConditionStatus:False 3m11s KubeDB Ops-manager Operator running pod; ConditionStatus:False + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-1 2m36s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-1 2m36s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-1 + Warning get pod; ConditionStatus:True; PodName:zk-quickstart-2 116s KubeDB Ops-manager Operator get pod; ConditionStatus:True; PodName:zk-quickstart-2 + Warning evict pod; ConditionStatus:True; PodName:zk-quickstart-2 116s KubeDB Ops-manager Operator evict pod; ConditionStatus:True; PodName:zk-quickstart-2 + +``` + +Now, we are going to verify from the Pod yaml whether the resources of the standalone database has updated to meet up the desired state, Let's check, + +```bash +$ kubectl get pod -n demo zk-quickstart-0 -o json | jq '.spec.containers[].resources' +{ + "limits": { + "cpu": "1", + "memory": "2Gi" + }, + "requests": { + "cpu": "1", + "memory": "2Gi" + } +} +``` + +The above output verifies that we have successfully scaled up the resources of the ZooKeeper standalone database. + +## Cleaning Up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete zk -n demo zk-quickstart +kubectl delete zookeeperopsrequest -n demo vscale +``` \ No newline at end of file diff --git a/docs/guides/zookeeper/tls/_index.md b/docs/guides/zookeeper/tls/_index.md new file mode 100644 index 0000000000..d1b1b06277 --- /dev/null +++ b/docs/guides/zookeeper/tls/_index.md @@ -0,0 +1,10 @@ +--- +title: Run ZooKeeper with TLS +menu: + docs_{{ .version }}: + identifier: zk-tls + name: TLS/SSL Encryption + parent: zk-zookeeper-guides + weight: 45 +menu_name: docs_{{ .version }} +--- diff --git a/docs/guides/zookeeper/tls/configure-ssl.md b/docs/guides/zookeeper/tls/configure-ssl.md new file mode 100644 index 0000000000..ca6fa9696b --- /dev/null +++ b/docs/guides/zookeeper/tls/configure-ssl.md @@ -0,0 +1,268 @@ +--- +title: ZooKeeper TLS/SSL Encryption +menu: + docs_{{ .version }}: + identifier: zk-tls-configure + name: ZooKeeper_SSL + parent: zk-tls + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Run ZooKeeper Ensemble with TLS/SSL + +KubeDB supports providing TLS/SSL encryption for ZooKeeper Ensemble. This tutorial will show you how to use KubeDB to run a ZooKeeper Ensemble with TLS/SSL encryption. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/). + +- Install [`cert-manger`](https://cert-manager.io/docs/installation/) v1.0.0 or later to your cluster to manage your SSL/TLS certificates. + +- Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/README.md). + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + + ```bash + $ kubectl create ns demo + namespace/demo created + ``` + +> Note: YAML files used in this tutorial are stored in [docs/examples/zookeeper](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/zookeeper) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Overview + +KubeDB uses following crd fields to enable SSL/TLS encryption in ZooKeeper. + +- `spec:` + - `enableSSL` + - `tls:` + - `issuerRef` + - `certificate` + +Read about the fields in details in [zookeeper Concept Guide](/docs/guides/zookeeper/concepts/zookeeper.md), + +Users must specify the `tls.issuerRef` field. KubeDB uses the `issuer` or `clusterIssuer` referenced in the `tls.issuerRef` field, and the certificate specs provided in `tls.certificate` to generate certificate secrets. These certificate secrets are then used to generate required certificates including `ca.crt`, `tls.crt`, `tls.key`, `keystore.jks` and `truststore.jks`. + +## Create Issuer/ ClusterIssuer + +We are going to create an example `Issuer` that will be used throughout the duration of this tutorial to enable SSL/TLS in ZooKeeper. Alternatively, you can follow this [cert-manager tutorial](https://cert-manager.io/docs/configuration/ca/) to create your own `Issuer`. + +- Start off by generating you ca certificates using openssl. + +```bash +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=zookeeper/O=kubedb" +``` + +- Now create a ca-secret using the certificate files you have just generated. + +```bash +kubectl create secret tls zookeeper-ca \ + --cert=ca.crt \ + --key=ca.key \ + --namespace=demo +``` + +Now, create an `Issuer` using the `ca-secret` you have just created. The `YAML` file looks like this: + +```yaml +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: zookeeper-ca-issuer + namespace: demo +spec: + ca: + secretName: zookeeper-ca +``` + +Apply the `YAML` file: + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/tls/zookeeper-issuer.yaml +issuer.cert-manager.io/zookeeper-ca-issuer created +``` + +## TLS/SSL encryption in ZooKeeper Ensemble + +Below is the YAML for ZooKeeper with TLS enabled: + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-tls + namespace: demo +spec: + version: "3.8.3" + enableSSL: true + tls: + issuerRef: + apiGroup: "cert-manager.io" + kind: Issuer + name: zookeeper-ca-issuer + adminServerPort: 8080 + replicas: 5 + storage: + resources: + requests: + storage: "1Gi" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" + +``` + +Here, +- `spec.enableSSL` is set to `true` to enable TLS/SSL encryption. +- `spec.tls.issuerRef` refers to the `Issuer` that we have created in the previous step. +- +### Deploy ZOoKeeper Ensemble with TLS/SSL + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/tls/zookeeper-tls.yaml +zookeeper.kubedb.com/zk-tls created +``` + +Now, wait until `zookeeper-tls created` has status `Ready`. i.e, + +```bash +$ watch kubectl get zookeeper -n demo +NAME TYPE VERSION STATUS AGE +zk-tls kubedb.com/v1alpha2 3.8.3 Ready 60s +``` + +### Verify TLS/SSL in ZooKeeper Ensemble + +```bash +$ kubectl describe secret -n demo zk-quickstart-client-cert +Name: zk-quickstart-client-cert +Namespace: demo +Labels: app.kubernetes.io/component=database + app.kubernetes.io/instance=zk-quickstart + app.kubernetes.io/managed-by=kubedb.com + app.kubernetes.io/name=zookeepers.kubedb.com + controller.cert-manager.io/fao=true +Annotations: cert-manager.io/alt-names: + *.zk-quickstart-pods.demo.svc.cluster.local,localhost,zk-quickstart,zk-quickstart-pods,zk-quickstart-pods.demo.svc,zk-quickstart-pods.demo... + cert-manager.io/certificate-name: zk-quickstart-client-cert + cert-manager.io/common-name: zk-quickstart-pods.demo.svc + cert-manager.io/ip-sans: 127.0.0.1 + cert-manager.io/issuer-group: cert-manager.io + cert-manager.io/issuer-kind: Issuer + cert-manager.io/issuer-name: zookeeper-ca-issuer + cert-manager.io/uri-sans: + +Type: kubernetes.io/tls + +Data +==== +ca.crt: 1159 bytes +keystore.jks: 3258 bytes +tls-combined.pem: 3198 bytes +tls.crt: 1493 bytes +tls.key: 1704 bytes +truststore.jks: 873 bytes +``` + +Now, Let's exec into a ZooKeeper pod and verify the configuration that the TLS is enabled. + +```bash +$ kubectl exec -it -n demo zk-quickstart-0 -- bash +Defaulted container "zookeeper" out of: zookeeper, zookeeper-init (init) +zookeeper@zk-quickstart-0:/apache-zookeeper-3.8.3-bin$ cd ../var/private/ssl +zookeeper@zk-quickstart-0:/var/private/ssl$ openssl s_client -connect localhost:2182 -CAfile ca.crt -cert tls.crt -key tls.key +CONNECTED(00000003) +depth=1 CN = zookeeper, O = kubedb +verify return:1 +depth=0 CN = zk-quickstart.demo.svc +verify return:1 +--- +Certificate chain + 0 s:CN = zk-quickstart.demo.svc + i:CN = zookeeper, O = kubedb + a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 + v:NotBefore: Nov 4 05:46:21 2024 GMT; NotAfter: Feb 2 05:46:21 2025 GMT +--- +Server certificate +-----BEGIN CERTIFICATE----- +MIIEJTCCAw2gAwIBAgIQaWLGhg/TgVF8oXGcsLQkKjANBgkqhkiG9w0BAQsFADAl +MRIwEAYDVQQDDAl6b29rZWVwZXIxDzANBgNVBAoMBmt1YmVkYjAeFw0yNDExMDQw +NTQ2MjFaFw0yNTAyMDIwNTQ2MjFaMCExHzAdBgNVBAMTFnprLXF1aWNrc3RhcnQu +ZGVtby5zdmMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCeeiLZeNa7 +wHOUwD76fmp45Ae9qlpHCW/lGz+lGO48FBDUBbG2Tm2BZVW2297HOzb/Lax6Molb +9qCDsV7ITCUYXLBGz0pCGqGYS/icZupShhKAvD33Gn8kH/QeANwFonpxBAtr36vi +WxwcRD+dfVAu7OCATwSakZh3zdbRPQXLiAVqj8qn4zNSYL5bzUXQ5dHFzvgwZve5 +FR3QYLvVjUEu2tFjCKM+/HTzQ/IMUAjcU0lU4qnWqnhgcGp8ZE3hDyL9OOOsjrWx +CGNhB0Orf6Efztkqq4FMZ//w3DUQgnRglGKl1rGK015//W0MGSPlT4uve6Z7zaRU +aUqa7Y8P5wZxAgMBAAGjggFTMIIBTzAOBgNVHQ8BAf8EBAMCAqQwHQYDVR0lBBYw +FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FC7Wrn4SOKhsT4TQFEMtSao72H5TMB8GA1UdIwQYMBaAFDe7/VhWOllB39U/xOht +MxmZu9wQMIHMBgNVHREEgcQwgcGCKyouemstcXVpY2tzdGFydC1wb2RzLmRlbW8u +c3ZjLmNsdXN0ZXIubG9jYWyCCWxvY2FsaG9zdIINemstcXVpY2tzdGFydIISemst +cXVpY2tzdGFydC1wb2Rzght6ay1xdWlja3N0YXJ0LXBvZHMuZGVtby5zdmOCKXpr +LXF1aWNrc3RhcnQtcG9kcy5kZW1vLnN2Yy5jbHVzdGVyLmxvY2FsghZ6ay1xdWlj +a3N0YXJ0LmRlbW8uc3ZjhwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCGGxgGzdjF +Vo9VALc6ddZD50M7bfh5L5z2KfSY4ZH7kuokM52LGzJYwREV3UpVAhjBqn0XEf9p +JX8ePo0Z9zjtWIIZg4ctjlCvKDy+HpKlqh2RJejnl+NoLPV628QJDiEksLzdVl4v +z36AwdGeUhADpvoGQiXUT6LgrD++Uv0akpDEzWOB2LUKsvCRKnxyBNyBqpsW8/Pu +DeC/RUGXT/JFtZtDBGp8d/FOIpJ0t/ZjrI9Hyu5DLFB08oTYmEVE3Lv2owZZV/o8 +6YqlpTu2efKEzMFZudUWpnGUrb69sZeDR9hwxGcAdKobTB8SZOBU61nsRn95BH7O +S4dKhcrbzP70 +-----END CERTIFICATE----- +subject=CN = zk-quickstart.demo.svc +issuer=CN = zookeeper, O = kubedb +--- +Acceptable client certificate CA names +CN = zookeeper, O = kubedb +Client Certificate Types: ECDSA sign, RSA sign, DSA sign +Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224:ECDSA+SHA1:RSA+SHA1:DSA+SHA1 +Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA256:ECDSA+SHA224:RSA+SHA224:DSA+SHA224 +Peer signing digest: SHA256 +Peer signature type: RSA-PSS +Server Temp Key: X25519, 253 bits +--- +SSL handshake has read 1611 bytes and written 2553 bytes +Verification: OK +--- +New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256 +Server public key is 2048 bit +Secure Renegotiation IS supported +Compression: NONE +Expansion: NONE +No ALPN negotiated +SSL-Session: + Protocol : TLSv1.2 + Cipher : ECDHE-RSA-AES128-GCM-SHA256 + Session-ID: 057DF7D5B8BCE6DA3EAE6101136E644057BE67AF0A4931DC8FD15848D4E74D38 + Session-ID-ctx: + Master-Key: 807690ACC8782745D1C8AB6E4CF42FCAE7B13CAAC75A27FF4538FEA136DB9E6A332FDDB18703367593EBAD77629919C3 + PSK identity: None + PSK identity hint: None + SRP username: None + Start Time: 1730703067 + Timeout : 7200 (sec) + Verify return code: 0 (ok) + Extended master secret: yes +--- +``` + +From the above output, we can see that we are able to connect to the ZooKeeper Ensemble using the TLS configuration. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete zookeeper -n demo zk-tls +kubectl delete issuer -n demo zookeeper-ca-issuer +kubectl delete ns demo +``` + +## Next Steps + +- Detail concepts of [ZooKeeper object](/docs/guides/zookeeper/concepts/zookeeper.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). \ No newline at end of file diff --git a/docs/guides/zookeeper/tls/overview.md b/docs/guides/zookeeper/tls/overview.md new file mode 100644 index 0000000000..3da9624413 --- /dev/null +++ b/docs/guides/zookeeper/tls/overview.md @@ -0,0 +1,70 @@ +--- +title: ZooKeeper TLS/SSL Encryption Overview +menu: + docs_{{ .version }}: + identifier: zk-tls-overview + name: Overview + parent: zk-tls + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# ZooKeeper TLS/SSL Encryption + +**Prerequisite :** To configure TLS/SSL in `ZooKeeper`, `KubeDB` uses `cert-manager` to issue certificates. So first you have to make sure that the cluster has `cert-manager` installed. To install `cert-manager` in your cluster following steps [here](https://cert-manager.io/docs/installation/kubernetes/). + +To issue a certificate, the following crd of `cert-manager` is used: + +- `Issuer/ClusterIssuer`: Issuers, and ClusterIssuers represent certificate authorities (CAs) that are able to generate signed certificates by honoring certificate signing requests. All cert-manager certificates require a referenced issuer that is in a ready condition to attempt to honor the request. You can learn more details [here](https://cert-manager.io/docs/concepts/issuer/). + +- `Certificate`: `cert-manager` has the concept of Certificates that define a desired x509 certificate which will be renewed and kept up to date. You can learn more details [here](https://cert-manager.io/docs/concepts/certificate/). + +**ZooKeeper CRD Specification :** + +KubeDB uses following crd fields to enable SSL/TLS encryption in `ZooKeeper`. + +- `spec:` + - `enableSSL` + - `tls:` + - `issuerRef` + - `certificates` + +Read about the fields in details from [zookeeper concept](/docs/guides/zookeeper/concepts/zookeeper.md), + +When, `enableSSL` is set to `true`, the users must specify the `tls.issuerRef` field. `KubeDB` uses the `issuer` or `clusterIssuer` referenced in the `tls.issuerRef` field, and the certificate specs provided in `tls.certificate` to generate certificate secrets using `Issuer/ClusterIssuers` specification. These certificates secrets including `ca.crt`, `tls.crt` and `tls.key` etc. are used to configure `zookeeper` server and clients. + +## How TLS/SSL configures in ZooKeeper + +The following figure shows how `KubeDB` enterprise used to configure TLS/SSL in ZooKeeper. Open the image in a new tab to see the enlarged version. + +
+Deploy ZooKeeper with TLS/SSL +
Fig: Deploy ZooKeeper with TLS/SSL
+
+ +Deploying ZooKeeper with TLS/SSL configuration process consists of the following steps: + +1. At first, a user creates a `Issuer/ClusterIssuer` CR. + +2. Then the user creates a `ZooKeeper` CR which refers to the `Issuer/ClusterIssuer` CR that the user created in the previous step. + +3. `KubeDB` Provisioner operator watches for the `ZooKeeper` CR. + +4. When it finds one, it creates `Secret`, `Service`, etc. for the `ZooKeeper` cluster. + +5. `KubeDB` Ops-manager operator watches for `ZooKeeper`(5c), `Issuer/ClusterIssuer`(5b), `Secret` and `Service`(5a). + +6. When it finds all the resources(`ZooKeeper`, `Issuer/ClusterIssuer`, `Secret`, `Service`), it creates `Certificates` by using `tls.issuerRef` and `tls.certificates` field specification from `ZooKeeper` CR. + +7. `cert-manager` watches for certificates. + +8. When it finds one, it creates certificate secrets `tls-secrets`(server, client, exporter secrets etc.) that holds the actual certificate signed by the CA. + +9. `KubeDB` Provisioner operator watches for the Certificate secrets `tls-secrets`. + +10. When it finds all the tls-secret, it creates the related `PetSets` so that ZooKeeper database can be configured with TLS/SSL. + +In the [next](/docs/guides/zookeeper/tls/configure-ssl.md) doc, we are going to show a step-by-step guide on how to configure a `ZooKeeper` cluster with TLS/SSL. \ No newline at end of file diff --git a/docs/guides/zookeeper/volume-expansion/_index.md b/docs/guides/zookeeper/volume-expansion/_index.md new file mode 100644 index 0000000000..b152726462 --- /dev/null +++ b/docs/guides/zookeeper/volume-expansion/_index.md @@ -0,0 +1,10 @@ +--- +title: Volume Expansion +menu: + docs_{{ .version }}: + identifier: zk-volume-expansion + name: Volume Expansion + parent: zk-zookeeper-guides + weight: 70 +menu_name: docs_{{ .version }} +--- \ No newline at end of file diff --git a/docs/guides/zookeeper/volume-expansion/overview.md b/docs/guides/zookeeper/volume-expansion/overview.md new file mode 100644 index 0000000000..371284bdd2 --- /dev/null +++ b/docs/guides/zookeeper/volume-expansion/overview.md @@ -0,0 +1,56 @@ +--- +title: ZooKeeper Volume Expansion Overview +menu: + docs_{{ .version }}: + identifier: zk-volume-expansion-overview + name: Overview + parent: zk-volume-expansion + weight: 10 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# ZooKeeper Volume Expansion + +This guide will give an overview on how KubeDB Ops-manager operator expand the volume of `ZooKeeper` cluster nodes. + +## Before You Begin + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + +## How Volume Expansion Process Works + +The following diagram shows how KubeDB Ops-manager operator expand the volumes of `ZooKeeper` database components. Open the image in a new tab to see the enlarged version. + +
+  Volume Expansion process of ZooKeeper +
Fig: Volume Expansion process of ZooKeeper
+
+ +The Volume Expansion process consists of the following steps: + +1. At first, a user creates a `ZooKeeper` Custom Resource (CR). + +2. `KubeDB` Provisioner operator watches the `ZooKeeper` CR. + +3. When the operator finds a `ZooKeeper` CR, it creates required number of `Petsets` and related necessary stuff like secrets, services, etc. + +4. Each petset creates a Persistent Volume according to the Volume Claim Template provided in the PetSet configuration. This Persistent Volume will be expanded by the `KubeDB` Ops-manager operator. + +5. Then, in order to expand the volume the `ZooKeeper` database the user creates a `ZooKeeperOpsRequest` CR with desired information. + +6. `KubeDB` Ops-manager operator watches the `ZooKeeperOpsRequest` CR. + +7. When it finds a `ZooKeeperOpsRequest` CR, it halts the `ZooKeeper` object which is referred from the `ZooKeeperOpsRequest`. So, the `KubeDB` Provisioner operator doesn't perform any operations on the `ZooKeeper` object during the volume expansion process. + +8. Then the `KubeDB` Ops-manager operator will expand the persistent volume to reach the expected size defined in the `ZooKeeperOpsRequest` CR. + +9. After the successful Volume Expansion of the related Petset Pods, the `KubeDB` Ops-manager operator updates the new volume size in the `ZooKeeper` object to reflect the updated state. + +10. After the successful Volume Expansion of the `ZooKeeper` components, the `KubeDB` Ops-manager operator resumes the `ZooKeeper` object so that the `KubeDB` Provisioner operator resumes its usual operations. + +In the [next](/docs/guides/zookeeper/volume-expansion/volume-expansion.md) docs, we are going to show a step-by-step guide on Volume Expansion of various ZooKeeper database components using `ZooKeeperOpsRequest` CRD. diff --git a/docs/guides/zookeeper/volume-expansion/volume-expansion.md b/docs/guides/zookeeper/volume-expansion/volume-expansion.md new file mode 100644 index 0000000000..ae2bba9d6f --- /dev/null +++ b/docs/guides/zookeeper/volume-expansion/volume-expansion.md @@ -0,0 +1,386 @@ +--- +title: ZooKeeper Volume Expansion +menu: + docs_{{ .version }}: + identifier: zk-volume-expansion-describe + name: Expand Storage Volume + parent: zk-volume-expansion + weight: 20 +menu_name: docs_{{ .version }} +section_menu_id: guides +--- + +> New to KubeDB? Please start [here](/docs/README.md). + +# Volume Expansion of ZooKeeper Ensemble + +This guide will show you how to use `KubeDB` Ops-manager operator to expand the volume of a ZooKeeper database. + +## Before You Begin + +- At first, you need to have a Kubernetes cluster, and the `kubectl` command-line tool must be configured to communicate with your cluster. + +- You must have a `StorageClass` that supports volume expansion. + +- Install `KubeDB` Provisioner and Ops-manager operator in your cluster following the steps [here](/docs/setup/README.md). + +- You should be familiar with the following `KubeDB` concepts: + - [ZooKeeper](/docs/guides/zookeeper/concepts/zookeeper.md) + - [ZooKeeperOpsRequest](/docs/guides/zookeeper/concepts/opsrequest.md) + - [Volume Expansion Overview](/docs/guides/zookeeper/volume-expansion/overview.md) + +To keep everything isolated, we are going to use a separate namespace called `demo` throughout this tutorial. + +```bash +$ kubectl create ns demo +namespace/demo created +``` + +> Note: The yaml files used in this tutorial are stored in [docs/examples/ZooKeeper](https://github.com/kubedb/docs/tree/{{< param "info.version" >}}/docs/examples/zookeeper) folder in GitHub repository [kubedb/docs](https://github.com/kubedb/docs). + +## Expand Volume of ZooKeeper Ensemble + +Here, we are going to deploy a `ZooKeeper` standalone using a supported version by `KubeDB` operator. Then we are going to apply `ZooKeeperOpsRequest` to expand its volume. + +### Prepare ZooKeeper Ensemble + +At first verify that your cluster has a storage class, that supports volume expansion. Let's check, + +```bash +$ kubectl get storageclass +NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE +longhorn (default) driver.longhorn.io Delete Immediate true 93s +longhorn-static driver.longhorn.io Delete Immediate true 90s +``` + +We can see from the output the `standard` storage class has `ALLOWVOLUMEEXPANSION` field as true. So, this storage class supports volume expansion. We can use it. + +Now, we are going to deploy a `ZooKeeper` standalone database with version `3.8.3`. + +#### Deploy ZooKeeper Ensemble + +In this section, we are going to deploy a ZooKeeper standalone database with 1GB volume. Then, in the next section we will expand its volume to 2GB using `ZooKeeperOpsRequest` CRD. Below is the YAML of the `ZooKeeper` CR that we are going to create, + +```yaml +apiVersion: kubedb.com/v1alpha2 +kind: ZooKeeper +metadata: + name: zk-quickstart + namespace: demo +spec: + version: "3.8.3" + adminServerPort: 8080 + replicas: 3 + storage: + resources: + requests: + storage: "1Gi" + storageClassName: "longhorn" + accessModes: + - ReadWriteOnce + deletionPolicy: "WipeOut" +``` + +Let's create the `ZooKeeper` CR we have shown above, + +```bash +$ kubectl create -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/volume-expansion/zookeeper.yaml +zookeeper.kubedb.com/zk-quickstart created +``` + +Now, wait until `zk-quickstart` has status `Ready`. i.e, + +```bash +$ kubectl get zk -n demo +NAME VERSION STATUS AGE +zk-quickstart 3.8.3 Ready 5m56s +``` + +Let's check volume size from PetSet, and from the persistent volume, + +```bash +$ kubectl get petset -n demo zk-quickstart -o json | jq '.spec.volumeClaimTemplates[].spec.resources.requests.storage' +"1Gi" + +$ kubectl get pv -n demo +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE +pvc-3551d7c0-0df6-4f94-b1e0-21834319ecab 1Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-0 longhorn 92s +pvc-b5882e9e-3c61-4609-b5ba-0eb9f32edbbc 1Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-2 longhorn 58s +pvc-dccf2b12-d695-4792-8e4b-de4342e7fed4 1Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-1 longhorn 74s +``` + +You can see the PetSet has 1GB storage, and the capacity of the persistent volume is also 1GB. + +We are now ready to apply the `ZooKeeperOpsRequest` CR to expand the volume of this database. + +### Volume Expansion + +Here, we are going to expand the volume of the standalone database. + +#### Create ZooKeeperOpsRequest + +In order to expand the volume of the database, we have to create a `ZooKeeperOpsRequest` CR with our desired volume size. Below is the YAML of the `ZooKeeperOpsRequest` CR that we are going to create, + +```yaml +apiVersion: ops.kubedb.com/v1alpha1 +kind: ZooKeeperOpsRequest +metadata: + name: zk-offline-volume-expansion + namespace: demo +spec: + type: VolumeExpansion + databaseRef: + name: zk-quickstart + volumeExpansion: + mode: "Offline" + node: 2Gi +``` + +Here, + +- `spec.databaseRef.name` specifies that we are performing volume expansion operation on `zk-quickstart` database. +- `spec.type` specifies that we are performing `VolumeExpansion` on our database. +- `spec.volumeExpansion.node` specifies the desired volume size. +- `spec.volumeExpansion.mode` specifies the desired volume expansion mode(`Online` or `Offline`). + +During `Online` VolumeExpansion KubeDB expands volume without pausing database object, it directly updates the underlying PVC. And for `Offline` volume expansion, the database is paused. The Pods are deleted and PVC is updated. Then the database Pods are recreated with updated PVC. + +Let's create the `ZooKeeperOpsRequest` CR we have shown above, + +```bash +$ kubectl apply -f https://github.com/kubedb/docs/raw/{{< param "info.version" >}}/docs/examples/zookeeper/volume-expansion/zkops-volume-exp-offline.yaml +zookeeperopsrequest.ops.kubedb.com/zk-offline-volume-expansion created +``` + +#### Verify ZooKeeper Standalone volume expanded successfully + +If everything goes well, `KubeDB` Ops-manager operator will update the volume size of `ZooKeeper` object and related `Petsets` and `Persistent Volume`. + +Let's wait for `ZooKeeperOpsRequest` to be `Successful`. Run the following command to watch `ZooKeeperOpsRequest` CR, + +```bash +$ kubectl get zookeeperopsrequest -n demo +NAME TYPE STATUS AGE +zk-offline-volume-expansion VolumeExpansion Successful 75s +``` + +We can see from the above output that the `ZooKeeperOpsRequest` has succeeded. If we describe the `ZooKeeperOpsRequest` we will get an overview of the steps that were followed to expand the volume of the database. + +```bash +$ kubectl describe zookeeperopsrequest -n demo zk-offline-volume-expansion +Name: zk-offline-volume-expansion +Namespace: demo +Labels: +Annotations: +API Version: ops.kubedb.com/v1alpha1 +Kind: ZooKeeperOpsRequest +Metadata: + Creation Timestamp: 2024-10-28T11:12:02Z + Generation: 1 + Resource Version: 1321277 + UID: 13851249-f148-4745-a565-0aaea704f830 +Spec: + Apply: IfReady + Database Ref: + Name: zk-quickstart + Type: VolumeExpansion + Volume Expansion: + Mode: Offline + Node: 2Gi +Status: + Conditions: + Last Transition Time: 2024-10-28T11:12:02Z + Message: ZooKeeper ops-request has started to expand volume of zookeeper nodes. + Observed Generation: 1 + Reason: VolumeExpansion + Status: True + Type: VolumeExpansion + Last Transition Time: 2024-10-28T11:12:20Z + Message: successfully deleted the petSets with orphan propagation policy + Observed Generation: 1 + Reason: OrphanPetSetPods + Status: True + Type: OrphanPetSetPods + Last Transition Time: 2024-10-28T11:12:10Z + Message: get petset; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetPetset + Last Transition Time: 2024-10-28T11:12:10Z + Message: delete petset; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: DeletePetset + Last Transition Time: 2024-10-28T11:15:55Z + Message: successfully updated node PVC sizes + Observed Generation: 1 + Reason: UpdateNodePVCs + Status: True + Type: UpdateNodePVCs + Last Transition Time: 2024-10-28T11:15:05Z + Message: get pod; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetPod + Last Transition Time: 2024-10-28T11:12:25Z + Message: patch ops request; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: PatchOpsRequest + Last Transition Time: 2024-10-28T11:12:25Z + Message: delete pod; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: DeletePod + Last Transition Time: 2024-10-28T11:13:00Z + Message: get pvc; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetPvc + Last Transition Time: 2024-10-28T11:13:00Z + Message: patch pvc; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: PatchPvc + Last Transition Time: 2024-10-28T11:15:45Z + Message: compare storage; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: CompareStorage + Last Transition Time: 2024-10-28T11:13:15Z + Message: create pod; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: CreatePod + Last Transition Time: 2024-10-28T11:16:00Z + Message: successfully reconciled the ZooKeeper resources + Observed Generation: 1 + Reason: UpdatePetSets + Status: True + Type: UpdatePetSets + Last Transition Time: 2024-10-28T11:16:05Z + Message: PetSet is recreated + Observed Generation: 1 + Reason: ReadyPetSets + Status: True + Type: ReadyPetSets + Last Transition Time: 2024-10-28T11:16:05Z + Message: get pet set; ConditionStatus:True + Observed Generation: 1 + Status: True + Type: GetPetSet + Last Transition Time: 2024-10-28T11:16:05Z + Message: Successfully completed volumeExpansion for ZooKeeper + Observed Generation: 1 + Reason: Successful + Status: True + Type: Successful + Observed Generation: 1 + Phase: Successful +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Starting 5m19s KubeDB Ops-manager Operator Start processing for ZooKeeperOpsRequest: demo/zk-offline-volume-expansion + Normal Starting 5m19s KubeDB Ops-manager Operator Pausing ZooKeeper database: demo/zk-quickstart + Normal Successful 5m19s KubeDB Ops-manager Operator Successfully paused ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zk-offline-volume-expansion + Warning get petset; ConditionStatus:True 5m11s KubeDB Ops-manager Operator get petset; ConditionStatus:True + Warning delete petset; ConditionStatus:True 5m11s KubeDB Ops-manager Operator delete petset; ConditionStatus:True + Warning get petset; ConditionStatus:True 5m6s KubeDB Ops-manager Operator get petset; ConditionStatus:True + Normal OrphanPetSetPods 5m1s KubeDB Ops-manager Operator successfully deleted the petSets with orphan propagation policy + Warning get pod; ConditionStatus:True 4m56s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 4m56s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning delete pod; ConditionStatus:True 4m56s KubeDB Ops-manager Operator delete pod; ConditionStatus:True + Warning get pod; ConditionStatus:False 4m51s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True 4m21s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 4m21s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning patch pvc; ConditionStatus:True 4m21s KubeDB Ops-manager Operator patch pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:False 4m21s KubeDB Ops-manager Operator compare storage; ConditionStatus:False + Warning get pod; ConditionStatus:True 4m16s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 4m16s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 4m11s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 4m11s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 4m6s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 4m6s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:True 4m6s KubeDB Ops-manager Operator compare storage; ConditionStatus:True + Warning create pod; ConditionStatus:True 4m6s KubeDB Ops-manager Operator create pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 4m6s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning get pod; ConditionStatus:True 4m1s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pod; ConditionStatus:True 3m56s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 3m56s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning delete pod; ConditionStatus:True 3m56s KubeDB Ops-manager Operator delete pod; ConditionStatus:True + Warning get pod; ConditionStatus:False 3m51s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True 3m21s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 3m21s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning patch pvc; ConditionStatus:True 3m21s KubeDB Ops-manager Operator patch pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:False 3m21s KubeDB Ops-manager Operator compare storage; ConditionStatus:False + Warning get pod; ConditionStatus:True 3m16s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 3m16s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 3m11s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 3m11s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 3m6s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 3m6s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 3m1s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 3m1s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:True 3m1s KubeDB Ops-manager Operator compare storage; ConditionStatus:True + Warning create pod; ConditionStatus:True 3m1s KubeDB Ops-manager Operator create pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 3m1s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning get pod; ConditionStatus:True 2m56s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pod; ConditionStatus:True 2m51s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 2m51s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning delete pod; ConditionStatus:True 2m51s KubeDB Ops-manager Operator delete pod; ConditionStatus:True + Warning get pod; ConditionStatus:False 2m46s KubeDB Ops-manager Operator get pod; ConditionStatus:False + Warning get pod; ConditionStatus:True 2m16s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 2m16s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning patch pvc; ConditionStatus:True 2m16s KubeDB Ops-manager Operator patch pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:False 2m16s KubeDB Ops-manager Operator compare storage; ConditionStatus:False + Warning get pod; ConditionStatus:True 2m11s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 2m11s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 2m6s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 2m6s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 2m1s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 2m1s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 116s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 116s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 111s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 111s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 106s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 106s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 101s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 101s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning get pod; ConditionStatus:True 96s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Warning get pvc; ConditionStatus:True 96s KubeDB Ops-manager Operator get pvc; ConditionStatus:True + Warning compare storage; ConditionStatus:True 96s KubeDB Ops-manager Operator compare storage; ConditionStatus:True + Warning create pod; ConditionStatus:True 96s KubeDB Ops-manager Operator create pod; ConditionStatus:True + Warning patch ops request; ConditionStatus:True 96s KubeDB Ops-manager Operator patch ops request; ConditionStatus:True + Warning get pod; ConditionStatus:True 91s KubeDB Ops-manager Operator get pod; ConditionStatus:True + Normal UpdateNodePVCs 86s KubeDB Ops-manager Operator successfully updated node PVC sizes + Normal UpdatePetSets 81s KubeDB Ops-manager Operator successfully reconciled the ZooKeeper resources + Warning get pet set; ConditionStatus:True 76s KubeDB Ops-manager Operator get pet set; ConditionStatus:True + Normal ReadyPetSets 76s KubeDB Ops-manager Operator PetSet is recreated + Normal Starting 76s KubeDB Ops-manager Operator Resuming ZooKeeper database: demo/zk-quickstart + Normal Successful 76s KubeDB Ops-manager Operator Successfully resumed ZooKeeper database: demo/zk-quickstart for ZooKeeperOpsRequest: zk-offline-volume-expansion +``` + +Now, we are going to verify from the `Petset`, and the `Persistent Volume` whether the volume of the standalone database has expanded to meet the desired state, Let's check, + +```bash +$ kubectl get petset -n demo zk-quickstart -o json | jq '.spec.volumeClaimTemplates[].spec.resources.requests.storage' +"2Gi" + +$ kubectl get pv -n demo +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE +pvc-1b112414-6162-4e75-99c9-3e62cb4efb4a 2Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-1 longhorn 16m +pvc-3159b881-1954-4008-8594-599bee9fd11e 2Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-0 longhorn 17m +pvc-43ba80bd-9029-413e-b89c-1f373fd0cd3d 2Gi RWO Delete Bound demo/zk-quickstart-data-zk-quickstart-2 longhorn 16m +``` + +The above output verifies that we have successfully expanded the volume of the ZooKeeper standalone database. + +## Cleaning Up + +To clean up the Kubernetes resources created by this tutorial, run: + +```bash +kubectl delete zk -n demo zk-quickstart +kubectl delete zookeeperopsrequest -n demo zk-offline-volume-expansion +``` diff --git a/docs/images/day-2-operation/zookeeper/zk-horizontal-scaling.svg b/docs/images/day-2-operation/zookeeper/zk-horizontal-scaling.svg new file mode 100644 index 0000000000..636eac7ce0 --- /dev/null +++ b/docs/images/day-2-operation/zookeeper/zk-horizontal-scaling.svg @@ -0,0 +1,3 @@ + + +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
4.Initiate Horizontal Scaling
4.Initiate Hori...
6.Pause
6.Pause
7.Scaling Pod
7.Scaling Pod
8.Update Replica
8.Update Replica
9.Resume
9.Resume
Horizontal Scaling stage
Horizontal Scaling stage
User
User
            Provisioner        
              
              
StatefulSet's
Pod
Stateful...
StatefulSet's
Pod
Stateful...
5.Watch
5.Watch
            Ops Manager            
ZooKeeper
 OpsReques
t
ZooKeeper...
ZooKeeper
ZooKeeper
refers to
refers to
Updated
ZooKeeper
Update...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/day-2-operation/zookeeper/zk-reconfigure-tls.svg b/docs/images/day-2-operation/zookeeper/zk-reconfigure-tls.svg new file mode 100644 index 0000000000..b4d3ab4479 --- /dev/null +++ b/docs/images/day-2-operation/zookeeper/zk-reconfigure-tls.svg @@ -0,0 +1,3 @@ + + +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
4.Initiate Re-configuring TLS
4.Initiate Re-c...
6.Pause
6.Pause
8.Restart Pods
8.Restart Pods
7.Update TLS configuration
7.Update TLS configurati...
9.Resume
9.Resume
Reconfiguring TLS stage
Reconfiguring TLS stage
User
User
            Provisioner        
              
              
StatefulSet's
Pod
Stateful...
5.Watch
5.Watch
            Ops Manager            
ZooKeeper
 OpsReques
t
ZooKeeper...
ZooKeeper
ZooKeeper
refers to
refers to
Updated
ZooKeeper
Update...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/day-2-operation/zookeeper/zk-reconfigure.svg b/docs/images/day-2-operation/zookeeper/zk-reconfigure.svg new file mode 100644 index 0000000000..0201874843 --- /dev/null +++ b/docs/images/day-2-operation/zookeeper/zk-reconfigure.svg @@ -0,0 +1,3 @@ + + +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
4.Initiate Re-configuring
4.Initiate Re-c...
6.Pause
6.Pause
8.Restart Pods
8.Restart Pods
7.Update Configuration
7.Update Configurati...
9.Resume
9.Resume
Reconfiguring stage
Reconfiguring stage
User
User
            Provisioner        
              
              
StatefulSet's
Pod
Stateful...
5.Watch
5.Watch
            Ops Manager            
ZooKeeper
 OpsReques
t
ZooKeeper...
ZooKeeper
ZooKeeper
refers to
refers to
Updated
ZooKeeper
Update...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/day-2-operation/zookeeper/zk-version-update.svg b/docs/images/day-2-operation/zookeeper/zk-version-update.svg index 97259b8047..6b9c1ad93b 100644 --- a/docs/images/day-2-operation/zookeeper/zk-version-update.svg +++ b/docs/images/day-2-operation/zookeeper/zk-version-update.svg @@ -1,4 +1,4 @@ -
1.Create zookeeper
1.Create zookeeper
2.Watch
2.Watch
3.Create
3.Create
4.Initiate Update
4.Initiate Upgr...
6.Pause
6.Pause
7.Update & Perform Checks
7.Update & Perform...
8.Update Image
8.Update Image
9.Resume
9.Resume
Updating stage
Updating stage
User
User
                Community            Operator
           StatefulSet
Statef...
5.Watch
5.Watch
            Enterprise            Operator
zookeeper OpsRequest
zookeeper OpsRe...
zookeeper
zookeeper
Updated/New
StatefulSet
Upda...
refers to
refers to
Updated zookeeper
Upgrad...
Text is not SVG - cannot display
\ No newline at end of file +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
4.Initiate Update
4.Initiate Upgr...
6.Pause
6.Pause
7.Update & Perform Checks
7.Update & Perform...
8.Update Image
8.Update Image
9.Resume
9.Resume
Updating stage
Updating stage
User
User
                Provisioner            
           StatefulSet
Statef...
5.Watch
5.Watch
            Ops Manager            
ZooKeeper OpsRequest
ZooKeeper OpsRe...
ZooKeeper
ZooKeeper
Updated/New
StatefulSet
Upda...
refers to
refers to
Updated ZooKeeper
Upgrad...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/day-2-operation/zookeeper/zk-vertical-scaling.svg b/docs/images/day-2-operation/zookeeper/zk-vertical-scaling.svg new file mode 100644 index 0000000000..eb0e06d1f5 --- /dev/null +++ b/docs/images/day-2-operation/zookeeper/zk-vertical-scaling.svg @@ -0,0 +1,4 @@ + + +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
refers to
refers to
4.Initiate Vertical Scaling
4.Initiate Ve...
6.Pause
6.Pause
7.Scaling Resources
7.Scaling Resources
8.Update Resources
8.Update Resources
9.Resume
9.Resume
Vertical Scaling stage
Vertical Scaling stage
User
User
                Provisioner            
              
              
StatefulSet's
Pod
Stateful...
5.Watch
5.Wat...
            Ops Manager            
ZooKeeper
ZooKeeper
Updated
ZooKeeper
Update...
ZooKeeper OpsRequest
ZooKeeper Ops...
StatefulSet's
Pod updated
StatefulSet's...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/day-2-operation/zookeeper/zk-volume-expansion.svg b/docs/images/day-2-operation/zookeeper/zk-volume-expansion.svg new file mode 100644 index 0000000000..a9700e964c --- /dev/null +++ b/docs/images/day-2-operation/zookeeper/zk-volume-expansion.svg @@ -0,0 +1,3 @@ + + +
1.Create ZooKeeper
1.Create ZooKeeper
2.Watch
2.Watch
3.Create
3.Create
5.Initiate Volume Expansion
5.Initiate Volu...
7.Pause
7.Pause
8.Expand Volume
8.Expand Volume
9.Update Volume
9.Update Volume
10.Resume
10.Resume
Volume Expansion stage
Volume Expansion stage
User
User
            Provisioner        
              
              
Persistent
Volume
Persiste...
6.Watch
6.Watch
            Ops Manager            
ZooKeeper
 OpsReques
t
ZooKeeper...
ZooKeeper
ZooKeeper
              
              
StatefulSet
Stateful...
Expanded Persistent 
Volume
Expanded...
4.Create
4.Create
refers to
refers to
Updated
ZooKeeper
Update...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/docs/images/zookeeper/zk-builtin-prom-target.png b/docs/images/zookeeper/zk-builtin-prom-target.png new file mode 100644 index 0000000000000000000000000000000000000000..15937cd1f38b1c8219568b1d0b1c45b3c9f6e7f7 GIT binary patch literal 129554 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 i+~r0vCcnXn%}|cj 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%0DyoB~gZT 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 literal 0 HcmV?d00001 diff --git a/docs/images/zookeeper/zk-tls.svg b/docs/images/zookeeper/zk-tls.svg new file mode 100644 index 0000000000..b0a3cc5be0 --- /dev/null +++ b/docs/images/zookeeper/zk-tls.svg @@ -0,0 +1,4 @@ + + + +            Ops Manager                          Provisioner            
service
se...
secret
se...
tls-secret
tls-secret
Cert- manager
Cert- ma...
StatefulSet
Statef...
Issuer/Cluster Issuer
Issuer...
ZooKeeper
ZooKeeper
Certificates
Certif...
User
User
2.Create
2.Create
1.Create
1.Create
5a.Watch
5a.Watch
3.Watch
3.Watch
4.Create
4.Create
5c.Watch
5c.Watch
6.Create
6.Create
7.Watch
7.Watch
uses
uses
8.Create
8.Create
9.Watch
9.Watch
10.Create
10.Create
5b.Watch
5b.Watch
refers to
refers to
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/images/zookeeper/zookeeper-prometheus.png b/docs/images/zookeeper/zookeeper-prometheus.png new file mode 100644 index 0000000000000000000000000000000000000000..ad73f32458441a566fb7871af54c627956cc23e2 GIT binary patch literal 114166 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

)3na9ISTuTK*=6vMwwk?M=fC=}vw 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 literal 0 HcmV?d00001