From dbbbf70b98e658e34abaa9a6c038126613d4d7ef Mon Sep 17 00:00:00 2001 From: the-redback Date: Mon, 12 Feb 2018 12:54:32 +0600 Subject: [PATCH 1/5] Improve structure of MongoDB User Guide --- docs/concepts/databases/mongodb.md | 30 +- .../mongodb/{ => Initialization}/demo-1.yaml | 2 +- .../mongodb/Initialization/demo-2.yaml | 18 + .../monitoring/builtin-prometheus/demo-1.yaml | 16 + .../monitoring/coreos-operator/demo-1.yaml} | 9 +- .../mongodb/private-registry/demo-1.yaml | 8 + .../mongodb/private-registry/demo-2.yaml | 17 + docs/examples/mongodb/quickstart/demo-1.yaml | 15 + docs/examples/mongodb/snapshot/demo-1.yaml | 15 + .../mongodb/{ => snapshot}/demo-2.yaml | 4 +- .../{demo-4.yaml => snapshot/demo-3.yaml} | 5 +- .../{demo-3.yaml => snapshot/demo-4.yaml} | 2 +- .../monitoring/builtin-prometheus/demo-0.yaml | 7 + .../monitoring/builtin-prometheus/demo-1.yaml | 43 ++ .../monitoring/builtin-prometheus/demo-2.yaml | 51 ++ .../builtin-prometheus/rbac/demo-2.yaml | 92 +++ .../{ => coreos-operator}/demo-0.yaml | 3 +- .../{ => coreos-operator}/demo-1.yaml | 3 +- .../coreos-operator/rbac/demo-0.yaml | 110 +++ .../coreos-operator/rbac/demo-1.yaml | 72 ++ docs/examples/mysql/demo-4.yaml | 1 + docs/guides/README.md | 2 +- docs/guides/mongodb/README.md | 48 ++ .../mongodb/initialization/using-script.md | 269 +++++++ .../mongodb/initialization/using-snapshot.md | 126 +++ .../monitoring/using-builtin-prometheus.md | 371 +++++++++ .../using-coreos-prometheus-operator.md | 321 ++++++++ docs/guides/mongodb/overview.md | 727 ------------------ .../using-private-registry.md | 180 +++++ docs/guides/mongodb/quickstart/quickstart.md | 429 +++++++++++ .../mongodb/snapshot/backup-and-restore.md | 311 ++++++++ .../mongodb/snapshot/scheduled-backup.md | 191 +++++ docs/images/mongodb/builtin-prometheus.png | Bin 0 -> 58533 bytes docs/images/mongodb/mgo-lifecycle.png | Bin 0 -> 70464 bytes docs/images/mongodb/mgo-scheduled.png | Bin 0 -> 36966 bytes docs/setup/install.md | 31 + docs/setup/uninstall.md | 5 + 37 files changed, 2786 insertions(+), 748 deletions(-) rename docs/examples/mongodb/{ => Initialization}/demo-1.yaml (94%) create mode 100644 docs/examples/mongodb/Initialization/demo-2.yaml create mode 100644 docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml rename docs/examples/{monitoring/demo-2.yaml => mongodb/monitoring/coreos-operator/demo-1.yaml} (76%) create mode 100644 docs/examples/mongodb/private-registry/demo-1.yaml create mode 100644 docs/examples/mongodb/private-registry/demo-2.yaml create mode 100644 docs/examples/mongodb/quickstart/demo-1.yaml create mode 100644 docs/examples/mongodb/snapshot/demo-1.yaml rename docs/examples/mongodb/{ => snapshot}/demo-2.yaml (78%) rename docs/examples/mongodb/{demo-4.yaml => snapshot/demo-3.yaml} (78%) rename docs/examples/mongodb/{demo-3.yaml => snapshot/demo-4.yaml} (95%) create mode 100644 docs/examples/monitoring/builtin-prometheus/demo-0.yaml create mode 100644 docs/examples/monitoring/builtin-prometheus/demo-1.yaml create mode 100644 docs/examples/monitoring/builtin-prometheus/demo-2.yaml create mode 100644 docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml rename docs/examples/monitoring/{ => coreos-operator}/demo-0.yaml (90%) rename docs/examples/monitoring/{ => coreos-operator}/demo-1.yaml (91%) create mode 100644 docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml create mode 100644 docs/examples/monitoring/coreos-operator/rbac/demo-1.yaml create mode 100644 docs/guides/mongodb/README.md create mode 100644 docs/guides/mongodb/initialization/using-script.md create mode 100644 docs/guides/mongodb/initialization/using-snapshot.md create mode 100644 docs/guides/mongodb/monitoring/using-builtin-prometheus.md create mode 100644 docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md delete mode 100644 docs/guides/mongodb/overview.md create mode 100644 docs/guides/mongodb/private-registry/using-private-registry.md create mode 100644 docs/guides/mongodb/quickstart/quickstart.md create mode 100644 docs/guides/mongodb/snapshot/backup-and-restore.md create mode 100644 docs/guides/mongodb/snapshot/scheduled-backup.md create mode 100644 docs/images/mongodb/builtin-prometheus.png create mode 100644 docs/images/mongodb/mgo-lifecycle.png create mode 100644 docs/images/mongodb/mgo-scheduled.png diff --git a/docs/concepts/databases/mongodb.md b/docs/concepts/databases/mongodb.md index 85cd33d23..c403d4613 100644 --- a/docs/concepts/databases/mongodb.md +++ b/docs/concepts/databases/mongodb.md @@ -36,7 +36,7 @@ spec: requests: storage: 50Mi databaseSecret: - secretName: mgo1-admin-auth + secretName: mgo1-auth nodeSelector: disktype: ssd init: @@ -59,7 +59,7 @@ spec: cpu: "500m" doNotPause: true monitor: - agent: coreos-prometheus-operator + agent: prometheus.io/coreos-operator prometheus: namespace: demo labels: @@ -88,15 +88,26 @@ spec: - `spec.storage.resources` can be used to request specific quantities of storage. This follows the same resource model used by PVCs. To learn how to configure `spec.storage`, please visit the links below: + - https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims ### spec.databaseSecret -`spec.databaseSecret` is an optional field that points to a Secret used to hold credentials for `mongodb` super user. If not set, KubeDB operator creates a new Secret `{mongodb-object-name}-admin-auth` for storing the password for `mongodb` superuser for each MongoDB object. If you want to use an existing secret please specify that when creating the MongoDB object using `spec.databaseSecret.secretName`. +`spec.databaseSecret` is an optional field that points to a Secret used to hold credentials for `mongodb` super user. If not set, KubeDB operator creates a new Secret `{mongodb-object-name}-auth` for storing the password for `mongodb` superuser for each MongoDB object. If you want to use an existing secret please specify that when creating the MongoDB object using `spec.databaseSecret.secretName`. -This secret contains a `.admin` key which contains the password for `mongodb` superuser. Example: +This secret contains a `user` key and a `password` key which contains the `username` and `password` respectively for `mongodb` superuser. Example: ```ini -vPlT2PzewCaC3XZP +apiVersion: v1 +data: + password: NnE4dV8yak1PVy1PT1pYaw== + user: cm9vdA== +kind: Secret +metadata: + ... + name: mgo1-auth + namespace: demo + ... +type: Opaque ``` @@ -163,17 +174,20 @@ KubeDB supports taking periodic snapshots for MongoDB database. This is an optio ### spec.doNotPause `spec.doNotPause` is an optional field that tells KubeDB operator that if this MongoDB object is deleted, whether it should be reverted automatically. This should be set to `true` for production databases to avoid accidental deletion. If not set or set to false, deleting a MongoDB object put the database into a dormant state. THe StatefulSet for a DormantDatabase is deleted but the underlying PVCs are left intact. This allows user to resume the database later. +### spec.imagePullSecret +`KubeDB` provides the flexibility of deploying MongoDB database from a Private Docker Registry. To learn how to deploym MongoDB from a Private Registry, please visit [here](/docs/guides/mongodb/private-registry/using-private-registry.md). ### spec.monitor -To learn how to monitor MongoDB databases, please visit [here](/docs/concepts/monitoring.md). - +MongoDB can be monitored with KubeDB using out-of-the-box builtin-Prometheus and out-of-the-box CoreOS-Prometheus Operator. To learn more, + - [Monitor MongoDB with builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md) + - [Monitor MongoDB with CoreOS-Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md) ### spec.resources `spec.resources` is an optional field. This can be used to request compute resources required by the database pods. To learn more, visit [here](http://kubernetes.io/docs/user-guide/compute-resources/). ## Next Steps -- Learn how to use KubeDB to run a MongoDB database [here](/docs/guides/mongodb/overview.md). +- Learn how to use KubeDB to run a MongoDB database [here](/docs/guides/mongodb/README.md). - See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). - Thinking about monitoring your database? KubeDB works [out-of-the-box with Prometheus](/docs/guides/monitoring.md). - Learn how to use KubeDB in a [RBAC](/docs/guides/rbac.md) enabled cluster. diff --git a/docs/examples/mongodb/demo-1.yaml b/docs/examples/mongodb/Initialization/demo-1.yaml similarity index 94% rename from docs/examples/mongodb/demo-1.yaml rename to docs/examples/mongodb/Initialization/demo-1.yaml index 9862be5f5..1d68762f1 100644 --- a/docs/examples/mongodb/demo-1.yaml +++ b/docs/examples/mongodb/Initialization/demo-1.yaml @@ -1,7 +1,7 @@ apiVersion: kubedb.com/v1alpha1 kind: MongoDB metadata: - name: mgo1 + name: mgo-init-script namespace: demo spec: version: 3.4 diff --git a/docs/examples/mongodb/Initialization/demo-2.yaml b/docs/examples/mongodb/Initialization/demo-2.yaml new file mode 100644 index 000000000..7c8dbf61f --- /dev/null +++ b/docs/examples/mongodb/Initialization/demo-2.yaml @@ -0,0 +1,18 @@ +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-init-snapshot + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + init: + snapshotSource: + name: snapshot-infant + namespace: demo diff --git a/docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml b/docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml new file mode 100644 index 000000000..14caaa075 --- /dev/null +++ b/docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml @@ -0,0 +1,16 @@ +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-mon-prometheus + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + monitor: + agent: prometheus.io/builtin diff --git a/docs/examples/monitoring/demo-2.yaml b/docs/examples/mongodb/monitoring/coreos-operator/demo-1.yaml similarity index 76% rename from docs/examples/monitoring/demo-2.yaml rename to docs/examples/mongodb/monitoring/coreos-operator/demo-1.yaml index e17fc03f3..51ddd65b7 100644 --- a/docs/examples/monitoring/demo-2.yaml +++ b/docs/examples/mongodb/monitoring/coreos-operator/demo-1.yaml @@ -1,10 +1,10 @@ apiVersion: kubedb.com/v1alpha1 -kind: Postgres +kind: MongoDB metadata: - name: pmon + name: mgo-mon-coreos namespace: demo spec: - version: 9.5 + version: 3.4 storage: storageClassName: "standard" accessModes: @@ -13,9 +13,10 @@ spec: requests: storage: 50Mi monitor: - agent: coreos-prometheus-operator + agent: prometheus.io/coreos-operator prometheus: namespace: demo labels: app: kubedb interval: 10s + diff --git a/docs/examples/mongodb/private-registry/demo-1.yaml b/docs/examples/mongodb/private-registry/demo-1.yaml new file mode 100644 index 000000000..eafdf211f --- /dev/null +++ b/docs/examples/mongodb/private-registry/demo-1.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: myregistrykey + namespace: demo +data: + .dockerconfigjson: +type: kubernetes.io/dockerconfigjson diff --git a/docs/examples/mongodb/private-registry/demo-2.yaml b/docs/examples/mongodb/private-registry/demo-2.yaml new file mode 100644 index 000000000..a810c67c8 --- /dev/null +++ b/docs/examples/mongodb/private-registry/demo-2.yaml @@ -0,0 +1,17 @@ +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-pvt-reg + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + imagePullSecrets: + - name: myregistrykey diff --git a/docs/examples/mongodb/quickstart/demo-1.yaml b/docs/examples/mongodb/quickstart/demo-1.yaml new file mode 100644 index 000000000..509737fd3 --- /dev/null +++ b/docs/examples/mongodb/quickstart/demo-1.yaml @@ -0,0 +1,15 @@ +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-quickstart + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi diff --git a/docs/examples/mongodb/snapshot/demo-1.yaml b/docs/examples/mongodb/snapshot/demo-1.yaml new file mode 100644 index 000000000..cbe1bb9a2 --- /dev/null +++ b/docs/examples/mongodb/snapshot/demo-1.yaml @@ -0,0 +1,15 @@ +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-infant + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi diff --git a/docs/examples/mongodb/demo-2.yaml b/docs/examples/mongodb/snapshot/demo-2.yaml similarity index 78% rename from docs/examples/mongodb/demo-2.yaml rename to docs/examples/mongodb/snapshot/demo-2.yaml index dd490b072..42d92be3a 100644 --- a/docs/examples/mongodb/demo-2.yaml +++ b/docs/examples/mongodb/snapshot/demo-2.yaml @@ -1,12 +1,12 @@ apiVersion: kubedb.com/v1alpha1 kind: Snapshot metadata: - name: mgo-xyz + name: snapshot-infant namespace: demo labels: kubedb.com/kind: MongoDB spec: - databaseName: mgo1 + databaseName: mgo-infant storageSecretName: mg-snap-secret gcs: bucket: restic diff --git a/docs/examples/mongodb/demo-4.yaml b/docs/examples/mongodb/snapshot/demo-3.yaml similarity index 78% rename from docs/examples/mongodb/demo-4.yaml rename to docs/examples/mongodb/snapshot/demo-3.yaml index 4e87a3607..79ba20b8f 100644 --- a/docs/examples/mongodb/demo-4.yaml +++ b/docs/examples/mongodb/snapshot/demo-3.yaml @@ -1,7 +1,7 @@ apiVersion: kubedb.com/v1alpha1 kind: MongoDB metadata: - name: recovered + name: mgo-recovered namespace: demo spec: version: 3.4 @@ -14,4 +14,5 @@ spec: storage: 50Mi init: snapshotSource: - name: mgo-xyz + name: snapshot-infant + namespace: demo diff --git a/docs/examples/mongodb/demo-3.yaml b/docs/examples/mongodb/snapshot/demo-4.yaml similarity index 95% rename from docs/examples/mongodb/demo-3.yaml rename to docs/examples/mongodb/snapshot/demo-4.yaml index fc2ed1971..281950650 100644 --- a/docs/examples/mongodb/demo-3.yaml +++ b/docs/examples/mongodb/snapshot/demo-4.yaml @@ -1,7 +1,7 @@ apiVersion: kubedb.com/v1alpha1 kind: MongoDB metadata: - name: mgo1 + name: mgo-scheduled namespace: demo spec: version: 3.4 diff --git a/docs/examples/monitoring/builtin-prometheus/demo-0.yaml b/docs/examples/monitoring/builtin-prometheus/demo-0.yaml new file mode 100644 index 000000000..1d9f59eb3 --- /dev/null +++ b/docs/examples/monitoring/builtin-prometheus/demo-0.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: demo +spec: + finalizers: + - kubernetes diff --git a/docs/examples/monitoring/builtin-prometheus/demo-1.yaml b/docs/examples/monitoring/builtin-prometheus/demo-1.yaml new file mode 100644 index 000000000..8803354f8 --- /dev/null +++ b/docs/examples/monitoring/builtin-prometheus/demo-1.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-server-conf + labels: + name: prometheus-server-conf + namespace: demo +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name diff --git a/docs/examples/monitoring/builtin-prometheus/demo-2.yaml b/docs/examples/monitoring/builtin-prometheus/demo-2.yaml new file mode 100644 index 000000000..ffd6b710c --- /dev/null +++ b/docs/examples/monitoring/builtin-prometheus/demo-2.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} + +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-service + namespace: demo +spec: + selector: + app: prometheus-server + type: LoadBalancer + ports: + - port: 9090 + targetPort: 9090 + nodePort: 30901 + diff --git a/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml b/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml new file mode 100644 index 000000000..f92abf11d --- /dev/null +++ b/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml @@ -0,0 +1,92 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: prometheus-server +rules: +- apiGroups: [""] + resources: + - nodes + - nodes/proxy + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: + - extensions + resources: + - ingresses + verbs: ["get", "list", "watch"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-server + namespace: demo +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: prometheus-server +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-server +subjects: +- kind: ServiceAccount + name: prometheus-server + namespace: demo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + serviceAccountName: prometheus-server + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} + +--- + +apiVersion: v1 +kind: Service +metadata: + name: prometheus-service + namespace: demo +spec: + selector: + app: prometheus-server + type: NodePort + ports: + - port: 9090 + targetPort: 9090 + nodePort: 30901 \ No newline at end of file diff --git a/docs/examples/monitoring/demo-0.yaml b/docs/examples/monitoring/coreos-operator/demo-0.yaml similarity index 90% rename from docs/examples/monitoring/demo-0.yaml rename to docs/examples/monitoring/coreos-operator/demo-0.yaml index ce6ef4c8b..2705d23f8 100644 --- a/docs/examples/monitoring/demo-0.yaml +++ b/docs/examples/monitoring/coreos-operator/demo-0.yaml @@ -5,6 +5,7 @@ metadata: spec: finalizers: - kubernetes + --- apiVersion: extensions/v1beta1 kind: Deployment @@ -22,7 +23,7 @@ spec: spec: containers: - name: prometheus-operator - image: quay.io/coreos/prometheus-operator:v0.10.1 + image: quay.io/coreos/prometheus-operator:v0.14.0 resources: requests: cpu: 100m diff --git a/docs/examples/monitoring/demo-1.yaml b/docs/examples/monitoring/coreos-operator/demo-1.yaml similarity index 91% rename from docs/examples/monitoring/demo-1.yaml rename to docs/examples/monitoring/coreos-operator/demo-1.yaml index f43ea6501..54221bb4f 100644 --- a/docs/examples/monitoring/demo-1.yaml +++ b/docs/examples/monitoring/coreos-operator/demo-1.yaml @@ -1,4 +1,4 @@ -apiVersion: monitoring.coreos.com/v1alpha1 +apiVersion: monitoring.coreos.com/v1 kind: Prometheus metadata: name: prometheus @@ -11,6 +11,7 @@ spec: resources: requests: memory: 400Mi + --- apiVersion: v1 kind: Service diff --git a/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml b/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml new file mode 100644 index 000000000..74e67ba15 --- /dev/null +++ b/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: demo +spec: + finalizers: + - kubernetes + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: prometheus-operator +rules: +- apiGroups: + - extensions + resources: + - thirdpartyresources + verbs: + - "*" +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - "*" +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + verbs: + - "*" +- apiGroups: + - apps + resources: + - statefulsets + verbs: ["*"] +- apiGroups: [""] + resources: + - configmaps + - secrets + verbs: ["*"] +- apiGroups: [""] + resources: + - pods + verbs: ["list", "delete"] +- apiGroups: [""] + resources: + - services + - endpoints + verbs: ["get", "create", "update"] +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +- apiGroups: [""] + resources: + - namespaces + verbs: ["list"] + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus-operator + namespace: demo + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: prometheus-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-operator +subjects: +- kind: ServiceAccount + name: prometheus-operator + namespace: demo + +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: prometheus-operator + namespace: demo + labels: + operator: prometheus +spec: + replicas: 1 + template: + metadata: + labels: + operator: prometheus + spec: + serviceAccountName: prometheus-operator + containers: + - name: prometheus-operator + image: quay.io/coreos/prometheus-operator:v0.14.0 + resources: + requests: + cpu: 100m + memory: 50Mi + limits: + cpu: 200m + memory: 100Mi + diff --git a/docs/examples/monitoring/coreos-operator/rbac/demo-1.yaml b/docs/examples/monitoring/coreos-operator/rbac/demo-1.yaml new file mode 100644 index 000000000..595da2f62 --- /dev/null +++ b/docs/examples/monitoring/coreos-operator/rbac/demo-1.yaml @@ -0,0 +1,72 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: prometheus +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: demo + +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus +subjects: +- kind: ServiceAccount + name: prometheus + namespace: demo + +--- +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: demo +spec: + serviceAccountName: prometheus + serviceMonitorSelector: + matchLabels: + app: kubedb + version: v1.7.0 + resources: + requests: + memory: 400Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: demo +spec: + type: LoadBalancer + ports: + - name: web + nodePort: 30900 + port: 9090 + protocol: TCP + targetPort: web + selector: + prometheus: prometheus diff --git a/docs/examples/mysql/demo-4.yaml b/docs/examples/mysql/demo-4.yaml index 1f53ce57a..921fa162c 100644 --- a/docs/examples/mysql/demo-4.yaml +++ b/docs/examples/mysql/demo-4.yaml @@ -15,3 +15,4 @@ spec: init: snapshotSource: name: m1-xyz + namespace: demo diff --git a/docs/guides/README.md b/docs/guides/README.md index b8303a782..83e498523 100644 --- a/docs/guides/README.md +++ b/docs/guides/README.md @@ -23,7 +23,7 @@ Guides show you how to perform tasks with KubeDB. - [Running MySQL](/docs/guides/mysql/overview.md): This tutorial will show you how to use KubeDB to run a MySQL database. - - [Running MongoDB](/docs/guides/mongodb/overview.md): This tutorial will show you how to use KubeDB to run a MongoDB database. + - [Running MongoDB](/docs/guides/mongodb/README.md): This tutorial will show you how to use KubeDB to run a MongoDB database. - [Running Redis](/docs/guides/redis/overview.md): This tutorial will show you how to use KubeDB to run a Redis database. diff --git a/docs/guides/mongodb/README.md b/docs/guides/mongodb/README.md new file mode 100644 index 000000000..04aa9c782 --- /dev/null +++ b/docs/guides/mongodb/README.md @@ -0,0 +1,48 @@ + + +> New to KubeDB? Please start [here](/docs/guides/README.md). + +## MongoDB versions supported by KubeDB + +| KubeDB Version | Mongo:3.4 | Mongo:3.6 | +|:--:|:--:|:--:| +| 0.1.0 - 0.7.0 | ✗ | ✗ | +| 0.8.0-beta.0 | ✓ | ✓ | +| 0.8.0-beta.1 | ✓ | ✓ | + +
+ +## KubeDB Features and their availability for MongoDB + +|Features |Availability| +|--|:--:| +|Clustering | ✗ | +|Persistent Volume | ✓ | +|Instant Backup | ✓ | +|Scheduled Backup | ✓ | +|Initialize using Snapshot | ✓ | +|Initialize using Script (\*.js and/or \*.sh) | ✓ | +|out-of-the-box builtin-Prometheus Monitoring | ✓ | +|out-of-the-box CoreOS-Prometheus-Operator Monitoring | ✓ | + +
+ +## Life Cycle of MongoDB in KubeDB +

+  lifecycle +

+ + +## User Guide +- [Quickstart MongoDB](/docs/guides/mongodb/quickstart/quickstart.md) with KubeDB Operator. +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Detail concepts of [Snapshot object](/docs/concepts/snapshot.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/initialization/using-script.md b/docs/guides/mongodb/initialization/using-script.md new file mode 100644 index 000000000..e4ea62dd8 --- /dev/null +++ b/docs/guides/mongodb/initialization/using-script.md @@ -0,0 +1,269 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Initialize MongoDB with \*.js and/or \*.sh Script +This tutorial will show you how to use KubeDB to initialize a MongoDB database with .js and/or .sh script. + +## 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +kube-system Active 45m +``` + +In this tutorial we will use .js script stored in GitHub repository [kubedb/mongodb-init-scripts](https://github.com/kubedb/mongodb-init-scripts). + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create a MongoDB database with Init-Script +Below is the `MongoDB` object created in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-init-script + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + init: + scriptSource: + gitRepo: + repository: "https://github.com/kubedb/mongodb-init-scripts.git" + directory: . + +``` + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/Initialization/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/Initialization/demo-1.yaml" +mongodb "mgo-init-script" created +``` + + +Here, + + - `spec.version` is the version of MongoDB database. In this tutorial, a MongoDB 3.4 database is going to be created. + + - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. + + - `spec.init.scriptSource` specifies a script source used to initialize the database before database server starts. The scripts will be executed alphabatically. In this tutorial, a sample .js script from the git repository `https://github.com/kubedb/mongodb-init-scripts.git` is used to create a test database. You can use other [volume sources](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes) instead of `gitrepo`. The \*.js and/or \*.sh sripts that are stored inside the root folder will be executed alphabatically. The scripts inside child folders will be skipped. + +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. Even if [RBAC is enabled](/docs/guides/rbac.md), it won't affect anything to run MongoDB database . + +```console +$ kubedb describe mg -n demo mgo-init-script +Name: mgo-init-script +Namespace: demo +StartTimestamp: Tue, 06 Feb 2018 09:56:07 +0600 +Status: Running +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-init-script + Replicas: 1 current / 1 desired + CreationTimestamp: Tue, 06 Feb 2018 09:56:12 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-init-script + Type: ClusterIP + IP: 10.106.175.209 + Port: db 27017/TCP + +Database Secret: + Name: mgo-init-script-auth + Type: Opaque + Data + ==== + password: 16 bytes + user: 4 bytes + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 6s 6s 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 6s 6s 1 MongoDB operator Normal Successful Successfully patched MongoDB + 9s 9s 1 MongoDB operator Normal Successful Successfully created StatefulSet + 9s 9s 1 MongoDB operator Normal Successful Successfully created MongoDB + 18s 18s 1 MongoDB operator Normal Successful Successfully created Service + + + +$ kubectl get statefulset -n demo +NAME DESIRED CURRENT AGE +mgo-init-script 1 1 46s + + + +$ kubectl get pvc -n demo +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +data-mgo-init-script-0 Bound pvc-ac84fbb9-0af1-11e8-a107-080027869227 50Mi RWO standard 1m + + + +$ kubectl get pv -n demo +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE +pvc-ac84fbb9-0af1-11e8-a107-080027869227 50Mi RWO Delete Bound demo/data-mgo-init-script-0 standard + + +$ kubectl get service -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 2m +mgo-init-script ClusterIP 10.106.175.209 27017/TCP 2m +``` + + +KubeDB operator sets the `status.phase` to `Running` once the database is successfully created. Run the following command to see the modified MongoDB object: + +```yaml +$ kubedb get mg -n demo mgo-init-script -o yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + clusterName: "" + creationTimestamp: 2018-02-06T03:56:07Z + finalizers: + - kubedb.com + generation: 0 + name: mgo-init-script + namespace: demo + resourceVersion: "4827" + selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo-init-script + uid: a9348cad-0af1-11e8-a107-080027869227 +spec: + databaseSecret: + secretName: mgo-init-script-auth + doNotPause: true + init: + scriptSource: + gitRepo: + directory: . + repository: https://github.com/kubedb/mongodb-init-scripts.git + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + storageClassName: standard + version: 3.4 +status: + creationTime: 2018-02-06T03:56:12Z + phase: Running +``` + +Please note that KubeDB operator has created a new Secret called `mgo-init-script-auth` *(format: {mongodb-object-name}-auth)* for storing the password for MongoDB superuser. This secret contains a `user` key which contains the *username* for MongoDB superuser and a `password` key which contains the *password* for MongoDB superuser. +If you want to use an existing secret please specify that when creating the MongoDB object using `spec.databaseSecret.secretName`. While creating this secret manually, make sure the secret contains these two keys containing data `user` and `password`. + +```console +$ kubectl get secrets -n demo mgo-init-script-auth -o json +apiVersion: v1 +data: + password: STJ1YnNiU3BUNzFOZUhXSA== + user: cm9vdA== +kind: Secret +metadata: + creationTimestamp: 2018-02-06T03:56:12Z + labels: + kubedb.com/kind: MongoDB + kubedb.com/name: mgo-init-script + name: mgo-init-script-auth + namespace: demo + resourceVersion: "4789" + selfLink: /api/v1/namespaces/demo/secrets/mgo-init-script-auth + uid: ac33c72d-0af1-11e8-a107-080027869227 +type: Opaque +``` + + +Now, you can connect to this database through [mongo-shell](https://docs.mongodb.com/v3.4/mongo/). In this tutorial, we are connecting to the MongoDB server from inside the pod. + +```console +$ kubectl get secrets -n demo mgo-init-script-auth -o jsonpath='{.data.\user}' | base64 -d +root + +$ kubectl get secrets -n demo mgo-init-script-auth -o jsonpath='{.data.\password}' | base64 -d +I2ubsbSpT71NeHWH + +$ kubectl exec -it mgo-init-script-0 -n demo sh + +> mongo admin +MongoDB shell version v3.4.10 +connecting to: mongodb://127.0.0.1:27017/admin +MongoDB server version: 3.4.10 +Welcome to the MongoDB shell. +For interactive help, type "help". +For more comprehensive documentation, see + http://docs.mongodb.org/ +Questions? Try the support group + http://groups.google.com/group/mongodb-user + +> db.auth("root","I2ubsbSpT71NeHWH") +1 + +> show dbs +admin 0.000GB +local 0.000GB +mydb 0.000GB + +> use mydb +switched to db mydb + +> db.movie.find() +{ "_id" : ObjectId("5a72b2b1e1a0770e3bdb56f1"), "name" : "batman" } + +> exit +bye +``` + +As you can see here, the initial script has successfully created a database named `mydb` and inserted data into that database successfully. + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/initialization/using-snapshot.md b/docs/guides/mongodb/initialization/using-snapshot.md new file mode 100644 index 000000000..72f893642 --- /dev/null +++ b/docs/guides/mongodb/initialization/using-snapshot.md @@ -0,0 +1,126 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Initialize MongoDB with Snapshot +This tutorial will show you how to use KubeDB to initialize a MongoDB database with an existing snapshot. + +## 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +A `Snapshot` is needed to be existed for this tutorial. Please follow the tutorial of [Snapshot](/docs/guides/mongodb/snapshot/backup-and-restore.md) to create a database and take [Instant Snapshot/Backup](/docs/guides/mongodb/snapshot/backup-and-restore.md#instant-backups) of that database. +Assuming you have created a namespace `demo` and a snapshot `snapshot-infant`, below there is an illustration of initializing a database with `snapshot-infant` snapshot. +If you have changed any of the names of namespace or snapshot, please modify the yamls that you will face while going through this tutorial to meet your specific namespace and snapshot name. + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create MongoDB with Init-Snapshot +Below is the `MongoDB` object created in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-init-snapshot + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + init: + snapshotSource: + name: snapshot-infant + namespace: demo +``` + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/Initialization/demo-2.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/Initialization/demo-2.yaml" +mongodb "mgo-init-snapshot" created +``` + +Here, + + - `spec.init.snapshotSource.name` refers to a Snapshot object for a MongoDB database in the same namespaces as this new `mgo-init-snapshot` MongoDB object. + +Now, wait several seconds. KubeDB operator will create a new StatefulSet. Then KubeDB operator launches a Kubernetes Job to initialize the new database using the data from `snapshot-infant` Snapshot. + +```console +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-infant Running 24m +mgo-init-snapshot Initializing 6s + + +$ kubedb describe mg -n demo mgo-init-snapshot +Name: mgo-init-snapshot +Namespace: demo +StartTimestamp: Tue, 06 Feb 2018 10:34:30 +0600 +Status: Running +Annotations: kubedb.com/initialized= +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-init-snapshot + Replicas: 1 current / 1 desired + CreationTimestamp: Tue, 06 Feb 2018 10:11:54 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-init-snapshot + Type: ClusterIP + IP: 10.100.233.80 + Port: db 27017/TCP + +Database Secret: + Name: mgo-init-snapshot-auth + Type: Opaque + Data + ==== + password: 16 bytes + user: 4 bytes + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 1m 1m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 1m 1m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 1m 1m 1 Job Controller Normal SuccessfulInitialize Successfully completed initialization + 1m 1m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 1m 1m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 1m 1m 1 MongoDB operator Normal Initializing Initializing from Snapshot: "snapshot-infant" + 1m 1m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 1m 1m 1 MongoDB operator Normal Successful Successfully patched MongoDB +``` + + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Detail concepts of [Snapshot object](/docs/concepts/snapshot.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md new file mode 100644 index 000000000..543039065 --- /dev/null +++ b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md @@ -0,0 +1,371 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Using Prometheus with KubeDB +This tutorial will show you how to monitor KubeDB databases using [Prometheus](https://prometheus.io/). + +## 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +kube-system Active 45m +``` + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create a MongoDB database +KubeDB implements a `MongoDB` CRD to define the specification of a MongoDB database. Below is the `MongoDB` object created in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-mon-prometheus + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + monitor: + agent: prometheus.io/builtin +``` + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/monitoring/builtin-prometheus/demo-1.yaml" +mongodb "mgo-mon-prometheus" created +``` + + +Here, + + - `spec.version` is the version of MongoDB database. In this tutorial, a MongoDB 3.4 database is going to be created. + + - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. + + - `spec.monitor` specifies that built-in [Prometheus](https://github.com/prometheus/prometheus) is used to monitor this database instance. KubeDB operator will configure the service of this database in a way that the Prometheus server will automatically find out the service endpoint aka `MongoDB Exporter` and will receive metrics from exporter. + +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching crd name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. + +```console +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-mon-prometheus Creating 30s + + +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-mon-prometheus Running 10m + +$ kubedb describe mg -n demo mgo-mon-prometheus +Name: mgo-mon-prometheus +Namespace: demo +StartTimestamp: Mon, 05 Feb 2018 17:38:29 +0600 +Status: Running +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-mon-prometheus + Replicas: 1 current / 1 desired + CreationTimestamp: Mon, 05 Feb 2018 17:37:54 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-mon-prometheus + Type: ClusterIP + IP: 10.104.88.103 + Port: db 27017/TCP + Port: prom-http 56790/TCP + +Database Secret: + Name: mgo-mon-prometheus-auth + Type: Opaque + Data + ==== + user: 4 bytes + password: 16 bytes + +Monitoring System: + Agent: prometheus.io/builtin + Prometheus: + Namespace: + Interval: + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 15m 15m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 15m 15m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 15m 15m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 15m 15m 1 MongoDB operator Normal Successful Successfully patched MongoDB +``` + + +Since `spec.monitoring` was configured, the database service object is configured accordingly. You can verify it running the following commands: + +```yaml +$ kubectl get services -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 22m +mgo-mon-prometheus ClusterIP 10.104.88.103 27017/TCP,56790/TCP 22m +``` + +```yaml +$ kubectl get services mgo-mon-prometheus -n demo -o yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + monitoring.appscode.com/agent: prometheus.io/builtin + prometheus.io/path: /kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo-mon-prometheus/metrics + prometheus.io/port: "56790" + prometheus.io/scrape: "true" + creationTimestamp: 2018-02-05T11:37:53Z + labels: + kubedb.com/kind: MongoDB + kubedb.com/name: mgo-mon-prometheus + name: mgo-mon-prometheus + namespace: demo + resourceVersion: "1709" + selfLink: /api/v1/namespaces/demo/services/mgo-mon-prometheus + uid: 00a3de77-0a69-11e8-9639-080027869227 +spec: + clusterIP: 10.104.88.103 + ports: + - name: db + port: 27017 + protocol: TCP + targetPort: db + - name: prom-http + port: 56790 + protocol: TCP + targetPort: prom-http + selector: + kubedb.com/kind: MongoDB + kubedb.com/name: mgo-mon-prometheus + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} +``` + +We can see that the service contains these specific annotations. The Prometheus server will discover the exporter using these specifications. +```yaml +prometheus.io/path: ... +prometheus.io/port: ... +prometheus.io/scrape: ... +``` + +## Deploy and configure Prometheus Server + +The Prometheus server is needed to configure so that it can discover endpoints of services. If a Prometheus server is already running in cluster and if it is configured in a way that it can discover service endpoints, no extra configuration will be needed. If there is no existing Prometheus server running, rest of this tutorial will create a Prometheus server with appropriate configuration. + +The configuration file to `Prometheus-Server` will be provided by `ConfigMap`. The below config map will be created: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-server-conf + labels: + name: prometheus-server-conf + namespace: demo +data: + prometheus.yml: |- + global: + scrape_interval: 5s + evaluation_interval: 5s + scrape_configs: + - job_name: 'kubernetes-service-endpoints' + + kubernetes_sd_configs: + - role: endpoints + + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name +``` + + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-1.yaml +configmap "prometheus-server-conf" created +``` + +Now, the below yaml is used to deploy Prometheus in kubernetes : +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-server + namespace: demo +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-server + template: + metadata: + labels: + app: prometheus-server + spec: + containers: + - name: prometheus + image: prom/prometheus:v2.1.0 + args: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus/" + ports: + - containerPort: 9090 + volumeMounts: + - name: prometheus-config-volume + mountPath: /etc/prometheus/ + - name: prometheus-storage-volume + mountPath: /prometheus/ + volumes: + - name: prometheus-config-volume + configMap: + defaultMode: 420 + name: prometheus-server-conf + - name: prometheus-storage-volume + emptyDir: {} +``` + +#### In RBAC enabled cluster +If RBAC *is* enabled, Run the following command to deploy prometheus in kubernetes: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml +clusterrole "prometheus-server" created +serviceaccount "prometheus-server" created +clusterrolebinding "prometheus-server" created +deployment "prometheus-server" created +service "prometheus-service" created + +# Verify RBAC stuffs +$ kubectl get clusterroles +NAME AGE +prometheus-server 57s + +$ kubectl get clusterrolebindings +NAME AGE +prometheus-server 1m + + +$ kubectl get serviceaccounts -n demo +NAME SECRETS AGE +default 1 48m +prometheus-server 1 1m +``` + + +#### In RBAC \*not\* enabled cluster +If RBAC *is not* enabled, Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-2.yaml +deployment "prometheus-server" created +service "prometheus-service" created + + +$ kubectl get pods -n demo --watch +NAME READY STATUS RESTARTS AGE +mgo-mon-prometheus-0 2/2 Running 0 48m +prometheus-server-79c7cf44fc-m95lm 1/1 Running 0 34s +``` + +#### Prometheus Dashboard +Now to open prometheus dashboard on Browser: + +```console +$ kubectl get svc -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 59m +mgo-mon-prometheus ClusterIP 10.104.88.103 27017/TCP,56790/TCP 59m +prometheus-service LoadBalancer 10.103.201.246 9090:30901/TCP 8s + + +$ minikube ip +192.168.99.100 + +$ minikube service prometheus-service -n demo --url +http://192.168.99.100:30901 +``` + + +Now, open your browser and go to the following URL: _http://{minikube-ip}:{prometheus-svc-nodeport}_ to visit Prometheus Dashboard. According to the above example, this URL will be [http://192.168.99.100:30901](http://192.168.99.100:30901). + +Now, if you go the Prometheus Dashboard, you should see that this database endpoint as one of the targets. +![prometheus-builtin](/docs/images/mongodb/builtin-prometheus.png) + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +# In rbac enabled cluster, +# $ kubectl delete clusterrole prometheus-server +# $ kubectl delete clusterrolebindings prometheus-server +# $ kubectl delete serviceaccounts -n demo prometheus-server + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + + +## Next Steps +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md b/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md new file mode 100644 index 000000000..92ab94aa8 --- /dev/null +++ b/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md @@ -0,0 +1,321 @@ + +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Using Prometheus (CoreOS operator) with KubeDB +This tutorial will show you how to monitor KubeDB databases using Prometheus via [CoreOS Prometheus Operator](https://github.com/coreos/prometheus-operator). + +## 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Deploy CoreOS-Prometheus Operator + +#### In RBAC enabled cluster +If RBAC *is* enabled, Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml +namespace "demo" created +clusterrole "prometheus-operator" created +serviceaccount "prometheus-operator" created +clusterrolebinding "prometheus-operator" created +deployment "prometheus-operator" created + +$ kubectl get pods -n demo --watch +NAME READY STATUS RESTARTS AGE +prometheus-operator-79cb9dcd4b-2njgq 1/1 Running 0 2m + + +$ kubectl get crd +NAME AGE +alertmanagers.monitoring.coreos.com 11m +prometheuses.monitoring.coreos.com 11m +servicemonitors.monitoring.coreos.com 11m +``` + + +Once the Prometheus operator CRDs are registered, run the following command to create a Prometheus. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/coreos-operator/rbac/demo-1.yaml +clusterrole "prometheus" created +serviceaccount "prometheus" created +clusterrolebinding "prometheus" created +prometheus "prometheus" created +service "prometheus" created + +# Verify RBAC stuffs +$ kubectl get clusterroles +NAME AGE +prometheus 48s +prometheus-operator 1m + + +$ kubectl get clusterrolebindings +NAME AGE +prometheus 7s +prometheus-operator 25s + + +$ kubectl get serviceaccounts -n demo +NAME SECRETS AGE +default 1 5m +prometheus 1 4m +prometheus-operator 1 5m +``` + + +#### In RBAC \*not\* enabled cluster +If RBAC *is not* enabled, Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/coreos-operator/demo-0.yaml +namespace "demo" created +deployment "prometheus-operator" created + + +$ kubectl get pods -n demo --watch +NAME READY STATUS RESTARTS AGE +prometheus-operator-5dcd844486-nprmk 0/1 ContainerCreating 0 27s +prometheus-operator-5dcd844486-nprmk 1/1 Running 0 46s + + +$ kubectl get crd +NAME AGE +alertmanagers.monitoring.coreos.com 45s +prometheuses.monitoring.coreos.com 44s +servicemonitors.monitoring.coreos.com 44s +``` + + +Once the Prometheus operator CRDs are registered, run the following command to create a Prometheus. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/coreos-operator/demo-1.yaml +prometheus "prometheus" created +service "prometheus" created + +``` + +#### Prometheus Dashboard +Now to open prometheus dashboard on Browser: + +```console +$ kubectl get svc -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +prometheus LoadBalancer 10.99.201.154 9090:30900/TCP 5m +prometheus-operated ClusterIP None 9090/TCP 5m + +$ minikube ip +192.168.99.100 + +$ minikube service prometheus -n demo --url +http://192.168.99.100:30900 +``` + + +Now, open your browser and go to the following URL: _http://{minikube-ip}:{prometheus-svc-nodeport}_ to visit Prometheus Dashboard. According to the above example, this URL will be [http://192.168.99.100:30900](http://192.168.99.100:30900). + +## Create a MongoDB database +KubeDB implements a `MongoDB` CRD to define the specification of a MongoDB database. Below is the `MongoDB` object created in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-mon-coreos + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + monitor: + agent: prometheus.io/coreos-operator + prometheus: + namespace: demo + labels: + app: kubedb + interval: 10s +``` + +The `MongoDB` CRD object contains `monitor` field in it's `spec`. It is also possible to add CoreOS-Prometheus monitor to an existing `MongoDB` database by adding the below part in it's `spec` field. +```yaml +spec: + monitor: + agent: prometheus.io/coreos-operator + prometheus: + namespace: demo + labels: + app: kubedb + interval: 10s +``` + +| Keys | Value | Description | +|--|--|--| +| `spec.monitor.agent` | string | `Required`. Indicates the monitoring agent used. Only valid value currently is `coreos-prometheus-operator` | +| `spec.monitor.prometheus.namespace` | string | `Required`. Indicates namespace where service monitors are created. This must be the same namespace of the Prometheus instance. | +| `spec.monitor.prometheus.labels` | map | `Required`. Indicates labels applied to service monitor. | +| `spec.monitor.prometheus.interval` | string | `Optional`. Indicates the scrape interval for database exporter endpoint (eg, '10s') | +| `spec.monitor.prometheus.port` | int |`Optional`. Indicates the port for database exporter endpoint (default is `56790`)| + +__Known Limitations:__ If the database password is updated, exporter must be restarted to use the new credentials. This issue is tracked [here](https://github.com/kubedb/project/issues/53). + +Run the following command to deploy the above `MongoDB` CRD object. + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/monitoring/coreos-operator/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/monitoring/coreos-operator/demo-1.yaml" +mongodb "mgo-mon-coreos" created +``` + + +Here, + + - `spec.version` is the version of MongoDB database. In this tutorial, a MongoDB 3.4 database is going to be created. + + - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. + + - `spec.monitor` specifies that CoreOS Prometheus operator is used to monitor this database instance. A ServiceMonitor should be created in the `demo` namespace with label `app=kubedb`. The exporter endpoint should be scrapped every 10 seconds. + +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching crd name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. + +```console +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-mon-coreos Creating 36s + +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-mon-coreos Running 1m + + +$ kubedb describe mg -n demo mgo-mon-coreos +Name: mgo-mon-coreos +Namespace: demo +StartTimestamp: Mon, 05 Feb 2018 11:20:20 +0600 +Status: Running +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-mon-coreos + Replicas: 1 current / 1 desired + CreationTimestamp: Mon, 05 Feb 2018 11:20:27 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-mon-coreos + Type: ClusterIP + IP: 10.107.145.36 + Port: db 27017/TCP + Port: prom-http 56790/TCP + +Database Secret: + Name: mgo-mon-coreos-auth + Type: Opaque + Data + ==== + password: 16 bytes + user: 4 bytes + +Monitoring System: + Agent: prometheus.io/coreos-operator + Prometheus: + Namespace: demo + Labels: app=kubedb + Interval: 10s + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 10m 10m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 10m 10m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 10m 10m 1 MongoDB operator Normal Successful Successfully created StatefulSet + 10m 10m 1 MongoDB operator Normal Successful Successfully created MongoDB + 11m 11m 1 MongoDB operator Normal Successful Successfully created Service +``` + + +Since `spec.monitoring` was configured, a ServiceMonitor object is created accordingly. You can verify it running the following commands: + +```yaml +$ kubectl get servicemonitor -n demo +NAME AGE +kubedb-demo-mgo-mon-coreos 11m + + + +$ kubectl get servicemonitor -n demo kubedb-demo-mgo-mon-coreos -o yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + clusterName: "" + creationTimestamp: 2018-02-05T05:20:46Z + labels: + app: kubedb + monitoring.appscode.com/service: mgo-mon-coreos.demo + name: kubedb-demo-mgo-mon-coreos + namespace: demo + resourceVersion: "57754" + selfLink: /apis/monitoring.coreos.com/v1/namespaces/demo/servicemonitors/kubedb-demo-mgo-mon-coreos + uid: 5215258a-0a34-11e8-8d7f-080027c05a6e +spec: + endpoints: + - interval: 10s + path: /kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo-mon-coreos/metrics + port: prom-http + targetPort: 0 + namespaceSelector: + matchNames: + - demo + selector: + matchLabels: + kubedb.com/kind: MongoDB + kubedb.com/name: mgo-mon-coreos +``` + + +Now, if you go the Prometheus Dashboard, you should see that this database endpoint as one of the targets. + + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +# In rbac enabled cluster, +# $ kubectl delete clusterrolebindings prometheus-operator prometheus +# $ kubectl delete clusterrole prometheus-operator prometheus + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + + +## Next Steps +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/overview.md b/docs/guides/mongodb/overview.md deleted file mode 100644 index 9debc3be1..000000000 --- a/docs/guides/mongodb/overview.md +++ /dev/null @@ -1,727 +0,0 @@ ---- -title: MongoDB -menu: - docs_0.8.0-beta.0: - identifier: guides-mongodb-overview - name: Overview - parent: guides-mongodb - weight: 10 -menu_name: docs_0.8.0-beta.0 -section_menu_id: guides -aliases: - - /docs/0.8.0-beta.0/guides/mongodb/ ---- - -> New to KubeDB? Please start [here](/docs/guides/README.md). - -# Running MongoDB -This tutorial will show you how to use KubeDB to run a MongoDB 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 [Minikube](https://github.com/kubernetes/minikube). - -Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). - -To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. This tutorial will also use a phpMyAdmin to connect and test MongoDB database, once it is running. Run the following command to prepare your cluster for this tutorial: - -```console -$ kubectl create -f ./docs/examples/mongodb/demo-0.yaml -namespace "demo" created - -$ kubectl get ns -NAME STATUS AGE -default Active 1h -demo Active 1m -kube-public Active 1h -kube-system Active 1h -``` - -## Create a MongoDB database -KubeDB implements a `MongoDB` CRD to define the specification of a MongoDB database. Below is the `MongoDB` object created in this tutorial. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: MongoDB -metadata: - name: mgo1 - namespace: demo -spec: - version: 3.4 - doNotPause: true - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - init: - scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mongodb-init-scripts.git" - directory: . - - -$ kubedb create -f ./docs/examples/mongodb/demo-1.yaml -validating "./docs/examples/mongodb/demo-1.yaml" -mongodb "mg1" created -``` - -Here, - - `spec.version` is the version of MongoDB database. In this tutorial, a MongoDB 3.4 database is going to be created. - - - `spec.doNotPause` tells KubeDB operator that if this object is deleted, it should be automatically reverted. This should be set to true for production databases to avoid accidental deletion. - - - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. - - - `spec.init.scriptSource` specifies a sql script source used to initialize the database after it is created. The sql scripts will be executed alphabatically. In this tutorial, a sample sql script from the git repository `https://github.com/kubedb/mongodb-init-scripts.git` is used to create a test database. - -KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. If [RBAC is enabled](/docs/guides/rbac.md), a ClusterRole, ServiceAccount and ClusterRoleBinding with the matching object name will be created and used as the service account name for the corresponding StatefulSet. - -```console -$ kubedb describe mg -n demo mgo1 -Name: mgo1 -Namespace: demo -StartTimestamp: Mon, 11 Dec 2017 12:38:54 +0600 -Status: Running -Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mgo1 - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 11 Dec 2017 12:38:58 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mgo1 - Type: ClusterIP - IP: 10.105.200.75 - Port: db 27017/TCP - -Database Secret: - Name: mgo1-admin-auth - Type: Opaque - Data - ==== - .admin: 16 bytes - -No Snapshots. - -Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 1m 1m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 1m 1m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 1m 1m 1 MongoDB operator Normal SuccessfulCreate Successfully created StatefulSet - 1m 1m 1 MongoDB operator Normal SuccessfulCreate Successfully created MongoDB - 5m 5m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 5m 5m 1 MongoDB operator Normal Creating Creating Kubernetes objects - - -$ kubectl get statefulset -n demo -NAME DESIRED CURRENT AGE -mgo1 1 1 6m - - -$ kubectl get pvc -n demo -NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE -data-mgo1-0 Bound pvc-f7746b65-de3d-11e7-879f-0800279fc284 50Mi RWO standard 6m - -$ kubectl get pv -n demo -NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE -pvc-f7746b65-de3d-11e7-879f-0800279fc284 50Mi RWO Delete Bound demo/data-mgo1-0 standard 6m - -$ kubectl get service -n demo -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubedb ClusterIP None 7m -mgo1 ClusterIP 10.105.200.75 27017/TCP 7m -``` - -KubeDB operator sets the `status.phase` to `Running` once the database is successfully created. Run the following command to see the modified MongoDB object: - -```yaml -$ kubedb get mg -n demo mgo1 -o yaml -apiVersion: kubedb.com/v1alpha1 -kind: MongoDB -metadata: - clusterName: "" - creationTimestamp: 2017-12-11T06:38:54Z - deletionGracePeriodSeconds: null - deletionTimestamp: null - generation: 0 - initializers: null - name: mgo1 - namespace: demo - resourceVersion: "717" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo1 - uid: f52ab165-de3d-11e7-879f-0800279fc284 -spec: - doNotPause: true - databaseSecret: - secretName: mgo1-admin-auth - init: - scriptSource: - gitRepo: - directory: . - repository: https://github.com/kubedb/mongodb-init-scripts.git - storage: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - storageClassName: standard - version: 3.4 -status: - creationTime: 2017-12-11T06:38:54Z - phase: Running -``` - -Please note that KubeDB operator has created a new Secret called `mgo1-admin-auth` (format: {mongodb-object-name}-admin-auth) for storing the password for `mongodb` superuser. This secret contains a `.admin` key which contains the password for `mongodb` superuser. If you want to use an existing secret please specify that when creating the MongoDB object using `spec.databaseSecret.secretName`. - -Now, you can connect to this database through [mongo-shell](https://docs.mongodb.com/v3.4/mongo/). In this tutorial, we are connecting to the MongoDB server from inside of pod. -```console -$ kubectl get secrets -n demo mgo1-admin-auth -o jsonpath='{.data.\.admin}' | base64 -d -aaqCftpLsaGDLVIo - -$ kubectl exec -it mgo1-0 -n demo sh - -> mongo admin -MongoDB shell version v3.4.10 -connecting to: mongodb://127.0.0.1:27017/admin -MongoDB server version: 3.4.10 -Welcome to the MongoDB shell. -For interactive help, type "help". -For more comprehensive documentation, see - http://docs.mongodb.org/ -Questions? Try the support group - http://groups.google.com/group/mongodb-user - -> db.auth("root","aaqCftpLsaGDLVIo") -1 - -> show dbs -admin 0.000GB -local 0.000GB -mydb 0.000GB - -> show users -{ - "_id" : "admin.root", - "user" : "root", - "db" : "admin", - "roles" : [ - { - "role" : "root", - "db" : "admin" - } - ] -} - -> use newdb -switched to db newdb - -> db.movie.insert({"name":"batman"}); -WriteResult({ "nInserted" : 1 }) - -> db.movie.find().pretty() -{ "_id" : ObjectId("5a2e435d7ec14e7bda785f16"), "name" : "batman" } - -> exit -bye -``` - - -## Database Snapshots - -### Instant Backups -Now, you can easily take a snapshot of this database by creating a `Snapshot` object. When a `Snapshot` object is created, KubeDB operator will launch a Job that runs the `mongodump` command and uploads the output bson file to various cloud providers S3, GCS, Azure, OpenStack Swift and/or locally mounted volumes using [osm](https://github.com/appscode/osm). - -In this tutorial, snapshots will be stored in a Google Cloud Storage (GCS) bucket. To do so, a secret is needed that has the following 2 keys: - -| Key | Description | -|-----------------------------------|------------------------------------------------------------| -| `GOOGLE_PROJECT_ID` | `Required`. Google Cloud project ID | -| `GOOGLE_SERVICE_ACCOUNT_JSON_KEY` | `Required`. Google Cloud service account json key | - -```console -$ echo -n '' > GOOGLE_PROJECT_ID -$ mv downloaded-sa-json.key > GOOGLE_SERVICE_ACCOUNT_JSON_KEY -$ kubectl create secret generic mg-snap-secret -n demo \ - --from-file=./GOOGLE_PROJECT_ID \ - --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY -secret "mg-snap-secret" created -``` - -```yaml -$ kubectl get secret mg-snap-secret -n demo -o yaml -apiVersion: v1 -data: - GOOGLE_PROJECT_ID: PHlvdXItcHJvamVjdC1pZD4= - GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== -kind: Secret -metadata: - creationTimestamp: 2017-12-11T08:40:34Z - name: mg-snap-secret - namespace: demo - resourceVersion: "4140" - selfLink: /api/v1/namespaces/demo/secrets/mg-snap-secret - uid: f44826c4-de4e-11e7-879f-0800279fc284 -type: Opaque -``` - -To lean how to configure other storage destinations for Snapshots, please visit [here](/docs/concepts/snapshot.md). Now, create the Snapshot object. - -```console -$ kubedb create -f ./docs/examples/mongodb/demo-2.yaml -validating "./docs/examples/mongodb/demo-2.yaml" -snapshot "mgo-xyz" created - -$ kubedb get snap -n demo -NAME DATABASE STATUS AGE -mgo-xyz mg/mgo1 Running 20s -``` - -```yaml -$ kubedb get snap -n demo mgo-xyz -o yaml -apiVersion: kubedb.com/v1alpha1 -kind: Snapshot -metadata: - clusterName: "" - creationTimestamp: 2017-12-11T08:41:54Z - deletionGracePeriodSeconds: null - deletionTimestamp: null - generation: 0 - initializers: null - labels: - kubedb.com/kind: MongoDB - kubedb.com/name: mgo1 - snapshots.kubedb.com/status: Running - name: mgo-xyz - namespace: demo - resourceVersion: "4243" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/snapshots/mgo-xyz - uid: 2421bd0a-de4f-11e7-879f-0800279fc284 -spec: - databaseName: mgo1 - gcs: - bucket: restic - storageSecretName: mg-snap-secret -status: - phase: Running - startTime: 2017-12-11T08:41:54Z -``` - -Here, - -- `metadata.labels` should include the type of database `kubedb.com/kind: MongoDB` whose snapshot will be taken. - -- `spec.databaseName` points to the database whose snapshot is taken. - -- `spec.storageSecretName` points to the Secret containing the credentials for snapshot storage destination. - -- `spec.gcs.bucket` points to the bucket name used to store the snapshot data. - - -You can also run the `kubedb describe` command to see the recent snapshots taken for a database. - -```console -$ kubedb describe mg -n demo mgo1 -Name: mgo1 -Namespace: demo -StartTimestamp: Mon, 11 Dec 2017 12:38:54 +0600 -Status: Running -Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mgo1 - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 11 Dec 2017 12:38:58 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mgo1 - Type: ClusterIP - IP: 10.105.200.75 - Port: db 27017/TCP - -Database Secret: - Name: mgo1-admin-auth - Type: Opaque - Data - ==== - .admin: 16 bytes - -Snapshots: - Name Bucket StartTime CompletionTime Phase - ---- ------ --------- -------------- ----- - mgo-xyz gs:restic Mon, 11 Dec 2017 14:41:54 +0600 Mon, 11 Dec 2017 14:48:58 +0600 Succeeded - -Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 2m 2m 1 Snapshot Controller Normal SuccessfulSnapshot Successfully completed snapshot - 9m 9m 1 Snapshot Controller Normal Starting Backup running -``` - -Once the snapshot Job is complete, you should see the output of the `mongodump` command stored in the GCS bucket. - -![snapshot-console](/docs/images/mongodb/mgo-xyz-snapshot.png) - -From the above image, you can see that the snapshot output is stored in a folder called `{bucket}/kubedb/{namespace}/{mongodb-object}/{snapshot}/`. - - -### Scheduled Backups -KubeDB supports taking periodic backups for a database using a [cron expression](https://github.com/robfig/cron/blob/v2/doc.go#L26). To take periodic backups, edit the MongoDB to add `spec.backupSchedule` section. - -```yaml -$ kubedb edit mg mgo1 -n demo -apiVersion: kubedb.com/v1alpha1 -kind: MongoDB -metadata: - clusterName: "" - creationTimestamp: 2017-12-11T06:38:54Z - generation: 0 - initializers: null - name: mgo1 - namespace: demo - resourceVersion: "5378" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo1 - uid: f52ab165-de3d-11e7-879f-0800279fc284 -spec: - doNotPause: true - databaseSecret: - secretName: mgo1-admin-auth - init: - scriptSource: - gitRepo: - directory: . - repository: https://github.com/kubedb/mongodb-init-scripts.git - storage: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - storageClassName: standard - version: 3.4 - backupSchedule: - cronExpression: '@every 1m' - gcs: - bucket: restic - storageSecretName: mg-snap-secret -status: - creationTime: 2017-12-11T06:38:54Z - phase: Running -``` - -Once the `spec.backupSchedule` is added, KubeDB operator will create a new Snapshot object on each tick of the cron expression. This triggers KubeDB operator to create a Job as it would for any regular instant backup process. You can see the snapshots as they are created using `kubedb get snap` command. -```console -$ kubedb get snap -n demo -NAME DATABASE STATUS AGE -mgo-xyz mg/mgo1 Succeeded 21m -mgo1-20171211-090039 mg/mgo1 Succeeded 2m -mgo1-20171211-090159 mg/mgo1 Succeeded 1m -mgo1-20171211-090259 mg/mgo1 Running 3s -``` - -### Restore from Snapshot -You can create a new database from a previously taken Snapshot. Specify the Snapshot name in the `spec.init.snapshotSource` field of a new MongoDB object. See the example `recovered` object below: - -```yaml -$ cat ./docs/examples/mongodb/demo-4.yaml -apiVersion: kubedb.com/v1alpha1 -kind: MongoDB -metadata: - name: recovered - namespace: demo -spec: - version: 3.4 - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - init: - snapshotSource: - name: mgo-xyz - - -$ kubedb create -f ./docs/examples/mongodb/demo-4.yaml -validating "./docs/examples/mongodb/demo-4.yaml" -mongodb "recovered" created -``` - -Here, - - `spec.init.snapshotSource.name` refers to a Snapshot object for a MongoDB database in the same namespaces as this new `recovered` MongoDB object. - -Now, wait several seconds. KubeDB operator will create a new StatefulSet. Then KubeDB operator launches a Kubernetes Job to initialize the new database using the data from `mgo-xyz` Snapshot. - -```console -$ kubedb get mg -n demo -NAME STATUS AGE -mgo1 Running 2h -recovered Running 1m - - -$ kubedb describe mg -n demo recovered -Name: recovered -Namespace: demo -StartTimestamp: Mon, 11 Dec 2017 15:04:34 +0600 -Status: Running -Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: recovered - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 11 Dec 2017 15:04:38 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: recovered - Type: ClusterIP - IP: 10.103.115.39 - Port: db 27017/TCP - -Database Secret: - Name: recovered-admin-auth - Type: Opaque - Data - ==== - .admin: 16 bytes - -No Snapshots. - -Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 1m 1m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 1m 1m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 1m 1m 1 MongoDB operator Normal SuccessfulInitialize Successfully completed initialization - 1m 1m 1 MongoDB operator Normal SuccessfulCreate Successfully created MongoDB - 1m 1m 1 MongoDB operator Normal SuccessfulCreate Successfully created StatefulSet - 1m 1m 1 MongoDB operator Normal Initializing Initializing from Snapshot: "mgo-xyz" - 2m 2m 1 MongoDB operator Normal SuccessfulValidate Successfully validate MongoDB - 2m 2m 1 MongoDB operator Normal Creating Creating Kubernetes objects -``` - -## Pause Database - -Since the MongoDB object created in this tutorial has `spec.doNotPause` set to true, if you delete the MongoDB object, KubeDB operator will recreate the object and essentially nullify the delete operation. You can see this below: - -```console -$ kubedb delete mg mgo1 -n demo -error: MongoDB "mgo1" can't be paused. To continue delete, unset spec.doNotPause and retry. -``` - -Now, run `kubedb edit mg mgo1 -n demo` to set `spec.doNotPause` to false or remove this field (which default to false). Then if you delete the MongoDB object, KubeDB operator will delete the StatefulSet and its pods, but leaves the PVCs unchanged. In KubeDB parlance, we say that `mgo1` MongoDB database has entered into dormant state. This is represented by KubeDB operator by creating a matching DormantDatabase object. - -```yaml -$ kubedb delete mg mgo1 -n demo -mongodb "mgo1" deleted - -$ kubedb get drmn -n demo mgo1 -NAME STATUS AGE -mgo1 Pausing 39s - -$ kubedb get drmn -n demo mgo1 -NAME STATUS AGE -mgo1 Paused 1m - - -$ kubedb get drmn -n demo mgo1 -o yaml -apiVersion: kubedb.com/v1alpha1 -kind: DormantDatabase -metadata: - annotations: - mongodbs.kubedb.com/init: '{"scriptSource":{"gitRepo":{"repository":"https://github.com/kubedb/mongodb-init-scripts.git","directory":"."}}}' - clusterName: "" - creationTimestamp: 2017-12-11T09:17:01Z - deletionGracePeriodSeconds: null - deletionTimestamp: null - generation: 0 - initializers: null - labels: - kubedb.com/kind: MongoDB - name: mgo1 - namespace: demo - resourceVersion: "7029" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mgo1 - uid: 0ba4a0df-de54-11e7-879f-0800279fc284 -spec: - origin: - metadata: - creationTimestamp: null - name: mgo1 - namespace: demo - spec: - mongodb: - databaseSecret: - secretName: mgo1-admin-auth - resources: {} - storage: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - storageClassName: standard - version: "3.4" -status: - creationTime: 2017-12-11T09:17:01Z - pausingTime: 2017-12-11T09:18:11Z - phase: Paused -``` - -Here, - - `spec.origin` is the spec of the original spec of the original MongoDB object. - - - `status.phase` points to the current database state `Paused`. - - -## Resume Dormant Database - -To resume the database from the dormant state, set `spec.resume` to `true` in the DormantDatabase object. - -```yaml -$ kubedb edit drmn -n demo mgo1 -apiVersion: kubedb.com/v1alpha1 -kind: DormantDatabase -metadata: - annotations: - mongodbs.kubedb.com/init: '{"scriptSource":{"gitRepo":{"repository":"https://github.com/kubedb/mongodb-init-scripts.git","directory":"."}}}' - clusterName: "" - creationTimestamp: 2017-12-11T09:17:01Z - deletionGracePeriodSeconds: null - deletionTimestamp: null - generation: 0 - initializers: null - labels: - kubedb.com/kind: MongoDB - name: mgo1 - namespace: demo - resourceVersion: "7029" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mgo1 - uid: 0ba4a0df-de54-11e7-879f-0800279fc284 -spec: - resume: true - origin: - metadata: - creationTimestamp: null - name: mgo1 - namespace: demo - spec: - mongodb: - databaseSecret: - secretName: mgo1-admin-auth - resources: {} - storage: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - storageClassName: standard - version: "3.4" -status: - creationTime: 2017-12-11T09:17:01Z - pausingTime: 2017-12-11T09:18:11Z - phase: Paused - -``` - -KubeDB operator will notice that `spec.resume` is set to true. KubeDB operator will delete the DormantDatabase object and create a new MongoDB object using the original spec. This will in turn start a new StatefulSet which will mount the originally created PVCs. Thus the original database is resumed. - -## Wipeout Dormant Database -You can also wipe out a DormantDatabase by setting `spec.wipeOut` to true. KubeDB operator will delete the PVCs, delete any relevant Snapshot objects for this database and also delete snapshot data stored in the Cloud Storage buckets. There is no way to resume a wiped out database. So, be sure before you wipe out a database. - -```yaml -$ kubedb edit drmn -n demo mgo1 -# set spec.wipeOut: true - -$ kubedb get drmn -n demo mgo1 -o yaml -apiVersion: kubedb.com/v1alpha1 -kind: DormantDatabase -metadata: - clusterName: "" - creationTimestamp: 2017-12-11T09:22:11Z - generation: 0 - initializers: null - labels: - kubedb.com/kind: MongoDB - name: mgo1 - namespace: demo - resourceVersion: "7497" - selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mgo1 - uid: c4b9cb9c-de54-11e7-879f-0800279fc284 -spec: - origin: - metadata: - annotations: - mongodbs.kubedb.com/init: '{"scriptSource":{"gitRepo":{"repository":"https://github.com/kubedb/mongodb-init-scripts.git","directory":"."}}}' - creationTimestamp: null - name: mgo1 - namespace: demo - spec: - mongodb: - databaseSecret: - secretName: mgo1-admin-auth - resources: {} - storage: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Mi - storageClassName: standard - version: "3.4" - wipeOut: true -status: - creationTime: 2017-12-11T09:22:11Z - pausingTime: 2017-12-11T09:23:11Z - phase: WipedOut - wipeOutTime: 2017-12-11T09:24:09Z - - -$ kubedb get drmn -n demo -NAME STATUS AGE -mgo1 WipedOut 3m -``` - - -## Delete Dormant Database -You still have a record that there used to be a MongoDB database `mgo1` in the form of a DormantDatabase database `mgo1`. Since you have already wiped out the database, you can delete the DormantDatabase object. - -```console -$ kubedb delete drmn mgo1 -n demo -dormantdatabase "mgo1" deleted -``` - -## Cleaning up -To cleanup the Kubernetes resources created by this tutorial, run: -```console -$ kubectl delete ns demo -namespace "demo" deleted -``` - -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). - - -## Next Steps -- Learn about the details of MongoDB object [here](/docs/concepts/databases/mongodb.md). -- See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). -- Thinking about monitoring your database? KubeDB works [out-of-the-box with Prometheus](/docs/guides/monitoring.md). -- Learn how to use KubeDB in a [RBAC](/docs/guides/rbac.md) enabled cluster. -- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). -- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/private-registry/using-private-registry.md b/docs/guides/mongodb/private-registry/using-private-registry.md new file mode 100644 index 000000000..706f3bb70 --- /dev/null +++ b/docs/guides/mongodb/private-registry/using-private-registry.md @@ -0,0 +1,180 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Deploy MongoDB from Private Docker Registry +`KubeDB` can be installed in a way that it only uses images from a specific docker-registry (may be private images) by providing the flag `--docker-registry=`. + +This tutorial will show you how to use KubeDB to run MongoDB database using Private Docker images. In this tutorial we will create a `ImagePullSecret` and add that secret in `MongoDB` CRD object specs. If you wish to follow other ways to pull private images see [official docs](https://kubernetes.io/docs/concepts/containers/images/) of kubernetes. + +## 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 [Minikube](https://github.com/kubernetes/minikube). + +You will also need a docker private [registry](https://docs.docker.com/registry/) or [private repository](https://docs.docker.com/docker-hub/repos/#private-repositories). In this tutorial we will use private repository of [docker hub](https://hub.docker.com/). + +Push necessary `KubeDB` images in your repository. For mongodb, total three images need to be pushed in private registry or repository for running `KubeDB` operator smoothly. + + - [kubedb/operator](https://hub.docker.com/r/kubedb/operator) + - [kubedb/mongo](https://hub.docker.com/r/kubedb/mongo) + - [kubedb/mongo-tools](https://hub.docker.com/r/kubedb/mongo-tools) + + +```console +$ export DOCKER_REGISTRY= + +$ docker pull kubedb/operator:0.8.0-beta.0-4 ; docker tag kubedb/operator:0.8.0-beta.0-4 $DOCKER_REGISTRY/operator:0.8.0-beta.0-4 ; docker push $DOCKER_REGISTRY/operator:0.8.0-beta.0-4 +$ docker pull kubedb/mongo:3.4 ; docker tag kubedb/mongo:3.4 $DOCKER_REGISTRY/mongo:3.4 ; docker push $DOCKER_REGISTRY/mongo:3.4 +$ docker pull kubedb/mongo:3.6 ; docker tag kubedb/mongo:3.6 $DOCKER_REGISTRY/mongo:3.6 ; docker push $DOCKER_REGISTRY/mongo:3.6 +$ docker pull kubedb/mongo-tools:3.4 ; docker tag kubedb/mongo-tools:3.4 $DOCKER_REGISTRY/mongo-tools:3.4 ; docker push $DOCKER_REGISTRY/mongo-tools:3.4 +$ docker pull kubedb/mongo-tools:3.6 ; docker tag kubedb/mongo-tools:3.6 $DOCKER_REGISTRY/mongo-tools:3.6 ; docker push $DOCKER_REGISTRY/mongo-tools:3.6 +``` + +KubeDB needs to be installed by providing `--docker-registry` and `--image-pull-secret` value. Follow the steps to [install `KubeDB-Operator`](/docs/setup/install.md) properly in cluster so that to points to the DOCKER_REGISTRY you wish to pull images from. + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +kube-system Active 45m +``` + +## Create ImagePullSecret +ImagePullSecrets is a type of a Kubernete Secret whose sole purpose is to pull private images from a Docker registry. It allows you to specify the Url of the docker registry, credentials for logging in and the image name of your private docker image. + +### Log in to Docker +Before creating `ImagePullSecret`, log in to your private registry manually. This will create a ~/.docker directory and a ~/.docker/config.json file. See here for details of [docker login](https://docs.docker.com/engine/reference/commandline/login/) options. + +```console +# docker login +$ docker login +Username: +Password: +Login Succeeded +``` + +When prompted, enter your Docker username and password. + +The login process creates or updates a config.json file that holds an authorization token. +View the config.json file. The output contains a section similar to this: + +```console +$ cat ~/.docker/config.json +{ + "auths": { + "https://index.docker.io/v1/": { + "auth": "c3R...zE2" + } + } +} +``` + +### Create a Secret that holds your authorization token +We will create a secret named `myregistrykey` in `demo` namespace so that kubernetes can pull `mongo` and `mongo-tools` images from private repository. + +```console +$ cat ~/.docker/config.json | base64 + + +$ gedit image-pull-secret.yaml +``` + + +Now paste the below yaml in the gedit editor and replace `` with base64 encoded `.docker/config.json`. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: myregistrykey + namespace: demo +data: + .dockerconfigjson: +type: kubernetes.io/dockerconfigjson +``` +Now save the yaml file and run the below command to create secret: + +```console +$ kubectl create -f image-pull-secret.yaml +secret "myregistrykey" created +``` + +## Deploy MongoDB database from Private Registry +While deploying `MongoDB` from private repository, you have to add `myregistrykey` secret in `MongoDB` `spec.imagePullSecrets`. +Below is the MongoDB CRD object we will create. +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-pvt-reg + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + imagePullSecrets: + - name: myregistrykey +``` +Now run the command to deploy this `MongoDB` object: + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/private-registry/demo-2.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/private-registry/demo-2.yaml" +mongodb "mgo-pvt-reg" created +``` + +To check if the images pulled successfully from the repository, see if the `MongoDB` is in running state: + +```console +$ kubectl get pods -n demo -w +NAME READY STATUS RESTARTS AGE +mgo-pvt-reg-0 0/1 Pending 0 0s +mgo-pvt-reg-0 0/1 Pending 0 0s +mgo-pvt-reg-0 0/1 ContainerCreating 0 0s +mgo-pvt-reg-0 1/1 Running 0 5m + + +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-pvt-reg Running 1m +``` + + +## Snapshot +We don't need to add `imagePullSecret` for `snapshot` objects. +User can create snapshot [in normal way](/docs/guides/mongodb/snapshot/backup-and-restore.md) and `KubeDB-Operator` will re-use the `ImagePullSecret` from `MongoDB` object. + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Detail concepts of [Snapshot object](/docs/concepts/snapshot.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/quickstart/quickstart.md b/docs/guides/mongodb/quickstart/quickstart.md new file mode 100644 index 000000000..8ae0771f6 --- /dev/null +++ b/docs/guides/mongodb/quickstart/quickstart.md @@ -0,0 +1,429 @@ + + +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# MongoDB QuickStart +This tutorial will show you how to use KubeDB to run a MongoDB database. + +

+  lifecycle +

+ +## 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +kube-system Active 45m +``` + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create a MongoDB database +KubeDB implements a `MongoDB` CRD to define the specification of a MongoDB database. Below is the `MongoDB` object created in this tutorial. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-quickstart + namespace: demo +spec: + version: 3.4 + doNotPause: true + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi +``` + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/quickstart/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/quickstart/demo-1.yaml" +mongodb "mgo-quickstart" created +``` + + +Here, + + - `spec.version` is the version of MongoDB database. In this tutorial, a MongoDB 3.4 database is going to be created. + + - `spec.doNotPause` tells KubeDB operator that if this object is deleted, it should be automatically reverted. This should be set to true for production databases to avoid accidental deletion. + + - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. + +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. Even if [RBAC is enabled](/docs/guides/rbac.md), it won't affect anything to run MongoDB database . + +```console +$ kubedb describe mg -n demo mgo-quickstart +Name: mgo-quickstart +Namespace: demo +StartTimestamp: Fri, 02 Feb 2018 15:11:58 +0600 +Status: Running +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-quickstart + Replicas: 1 current / 1 desired + CreationTimestamp: Fri, 02 Feb 2018 15:11:24 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-quickstart + Type: ClusterIP + IP: 10.103.114.139 + Port: db 27017/TCP + +Database Secret: + Name: mgo-quickstart-auth + Type: Opaque + Data + ==== + password: 16 bytes + user: 4 bytes + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 2m 2m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 2m 2m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 2m 2m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 2m 2m 1 MongoDB operator Normal Successful Successfully patched MongoDB + + +$ kubectl get statefulset -n demo +NAME DESIRED CURRENT AGE +mgo-quickstart 1 1 4m + + +$ kubectl get pvc -n demo +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE +data-mgo-quickstart-0 Bound pvc-16158aae-07fa-11e8-946f-080027c05a6e 50Mi RWO standard 2m + + +$ kubectl get pv -n demo +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE +pvc-16158aae-07fa-11e8-946f-080027c05a6e 50Mi RWO Delete Bound demo/data-mgo-quickstart-0 standard 3m + + +$ kubectl get service -n demo +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 3m +mgo-quickstart ClusterIP 10.107.133.189 27017/TCP 3m +``` + + +KubeDB operator sets the `status.phase` to `Running` once the database is successfully created. Run the following command to see the modified MongoDB object: + +```yaml +$ kubedb get mg -n demo mgo-quickstart -o yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + clusterName: "" + creationTimestamp: 2018-02-02T09:18:39Z + finalizers: + - kubedb.com + generation: 0 + name: mgo-quickstart + namespace: demo + resourceVersion: "46856" + selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mongodbs/mgo-quickstart + uid: 0de4d2a2-07fa-11e8-946f-080027c05a6e +spec: + databaseSecret: + secretName: mgo-quickstart-auth + doNotPause: true + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + storageClassName: standard + version: 3.4 +status: + creationTime: 2018-02-02T09:18:50Z + phase: Running +``` + +Please note that KubeDB operator has created a new Secret called `mgo-quickstart-auth` *(format: {mongodb-object-name}-auth)* for storing the password for `mongodb` superuser. This secret contains a `user` key which contains the *username* for MongoDB superuser and a `password` key which contains the *password* for MongoDB superuser. + If you want to use an existing secret please specify that when creating the MongoDB object using `spec.databaseSecret.secretName`. While creating this secret manually, make sure the secret contains these two keys containing data `user` and `password`. + +Now, you can connect to this database through [mongo-shell](https://docs.mongodb.com/v3.4/mongo/). In this tutorial, we are connecting to the MongoDB server from inside the pod. + +```console +$ kubectl get secrets -n demo mgo-quickstart-auth -o jsonpath='{.data.\user}' | base64 -d +root + +$ kubectl get secrets -n demo mgo-quickstart-auth -o jsonpath='{.data.\password}' | base64 -d +aaqCftpLsaGDLVIo + +$ kubectl exec -it mgo-quickstart-0 -n demo sh + +> mongo admin +MongoDB shell version v3.4.10 +connecting to: mongodb://127.0.0.1:27017/admin +MongoDB server version: 3.4.10 +Welcome to the MongoDB shell. +For interactive help, type "help". +For more comprehensive documentation, see + http://docs.mongodb.org/ +Questions? Try the support group + http://groups.google.com/group/mongodb-user + +> db.auth("root","aaqCftpLsaGDLVIo") +1 + +> show dbs +admin 0.000GB +local 0.000GB +mydb 0.000GB + +> show users +{ + "_id" : "admin.root", + "user" : "root", + "db" : "admin", + "roles" : [ + { + "role" : "root", + "db" : "admin" + } + ] +} + +> use newdb +switched to db newdb + +> db.movie.insert({"name":"batman"}); +WriteResult({ "nInserted" : 1 }) + +> db.movie.find().pretty() +{ "_id" : ObjectId("5a2e435d7ec14e7bda785f16"), "name" : "batman" } + +> exit +bye +``` + +## Pause Database + +The Admission Webhook of KubeDB gives some extra strength to `KubeDB-Operator` and one of the features is `spec.doNotPause`. If admission webhook is enabled, It prevents user from deleting the database as long as the `spec.doNotPause` is set to true. Since the MongoDB object created in this tutorial has `spec.doNotPause` set to true, if you delete the MongoDB object, KubeDB operator will nullify the delete operation. You can see this below: + +```console +$ kubedb delete mg mgo-quickstart -n demo +error: MongoDB "mgo-quickstart" can't be paused. To continue delete, unset spec.doNotPause and retry. +``` + + +Now, run `kubedb edit mg mgo-quickstart -n demo` to set `spec.doNotPause` to false or remove this field (which default to false). Then if you delete the MongoDB object, KubeDB operator will delete the StatefulSet and its pods, but leaves the PVCs unchanged. In KubeDB parlance, we say that `mgo-quickstart` MongoDB database has entered into dormant state. This is represented by KubeDB operator by creating a matching DormantDatabase object. + +```yaml +$ kubedb delete mg mgo-quickstart -n demo +mongodb "mgo-quickstart" deleted + +$ kubedb get drmn -n demo mgo-quickstart +NAME STATUS AGE +mgo-quickstart Pausing 39s + +$ kubedb get drmn -n demo mgo-quickstart +NAME STATUS AGE +mgo-quickstart Paused 1m + + + +$ kubedb get drmn -n demo mgo-quickstart -o yaml +apiVersion: kubedb.com/v1alpha1 +kind: DormantDatabase +metadata: + clusterName: "" + creationTimestamp: 2018-02-02T09:24:49Z + finalizers: + - kubedb.com + generation: 0 + labels: + kubedb.com/kind: MongoDB + name: mgo-quickstart + namespace: demo + resourceVersion: "47107" + selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mgo-quickstart + uid: eadf575b-07fa-11e8-946f-080027c05a6e +spec: + origin: + metadata: + creationTimestamp: null + name: mgo-quickstart + namespace: demo + spec: + mongodb: + databaseSecret: + secretName: mgo-quickstart-auth + resources: {} + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + storageClassName: standard + version: "3.4" +status: + creationTime: 2018-02-02T09:24:50Z + pausingTime: 2018-02-02T09:25:11Z + phase: Paused +``` + + +Here, + + - `spec.origin` is the spec of the original spec of the original MongoDB object. + + - `status.phase` points to the current database state `Paused`. + + +## Resume Dormant Database + +To resume the database from the dormant state, set `spec.resume` to `true` in the DormantDatabase object. + +```yaml +$ kubedb edit drmn -n demo mgo-quickstart +apiVersion: kubedb.com/v1alpha1 +kind: DormantDatabase +metadata: + name: mgo-quickstart + namespace: demo + ... +spec: + resume: true + ... +status: + phase: Paused + ... +``` + + +KubeDB operator will notice that `spec.resume` is set to true. KubeDB operator will delete the DormantDatabase object and create a new MongoDB object using the original spec. This will in turn start a new StatefulSet which will mount the originally created PVCs. Thus the original database is resumed. + +Please note that the dormant database can also be resumed by creating same `MongoDB` database by using same Specs. In this tutorial, the dormant database can be resumed by creating `MongoDB` database using demo-1.yaml file. The below command resumes the dormant database `mgo-quickstart` that was created before. + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/quickstart/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/quickstart/demo-1.yaml" +mongodb "mgo-quickstart" created +``` + + +## Wipeout Dormant Database +You can also wipe out a DormantDatabase by setting `spec.wipeOut` to true. KubeDB operator will delete the PVCs, delete any relevant Snapshot objects for this database and also delete snapshot data stored in the Cloud Storage buckets. There is no way to resume a wiped out database. So, be sure before you wipe out a database. + +```yaml +$ kubedb edit drmn -n demo mgo-quickstart +# set spec.wipeOut: true + +$ kubedb get drmn -n demo mgo-quickstart -o yaml +apiVersion: kubedb.com/v1alpha1 +kind: DormantDatabase +metadata: + clusterName: "" + creationTimestamp: 2018-02-02T09:30:06Z + finalizers: + - kubedb.com + generation: 0 + labels: + kubedb.com/kind: MongoDB + name: mgo-quickstart + namespace: demo + resourceVersion: "47440" + selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mgo-quickstart + uid: a75e6314-07fb-11e8-946f-080027c05a6e +spec: + origin: + metadata: + creationTimestamp: null + name: mgo-quickstart + namespace: demo + spec: + mongodb: + databaseSecret: + secretName: mgo-quickstart-auth + resources: {} + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + storageClassName: standard + version: "3.4" + wipeOut: true +status: + creationTime: 2018-02-02T09:30:07Z + pausingTime: 2018-02-02T09:30:21Z + phase: WipedOut + wipeOutTime: 2018-02-02T09:30:51Z + + +$ kubedb get drmn -n demo +NAME STATUS AGE +mgo-quickstart WipedOut 1m + +``` + + +## Delete Dormant Database +You still have a record that there used to be a MongoDB database `mgo-quickstart` in the form of a DormantDatabase database `mgo-quickstart`. Since you have already wiped out the database, you can delete the DormantDatabase object. + +```console +$ kubedb delete drmn mgo-quickstart -n demo +dormantdatabase "mgo-quickstart" deleted +``` + + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg mgo-quickstart -n demo --force +$ kubedb delete drmn mgo-quickstart -n demo --force + +# or +# $ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/mongodb/snapshot/backup-and-restore.md b/docs/guides/mongodb/snapshot/backup-and-restore.md new file mode 100644 index 000000000..545b13ffb --- /dev/null +++ b/docs/guides/mongodb/snapshot/backup-and-restore.md @@ -0,0 +1,311 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Database Snapshots +This tutorial will show you how to use KubeDB to take snapshot of a MongoDB 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +A `MongoDB` database is needed to take snapshot for this tutorial. To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 1h +demo Active 1m +kube-public Active 1h +kube-system Active 1h + +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-1.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-1.yaml" +mongodb "mgo-infant" created +``` + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Instant Backups +You can easily take a snapshot of `MongoDB` database by creating a `Snapshot` object. When a `Snapshot` object is created, KubeDB operator will launch a Job that runs the `mongodump` command and uploads the output bson file to various cloud providers S3, GCS, Azure, OpenStack Swift and/or locally mounted volumes using [osm](https://github.com/appscode/osm). + +In this tutorial, snapshots will be stored in a Google Cloud Storage (GCS) bucket. To do so, a secret is needed that has the following 2 keys: + +| Key | Description | +|-----------------------------------|------------------------------------------------------------| +| `GOOGLE_PROJECT_ID` | `Required`. Google Cloud project ID | +| `GOOGLE_SERVICE_ACCOUNT_JSON_KEY` | `Required`. Google Cloud service account json key | + +```console +$ echo -n '' > GOOGLE_PROJECT_ID +$ mv downloaded-sa-json.key > GOOGLE_SERVICE_ACCOUNT_JSON_KEY +$ kubectl create secret generic mg-snap-secret -n demo \ + --from-file=./GOOGLE_PROJECT_ID \ + --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY +secret "mg-snap-secret" created +``` + + +```yaml +$ kubectl get secret mg-snap-secret -n demo -o yaml +apiVersion: v1 +data: + GOOGLE_PROJECT_ID: PHlvdXItcHJvamVjdC1pZD4= + GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== +kind: Secret +metadata: + creationTimestamp: 2018-02-02T10:02:09Z + name: mg-snap-secret + namespace: demo + resourceVersion: "48679" + selfLink: /api/v1/namespaces/demo/secrets/mg-snap-secret + uid: 220a7c60-0800-11e8-946f-080027c05a6e +type: Opaque +``` + + +To lean how to configure other storage destinations for Snapshots, please visit [here](/docs/concepts/snapshot.md). Now, create the Snapshot object. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Snapshot +metadata: + name: snapshot-infant + namespace: demo + labels: + kubedb.com/kind: MongoDB +spec: + databaseName: mgo-infant + storageSecretName: mg-snap-secret + gcs: + bucket: restic +``` + + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-2.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-2.yaml" +snapshot "snapshot-infant" created + + +$ kubedb get snap -n demo +NAME DATABASE STATUS AGE +snapshot-infant mg/mgo-infant Running 47s +``` + + +```yaml +$ kubedb get snap -n demo snapshot-infant -o yaml +apiVersion: kubedb.com/v1alpha1 +kind: Snapshot +metadata: + clusterName: "" + creationTimestamp: 2018-02-02T10:05:36Z + finalizers: + - kubedb.com + generation: 0 + labels: + kubedb.com/kind: MongoDB + kubedb.com/name: mgo-infant + name: snapshot-infant + namespace: demo + resourceVersion: "48991" + selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/snapshots/snapshot-infant + uid: 9d4f37a0-0800-11e8-946f-080027c05a6e +spec: + databaseName: mgo-infant + gcs: + bucket: restic + storageSecretName: mg-snap-secret +status: + completionTime: 2018-02-02T10:06:43Z + phase: Succeeded + startTime: 2018-02-02T10:05:37Z +``` + + +Here, + +- `metadata.labels` should include the type of database `kubedb.com/kind: MongoDB` whose snapshot will be taken. + +- `spec.databaseName` points to the database whose snapshot is taken. + +- `spec.storageSecretName` points to the Secret containing the credentials for snapshot storage destination. + +- `spec.gcs.bucket` points to the bucket name used to store the snapshot data. + + +You can also run the `kubedb describe` command to see the recent snapshots taken for a database. + +```console +$ kubedb describe mg -n demo mgo-infant +Name: mgo-infant +Namespace: demo +StartTimestamp: Fri, 02 Feb 2018 16:04:50 +0600 +Status: Running +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-infant + Replicas: 1 current / 1 desired + CreationTimestamp: Fri, 02 Feb 2018 16:04:56 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-infant + Type: ClusterIP + IP: 10.99.34.23 + Port: db 27017/TCP + +Database Secret: + Name: mgo-infant-auth + Type: Opaque + Data + ==== + password: 16 bytes + user: 4 bytes + +Snapshots: + Name Bucket StartTime CompletionTime Phase + ---- ------ --------- -------------- ----- + snapshot-infant gs:restic Fri, 02 Feb 2018 16:05:37 +0600 Fri, 02 Feb 2018 16:06:43 +0600 Succeeded + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 8m 8m 1 Job Controller Normal SuccessfulSnapshot Successfully completed snapshot + 9m 9m 1 Snapshot Controller Normal Starting Backup running + 9m 9m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 9m 9m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 9m 9m 1 MongoDB operator Normal Successful Successfully created StatefulSet + 9m 9m 1 MongoDB operator Normal Successful Successfully created MongoDB + 10m 10m 1 MongoDB operator Normal Successful Successfully created Service +``` + + +Once the snapshot Job is complete, you should see the output of the `mongodump` command stored in the GCS bucket. + +![snapshot-console](/docs/images/mongodb/mgo-xyz-snapshot.png) + +From the above image, you can see that the snapshot output is stored in a folder called `{bucket}/kubedb/{namespace}/{mongodb-object}/{snapshot}/`. + + +## Restore from Snapshot +You can create a new database from a previously taken Snapshot. Specify the Snapshot name in the `spec.init.snapshotSource` field of a new MongoDB object. See the example `mgo-recovered` object below: + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-recovered + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + init: + snapshotSource: + name: snapshot-infant + namespace: demo +``` + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-3.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-3.yaml" +mongodb "mgo-recovered" created +``` + +Here, + + - `spec.init.snapshotSource.name` refers to a Snapshot object for a MongoDB database in the same namespaces as this new `mgo-recovered` MongoDB object. + +Now, wait several seconds. KubeDB operator will create a new StatefulSet. Then KubeDB operator launches a Kubernetes Job to initialize the new database using the data from `mgo-xyz` Snapshot. + +```console +$ kubedb get mg -n demo +NAME STATUS AGE +mgo-infant Running 23m +mgo-recovered Running 4m + +$ kubedb describe mg -n demo mgo-recovered +Name: mgo-recovered +Namespace: demo +StartTimestamp: Fri, 02 Feb 2018 16:24:23 +0600 +Status: Running +Annotations: kubedb.com/initialized= +Volume: + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mgo-recovered + Replicas: 1 current / 1 desired + CreationTimestamp: Fri, 02 Feb 2018 16:24:36 +0600 + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mgo-recovered + Type: ClusterIP + IP: 10.107.157.253 + Port: db 27017/TCP + +Database Secret: + Name: mgo-recovered-auth + Type: Opaque + Data + ==== + user: 4 bytes + password: 16 bytes + +No Snapshots. + +Events: + FirstSeen LastSeen Count From Type Reason Message + --------- -------- ----- ---- -------- ------ ------- + 3m 3m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 3m 3m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 3m 3m 1 Job Controller Normal SuccessfulInitialize Successfully completed initialization + 4m 4m 1 MongoDB operator Normal Successful Successfully patched StatefulSet + 4m 4m 1 MongoDB operator Normal Successful Successfully patched MongoDB + 4m 4m 1 MongoDB operator Normal Initializing Initializing from Snapshot: "snapshot-infant" + 4m 4m 1 MongoDB operator Normal Successful Successfully created StatefulSet + 4m 4m 1 MongoDB operator Normal Successful Successfully created MongoDB + 4m 4m 1 MongoDB operator Normal Successful Successfully created Service +``` + + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). +- Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/mongodb/snapshot/scheduled-backup.md b/docs/guides/mongodb/snapshot/scheduled-backup.md new file mode 100644 index 000000000..53ede62c9 --- /dev/null +++ b/docs/guides/mongodb/snapshot/scheduled-backup.md @@ -0,0 +1,191 @@ +> New to KubeDB? Please start [here](/docs/guides/README.md). + +# Database Scheduled Snapshots +This tutorial will show you how to use KubeDB to take scheduled snapshot of a MongoDB 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 [Minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 1h +demo Active 1m +kube-public Active 1h +kube-system Active 1h +``` + +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + + +## Scheduled Backups +KubeDB supports taking periodic backups for a database using a [cron expression](https://github.com/robfig/cron/blob/v2/doc.go#L26). KubeDB operator will launch a Job periodically that runs the `mongodump` command and uploads the output bson file to various cloud providers S3, GCS, Azure, OpenStack Swift and/or locally mounted volumes using [osm](https://github.com/appscode/osm). + +In this tutorial, snapshots will be stored in a Google Cloud Storage (GCS) bucket. To do so, a secret is needed that has the following 2 keys: + +| Key | Description | +|-----------------------------------|------------------------------------------------------------| +| `GOOGLE_PROJECT_ID` | `Required`. Google Cloud project ID | +| `GOOGLE_SERVICE_ACCOUNT_JSON_KEY` | `Required`. Google Cloud service account json key | + +```console +$ echo -n '' > GOOGLE_PROJECT_ID +$ mv downloaded-sa-json.key > GOOGLE_SERVICE_ACCOUNT_JSON_KEY +$ kubectl create secret generic mg-snap-secret -n demo \ + --from-file=./GOOGLE_PROJECT_ID \ + --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY +secret "mg-snap-secret" created +``` + + +```yaml +$ kubectl get secret mg-snap-secret -n demo -o yaml +apiVersion: v1 +data: + GOOGLE_PROJECT_ID: PHlvdXItcHJvamVjdC1pZD4= + GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== +kind: Secret +metadata: + creationTimestamp: 2018-02-02T10:02:09Z + name: mg-snap-secret + namespace: demo + resourceVersion: "48679" + selfLink: /api/v1/namespaces/demo/secrets/mg-snap-secret + uid: 220a7c60-0800-11e8-946f-080027c05a6e +type: Opaque +``` + + +To learn how to configure other storage destinations for Snapshots, please visit [here](/docs/concepts/snapshot.md). Now, create the `MongoDB` object with scheduled snapshot. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-scheduled + namespace: demo +spec: + version: 3.4 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + init: + scriptSource: + gitRepo: + repository: "https://github.com/kubedb/mongodb-init-scripts.git" + directory: . + backupSchedule: + cronExpression: "@every 1m" + storageSecretName: mg-snap-secret + gcs: + bucket: restic +``` + + +```console +$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-4.yaml +validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-4.yaml" +mongodb "mgo-scheduled" created +``` + +It is also possible to add backup scheduler to an existing `MongoDB`. You just have to edit the `MongoDB` CRD and add below spec: +```yaml +$ kubedb edit mg {db-name} -n demo +spec: + backupSchedule: + cronExpression: '@every 1m' + gcs: + bucket: restic + storageSecretName: mg-snap-secret +``` + +Once the `spec.backupSchedule` is added, KubeDB operator will create a new Snapshot object on each tick of the cron expression. This triggers KubeDB operator to create a Job as it would for any regular instant backup process. You can see the snapshots as they are created using `kubedb get snap` command. + +```console +$ kubedb get snap -n demo +NAME DATABASE STATUS AGE +mgo-scheduled-20180202-104632 mg/mgo-scheduled Succeeded 4m +mgo-scheduled-20180202-104737 mg/mgo-scheduled Succeeded 3m +mgo-scheduled-20180202-104837 mg/mgo-scheduled Succeeded 2m +mgo-scheduled-20180202-104937 mg/mgo-scheduled Running 10s +``` + +you should see the output of the `mongodump` command for each snapshot stored in the GCS bucket. + +![snapshot-console](/docs/images/mongodb/mgo-scheduled.png) + +From the above image, you can see that the snapshot output is stored in a folder called `{bucket}/kubedb/{namespace}/{mongodb-object}/{snapshot}/`. + + +## Remove Scheduler +To remove scheduler, edit the MongoDB object to remove `spec.backupSchedule` section. + +```yaml +$ kubedb edit mg mgo-scheduled -n demo +apiVersion: kubedb.com/v1alpha1 +kind: MongoDB +metadata: + name: mgo-scheduled + namespace: demo + ... +spec: +# backupSchedule: +# cronExpression: '@every 1m' +# gcs: +# bucket: restic +# storageSecretName: mg-snap-secret + databaseSecret: + secretName: mgo-scheduled-auth + init: + scriptSource: + gitRepo: + directory: . + repository: https://github.com/kubedb/mongodb-init-scripts.git + storage: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + storageClassName: standard + version: 3.4 +status: + creationTime: 2018-02-02T10:46:18Z + phase: Running + +``` + +## Cleaning up +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +$ kubedb delete mg,drmn,snap -n demo --all --force + +$ kubectl delete ns demo +namespace "demo" deleted +``` + +If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). + +## Next Steps +- See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). +- Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). +- Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). +- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). +- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. +- Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). +- Wondering what features are coming next? Please visit [here](/docs/roadmap.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/images/mongodb/builtin-prometheus.png b/docs/images/mongodb/builtin-prometheus.png new file mode 100644 index 0000000000000000000000000000000000000000..26b521eacb289b589fa3b806648845df8581ec71 GIT binary patch literal 58533 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 literal 0 HcmV?d00001 diff --git a/docs/images/mongodb/mgo-scheduled.png b/docs/images/mongodb/mgo-scheduled.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e3380d8131b646282c7608d864bf4dce81cb04 GIT binary patch literal 36966 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 --image-pull-secret= + +Successfully created operator deployment. +Successfully created operator service. +``` + +See the official docs of kubernetes for other [methods to pull private images](https://kubernetes.io/docs/concepts/containers/images/) and steps to [create ImagePullSecrets](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). + ## Verify installation To check if KubeDB operator pods have started, run the following command: + ```console $ kubectl get pods --all-namespaces -l app=kubedb --watch ``` @@ -68,6 +97,7 @@ $ kubectl get pods --all-namespaces -l app=kubedb --watch Once the operator pods are running, you can cancel the above command by typing `Ctrl+C`. Now, to confirm CRD groups have been registered by the operator, run the following command: + ```console $ kubectl get crd -l app=kubedb ``` @@ -84,4 +114,5 @@ $ kubedb init --version='0.8.0-beta.0' --upgrade Successfully upgraded operator deployment. ``` + To learn about various options of `init` command, please visit [here](/docs/reference/kubedb_init.md). diff --git a/docs/setup/uninstall.md b/docs/setup/uninstall.md index 0d4c80de2..2552ce420 100644 --- a/docs/setup/uninstall.md +++ b/docs/setup/uninstall.md @@ -16,6 +16,7 @@ section_menu_id: setup Please follow the steps below to uninstall KubeDB: 1. Delete the deployment and service used for KubeDB operator. + ```console $ kubectl delete deployment -l app=kubedb -n $ kubectl delete service -l app=kubedb -n @@ -27,11 +28,13 @@ $ kubectl delete clusterrole -l app=kubedb -n ``` 2. Now, wait several seconds for KubeDB to stop running. To confirm that KubeDB operator pod(s) have stopped running, run: + ```console $ kubectl get pods --all-namespaces -l app=kubedb ``` 3. To keep a copy of your existing KubeDB objects, run: + ```console kubectl get postgres.kubedb.com --all-namespaces -o yaml > postgres.yaml kubectl get elasticsearch.kubedb.com --all-namespaces -o yaml > elastic.yaml @@ -40,6 +43,7 @@ kubectl get dormant-database.kubedb.com --all-namespaces -o yaml > data.yaml ``` 4. To delete existing KubeDB objects from all namespaces, run the following command in each namespace one by one. + ``` kubectl delete postgres.kubedb.com --all --cascade=false kubectl delete elasticsearch.kubedb.com --all --cascade=false @@ -48,6 +52,7 @@ kubectl delete dormant-database.kubedb.com --all --cascade=false ``` 5. Delete the old CRD-registration. + ```console kubectl delete crd -l app=kubedb ``` From 53ce972fcc0c331b3cc024c1318f0e3012b901d1 Mon Sep 17 00:00:00 2001 From: the-redback Date: Wed, 14 Feb 2018 10:05:15 +0600 Subject: [PATCH 2/5] merged master --- docs/setup/install.md | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/docs/setup/install.md b/docs/setup/install.md index 1cf108c56..8d362ad22 100644 --- a/docs/setup/install.md +++ b/docs/setup/install.md @@ -132,36 +132,8 @@ $ helm install stable/kubedb --name my-release \ To see the detailed configuration options, visit [here](https://github.com/kubedb/cli/tree/master/chart/stable/kubedb). -#### Private Docker Registry - -If you are using a private Docker registry, you need to pull the following docker images: - - - [kubedb/operator](https://hub.docker.com/r/kubedb/operator) - - [kubedb/postgres](https://hub.docker.com/r/kubedb/postgres) - - [kubedb/postgres-tools](https://hub.docker.com/r/kubedb/postgres-tools) - - [kubedb/elasticsearch](https://hub.docker.com/r/kubedb/elasticsearch) - - [kubedb/elasticsearch-tools](https://hub.docker.com/r/kubedb/elasticsearch-tools) - - [kubedb/mongo](https://hub.docker.com/r/kubedb/mongo) - - [kubedb/mongo-tools](https://hub.docker.com/r/kubedb/mongo-tools) - - [kubedb/mysql](https://hub.docker.com/r/kubedb/mysql) - - [kubedb/mysql-tools](https://hub.docker.com/r/kubedb/mysql-tools) - - [kubedb/redis](https://hub.docker.com/r/kubedb/redis) - - [kubedb/memcached](https://hub.docker.com/r/kubedb/memcached) - -To pass the address of your private registry and optionally a image pull secret use flags `--docker-registry` and `--image-pull-secret` respectively. - -```console -$ kubedb init --docker-registry= --image-pull-secret= - -Successfully created operator deployment. -Successfully created operator service. -``` - -See the official docs of kubernetes for other [methods to pull private images](https://kubernetes.io/docs/concepts/containers/images/) and steps to [create ImagePullSecrets](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). - ## Verify installation To check if KubeDB operator pods have started, run the following command: - ```console $ kubectl get pods --all-namespaces -l app=kubedb --watch ``` @@ -169,7 +141,6 @@ $ kubectl get pods --all-namespaces -l app=kubedb --watch Once the operator pods are running, you can cancel the above command by typing `Ctrl+C`. Now, to confirm CRD groups have been registered by the operator, run the following command: - ```console $ kubectl get crd -l app=kubedb ``` From be90376d4aa1c286599d6a9ab861fd5159ccb3f0 Mon Sep 17 00:00:00 2001 From: the-redback Date: Wed, 14 Feb 2018 10:47:34 +0600 Subject: [PATCH 3/5] removed uninstall line. --- docs/guides/mongodb/initialization/using-script.md | 2 -- docs/guides/mongodb/initialization/using-snapshot.md | 1 - docs/guides/mongodb/monitoring/using-builtin-prometheus.md | 2 -- .../mongodb/monitoring/using-coreos-prometheus-operator.md | 2 -- docs/guides/mongodb/private-registry/using-private-registry.md | 1 - docs/guides/mongodb/quickstart/quickstart.md | 2 -- docs/guides/mongodb/snapshot/backup-and-restore.md | 1 - docs/guides/mongodb/snapshot/scheduled-backup.md | 1 - 8 files changed, 12 deletions(-) diff --git a/docs/guides/mongodb/initialization/using-script.md b/docs/guides/mongodb/initialization/using-script.md index e4ea62dd8..2980dcac0 100644 --- a/docs/guides/mongodb/initialization/using-script.md +++ b/docs/guides/mongodb/initialization/using-script.md @@ -254,8 +254,6 @@ namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). - ## Next Steps - Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). - [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. diff --git a/docs/guides/mongodb/initialization/using-snapshot.md b/docs/guides/mongodb/initialization/using-snapshot.md index 72f893642..e4d9e601d 100644 --- a/docs/guides/mongodb/initialization/using-snapshot.md +++ b/docs/guides/mongodb/initialization/using-snapshot.md @@ -114,7 +114,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). ## Next Steps - Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). diff --git a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md index 543039065..36b5afd99 100644 --- a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md +++ b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md @@ -355,8 +355,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). - ## Next Steps - Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). diff --git a/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md b/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md index 92ab94aa8..85cb4e0e0 100644 --- a/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md +++ b/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md @@ -306,8 +306,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). - ## Next Steps - Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). diff --git a/docs/guides/mongodb/private-registry/using-private-registry.md b/docs/guides/mongodb/private-registry/using-private-registry.md index 706f3bb70..b2e125c3d 100644 --- a/docs/guides/mongodb/private-registry/using-private-registry.md +++ b/docs/guides/mongodb/private-registry/using-private-registry.md @@ -164,7 +164,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). ## Next Steps - [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. diff --git a/docs/guides/mongodb/quickstart/quickstart.md b/docs/guides/mongodb/quickstart/quickstart.md index 8ae0771f6..421b85c5b 100644 --- a/docs/guides/mongodb/quickstart/quickstart.md +++ b/docs/guides/mongodb/quickstart/quickstart.md @@ -413,8 +413,6 @@ namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). - ## Next Steps - [Snapshot and Restore](/docs/guides/mongodb/snapshot/backup-and-restore.md) process of MongoDB databases using KubeDB. - Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. diff --git a/docs/guides/mongodb/snapshot/backup-and-restore.md b/docs/guides/mongodb/snapshot/backup-and-restore.md index 545b13ffb..138dc1196 100644 --- a/docs/guides/mongodb/snapshot/backup-and-restore.md +++ b/docs/guides/mongodb/snapshot/backup-and-restore.md @@ -295,7 +295,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). ## Next Steps - See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). diff --git a/docs/guides/mongodb/snapshot/scheduled-backup.md b/docs/guides/mongodb/snapshot/scheduled-backup.md index 53ede62c9..646947c7a 100644 --- a/docs/guides/mongodb/snapshot/scheduled-backup.md +++ b/docs/guides/mongodb/snapshot/scheduled-backup.md @@ -176,7 +176,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` -If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). ## Next Steps - See the list of supported storage providers for snapshots [here](/docs/concepts/snapshot.md). From 914bda0042e65dae4024b19161295361eb686fe4 Mon Sep 17 00:00:00 2001 From: the-redback Date: Wed, 14 Feb 2018 17:49:23 +0600 Subject: [PATCH 4/5] Fixed next step --- docs/guides/mongodb/monitoring/using-builtin-prometheus.md | 1 - docs/guides/mongodb/private-registry/using-private-registry.md | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md index 36b5afd99..013dce943 100644 --- a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md +++ b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md @@ -363,7 +363,6 @@ namespace "demo" deleted - Take [Scheduled Snapshot](/docs/guides/mongodb/snapshot/scheduled-backup.md) of MongoDB databases using KubeDB. - Initialize [MongoDB with Script](/docs/guides/mongodb/initialization/using-script.md). - Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). -- Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). - Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. - Wondering what features are coming next? Please visit [here](/docs/roadmap.md). - Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). diff --git a/docs/guides/mongodb/private-registry/using-private-registry.md b/docs/guides/mongodb/private-registry/using-private-registry.md index b2e125c3d..21f38c0c7 100644 --- a/docs/guides/mongodb/private-registry/using-private-registry.md +++ b/docs/guides/mongodb/private-registry/using-private-registry.md @@ -172,7 +172,6 @@ namespace "demo" deleted - Initialize [MongoDB with Snapshot](/docs/guides/mongodb/initialization/using-snapshot.md). - Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). - Monitor your MongoDB database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md). -- Use [Private Docker Registry](/docs/guides/mongodb/private-registry/using-private-registry.md) to deploy MongoDB with KubeDB. - Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). - Detail concepts of [Snapshot object](/docs/concepts/snapshot.md). - Wondering what features are coming next? Please visit [here](/docs/roadmap.md). From c52a9335ccd5f4bf398b48e0520afc51e1daade0 Mon Sep 17 00:00:00 2001 From: tamal Date: Wed, 14 Feb 2018 17:00:12 -0800 Subject: [PATCH 5/5] Various corrections --- docs/concepts/databases/mongodb.md | 15 +-- .../builtin-prometheus/rbac/demo-2.yaml | 4 +- .../monitoring/coreos-operator/demo-0.yaml | 3 +- .../coreos-operator/rbac/demo-0.yaml | 7 +- docs/guides/mongodb/README.md | 2 - .../mongodb/initialization/using-script.md | 5 +- .../mongodb/initialization/using-snapshot.md | 10 +- .../monitoring/using-builtin-prometheus.md | 6 +- .../using-private-registry.md | 100 ++++++------------ docs/guides/mongodb/quickstart/quickstart.md | 15 +-- .../mongodb/snapshot/backup-and-restore.md | 10 +- 11 files changed, 60 insertions(+), 117 deletions(-) diff --git a/docs/concepts/databases/mongodb.md b/docs/concepts/databases/mongodb.md index c403d4613..d36c9b3ec 100644 --- a/docs/concepts/databases/mongodb.md +++ b/docs/concepts/databases/mongodb.md @@ -81,15 +81,15 @@ spec: ### spec.storage `spec.storage` is an optional field that specifies the StorageClass of PVCs dynamically allocated to store data for the database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. - - `spec.storage.storageClassName` is the name of the StorageClass used to provision PVCs. PVCs don’t necessarily have to request a class. A PVC with its storageClassName set equal to "" is always interpreted to be requesting a PV with no class, so it can only be bound to PVs with no class (no annotation or one set equal to ""). A PVC with no storageClassName is not quite the same and is treated differently by the cluster depending on whether the DefaultStorageClass admission plugin is turned on. +- `spec.storage.storageClassName` is the name of the StorageClass used to provision PVCs. PVCs don’t necessarily have to request a class. A PVC with its storageClassName set equal to "" is always interpreted to be requesting a PV with no class, so it can only be bound to PVs with no class (no annotation or one set equal to ""). A PVC with no storageClassName is not quite the same and is treated differently by the cluster depending on whether the DefaultStorageClass admission plugin is turned on. - - `spec.storage.accessModes` uses the same conventions as Kubernetes PVCs when requesting storage with specific access modes. +- `spec.storage.accessModes` uses the same conventions as Kubernetes PVCs when requesting storage with specific access modes. - - `spec.storage.resources` can be used to request specific quantities of storage. This follows the same resource model used by PVCs. +- `spec.storage.resources` can be used to request specific quantities of storage. This follows the same resource model used by PVCs. To learn how to configure `spec.storage`, please visit the links below: - - https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims +- https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims ### spec.databaseSecret @@ -178,9 +178,10 @@ KubeDB supports taking periodic snapshots for MongoDB database. This is an optio `KubeDB` provides the flexibility of deploying MongoDB database from a Private Docker Registry. To learn how to deploym MongoDB from a Private Registry, please visit [here](/docs/guides/mongodb/private-registry/using-private-registry.md). ### spec.monitor -MongoDB can be monitored with KubeDB using out-of-the-box builtin-Prometheus and out-of-the-box CoreOS-Prometheus Operator. To learn more, - - [Monitor MongoDB with builtin-Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md) - - [Monitor MongoDB with CoreOS-Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md) +MongoDB managed by KubeDB can be monitored with builtin-Prometheus and CoreOS-Prometheus operator out-of-the-box. To learn more, + +- [Monitor MongoDB with builtin Prometheus](/docs/guides/mongodb/monitoring/using-builtin-prometheus.md) +- [Monitor MongoDB with CoreOS Prometheus operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md) ### spec.resources `spec.resources` is an optional field. This can be used to request compute resources required by the database pods. To learn more, visit [here](http://kubernetes.io/docs/user-guide/compute-resources/). diff --git a/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml b/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml index f92abf11d..e6f011dd1 100644 --- a/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml +++ b/docs/examples/monitoring/builtin-prometheus/rbac/demo-2.yaml @@ -74,9 +74,7 @@ spec: name: prometheus-server-conf - name: prometheus-storage-volume emptyDir: {} - --- - apiVersion: v1 kind: Service metadata: @@ -89,4 +87,4 @@ spec: ports: - port: 9090 targetPort: 9090 - nodePort: 30901 \ No newline at end of file + nodePort: 30901 diff --git a/docs/examples/monitoring/coreos-operator/demo-0.yaml b/docs/examples/monitoring/coreos-operator/demo-0.yaml index 2705d23f8..5e3348fe2 100644 --- a/docs/examples/monitoring/coreos-operator/demo-0.yaml +++ b/docs/examples/monitoring/coreos-operator/demo-0.yaml @@ -5,7 +5,6 @@ metadata: spec: finalizers: - kubernetes - --- apiVersion: extensions/v1beta1 kind: Deployment @@ -23,7 +22,7 @@ spec: spec: containers: - name: prometheus-operator - image: quay.io/coreos/prometheus-operator:v0.14.0 + image: quay.io/coreos/prometheus-operator:v0.16.0 resources: requests: cpu: 100m diff --git a/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml b/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml index 74e67ba15..af0f7652d 100644 --- a/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml +++ b/docs/examples/monitoring/coreos-operator/rbac/demo-0.yaml @@ -5,7 +5,6 @@ metadata: spec: finalizers: - kubernetes - --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole @@ -59,14 +58,12 @@ rules: resources: - namespaces verbs: ["list"] - --- apiVersion: v1 kind: ServiceAccount metadata: name: prometheus-operator namespace: demo - --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding @@ -80,7 +77,6 @@ subjects: - kind: ServiceAccount name: prometheus-operator namespace: demo - --- apiVersion: extensions/v1beta1 kind: Deployment @@ -99,7 +95,7 @@ spec: serviceAccountName: prometheus-operator containers: - name: prometheus-operator - image: quay.io/coreos/prometheus-operator:v0.14.0 + image: quay.io/coreos/prometheus-operator:v0.16.0 resources: requests: cpu: 100m @@ -107,4 +103,3 @@ spec: limits: cpu: 200m memory: 100Mi - diff --git a/docs/guides/mongodb/README.md b/docs/guides/mongodb/README.md index 04aa9c782..1654efb0b 100644 --- a/docs/guides/mongodb/README.md +++ b/docs/guides/mongodb/README.md @@ -1,5 +1,3 @@ - - > New to KubeDB? Please start [here](/docs/guides/README.md). ## MongoDB versions supported by KubeDB diff --git a/docs/guides/mongodb/initialization/using-script.md b/docs/guides/mongodb/initialization/using-script.md index 2980dcac0..914b79aea 100644 --- a/docs/guides/mongodb/initialization/using-script.md +++ b/docs/guides/mongodb/initialization/using-script.md @@ -1,6 +1,7 @@ > New to KubeDB? Please start [here](/docs/guides/README.md). -# Initialize MongoDB with \*.js and/or \*.sh Script +# Initialize MongoDB using Script + This tutorial will show you how to use KubeDB to initialize a MongoDB database with .js and/or .sh script. ## Before You Begin @@ -68,7 +69,7 @@ Here, - `spec.init.scriptSource` specifies a script source used to initialize the database before database server starts. The scripts will be executed alphabatically. In this tutorial, a sample .js script from the git repository `https://github.com/kubedb/mongodb-init-scripts.git` is used to create a test database. You can use other [volume sources](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes) instead of `gitrepo`. The \*.js and/or \*.sh sripts that are stored inside the root folder will be executed alphabatically. The scripts inside child folders will be skipped. -KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. Even if [RBAC is enabled](/docs/guides/rbac.md), it won't affect anything to run MongoDB database . +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. No MongoDB specific RBAC roles are required for [RBAC enabled clusters](/docs/guides/rbac.md). ```console $ kubedb describe mg -n demo mgo-init-script diff --git a/docs/guides/mongodb/initialization/using-snapshot.md b/docs/guides/mongodb/initialization/using-snapshot.md index e4d9e601d..b4b217430 100644 --- a/docs/guides/mongodb/initialization/using-snapshot.md +++ b/docs/guides/mongodb/initialization/using-snapshot.md @@ -8,11 +8,9 @@ At first, you need to have a Kubernetes cluster, and the kubectl command-line to Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). -A `Snapshot` is needed to be existed for this tutorial. Please follow the tutorial of [Snapshot](/docs/guides/mongodb/snapshot/backup-and-restore.md) to create a database and take [Instant Snapshot/Backup](/docs/guides/mongodb/snapshot/backup-and-restore.md#instant-backups) of that database. -Assuming you have created a namespace `demo` and a snapshot `snapshot-infant`, below there is an illustration of initializing a database with `snapshot-infant` snapshot. -If you have changed any of the names of namespace or snapshot, please modify the yamls that you will face while going through this tutorial to meet your specific namespace and snapshot name. +This tutorial assumes that you have created a namespace `demo` and a snapshot `snapshot-infant`. Follow the steps [here](/docs/guides/mongodb/snapshot/backup-and-restore.md) to create a database and take [instant snapshot](/docs/guides/mongodb/snapshot/backup-and-restore.md#instant-backups), if you have not done so already. If you have changed the name of either namespace or snapshot object, please modify the YAMLs used in this tutorial accordingly. -Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). +Note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). ## Create MongoDB with Init-Snapshot Below is the `MongoDB` object created in this tutorial. @@ -46,9 +44,9 @@ mongodb "mgo-init-snapshot" created Here, - - `spec.init.snapshotSource.name` refers to a Snapshot object for a MongoDB database in the same namespaces as this new `mgo-init-snapshot` MongoDB object. +- `spec.init.snapshotSource.name` refers to a Snapshot object for a MongoDB database in the same namespaces as this new `mgo-init-snapshot` MongoDB object. -Now, wait several seconds. KubeDB operator will create a new StatefulSet. Then KubeDB operator launches a Kubernetes Job to initialize the new database using the data from `snapshot-infant` Snapshot. +Now, wait several seconds. KubeDB operator will create a new `StatefulSet`. Then KubeDB operator launches a Kubernetes Job to initialize the new database using the data from `snapshot-infant` Snapshot. ```console $ kubedb get mg -n demo diff --git a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md index 013dce943..ec83297f6 100644 --- a/docs/guides/mongodb/monitoring/using-builtin-prometheus.md +++ b/docs/guides/mongodb/monitoring/using-builtin-prometheus.md @@ -171,6 +171,7 @@ status: ``` We can see that the service contains these specific annotations. The Prometheus server will discover the exporter using these specifications. + ```yaml prometheus.io/path: ... prometheus.io/port: ... @@ -182,6 +183,7 @@ prometheus.io/scrape: ... The Prometheus server is needed to configure so that it can discover endpoints of services. If a Prometheus server is already running in cluster and if it is configured in a way that it can discover service endpoints, no extra configuration will be needed. If there is no existing Prometheus server running, rest of this tutorial will create a Prometheus server with appropriate configuration. The configuration file to `Prometheus-Server` will be provided by `ConfigMap`. The below config map will be created: + ```yaml apiVersion: v1 kind: ConfigMap @@ -228,13 +230,13 @@ data: target_label: kubernetes_name ``` - ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-1.yaml configmap "prometheus-server-conf" created ``` Now, the below yaml is used to deploy Prometheus in kubernetes : + ```yaml apiVersion: apps/v1 kind: Deployment @@ -334,7 +336,6 @@ $ minikube service prometheus-service -n demo --url http://192.168.99.100:30901 ``` - Now, open your browser and go to the following URL: _http://{minikube-ip}:{prometheus-svc-nodeport}_ to visit Prometheus Dashboard. According to the above example, this URL will be [http://192.168.99.100:30901](http://192.168.99.100:30901). Now, if you go the Prometheus Dashboard, you should see that this database endpoint as one of the targets. @@ -355,7 +356,6 @@ $ kubectl delete ns demo namespace "demo" deleted ``` - ## Next Steps - Monitor your MongoDB database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mongodb/monitoring/using-coreos-prometheus-operator.md). - Detail concepts of [MongoDB object](/docs/concepts/databases/mongodb.md). diff --git a/docs/guides/mongodb/private-registry/using-private-registry.md b/docs/guides/mongodb/private-registry/using-private-registry.md index 21f38c0c7..f1d738c57 100644 --- a/docs/guides/mongodb/private-registry/using-private-registry.md +++ b/docs/guides/mongodb/private-registry/using-private-registry.md @@ -1,22 +1,20 @@ > New to KubeDB? Please start [here](/docs/guides/README.md). -# Deploy MongoDB from Private Docker Registry -`KubeDB` can be installed in a way that it only uses images from a specific docker-registry (may be private images) by providing the flag `--docker-registry=`. +# Using Private Docker Registry -This tutorial will show you how to use KubeDB to run MongoDB database using Private Docker images. In this tutorial we will create a `ImagePullSecret` and add that secret in `MongoDB` CRD object specs. If you wish to follow other ways to pull private images see [official docs](https://kubernetes.io/docs/concepts/containers/images/) of kubernetes. +KubeDB operator supports using private Docker registry. This tutorial will show you how to use KubeDB to run MongoDB database using private Docker images. ## 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 [Minikube](https://github.com/kubernetes/minikube). You will also need a docker private [registry](https://docs.docker.com/registry/) or [private repository](https://docs.docker.com/docker-hub/repos/#private-repositories). In this tutorial we will use private repository of [docker hub](https://hub.docker.com/). -Push necessary `KubeDB` images in your repository. For mongodb, total three images need to be pushed in private registry or repository for running `KubeDB` operator smoothly. +You have to push the required images from KubeDB's [Docker hub account](https://hub.docker.com/r/kubedb/) into your private registry. For mongodb, push the following images to your private registry. - [kubedb/operator](https://hub.docker.com/r/kubedb/operator) - [kubedb/mongo](https://hub.docker.com/r/kubedb/mongo) - [kubedb/mongo-tools](https://hub.docker.com/r/kubedb/mongo-tools) - ```console $ export DOCKER_REGISTRY= @@ -27,85 +25,50 @@ $ docker pull kubedb/mongo-tools:3.4 ; docker tag kubedb/mongo-tools:3.4 $DOCKER $ docker pull kubedb/mongo-tools:3.6 ; docker tag kubedb/mongo-tools:3.6 $DOCKER_REGISTRY/mongo-tools:3.6 ; docker push $DOCKER_REGISTRY/mongo-tools:3.6 ``` -KubeDB needs to be installed by providing `--docker-registry` and `--image-pull-secret` value. Follow the steps to [install `KubeDB-Operator`](/docs/setup/install.md) properly in cluster so that to points to the DOCKER_REGISTRY you wish to pull images from. - -To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: - -```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml -namespace "demo" created - -$ kubectl get ns -NAME STATUS AGE -default Active 45m -demo Active 10s -kube-public Active 45m -kube-system Active 45m -``` - ## Create ImagePullSecret -ImagePullSecrets is a type of a Kubernete Secret whose sole purpose is to pull private images from a Docker registry. It allows you to specify the Url of the docker registry, credentials for logging in and the image name of your private docker image. -### Log in to Docker -Before creating `ImagePullSecret`, log in to your private registry manually. This will create a ~/.docker directory and a ~/.docker/config.json file. See here for details of [docker login](https://docs.docker.com/engine/reference/commandline/login/) options. +ImagePullSecrets is a type of a Kubernete Secret whose sole purpose is to pull private images from a Docker registry. It allows you to specify the url of the docker registry, credentials for logging in and the image name of your private docker image. -```console -# docker login -$ docker login -Username: -Password: -Login Succeeded -``` - -When prompted, enter your Docker username and password. - -The login process creates or updates a config.json file that holds an authorization token. -View the config.json file. The output contains a section similar to this: +Run the following command, substituting the appropriate uppercase values to create an image pull secret for your private docker registry: ```console -$ cat ~/.docker/config.json -{ - "auths": { - "https://index.docker.io/v1/": { - "auth": "c3R...zE2" - } - } -} +$ kubectl create secret docker-registry myregistrykey \ + --docker-server=DOCKER_REGISTRY_SERVER \ + --docker-username=DOCKER_USER \ + --docker-email=DOCKER_EMAIL \ + --docker-password=DOCKER_PASSWORD + +secret "myregistrykey" created. ``` -### Create a Secret that holds your authorization token -We will create a secret named `myregistrykey` in `demo` namespace so that kubernetes can pull `mongo` and `mongo-tools` images from private repository. +If you wish to follow other ways to pull private images see [official docs](https://kubernetes.io/docs/concepts/containers/images/) of kubernetes. -```console -$ cat ~/.docker/config.json | base64 - -$ gedit image-pull-secret.yaml -``` +## Install KubeDB operator +When installing KubeDB operator, set the flags `--docker-registry` and `--image-pull-secret` to appropriate value. Follow the steps to [install KubeDB operator](/docs/setup/install.md) properly in cluster so that to points to the DOCKER_REGISTRY you wish to pull images from. -Now paste the below yaml in the gedit editor and replace `` with base64 encoded `.docker/config.json`. +## Create Demo namespace -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: myregistrykey - namespace: demo -data: - .dockerconfigjson: -type: kubernetes.io/dockerconfigjson -``` -Now save the yaml file and run the below command to create secret: +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. Run the following command to prepare your cluster for this tutorial: ```console -$ kubectl create -f image-pull-secret.yaml -secret "myregistrykey" created +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/demo-0.yaml +namespace "demo" created + +$ kubectl get ns +NAME STATUS AGE +default Active 45m +demo Active 10s +kube-public Active 45m +kube-system Active 45m ``` ## Deploy MongoDB database from Private Registry + While deploying `MongoDB` from private repository, you have to add `myregistrykey` secret in `MongoDB` `spec.imagePullSecrets`. Below is the MongoDB CRD object we will create. + ```yaml apiVersion: kubedb.com/v1alpha1 kind: MongoDB @@ -125,6 +88,7 @@ spec: imagePullSecrets: - name: myregistrykey ``` + Now run the command to deploy this `MongoDB` object: ```console @@ -149,10 +113,10 @@ NAME STATUS AGE mgo-pvt-reg Running 1m ``` - ## Snapshot -We don't need to add `imagePullSecret` for `snapshot` objects. -User can create snapshot [in normal way](/docs/guides/mongodb/snapshot/backup-and-restore.md) and `KubeDB-Operator` will re-use the `ImagePullSecret` from `MongoDB` object. + +We don't need to add `imagePullSecret` for `snapshot` objects. +Just create [snapshot object](/docs/guides/mongodb/snapshot/backup-and-restore.md) and KubeDB operator will reuse the `ImagePullSecret` from `MongoDB` object. ## Cleaning up To cleanup the Kubernetes resources created by this tutorial, run: diff --git a/docs/guides/mongodb/quickstart/quickstart.md b/docs/guides/mongodb/quickstart/quickstart.md index 421b85c5b..14b81edbb 100644 --- a/docs/guides/mongodb/quickstart/quickstart.md +++ b/docs/guides/mongodb/quickstart/quickstart.md @@ -1,5 +1,3 @@ - - > New to KubeDB? Please start [here](/docs/guides/README.md). # MongoDB QuickStart @@ -66,7 +64,7 @@ Here, - `spec.storage` specifies the StorageClass of PVC dynamically allocated to store data for this database. This storage spec will be passed to the StatefulSet created by KubeDB operator to run database pods. You can specify any StorageClass available in your cluster with appropriate resource requests. If no storage spec is given, an `emptyDir` is used. -KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. Even if [RBAC is enabled](/docs/guides/rbac.md), it won't affect anything to run MongoDB database . +KubeDB operator watches for `MongoDB` objects using Kubernetes api. When a `MongoDB` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MongoDB object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. No MongoDB specific RBAC permission is required in [RBAC enabled clusters](/docs/guides/rbac.md). ```console $ kubedb describe mg -n demo mgo-quickstart @@ -227,14 +225,13 @@ bye ## Pause Database -The Admission Webhook of KubeDB gives some extra strength to `KubeDB-Operator` and one of the features is `spec.doNotPause`. If admission webhook is enabled, It prevents user from deleting the database as long as the `spec.doNotPause` is set to true. Since the MongoDB object created in this tutorial has `spec.doNotPause` set to true, if you delete the MongoDB object, KubeDB operator will nullify the delete operation. You can see this below: +KubeDB takes advantage of `ValidationWebhook` feature in Kubernetes 1.9.0 or later clusters to implement `doNotPause` feature. If admission webhook is enabled, It prevents user from deleting the database as long as the `spec.doNotPause` is set to true. Since the MongoDB object created in this tutorial has `spec.doNotPause` set to true, if you delete the MongoDB object, KubeDB operator will nullify the delete operation. You can see this below: ```console $ kubedb delete mg mgo-quickstart -n demo error: MongoDB "mgo-quickstart" can't be paused. To continue delete, unset spec.doNotPause and retry. ``` - Now, run `kubedb edit mg mgo-quickstart -n demo` to set `spec.doNotPause` to false or remove this field (which default to false). Then if you delete the MongoDB object, KubeDB operator will delete the StatefulSet and its pods, but leaves the PVCs unchanged. In KubeDB parlance, we say that `mgo-quickstart` MongoDB database has entered into dormant state. This is represented by KubeDB operator by creating a matching DormantDatabase object. ```yaml @@ -292,7 +289,6 @@ status: phase: Paused ``` - Here, - `spec.origin` is the spec of the original spec of the original MongoDB object. @@ -320,7 +316,6 @@ status: ... ``` - KubeDB operator will notice that `spec.resume` is set to true. KubeDB operator will delete the DormantDatabase object and create a new MongoDB object using the original spec. This will in turn start a new StatefulSet which will mount the originally created PVCs. Thus the original database is resumed. Please note that the dormant database can also be resumed by creating same `MongoDB` database by using same Specs. In this tutorial, the dormant database can be resumed by creating `MongoDB` database using demo-1.yaml file. The below command resumes the dormant database `mgo-quickstart` that was created before. @@ -331,8 +326,8 @@ validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examp mongodb "mgo-quickstart" created ``` - ## Wipeout Dormant Database + You can also wipe out a DormantDatabase by setting `spec.wipeOut` to true. KubeDB operator will delete the PVCs, delete any relevant Snapshot objects for this database and also delete snapshot data stored in the Cloud Storage buckets. There is no way to resume a wiped out database. So, be sure before you wipe out a database. ```yaml @@ -388,8 +383,8 @@ mgo-quickstart WipedOut 1m ``` - ## Delete Dormant Database + You still have a record that there used to be a MongoDB database `mgo-quickstart` in the form of a DormantDatabase database `mgo-quickstart`. Since you have already wiped out the database, you can delete the DormantDatabase object. ```console @@ -397,8 +392,8 @@ $ kubedb delete drmn mgo-quickstart -n demo dormantdatabase "mgo-quickstart" deleted ``` - ## Cleaning up + To cleanup the Kubernetes resources created by this tutorial, run: ```console diff --git a/docs/guides/mongodb/snapshot/backup-and-restore.md b/docs/guides/mongodb/snapshot/backup-and-restore.md index 138dc1196..cdf0e7ee9 100644 --- a/docs/guides/mongodb/snapshot/backup-and-restore.md +++ b/docs/guides/mongodb/snapshot/backup-and-restore.md @@ -1,7 +1,7 @@ > New to KubeDB? Please start [here](/docs/guides/README.md). # Database Snapshots -This tutorial will show you how to use KubeDB to take snapshot of a MongoDB database. +This tutorial will show you how to take snapshots of a KubeDB managed MongoDB 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 [Minikube](https://github.com/kubernetes/minikube). @@ -26,7 +26,7 @@ validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examp mongodb "mgo-infant" created ``` -Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). +Please note that the yaml files that are used in this tutorial, stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). ## Instant Backups You can easily take a snapshot of `MongoDB` database by creating a `Snapshot` object. When a `Snapshot` object is created, KubeDB operator will launch a Job that runs the `mongodump` command and uploads the output bson file to various cloud providers S3, GCS, Azure, OpenStack Swift and/or locally mounted volumes using [osm](https://github.com/appscode/osm). @@ -47,7 +47,6 @@ $ kubectl create secret generic mg-snap-secret -n demo \ secret "mg-snap-secret" created ``` - ```yaml $ kubectl get secret mg-snap-secret -n demo -o yaml apiVersion: v1 @@ -65,7 +64,6 @@ metadata: type: Opaque ``` - To lean how to configure other storage destinations for Snapshots, please visit [here](/docs/concepts/snapshot.md). Now, create the Snapshot object. ```yaml @@ -83,19 +81,16 @@ spec: bucket: restic ``` - ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-2.yaml validating "https://raw.githubusercontent.com/kubedb/cli/0.8.0-beta.1/docs/examples/mongodb/snapshot/demo-2.yaml" snapshot "snapshot-infant" created - $ kubedb get snap -n demo NAME DATABASE STATUS AGE snapshot-infant mg/mgo-infant Running 47s ``` - ```yaml $ kubedb get snap -n demo snapshot-infant -o yaml apiVersion: kubedb.com/v1alpha1 @@ -125,7 +120,6 @@ status: startTime: 2018-02-02T10:05:37Z ``` - Here, - `metadata.labels` should include the type of database `kubedb.com/kind: MongoDB` whose snapshot will be taken.