From 7452ab301a9b08fd6c1aeeebd51934095da3f789 Mon Sep 17 00:00:00 2001 From: the-redback Date: Mon, 1 Oct 2018 10:52:42 +0600 Subject: [PATCH] Updated MySQL doc for 0.9.0 --- docs/concepts/catalog/mysql.md | 79 +++++ docs/concepts/databases/mysql.md | 296 ++++++++++++------ .../examples/mysql/Initialization/demo-1.yaml | 5 +- .../examples/mysql/Initialization/demo-2.yaml | 2 + docs/examples/mysql/cli/mysql-demo.yaml | 2 +- .../mysql/custom-config/mysql-custom.yaml | 4 +- .../mysql/private-registry/demo-2.yaml | 6 +- docs/examples/mysql/quickstart/demo-2.yaml | 1 + docs/examples/mysql/snapshot/demo-2.yaml | 2 +- docs/examples/mysql/snapshot/demo-3.yaml | 2 + docs/examples/mysql/snapshot/demo-4.yaml | 7 +- docs/guides/mysql/README.md | 47 +-- docs/guides/mysql/cli/cli.md | 149 +++++---- .../custom-config/using-custom-config.md | 76 ++--- .../mysql/initialization/using-script.md | 227 ++++++++------ .../mysql/initialization/using-snapshot.md | 114 ++++--- .../monitoring/using-builtin-prometheus.md | 233 ++++++++------ .../using-coreos-prometheus-operator.md | 223 +++++++------ .../using-private-registry.md | 132 ++++---- docs/guides/mysql/quickstart/quickstart.md | 292 +++++++++++------ .../mysql/snapshot/backup-and-restore.md | 281 ++++++++++------- .../guides/mysql/snapshot/scheduled-backup.md | 72 ++--- docs/images/mysql/mysql-lifecycle.png | Bin 66555 -> 82540 bytes 23 files changed, 1373 insertions(+), 879 deletions(-) create mode 100644 docs/concepts/catalog/mysql.md diff --git a/docs/concepts/catalog/mysql.md b/docs/concepts/catalog/mysql.md new file mode 100644 index 000000000..3af04156d --- /dev/null +++ b/docs/concepts/catalog/mysql.md @@ -0,0 +1,79 @@ +--- +title: MySQLVersion +menu: + docs_0.9.0-beta.1: + identifier: mysql-version + name: MySQLVersion + parent: catalog + weight: 30 +menu_name: docs_0.9.0-beta.1 +section_menu_id: concepts +--- + +# MySQLVersion + +## What is MySQLVersion + +`MySQLVersion` is a Kubernetes `Custom Resource Definitions` (CRD). It provides a declarative configuration to specify the docker images to be used for [MySQL](https://www.mysql.org/) database deployed with KubeDB in Kubernetes native way. + +When you install KubeDB, `MySQLVersion` crd will be created automatically for every supported MySQL versions. You have to specify the name of `MySQLVersion` crd in `spec.version` field of [MySQL](/docs/concepts/databases/mysql.md) crd. Then, KubeDB will use the docker images specified in the `MySQLVersion` crd to create your expected database. + +Using a separate crd for specifying respective docker images allows us to modify the images independent of KubeDB operator. This will also allow the users to use a custom image for the database. + +## MySQLVersion Specification + +As with all other Kubernetes objects, a MySQLVersion needs `apiVersion`, `kind`, and `metadata` fields. It also needs a `.spec` section. + +```yaml +apiVersion: catalog.kubedb.com/v1alpha1 +kind: MySQLVersion +metadata: + name: "8.0-v1" + labels: + app: kubedb +spec: + version: "8.0" + db: + image: "${KUBEDB_DOCKER_REGISTRY}/mysql:8.0-v1" + exporter: + image: "${KUBEDB_DOCKER_REGISTRY}/mysqld-exporter:v0.11.0" + tools: + image: "${KUBEDB_DOCKER_REGISTRY}/mysql-tools:8.0-v1" +``` + +### metadata.name + +`metadata.name` is a required field that specify the name of the `MySQLVersion` crd. You have to specify this name in `spec.version` field of [MySQL](/docs/concepts/databases/mysql.md) crd. + +We follow this convention for naming MySQLVersion crd: + +- Name format: `{Original MySQL image version}-{modification tag}` + +We modify original MySQL docker image to support additional features. An image with higher modification tag will have more feature than the images with lower modification tag. Hence, it is recommended to use MySQLVersion crd with highest modification tag to enjoy latest features. + +### spec.version + +`spec.version` is a required field that specifies the original version of MySQL database that has been used to build the docker image specified in `spec.db.image` field. + +### spec.deprecated + +`spec.deprecated` is an optional field that specifies whether the docker images specified here is supported by the current KubeDB operator. For example, we have modified `kubedb/mysql:8.0` docker image to support custom configuration and re-tagged as `kubedb/mysql:8.0-v1`. Now, KubeDB `0.9.0` supports providing custom configuration which required `kubedb/mysql:8.0-v1` docker image. So, we have marked `kubedb/mysql:8.0` as deprecated for KubeDB `0.9.0`. + +The default value of this field is `false`. If `spec.depcrecated` is set `true`, KubeDB operator will not create the database and other respective resources for this version. + +### spec.db.image + +`spec.db.image` is a required field that specifies the docker image which will be used to create Statefulset by KubeDB operator to create expected MySQL database. + +### spec.exporter.image + +`spec.exporter.image` is required field that specifies the image which will be used to export Prometheus metrics. + +### spec.tools.image + +`spec.tools.image` is a required field that specifies the image which will be used to take backup and initialize database from snapshot. + +## Next Steps + +- Learn about MySQL crd [here](/docs/concepts/databases/mysql.md). +- Deploy your first MySQL database with KubeDB by following the guide [here](/docs/guides/mysql/quickstart/quickstart.md). diff --git a/docs/concepts/databases/mysql.md b/docs/concepts/databases/mysql.md index d7c11450f..11a964fd5 100644 --- a/docs/concepts/databases/mysql.md +++ b/docs/concepts/databases/mysql.md @@ -29,7 +29,10 @@ metadata: name: m1 namespace: demo spec: - version: "8.0" + version: "8.0-v1" + databaseSecret: + secretName: m1-auth + storageType: "Durable" storage: storageClassName: "standard" accessModes: @@ -37,34 +40,16 @@ spec: resources: requests: storage: 50Mi - databaseSecret: - secretName: m1-auth - configSource: - configMap: - name: my-custom-config - env: - - name: MYSQL_DATABASE - value: myDB - nodeSelector: - disktype: ssd init: scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . + configMap: + name: mg-init-script backupSchedule: cronExpression: "@every 6h" storageSecretName: ms-snap-secret gcs: - bucket: restic + bucket: kubedb prefix: demo - resources: - requests: - memory: "64Mi" - cpu: "250m" - limits: - memory: "128Mi" - cpu: "500m" doNotPause: true monitor: agent: prometheus.io/coreos-operator @@ -73,46 +58,63 @@ spec: labels: app: kubedb interval: 10s - resources: - requests: - memory: "64Mi" - cpu: "250m" - limits: - memory: "128Mi" - cpu: "500m" + configSource: + configMap: + name: mg-custom-config + podTemplate: + annotation: + passMe: ToDatabasePod + controller: + annotation: + passMe: ToStatefulSet + spec: + schedulerName: my-scheduler + nodeSelector: + disktype: ssd + imagePullSecrets: + - name: myregistrykey + env: + - name: MYSQL_DATABASE + value: myDB + resources: + requests: + memory: "64Mi" + cpu: "250m" + limits: + memory: "128Mi" + cpu: "500m" + serviceTemplate: + annotation: + passMe: ToService + spec: + type: NodePort + updateStrategy: "RollingUpdate" + terminationPolicy: "Pause" ``` ### spec.version -`spec.version` is a required field specifying the version of MySQL database. Official [mysql docker images](https://hub.docker.com/r/library/mysql/tags/) will be used for the specific version. - -### spec.storage - -Since 0.8.0, `spec.storage` is a required 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. +`spec.version` is a required field specifying the name of the [MySQLVersion](/docs/concepts/catalog/mysql.md) crd where the docker images are specified. Currently, when you install KubeDB, it creates the following `MySQLVersion` crd, -- `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.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 +- `8.0-v1`, `8.0`, `8-v1`, `8` +- `5.7-v1`, `5.7`, `5-v1`, `5` ### spec.databaseSecret -`spec.databaseSecret` is an optional field that points to a Secret used to hold credentials for `mysql` superuser. If not set, KubeDB operator creates a new Secret `{mysql-object-name}-auth` for storing the password for `mysql` superuser for each MySQL object. If you want to use an existing secret please specify that when creating the MySQL object using `spec.databaseSecret.secretName`. +`spec.databaseSecret` is an optional field that points to a Secret used to hold credentials for `mysql` root user. If not set, KubeDB operator creates a new Secret `{mysql-object-name}-auth` for storing the password for `mysql` root user for each MySQL object. If you want to use an existing secret please specify that when creating the MySQL object using `spec.databaseSecret.secretName`. This secret contains a `user` key and a `password` key which contains the `username` and `password` respectively for `mysql` root user. Here, the value of `user` key is fixed to be `root`. Example: ```console -$ kubectl create secret generic m1-auth -n demo --from-literal=user=root --from-literal=password=6q8u_2jMOW-OOZXk +$ kubectl create secret generic m1-auth -n demo \ +--from-literal=user=root \ +--from-literal=password=6q8u_2jMOW-OOZXk secret "m1-auth" created ``` -```console -$ kubectl get secret -n demo m1-auth -o yaml +```yaml apiVersion: v1 data: password: NnE4dV8yak1PVy1PT1pYaw== @@ -126,55 +128,36 @@ metadata: type: Opaque ``` -### spec.configSource - -`spec.configSource` is an optional field that allows users to provide custom configuration for MySQL. This field accepts a [`VolumeSource`](https://github.com/kubernetes/api/blob/release-1.11/core/v1/types.go#L47). So you can use any kubernetes supported volume source such as `configMap`, `secret`, `azureDisk` etc. To learn more about how to use a custom configuration file see [here](/docs/guides/mysql/custom-config/using-custom-config.md). - -### spec.env +### spec.storageType -`spec.env` is an optional field that specifies the environment variables to pass to the MySQL docker image. To know about supported environment variables, please visit [here](https://hub.docker.com/_/mysql/). +`spec.storageType` is an optional field that specifies the type of storage to use for database. It can be either `Durable` or `Ephemeral`. The default value of this field is `Durable`. If `Ephemeral` is used then KubeDB will create MySQL database using [emptyDir](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) volume. In this case, you don't have to specify `spec.storage` field. -Note that, Kubedb does not allow `MYSQL_ROOT_PASSWORD`, `MYSQL_ALLOW_EMPTY_PASSWORD`, `MYSQL_RANDOM_ROOT_PASSWORD`, and `MYSQL_ONETIME_PASSWORD` environment variables to set in `spec.env`. If you want to set the root password, please use `spec.databaseSecret` instead described earlier. +### spec.storage -If you try to set any of the forbidden environment variables i.e. `MYSQL_ROOT_PASSWORD` in MySQL crd, Kubed operator will reject the request with following error, -``` -Error from server (Forbidden): error when creating "./mysql.yaml": admission webhook "mysql.validators.kubedb.com" denied the request: environment variable MYSQL_ROOT_PASSWORD is forbidden to use in MySQL spec -``` +Since 0.9.0, If you set `spec.storageType:` to `Durable`, then `spec.storage` is a required 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. -Also note that Kubedb does not allow to update the environment variables as updating them does not have any effect once the database is created. If you try to update environment variables, Kubedb operator will reject the request with following error, -``` -Error from server (BadRequest): error when applying patch: -.... -for: "./mysql.yaml": admission webhook "mysql.validators.kubedb.com" denied the request: precondition failed for: -.... -spec:map[env:[map[name: value:]]]].At least one of the following was changed: - apiVersion - kind - name - namespace - spec.version - spec.storage - spec.databaseSecret - spec.nodeSelector - spec.init - spec.env -``` +- `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.resources` can be used to request specific quantities of storage. This follows the same resource model used by PVCs. -### spec.nodeSelector +To learn how to configure `spec.storage`, please visit the links below: -`spec.nodeSelector` is an optional field that specifies a map of key-value pairs. For the pod to be eligible to run on a node, the node must have each of the indicated key-value pairs as labels (it can have additional labels as well). To learn more, see [here](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) . +- https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims ### spec.init `spec.init` is an optional section that can be used to initialize a newly created MySQL database. MySQL databases can be initialized in one of two ways: + 1. Initialize from Script + 2. Initialize from Snapshot + #### Initialize via Script -To initialize a MySQL database using a script (shell script, sql script etc.), set the `spec.init.scriptSource` section when creating a MySQL object. It will execute files alphabetically with extensions `.sh` , `.sql` and `.sql.gz` that are found in the repository. ScriptSource must have following information: +To initialize a MySQL database using a script (shell script, sql script etc.), set the `spec.init.scriptSource` section when creating a MySQL object. It will execute files alphabetically with extensions `.sh` , `.sql` and `.sql.gz` that are found in the repository. The scripts inside child folders will be skipped. ScriptSource must have following information: - [VolumeSource](https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes): Where your script is loaded from. -Below is an example showing how a shell script from a git repository can be used to initialize a MySQL database. +Below is an example showing how a script from a configMap can be used to initialize a MySQL database. ```yaml apiVersion: kubedb.com/v1alpha1 @@ -182,21 +165,21 @@ kind: MySQL metadata: name: m1 spec: - version: 8.0 + version: 8.0-v1 init: scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . + configMap: + name: mysql-init-script ``` -In the above example, KubeDB operator will launch a Job to execute all sql script of `mysql-init-script` repo in alphabetical order once StatefulSet pods are running. +In the above example, KubeDB operator will launch a Job to execute all js script of `mysql-init-script` in alphabetical order once StatefulSet pods are running. For more details tutorial on how to initialize from script, please visit [here](/docs/guides/mysql/initialization/script-source.md). #### Initialize from Snapshots To initialize from prior snapshots, set the `spec.init.snapshotSource` section when creating a MySQL object. In this case, SnapshotSource must have following information: - `name:` Name of the Snapshot +- `namespace:` Namespace of the Snapshot ```yaml apiVersion: kubedb.com/v1alpha1 @@ -204,13 +187,18 @@ kind: MySQL metadata: name: m1 spec: - version: 8.0 + version: 8.0-v1 init: snapshotSource: name: "snapshot-xyz" + namespace: "demo" ``` -In the above example, MySQL database will be initialized from Snapshot `snapshot-xyz` in `default` namespace. Here, KubeDB operator will launch a Job to initialize MySQL once StatefulSet pods are running. +In the above example, MySQL database will be initialized from Snapshot `snapshot-xyz` in `demo` namespace. Here, KubeDB operator will launch a Job to initialize MySQL once StatefulSet pods are running. + +When initializing from Snapshot, root user credentials must have to match with the previous one. For example, let's say, Snapshot `snapshot-xyz` is for MySQL `mysql-old`. In this case, new MySQL `mysql-db` should use the same credentials for root user of `mysql-old`. Otherwise, the restoration process will fail. + +For more details tutorial on how to initialize from snapshot, please visit [here](/docs/guides/mysql/initialization/snapshot-source.md). ### spec.backupSchedule @@ -218,26 +206,146 @@ KubeDB supports taking periodic snapshots for MySQL database. This is an optiona - `spec.backupSchedule.cronExpression` is a required [cron expression](https://github.com/robfig/cron/blob/v2/doc.go#L26). This specifies the schedule for backup operations. - `spec.backupSchedule.{storage}` is a required field that is used as the destination for storing snapshot data. KubeDB supports cloud storage providers like S3, GCS, Azure and OpenStack Swift. It also supports any locally mounted Kubernetes volumes, like NFS, Ceph, etc. Only one backend can be used at a time. To learn how to configure this, please visit [here](/docs/concepts/snapshot.md). -- `spec.backupSchedule.resources` is an optional field that can request compute resources required by Jobs used to take a snapshot or initialize databases from a snapshot. To learn more, visit [here](http://kubernetes.io/docs/user-guide/compute-resources/). - -### spec.doNotPause -`spec.doNotPause` is an optional field that tells KubeDB operator that if this MySQL 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 MySQL object put the database into a dormant state. THe StatefulSet for a DormantDatabase is deleted but the underlying PVCs are left intact. This allows users to resume the database later. +You can also specify a template for pod of backup job through `spec.backupSchedule.podTemplate`. KubeDB will use the information you have provided in `podTemplate` to create the backup job. KubeDB accept following fields to set in `spec.backupSchedule.podTemplate`: + +- annotations (pod's annotation) +- controller.annotations (job's annotation) +- spec: + - args + - env + - resources + - imagePullSecrets + - initContainers + - nodeSelector + - affinity + - schedulerName + - tolerations + - priorityClassName + - priority + - securityContext -### spec.imagePullSecret +### spec.doNotPause -`KubeDB` provides the flexibility of deploying MySQL database from a private Docker registry. To learn how to deploym MySQL from a private registry, please visit [here](/docs/guides/mysql/private-registry/using-private-registry.md). +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 users from deleting the database as long as the `spec.doNotPause` is set `true`. If not set or set to `false`, deleting a MySQL object put the database into a dormant state. The StatefulSet for a DormantDatabase is deleted but the underlying PVCs are left intact. This allows users to resume the database later. ### spec.monitor MySQL managed by KubeDB can be monitored with builtin-Prometheus and CoreOS-Prometheus operator out-of-the-box. To learn more, - [Monitor MySQL with builtin Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md) -- [Monitor MySQL with CoreOS Prometheus Operator](/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md) +- [Monitor MySQL with CoreOS Prometheus operator](/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md) + +### spec.configSource + +`spec.configSource` is an optional field that allows users to provide custom configuration for MySQL. This field accepts a [`VolumeSource`](https://github.com/kubernetes/api/blob/release-1.11/core/v1/types.go#L47). So you can use any kubernetes supported volume source such as `configMap`, `secret`, `azureDisk` etc. To learn more about how to use a custom configuration file see [here](/docs/guides/mysql/custom-config/using-custom-config.md). + +### spec.podTemplate + +KubeDB allows providing a template for database pod through `spec.podTemplate`. KubeDB operator will pass the information provided in `spec.podTemplate` to the StatefulSet created for MySQL database. + +KubeDB accept following fields to set in `spec.podTemplate:` + +- annotations (pod's annotation) +- controller.annotations (statefulset's annotation) +- spec: + - env + - resources + - initContainers + - imagePullSecrets + - nodeSelector + - affinity + - schedulerName + - tolerations + - priorityClassName + - priority + - securityContext + +Uses of some field of `spec.podTemplate` is described below, + +#### spec.podTemplate.spec.env + +`spec.podTemplate.spec.env` is an optional field that specifies the environment variables to pass to the MySQL docker image. To know about supported environment variables, please visit [here](https://hub.docker.com/_/mysql/). + +Note that, Kubedb does not allow `MYSQL_ROOT_PASSWORD`, `MYSQL_ALLOW_EMPTY_PASSWORD`, `MYSQL_RANDOM_ROOT_PASSWORD`, and `MYSQL_ONETIME_PASSWORD` environment variables to set in `spec.env`. If you want to set the root password, please use `spec.databaseSecret` instead described earlier. + +If you try to set any of the forbidden environment variables i.e. `MYSQL_ROOT_PASSWORD` in MySQL crd, Kubed operator will reject the request with following error, + +```ini +Error from server (Forbidden): error when creating "./mysql.yaml": admission webhook "mysql.validators.kubedb.com" denied the request: environment variable MYSQL_ROOT_PASSWORD is forbidden to use in MySQL spec +``` + +Also note that Kubedb does not allow to update the environment variables as updating them does not have any effect once the database is created. If you try to update environment variables, Kubedb operator will reject the request with following error, + +```ini +Error from server (BadRequest): error when applying patch: +... +for: "./mysql.yaml": admission webhook "mysql.validators.kubedb.com" denied the request: precondition failed for: +...At least one of the following was changed: + apiVersion + kind + name + namespace + spec.databaseSecret + spec.init + spec.storageType + spec.storage + spec.podTemplate.spec.nodeSelector + spec.podTemplate.spec.env +``` + +#### spec.podTemplate.spec.imagePullSecrets + +`KubeDB` provides the flexibility of deploying MySQL database from a private Docker registry. `spec.podTemplate.spec.imagePullSecrets` is an optional field that points to secrets to be used for pulling docker image if you are using a private docker registry. To learn how to deploy MySQL from a private registry, please visit [here](/docs/guides/mysql/private-registry/using-private-registry.md). + +#### spec.podTemplate.spec.nodeSelector + +`spec.podTemplate.spec.nodeSelector` is an optional field that specifies a map of key-value pairs. For the pod to be eligible to run on a node, the node must have each of the indicated key-value pairs as labels (it can have additional labels as well). To learn more, see [here](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) . + +#### spec.podTemplate.spec.resources + +`spec.podTemplate.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/). + +### spec.serviceTemplate + +You can also provide a template for the services created by KubeDB operator for MySQL database through `spec.serviceTemplate`. This will allow you to set the type and other properties of the services. + +KubeDB allows following fields to set in `spec.serviceTemplate`: + +- annotations +- type +- clusterIP +- externalIPs +- loadBalancerIP +- loadBalancerSourceRanges +- externalTrafficPolicy +- healthCheckNodePort + +### spec.updateStrategy + +You can specify [update strategy](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies) of StatefulSet created by KubeDB for MySQL database thorough `spec.updateStrategy` field. The default value of this field is `RollingUpdate`. In future, we will use this field to determine how automatic migration from old KubeDB version to new one should behave. + +### spec.terminationPolicy + +You can control which resources KubeDB should keep or delete when you delete MySQL crd through `spec.terminationPolicy`. KubeDB provides following three termination policies: + +- Pause +- Delete +- WipeOut + +Following table show what KubeDB does when you delete MySQL crd for different termination policies, -### spec.resources +| Behaviour | Pause | Delete | WipeOut | +| -------------------------------------- | :------: | :------: | :------: | +| 1. Create Dormant Database | ✓ | ✗ | ✗ | +| 2. Delete StatefulSet | ✓ | ✓ | ✓ | +| 3. Delete Services | ✓ | ✓ | ✓ | +| 4. Delete PVCs | ✗ | ✓ | ✓ | +| 5. Delete Secrets | ✗ | ✗ | ✓ | +| 6. Delete Snapshots | ✗ | ✗ | ✓ | +| 7. Delete Snapshot data from bucket | ✗ | ✗ | ✓ | -`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/). +If you don't specify `spec.terminationPolicy` KubeDB uses `Pause` termination policy by default. ## Next Steps diff --git a/docs/examples/mysql/Initialization/demo-1.yaml b/docs/examples/mysql/Initialization/demo-1.yaml index 91bf90535..b64ec8e42 100644 --- a/docs/examples/mysql/Initialization/demo-1.yaml +++ b/docs/examples/mysql/Initialization/demo-1.yaml @@ -15,6 +15,5 @@ spec: storage: 50Mi init: scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . + configMap: + name: my-init-script diff --git a/docs/examples/mysql/Initialization/demo-2.yaml b/docs/examples/mysql/Initialization/demo-2.yaml index a3301aa09..82a66c85e 100644 --- a/docs/examples/mysql/Initialization/demo-2.yaml +++ b/docs/examples/mysql/Initialization/demo-2.yaml @@ -5,6 +5,8 @@ metadata: namespace: demo spec: version: "8.0-v1" + databaseSecret: + secretName: mysql-infant-auth storage: storageClassName: "standard" accessModes: diff --git a/docs/examples/mysql/cli/mysql-demo.yaml b/docs/examples/mysql/cli/mysql-demo.yaml index 896b8213a..1e193022c 100644 --- a/docs/examples/mysql/cli/mysql-demo.yaml +++ b/docs/examples/mysql/cli/mysql-demo.yaml @@ -1,7 +1,7 @@ apiVersion: kubedb.com/v1alpha1 kind: MySQL metadata: - name: mysql-demo + name: mysql-qa spec: version: "8.0-v1" storage: diff --git a/docs/examples/mysql/custom-config/mysql-custom.yaml b/docs/examples/mysql/custom-config/mysql-custom.yaml index 44d95ca35..36c602af6 100644 --- a/docs/examples/mysql/custom-config/mysql-custom.yaml +++ b/docs/examples/mysql/custom-config/mysql-custom.yaml @@ -7,8 +7,8 @@ spec: version: "8.0-v1" doNotPause: true configSource: - configMap: - name: my-custom-config + configMap: + name: my-custom-config storage: storageClassName: "standard" accessModes: diff --git a/docs/examples/mysql/private-registry/demo-2.yaml b/docs/examples/mysql/private-registry/demo-2.yaml index f9fbfff16..f7287d207 100644 --- a/docs/examples/mysql/private-registry/demo-2.yaml +++ b/docs/examples/mysql/private-registry/demo-2.yaml @@ -13,5 +13,7 @@ spec: resources: requests: storage: 50Mi - imagePullSecrets: - - name: myregistrykey + podTemplate: + spec: + imagePullSecrets: + - name: myregistrykey diff --git a/docs/examples/mysql/quickstart/demo-2.yaml b/docs/examples/mysql/quickstart/demo-2.yaml index 556d7ef2d..e42320c69 100644 --- a/docs/examples/mysql/quickstart/demo-2.yaml +++ b/docs/examples/mysql/quickstart/demo-2.yaml @@ -6,6 +6,7 @@ metadata: spec: version: "8.0-v1" doNotPause: true + storageType: Durable storage: storageClassName: "standard" accessModes: diff --git a/docs/examples/mysql/snapshot/demo-2.yaml b/docs/examples/mysql/snapshot/demo-2.yaml index 40b689c2f..427731312 100644 --- a/docs/examples/mysql/snapshot/demo-2.yaml +++ b/docs/examples/mysql/snapshot/demo-2.yaml @@ -9,4 +9,4 @@ spec: databaseName: mysql-infant storageSecretName: my-snap-secret gcs: - bucket: restic + bucket: kubedb diff --git a/docs/examples/mysql/snapshot/demo-3.yaml b/docs/examples/mysql/snapshot/demo-3.yaml index 5ffc4fb3b..bb0f0bbf7 100644 --- a/docs/examples/mysql/snapshot/demo-3.yaml +++ b/docs/examples/mysql/snapshot/demo-3.yaml @@ -5,6 +5,8 @@ metadata: namespace: demo spec: version: "8.0-v1" + databaseSecret: + secretName: mysql-infant-auth storage: storageClassName: "standard" accessModes: diff --git a/docs/examples/mysql/snapshot/demo-4.yaml b/docs/examples/mysql/snapshot/demo-4.yaml index 383281dd1..b66cdfdf9 100644 --- a/docs/examples/mysql/snapshot/demo-4.yaml +++ b/docs/examples/mysql/snapshot/demo-4.yaml @@ -12,13 +12,8 @@ spec: resources: requests: storage: 50Mi - init: - scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . backupSchedule: cronExpression: "@every 1m" storageSecretName: my-snap-secret gcs: - bucket: restic + bucket: kubedb diff --git a/docs/guides/mysql/README.md b/docs/guides/mysql/README.md index b3c935b94..96db4c26a 100644 --- a/docs/guides/mysql/README.md +++ b/docs/guides/mysql/README.md @@ -17,36 +17,46 @@ aliases: ## Supported MySQL Features -|Features | Availability | -|--------------------------------------------------------|:------------:| -|Clustering | ✗ | -|Persistent Volume | ✓ | -|Instant Backup | ✓ | -|Scheduled Backup | ✓ | -|Initialize using Snapshot | ✓ | -|Initialize using Script (\*.sql, \*sql.gz and/or \*.sh) | ✓ | -|Builtin Prometheus Discovery | ✓ | -|Using CoreOS Prometheus Operator | ✓ | +| Features | Availability | +| ------------------------------------------------------- | :----------: | +| Clustering | ✗ | +| Persistent Volume | ✓ | +| Instant Backup | ✓ | +| Scheduled Backup | ✓ | +| Initialize using Snapshot | ✓ | +| Initialize using Script (\*.sql, \*sql.gz and/or \*.sh) | ✓ | +| Custom Configuration | ✓ | +| Using Custom docker image | ✓ | +| Builtin Prometheus Discovery | ✓ | +| Using CoreOS Prometheus Operator | ✓ |
## Life Cycle of a MySQL Object

-  lifecycle +  lifecycle


## Supported MySQL Versions -| KubeDB Version | MySQL:8.0 | MySQL:5.7 | -|:--------------:|:---------:|:---------:| -| 0.1.0 - 0.7.0 | ✗ | ✗ | -| 0.8.0-beta.2 | ✓ | ✗ | -| 0.8.0-rc.0 | ✓ | ✓ | -| 0.8.0 | ✓ | ✓ | -| 0.9.0-beta.1 | ✓ | ✓ | +| KubeDB Version | MySQL 8.0, 8 | 5.7, 5 | 8.0-v1, 8-v1 | 5.7-v1, 5-v1 | +| :------------: | :----------: | :------: | :----------: | :----------: | +| 0.1.0 - 0.7.0 | ✗ | ✗ | ✗ | ✗ | +| 0.8.0 | ✓ | ✓ | ✗ | ✗ | +| 0.9.0-beta.1 | ✗ | ✗ | ✓ | ✓ | + +
+ +## External tools dependency + +| Tool | Version | +| -------------------------------------- | :-----: | +| [osm](https://github.com/appscode/osm) | 0.8.0 | + +
## User Guide @@ -60,6 +70,7 @@ aliases: - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Use [kubedb cli](/docs/guides/mysql/cli/cli.md) to manage databases like kubectl for Kubernetes. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/cli/cli.md b/docs/guides/mysql/cli/cli.md index 07b072a46..595ccf817 100644 --- a/docs/guides/mysql/cli/cli.md +++ b/docs/guides/mysql/cli/cli.md @@ -24,14 +24,14 @@ KubeDB comes with its own cli. It is called `kubedb` cli. `kubedb` can be used t ```console $ kubedb create -f mysql-demo.yaml -mysql "mysql-demo" created +mysql.kubedb.com/mysql-demo created ``` You can provide namespace as a flag `--namespace`. Provided namespace should match with namespace specified in input file. ```console $ kubedb create -f mysql-demo.yaml --namespace=kube-system -mysql "mysql-demo" created +mysql.kubedb.com/mysql-demo created ``` `kubedb create` command also considers `stdin` as input. @@ -48,11 +48,11 @@ To learn about various options of `create` command, please visit [here](/docs/re ```console $ kubedb get mysql -NAME STATUS AGE -mysql-demo Running 5h -mysql-dev Running 4h -mysql-prod Running 30m -mysql-qa Running 2h +NAME VERSION STATUS AGE +mysql-demo 8.0-v1 Running 2m +mysql-dev 8.0-v1 Running 1m +mysql-prod 8.0-v1 Running 1m +mysql-qa 8.0-v1 Running 1m ``` To get YAML of an object, use `--output=yaml` flag. @@ -62,19 +62,27 @@ $ kubedb get mysql mysql-demo --output=yaml apiVersion: kubedb.com/v1alpha1 kind: MySQL metadata: - clusterName: "" - creationTimestamp: 2018-03-01T07:02:10Z + creationTimestamp: 2018-09-27T13:07:23Z finalizers: - kubedb.com - generation: 0 + generation: 2 name: mysql-demo namespace: default - resourceVersion: "6910" + resourceVersion: "19279" selfLink: /apis/kubedb.com/v1alpha1/namespaces/default/mysqls/mysql-demo - uid: 76379db5-1d1e-11e8-8599-0800272b52b5 + uid: 46034ac3-c256-11e8-b2cc-080027d9f35e spec: databaseSecret: secretName: mysql-demo-auth + podTemplate: + controller: {} + metadata: {} + spec: + resources: {} + replicas: 1 + serviceTemplate: + metadata: {} + spec: {} storage: accessModes: - ReadWriteOnce @@ -82,27 +90,31 @@ spec: requests: storage: 50Mi storageClassName: standard - version: "8.0" + storageType: Durable + terminationPolicy: Pause + updateStrategy: + type: RollingUpdate + version: 8.0-v1 status: - creationTime: 2018-03-01T07:02:10Z + observedGeneration: 2$4213139756412538772 phase: Running ``` To get JSON of an object, use `--output=json` flag. ```console -$ kubedb get mysql mysql-demo --output=json +kubedb get mysql mysql-demo --output=json ``` To list all KubeDB objects, use following command: ```console $ kubedb get all -o wide -NAME VERSION STATUS AGE -my/mysql-demo 8.0 Running 3h -my/mysql-dev 8.0 Running 3h -my/mysql-prod 8.0 Running 3h -my/mysql-qa 8.0 Running 3h +NAME VERSION STATUS AGE +mysql.kubedb.com/mysql-demo 8.0-v1 Running 3m +mysql.kubedb.com/mysql-dev 8.0-v1 Running 2m +mysql.kubedb.com/mysql-prod 8.0-v1 Running 2m +mysql.kubedb.com/mysql-qa 8.0-v1 Running 2m NAME DATABASE BUCKET STATUS AGE snap/mysql-demo-20170605-073557 my/mysql-demo gs:bucket-name Succeeded 9m @@ -155,44 +167,64 @@ To learn about various options of `get` command, please visit [here](/docs/refer ```console $ kubedb describe my mysql-demo -Name: mysql-demo -Namespace: default -StartTimestamp: Thu, 01 Mar 2018 15:03:52 +0600 -Status: Running +Name: mysql-demo +Namespace: default +CreationTimestamp: Thu, 27 Sep 2018 19:07:23 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO StatefulSet: - Name: mysql-demo - Replicas: 1 current / 1 desired - CreationTimestamp: Thu, 01 Mar 2018 13:02:12 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + Name: mysql-demo + CreationTimestamp: Thu, 27 Sep 2018 19:07:25 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-demo + Annotations: + Replicas: 824638226772 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed Service: - Name: mysql-demo - Type: ClusterIP - IP: 10.97.55.246 - Port: db 3306/TCP + Name: mysql-demo + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-demo + Annotations: + Type: ClusterIP + IP: 10.102.105.123 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.5:3306 Database Secret: - Name: mysql-demo-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-demo-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-demo + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 2m 2m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 2m 2m 1 MySQL operator Normal Successful Successfully patched MySQL - 2m 2m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 2m 2m 1 MySQL operator Normal Successful Successfully patched MySQL + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 4m MySQL operator Successfully created Service + Normal Successful 4m MySQL operator Successfully created StatefulSet + Normal Successful 4m MySQL operator Successfully created MySQL + Normal Successful 4m MySQL operator Successfully patched StatefulSet + Normal Successful 4m MySQL operator Successfully patched MySQL + Normal Successful 3m MySQL operator Successfully patched StatefulSet + Normal Successful 3m MySQL operator Successfully patched MySQL ``` `kubedb describe` command provides following basic information about a MySQL database. @@ -204,32 +236,30 @@ Events: - Snapshots (If any) - Monitoring system (If available) -To hide details about StatefulSet & Service, use flag `--show-workload=false` -To hide details about Secret, use flag `--show-secret=false` To hide events on KubeDB object, use flag `--show-events=false` To describe all MySQL objects in `default` namespace, use following command ```console -$ kubedb describe my +kubedb describe my ``` To describe all MySQL objects from every namespace, provide `--all-namespaces` flag. ```console -$ kubedb describe my --all-namespaces +kubedb describe my --all-namespaces ``` To describe all KubeDB objects from every namespace, use the following command: ```console -$ kubedb describe all --all-namespaces +kubedb describe all --all-namespaces ``` You can also describe KubeDB objects with matching labels. The following command will describe all MySQL objects with specified labels from every namespace. ```console -$ kubedb describe my --all-namespaces --selector='group=dev' +kubedb describe my --all-namespaces --selector='group=dev' ``` To learn about various options of `describe` command, please visit [here](/docs/reference/kubedb_describe.md). @@ -265,11 +295,12 @@ Various fields of a KubeDB object can't be edited using `edit` command. The foll If StatefulSets exists for a MySQL database, following fields can't be modified as well. -- spec.version - spec.databaseSecret -- spec.storage -- spec.nodeSelector - spec.init +- spec.storageType +- spec.storage +- spec.podTemplate.spec.nodeSelector +- spec.podTemplate.spec.env For DormantDatabase, `spec.origin` can't be edited using `kubedb edit` @@ -281,14 +312,14 @@ To learn about various options of `edit` command, please visit [here](/docs/refe ```console $ kubedb delete mysql mysql-dev -mysql "mysql-dev" deleted +mysql.kubedb.com "mysql-dev" deleted ``` You can also use YAML files to delete objects. The following command will delete a mysql using the type and name specified in `mysql.yaml`. ```console $ kubedb delete -f mysql-demo.yaml -mysql "mysql-dev" deleted +mysql.kubedb.com "mysql-dev" deleted ``` `kubedb delete` command also takes input from `stdin`. @@ -300,7 +331,7 @@ cat mysql-demo.yaml | kubedb delete -f - To delete database with matching labels, use `--selector` flag. The following command will delete mysql with label `mysql.kubedb.com/name=mysql-demo`. ```console -$ kubedb delete mysql -l mysql.kubedb.com/name=mysql-demo +kubedb delete mysql -l mysql.kubedb.com/name=mysql-demo ``` To learn about various options of `delete` command, please visit [here](/docs/reference/kubedb_delete.md). diff --git a/docs/guides/mysql/custom-config/using-custom-config.md b/docs/guides/mysql/custom-config/using-custom-config.md index 3da16d9f3..bdb172b06 100644 --- a/docs/guides/mysql/custom-config/using-custom-config.md +++ b/docs/guides/mysql/custom-config/using-custom-config.md @@ -17,21 +17,20 @@ KubeDB supports providing custom configuration for MySQL. This tutorial will sho ## 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). +- 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). +- 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. +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. -```console -$ kubectl create ns demo -namespace "demo" created - -$ kubectl get ns demo -NAME STATUS AGE -demo Active 5s -``` + ```console + $ kubectl create ns demo + namespace/demo created + + $ kubectl get ns demo + NAME STATUS AGE + demo Active 5s + ``` > Note: Yaml files used in this tutorial are stored in [docs/examples/mysql](https://github.com/kubedb/cli/tree/master/docs/examples/mysql) folder in github repository [kubedb/cli](https://github.com/kubedb/cli). @@ -47,8 +46,14 @@ In this tutorial, we will configure [max_connections](https://dev.mysql.com/doc/ At first, let's create `my-config.cnf` file setting `max_connections` and `read_buffer_size` parameters. -```ini -cat > my-config.cnf +```console +cat < my-config.cnf +[mysqld] +max_connections = 200 +read_buffer_size = 1048576 +EOF + +$ cat my-config.cnf [mysqld] max_connections = 200 read_buffer_size = 1048576 @@ -60,13 +65,13 @@ Now, create a configMap with this configuration file. ```console $ kubectl create configmap -n demo my-custom-config --from-file=./my-config.cnf -configmap "my-custom-config" created +configmap/my-custom-config created ``` Verify the config map has the configuration file. ```yaml -$ kubectl get configmap -n demo my-custom-config -o yaml +$ kubectl get configmap -n demo my-custom-config -o yaml apiVersion: v1 data: my-config.cnf: | @@ -75,7 +80,6 @@ data: read_buffer_size = 1048576 kind: ConfigMap metadata: - ... name: my-custom-config namespace: demo ... @@ -85,7 +89,7 @@ Now, create MySQL crd specifying `spec.configSource` field. ```console $ kubectl apply -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/custom-config//mysql-custom.yaml -mysql.kubedb.com "custom-mysql" created +mysql.kubedb.com/custom-mysql created ``` Below is the YAML for the MySQL crd we just created. @@ -97,11 +101,11 @@ metadata: name: custom-mysql namespace: demo spec: - version: "8.0" + version: "8.0-v1" doNotPause: true configSource: - configMap: - name: my-custom-config + configMap: + name: my-custom-config storage: storageClassName: "standard" accessModes: @@ -116,9 +120,9 @@ Now, wait a few minutes. KubeDB operator will create necessary PVC, statefulset, Check that the statefulset's pod is running ```console -$ kubectl get pod -n demo custom-mysql-0 +$ kubectl get pod -n demo NAME READY STATUS RESTARTS AGE -custom-mysql-0 1/1 Running 0 7m +custom-mysql-0 1/1 Running 0 44s ``` Check the pod's log to see if the database is ready @@ -147,11 +151,11 @@ First, deploy [phpMyAdmin](https://hub.docker.com/r/phpmyadmin/phpmyadmin/) to c ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-1.yaml -deployment.extensions "myadmin" created -service "myadmin" created +deployment.extensions/myadmin created +service/myadmin created ``` -Then, open your browser and go to the following URL: http://{cluster-ip}:{myadmin-svc-nodeport}. For minikube you can get this URL by running the following command: +Then, open your browser and go to the following URL: _http://{cluster-ip}:{myadmin-svc-nodeport}_. For minikube you can get this URL by running the following command: ```console $ minikube service myadmin -n demo --url @@ -182,21 +186,17 @@ Once, you have connected to the database with phpMyAdmin go to **Variables** tab To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo my/custom-mysql -p '{"spec":{"doNotPause":false}}' --type="merge" - -$ kubectl delete -n demo my/custom-mysql - -$ kubectl patch -n demo drmn/custom-mysql -p '{"spec":{"wipeOut":true}}' --type="merge" - -$ kubectl delete -n demo drmn/custom-mysql - -$ kubectl delete -n demo configmap my-custom-config +kubectl patch -n demo my/custom-mysql -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo my/custom-mysql -$ kubectl delete deployment -n demo myadmin +kubectl patch -n demo drmn/custom-mysql -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/custom-mysql -$ kubectl delete service -n demo myadmin +kubectl delete -n demo configmap my-custom-config +kubectl delete deployment -n demo myadmin +kubectl delete service -n demo myadmin -$ kubectl delete ns demo +kubectl delete ns demo ``` If you would like to uninstall KubeDB operator, please follow the steps [here](/docs/setup/uninstall.md). diff --git a/docs/guides/mysql/initialization/using-script.md b/docs/guides/mysql/initialization/using-script.md index 63a0dbd46..b7b3a5e08 100644 --- a/docs/guides/mysql/initialization/using-script.md +++ b/docs/guides/mysql/initialization/using-script.md @@ -9,6 +9,7 @@ menu: menu_name: docs_0.8.0 section_menu_id: guides --- + > New to KubeDB? Please start [here](/docs/concepts/README.md). # Initialize MySQL using Script @@ -16,47 +17,62 @@ section_menu_id: guides This tutorial will show you how to use KubeDB to initialize a MySQL database with \*.sql, \*.sh and/or \*.sql.gz script. In this tutorial we will use .sql script stored in GitHub repository [kubedb/mysql-init-scripts](https://github.com/kubedb/mysql-init-scripts). -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: The yaml files that are used in this tutorial are stored in [docs/examples](https://github.com/kubedb/cli/tree/master/docs/examples) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). ## 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). +- 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). +- 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 MySQL database, once it is running. Run the following command to prepare your cluster for this tutorial: +- 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 MySQL database, once it is running. Run the following command to prepare your cluster for this tutorial: -```console -$ kubectl create ns demo -namespace "demo" created + ```console + $ kubectl create ns demo + namespace/demo created + + $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-1.yaml + deployment.extensions/myadmin created + service/myadmin created + + $ kubectl get pods -n demo + NAME READY STATUS RESTARTS AGE + myadmin-584d845666-rtkzg 1/1 Running 0 9m + + $ kubectl get service -n demo + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + myadmin LoadBalancer 10.108.49.82 80:30192/TCP 9m + + $ minikube ip + 192.168.99.100 + ``` -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-1.yaml -deployment "myadmin" created -service "myadmin" created + Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. + You can also get this URl by running the following command: -$ kubectl get pods -n demo --watch -NAME READY STATUS RESTARTS AGE -myadmin-c4db4df95-4tgkx 0/1 ContainerCreating 0 27s -myadmin-c4db4df95-4tgkx 1/1 Running 0 1m + ```console + $ minikube service myadmin -n demo --url + http://192.168.99.100:32673 + ``` -$ kubectl get service -n demo -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -myadmin LoadBalancer 10.101.247.127 80:32673/TCP 50s + According to the above example, this URL will be [http://192.168.99.100:32673](http://192.168.99.100:32673). The login informations to phpMyAdmin _(host, username and password)_ will be retrieved later in this tutorial. + +## Prepare Initialization Scripts -$ minikube ip -192.168.99.100 -``` +MySQL supports initialization with `.sh`, `.sql` and `.sql.gz` files. In this tutorial, we will use `init.sql` script from [mysql-init-scripts](https://github.com/kubedb/mysql-init-scripts) git repository to create a TABLE `kubedb_table` in `mysql` database. -Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. -You can also get this URl by running the following command: +As [gitRepo](https://kubernetes.io/docs/concepts/storage/volumes/#gitrepo) volume has been deprecated, we will use a ConfigMap as script source. You can use any Kubernetes supported [volume](https://kubernetes.io/docs/concepts/storage/volumes) as script source. + +At first, we will create a ConfigMap from `init.sql` file. Then, we will provide this ConfigMap as script source in `init.scriptSource` of MySQL crd spec. + +Let's create a ConfigMap with initialization script, ```console -$ minikube service myadmin -n demo --url -http://192.168.99.100:32673 +$ kubectl create configmap -n demo my-init-script \ +--from-literal=init.sql="$(curl -fsSL https://raw.githubusercontent.com/kubedb/mysql-init-scripts/master/init.sql)" +configmap/my-init-script created ``` -According to the above example, this URL will be [http://192.168.99.100:32673](http://192.168.99.100:32673). The login informations to phpMyAdmin _(host, username and password)_ will be retrieved later in this tutorial. - ## Create a MySQL database with Init-Script Below is the `MySQL` object created in this tutorial. @@ -68,7 +84,7 @@ metadata: name: mysql-init-script namespace: demo spec: - version: "8.0" + version: "8.0-v1" doNotPause: true storage: storageClassName: "standard" @@ -79,88 +95,99 @@ spec: storage: 50Mi init: scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . - + configMap: + name: my-init-script ``` ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/Initialization/demo-1.yaml -mysql "mysql-init-script" created +mysql.kubedb.com/mysql-init-script created ``` Here, -- `spec.version` is the version of MySQL database. In this tutorial, a MySQL 8.0 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. Since release 0.8.0, a storage spec is required for MySQL. -- `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/mysql-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 \*.sql, \*sql.gz and/or \*.sh sripts that are stored inside the root folder will be executed alphabatically. The scripts inside child folders will be skipped. +- `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 .sql script from the git repository `https://github.com/kubedb/mysql-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 \*.sql, \*sql.gz 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 `MySQL` objects using Kubernetes api. When a `MySQL` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MySQL object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. No MySQL specific RBAC roles are required for [RBAC enabled clusters](/docs/setup/install.md#using-yaml). ```console $ kubedb describe my -n demo mysql-init-script -Name: mysql-init-script -Namespace: demo -StartTimestamp: Fri, 09 Feb 2018 17:18:14 +0600 -Status: Running +Name: mysql-init-script +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 17:06:37 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO StatefulSet: - Name: mysql-init-script - Replicas: 1 current / 1 desired - CreationTimestamp: Fri, 09 Feb 2018 17:18:15 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + Name: mysql-init-script + CreationTimestamp: Thu, 27 Sep 2018 17:06:39 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-init-script + Annotations: + Replicas: 824637787500 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed Service: - Name: mysql-init-script - Type: ClusterIP - IP: 10.101.136.66 - Port: db 3306/TCP + Name: mysql-init-script + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-init-script + Annotations: + Type: ClusterIP + IP: 10.102.60.242 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.6:3306 Database Secret: - Name: mysql-init-script-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-init-script-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-init-script + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 9m 9m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 9m 9m 1 MySQL operator Normal Successful Successfully patched MySQL - 9m 9m 1 MySQL operator Normal Successful Successfully created StatefulSet - 9m 9m 1 MySQL operator Normal Successful Successfully created MySQL - 9m 9m 1 MySQL operator Normal Successful Successfully created Service - - + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 1m MySQL operator Successfully created Service + Normal Successful 41s MySQL operator Successfully created StatefulSet + Normal Successful 41s MySQL operator Successfully created MySQL + Normal Successful 40s MySQL operator Successfully patched StatefulSet + Normal Successful 40s MySQL operator Successfully patched MySQL + Normal Successful 37s MySQL operator Successfully patched StatefulSet + Normal Successful 37s MySQL operator Successfully patched MySQL $ kubectl get statefulset -n demo NAME DESIRED CURRENT AGE -mysql-init-script 1 1 10m - +mysql-init-script 1 1 1m $ kubectl get pvc -n demo NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE -data-mysql-init-script-0 Bound pvc-ec9fd7b2-0d8a-11e8-9091-08002751ae8c 50Mi RWO standard 12m - +data-mysql-init-script-0 Bound pvc-68e49ec6-c245-11e8-b2cc-080027d9f35e 50Mi RWO standard 1m $ kubectl get pv -n demo NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE -pvc-ec9fd7b2-0d8a-11e8-9091-08002751ae8c 50Mi RWO Delete Bound demo/data-mysql-init-script-0 standard 12m - +pvc-68e49ec6-c245-11e8-b2cc-080027d9f35e 50Mi RWO Delete Bound demo/data-mysql-init-script-0 standard 1m $ kubectl get service -n demo -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubedb ClusterIP None 13m -mysql-init-script ClusterIP 10.101.136.66 3306/TCP 13m +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 2m +myadmin LoadBalancer 10.108.49.82 80:30192/TCP 22m +mysql-init-script ClusterIP 10.102.60.242 3306/TCP 2m ``` KubeDB operator sets the `status.phase` to `Running` once the database is successfully created. Run the following command to see the modified MySQL object: @@ -170,26 +197,32 @@ $ kubedb get my -n demo mysql-init-script -o yaml apiVersion: kubedb.com/v1alpha1 kind: MySQL metadata: - clusterName: "" - creationTimestamp: 2018-02-09T11:18:14Z + creationTimestamp: 2018-09-27T11:06:37Z finalizers: - kubedb.com - generation: 0 + generation: 2 name: mysql-init-script namespace: demo - resourceVersion: "28624" + resourceVersion: "9070" selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mysqls/mysql-init-script - uid: ebbcc002-0d8a-11e8-9091-08002751ae8c + uid: 677921ee-c245-11e8-b2cc-080027d9f35e spec: - replicas: 1 databaseSecret: secretName: mysql-init-script-auth doNotPause: true init: scriptSource: - gitRepo: - directory: . - repository: https://github.com/kubedb/mysql-init-scripts.git + configMap: + name: my-init-script + podTemplate: + controller: {} + metadata: {} + spec: + resources: {} + replicas: 1 + serviceTemplate: + metadata: {} + spec: {} storage: accessModes: - ReadWriteOnce @@ -197,9 +230,13 @@ spec: requests: storage: 50Mi storageClassName: standard - version: "8.0" + storageType: Durable + terminationPolicy: Pause + updateStrategy: + type: RollingUpdate + version: 8.0-v1 status: - creationTime: 2018-02-09T11:18:14Z + observedGeneration: 2$4213139756412538772 phase: Running ``` @@ -210,17 +247,17 @@ Now, you can connect to this database from the phpMyAdmin dashboard using the da ```console $ kubectl get pods mysql-init-script-0 -n demo -o yaml | grep IP - hostIP: 192.168.99.100 - podIP: 172.17.0.5 + hostIP: 10.0.2.15 + podIP: 172.17.0.6 $ kubectl get secrets -n demo mysql-init-script-auth -o jsonpath='{.data.\user}' | base64 -d root $ kubectl get secrets -n demo mysql-init-script-auth -o jsonpath='{.data.\password}' | base64 -d -h1sPb6ZTHQmKC1ng +1Pc7bwSygrv1MX1Q ``` -Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. To log into the phpMyAdmin, use host __`172.17.0.5`__ , username __`root`__ and password __`h1sPb6ZTHQmKC1ng`__. +Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. To log into the phpMyAdmin, use host __`172.17.0.6`__ , username __`root`__ and password __`1Pc7bwSygrv1MX1Q`__. As you can see here, the initial script has successfully created a table named `kubedb_table` in `mysql` database and inserted three rows of data into that table successfully. @@ -229,14 +266,13 @@ As you can see here, the initial script has successfully created a table named ` To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-init-script -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-init-script +kubectl patch -n demo mysql/mysql-init-script -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-init-script -$ kubectl patch -n demo drmn/mysql-init-script -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-init-script +kubectl patch -n demo drmn/mysql-init-script -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-init-script -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps @@ -249,5 +285,6 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/initialization/using-snapshot.md b/docs/guides/mysql/initialization/using-snapshot.md index aa378ec40..61abea951 100644 --- a/docs/guides/mysql/initialization/using-snapshot.md +++ b/docs/guides/mysql/initialization/using-snapshot.md @@ -17,13 +17,13 @@ This tutorial will show you how to use KubeDB to initialize a MySQL database wit ## 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). +- 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). +- Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). -This tutorial assumes that you have created a namespace `demo` and a snapshot `snapshot-infant`. Follow the steps [here](/docs/guides/mysql/snapshot/backup-and-restore.md) to create a database and take [instant snapshot](/docs/guides/mysql/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. +- This tutorial assumes that you have created a namespace `demo` and a snapshot `snapshot-infant`. Follow the steps [here](/docs/guides/mysql/snapshot/backup-and-restore.md) to create a database and take [instant snapshot](/docs/guides/mysql/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. -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: The yaml files that are used in this tutorial are 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 MySQL with Init-Snapshot @@ -36,7 +36,9 @@ metadata: name: mysql-init-snapshot namespace: demo spec: - version: "8.0" + version: "8.0-v1" + databaseSecret: + secretName: mysql-infant-auth storage: storageClassName: "standard" accessModes: @@ -52,7 +54,7 @@ spec: ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/Initialization/demo-2.yaml -mysql "mysql-init-snapshot" created +mysql.kubedb.com/mysql-init-snapshot created ``` Here, @@ -63,56 +65,74 @@ Now, wait several seconds. KubeDB operator will create a new `StatefulSet`. Then ```console $ kubedb get my -n demo -NAME STATUS AGE -mysql-infant Running 15m -mysql-init-snapshot Initializing 11s +NAME VERSION STATUS AGE +mysql-infant 8.0-v1 Running 8m +mysql-init-snapshot 8.0-v1 Initializing 1m $ kubedb get my -n demo -NAME STATUS AGE -mysql-infant Running 17m -mysql-init-snapshot Running 2m +NAME VERSION STATUS AGE +mysql-infant 8.0-v1 Running 20m +mysql-init-snapshot 8.0-v1 Running 13m $ kubedb describe my -n demo mysql-init-snapshot -Name: mysql-init-snapshot -Namespace: demo -StartTimestamp: Mon, 12 Feb 2018 11:09:12 +0600 -Status: Running -Annotations: kubedb.com/initialized= +Name: mysql-init-snapshot +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 17:54:16 +0600 +Labels: +Annotations: kubedb.com/initialized= +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO StatefulSet: - Name: mysql-init-snapshot - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 12 Feb 2018 11:09:13 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + Name: mysql-init-snapshot + CreationTimestamp: Thu, 27 Sep 2018 17:54:17 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-init-snapshot + Annotations: + Replicas: 824642013116 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed Service: - Name: mysql-init-snapshot - Type: ClusterIP - IP: 10.105.136.174 - Port: db 3306/TCP + Name: mysql-init-snapshot + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-init-snapshot + Annotations: + Type: ClusterIP + IP: 10.104.217.79 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.5:3306 Database Secret: - Name: mysql-init-snapshot-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-infant-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-infant + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 19s 19s 1 Job Controller Normal SuccessfulSnapshot Successfully completed initialization - 2m 2m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 2m 2m 1 MySQL operator Normal Successful Successfully patched MySQL - 2m 2m 1 MySQL operator Normal Successful Successfully created StatefulSet - 2m 2m 1 MySQL operator Normal Initializing Initializing from Snapshot: "snap-mysql-infant" + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 13m MySQL operator Successfully created Service + Normal Successful 12m MySQL operator Successfully created MySQL + Normal Successful 12m MySQL operator Successfully created StatefulSet + Normal Initializing 12m MySQL operator Initializing from Snapshot: "snap-mysql-infant" + Normal Successful 12m MySQL operator Successfully patched StatefulSet + Normal Successful 12m MySQL operator Successfully patched MySQL + Normal SuccessfulInitialize 6m Job Controller Successfully completed initialization ``` ## Cleaning up @@ -120,14 +140,13 @@ Events: To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-init-snapshot -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-init-snapshot +kubectl patch -n demo mysql/mysql-infant mysql/mysql-init-snapshot -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-infant mysql/mysql-init-snapshot -$ kubectl patch -n demo drmn/mysql-init-snapshot -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-init-snapshot +kubectl patch -n demo drmn/mysql-infant drmn/mysql-init-snapshot -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-infant drmn/mysql-init-snapshot -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps @@ -136,6 +155,7 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/monitoring/using-builtin-prometheus.md b/docs/guides/mysql/monitoring/using-builtin-prometheus.md index d1266c3c2..ad979130f 100644 --- a/docs/guides/mysql/monitoring/using-builtin-prometheus.md +++ b/docs/guides/mysql/monitoring/using-builtin-prometheus.md @@ -18,29 +18,26 @@ This tutorial will show you how to monitor KubeDB databases using [Prometheus](h ## 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). +- 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). +- 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: +- 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 ns demo -namespace "demo" created - -$ kubectl get ns -NAME STATUS AGE -default Active 45m -demo Active 10s -kube-public Active 45m -kube-system Active 45m -``` + ```console + $ kubectl create ns demo + namespace "demo" created + + $ kubectl get ns + NAME STATUS AGE + demo Active 10s + ``` -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: The yaml files that are used in this tutorial are 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 MySQL database +## Monitor with builtin Prometheus -KubeDB implements a `MySQL` CRD to define the specification of a MySQL database. Below is the `MySQL` object created in this tutorial. +User can define `spec.monitor` either while creating the CRD object, Or can update the spec of existing CRD object to add the `spec.monitor` part. Below is the `MySQL` object created in this tutorial. ```yaml apiVersion: kubedb.com/v1alpha1 @@ -49,7 +46,7 @@ metadata: name: mysql-mon-prometheus namespace: demo spec: - version: "8.0" + version: "8.0-v1" storage: storageClassName: "standard" accessModes: @@ -63,82 +60,113 @@ spec: ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/monitoring/builtin-prometheus/demo-1.yaml -mysql "mysql-mon-prometheus" created +mysql.kubedb.com/mysql-mon-prometheus created ``` Here, -- `spec.version` is the version of MySQL database. In this tutorial, a MySQL 8.0 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. Since release 0.8.0, a storage spec is required for MySQL. - `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 `MySQL Exporter` and will receive metrics from exporter. -KubeDB operator watches for `MySQL` objects using Kubernetes api. When a `MySQL` 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. +KubeDB will create a separate stats service with name `-stats` for monitoring purpose. KubeDB operator will configure this monitoring service once the MySQL is successfully running. ```console $ kubedb get my -n demo -NAME STATUS AGE -mysql-mon-prometheus Running 19s +NAME VERSION STATUS AGE +mysql-mon-prometheus 8.0-v1 Running 13m $ kubedb describe my -n demo mysql-mon-prometheus -Name: mysql-mon-prometheus -Namespace: demo -StartTimestamp: Mon, 12 Feb 2018 11:52:27 +0600 -Status: Running +Name: mysql-mon-prometheus +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 16:02:43 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mysql-mon-prometheus - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 12 Feb 2018 11:52:29 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mysql-mon-prometheus - Type: ClusterIP - IP: 10.101.55.20 - Port: db 3306/TCP - Port: prom-http 56790/TCP + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mysql-mon-prometheus + CreationTimestamp: Thu, 27 Sep 2018 16:02:45 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-prometheus + Annotations: + Replicas: 824639361756 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mysql-mon-prometheus + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-prometheus + Annotations: + Type: ClusterIP + IP: 10.105.118.238 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.5:3306 + +Service: + Name: mysql-mon-prometheus-stats + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-prometheus + Annotations: monitoring.appscode.com/agent=prometheus.io/builtin + prometheus.io/path=/kubedb.com/v1alpha1/namespaces/demo/mysqls/mysql-mon-prometheus/metrics + prometheus.io/port=56790 + prometheus.io/scrape=true + Type: ClusterIP + IP: 10.110.18.171 + Port: prom-http 56790/TCP + TargetPort: prom-http/TCP + Endpoints: 172.17.0.5:56790 Database Secret: - Name: mysql-mon-prometheus-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-mon-prometheus-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-prometheus + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes Monitoring System: - Agent: prometheus.io/builtin + Agent: prometheus.io/builtin Prometheus: - Namespace: - Interval: + Port: 56790 No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 11s 11s 1 MySQL operator Normal Successful Successfully patched StatefulSet - 11s 11s 1 MySQL operator Normal Successful Successfully patched MySQL - 14s 14s 1 MySQL operator Normal Successful Successfully created StatefulSet - 14s 14s 1 MySQL operator Normal Successful Successfully created MySQL - 30s 30s 1 MySQL operator Normal Successful Successfully created Service + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 13m MySQL operator Successfully created Service + Normal Successful 13m MySQL operator Successfully created StatefulSet + Normal Successful 13m MySQL operator Successfully created MySQL + Normal Successful 13m MySQL operator Successfully created stats service + Normal Successful 12m MySQL operator Successfully patched StatefulSet + Normal Successful 12m MySQL operator Successfully patched MySQL + Normal Successful 12m MySQL operator Successfully patched StatefulSet + Normal Successful 12m MySQL operator Successfully patched MySQL ``` -Since `spec.monitoring` was configured, the database service object is configured accordingly. You can verify it running the following commands: +Since `spec.monitoring` was configured, the database monitoring service object is configured accordingly. You can verify it running the following commands: ```console $ kubectl get services -n demo -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -kubedb ClusterIP None 53s -mysql-mon-prometheus ClusterIP 10.101.55.20 3306/TCP,56790/TCP 52s +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 31m +mysql-mon-prometheus ClusterIP 10.105.118.238 3306/TCP 14m +mysql-mon-prometheus-stats ClusterIP 10.110.18.171 56790/TCP 13m ``` ```yaml -$ kubectl get services mysql-mon-prometheus -n demo -o yaml +$ kubectl get services mysql-mon-prometheus-stats -n demo -o yaml apiVersion: v1 kind: Service metadata: @@ -147,22 +175,24 @@ metadata: prometheus.io/path: /kubedb.com/v1alpha1/namespaces/demo/mysqls/mysql-mon-prometheus/metrics prometheus.io/port: "56790" prometheus.io/scrape: "true" - creationTimestamp: 2018-02-12T05:52:28Z + creationTimestamp: 2018-09-27T10:03:36Z labels: kubedb.com/kind: MySQL kubedb.com/name: mysql-mon-prometheus - name: mysql-mon-prometheus + name: mysql-mon-prometheus-stats namespace: demo - resourceVersion: "38255" - selfLink: /api/v1/namespaces/demo/services/mysql-mon-prometheus - uid: e86bb1a4-0fb8-11e8-a2d6-08002751ae8c + ownerReferences: + - apiVersion: kubedb.com/v1alpha1 + blockOwnerDeletion: false + kind: MySQL + name: mysql-mon-prometheus + uid: 7a30757a-c23c-11e8-b2cc-080027d9f35e + resourceVersion: "4015" + selfLink: /api/v1/namespaces/demo/services/mysql-mon-prometheus-stats + uid: 99cdcd40-c23c-11e8-b2cc-080027d9f35e spec: - clusterIP: 10.101.55.20 + clusterIP: 10.110.18.171 ports: - - name: db - port: 3306 - protocol: TCP - targetPort: db - name: prom-http port: 56790 protocol: TCP @@ -236,9 +266,11 @@ data: target_label: kubernetes_name ``` +Create above ConfigMap + ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-1.yaml -configmap "prometheus-server-conf" created +configmap/prometheus-server-conf created ``` Now, the below yaml is used to deploy Prometheus in kubernetes : @@ -285,25 +317,24 @@ Run the following command to deploy prometheus-server ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-2.yaml -clusterrole "prometheus-server" created -serviceaccount "prometheus-server" created -clusterrolebinding "prometheus-server" created -deployment "prometheus-server" created -service "prometheus-service" created +clusterrole.rbac.authorization.k8s.io/prometheus-server created +serviceaccount/prometheus-server created +clusterrolebinding.rbac.authorization.k8s.io/prometheus-server created +deployment.apps/prometheus-server created +service/prometheus-service created # Verify RBAC stuffs -$ kubectl get clusterroles +$ kubectl get clusterroles prometheus-server NAME AGE -prometheus-server 57s +prometheus-server 28s -$ kubectl get clusterrolebindings +$ kubectl get clusterrolebindings prometheus-server NAME AGE -prometheus-server 1m - +prometheus-server 59s $ kubectl get serviceaccounts -n demo NAME SECRETS AGE -default 1 48m +default 1 52m prometheus-server 1 1m ``` @@ -313,11 +344,11 @@ 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 4m -mysql-mon-prometheus ClusterIP 10.101.55.20 3306/TCP,56790/TCP 4m -prometheus-service LoadBalancer 10.105.89.246 9090:30901/TCP 2m - +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedb ClusterIP None 34m +mysql-mon-prometheus ClusterIP 10.105.118.238 3306/TCP 17m +mysql-mon-prometheus-stats ClusterIP 10.110.18.171 56790/TCP 16m +prometheus-service NodePort 10.100.155.55 9090:30901/TCP 1m $ minikube ip 192.168.99.100 @@ -328,6 +359,8 @@ 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). +If you are not using minikube, browse prometheus dashboard using following address `http://{Node's ExternalIP}:{NodePort of prometheus-service}`. + Now, if you go the Prometheus Dashboard, you should see that this database endpoint as one of the targets. ![prometheus-builtin](/docs/images/mysql/mysql-builtin.png) @@ -336,24 +369,22 @@ Now, if you go the Prometheus Dashboard, you should see that this database endpo To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-mon-prometheus -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-mon-prometheus +kubectl patch -n demo mysql/mysql-mon-prometheus -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-mon-prometheus -$ kubectl patch -n demo drmn/mysql-mon-prometheus -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-mon-prometheus +kubectl patch -n demo drmn/mysql-mon-prometheus -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-mon-prometheus -$ kubectl delete clusterrole prometheus-server -$ kubectl delete clusterrolebindings prometheus-server -$ kubectl delete serviceaccounts -n demo prometheus-server +kubectl delete -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/builtin-prometheus/demo-2.yaml -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps - Monitor your MySQL database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md). - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.md). - [Snapshot and Restore](/docs/guides/mysql/snapshot/backup-and-restore.md) process of MySQL databases using KubeDB. - Take [Scheduled Snapshot](/docs/guides/mysql/snapshot/scheduled-backup.md) of MySQL databases using KubeDB. - Initialize [MySQL with Script](/docs/guides/mysql/initialization/using-script.md). diff --git a/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md b/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md index e69f37e66..0d8a6f0fc 100644 --- a/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md +++ b/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md @@ -18,13 +18,22 @@ This tutorial will show you how to monitor KubeDB databases using Prometheus via ## 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). +- 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). +- 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. +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. -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). + ```console + $ kubectl create ns demo + namespace "demo" created + + $ kubectl get ns + NAME STATUS AGE + demo Active 10s + ``` + +> Note: The yaml files that are used in this tutorial are 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 @@ -32,33 +41,43 @@ Run the following command to deploy CoreOS-Prometheus operator. ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/coreos-operator/demo-0.yaml -namespace "demo" created -clusterrole "prometheus-operator" created -serviceaccount "prometheus-operator" created -clusterrolebinding "prometheus-operator" created -deployment "prometheus-operator" created +namespace/demo created +clusterrole.rbac.authorization.k8s.io/prometheus-operator created +serviceaccount/prometheus-operator created +clusterrolebinding.rbac.authorization.k8s.io/prometheus-operator created +deployment.extensions/prometheus-operator created +``` + +Wait for running the Deployment’s Pods. +```console $ kubectl get pods -n demo --watch -NAME READY STATUS RESTARTS AGE -prometheus-operator-79cb9dcd4b-2njgq 1/1 Running 0 2m +NAME READY STATUS RESTARTS AGE +prometheus-operator-857455484c-dg4qg 0/1 ContainerCreating 0 34s +prometheus-operator-857455484c-dg4qg 1/1 Running 0 45s +``` +This CoreOS-Prometheus operator will create some supported Custom Resource Definition (CRD). +```console $ kubectl get crd -NAME AGE -alertmanagers.monitoring.coreos.com 11m -prometheuses.monitoring.coreos.com 11m -servicemonitors.monitoring.coreos.com 11m +NAME CREATED AT +... +alertmanagers.monitoring.coreos.com 2018-09-24T12:42:22Z +prometheuses.monitoring.coreos.com 2018-09-24T12:42:22Z +servicemonitors.monitoring.coreos.com 2018-09-24T12:42:22Z +... ``` 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.9.0-beta.1/docs/examples/monitoring/coreos-operator/demo-1.yaml -clusterrole "prometheus" created -serviceaccount "prometheus" created -clusterrolebinding "prometheus" created -prometheus "prometheus" created -service "prometheus" created +clusterrole.rbac.authorization.k8s.io/prometheus created +serviceaccount/prometheus created +clusterrolebinding.rbac.authorization.k8s.io/prometheus created +prometheus.monitoring.coreos.com/prometheus created +service/prometheus created # Verify RBAC stuffs $ kubectl get clusterroles @@ -66,18 +85,16 @@ 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 +default 1 3m +prometheus 1 1m +prometheus-operator 1 3m ``` ### Prometheus Dashboard @@ -86,10 +103,9 @@ 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.98.86.76 9090:30900/TCP 16s -prometheus-operated ClusterIP None 9090/TCP 16s - +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +prometheus LoadBalancer 10.100.197.251 9090:30900/TCP 1m +prometheus-operated ClusterIP None 9090/TCP 1m $ minikube ip 192.168.99.100 @@ -100,6 +116,8 @@ 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). +If you are not using minikube, browse prometheus dashboard using following address `http://{Node's ExternalIP}:{NodePort of prometheus-service}`. + ## Create a MySQL database KubeDB implements a `MySQL` CRD to define the specification of a MySQL database. Below is the `MySQL` object created in this tutorial. @@ -111,7 +129,7 @@ metadata: name: mysql-mon-coreos namespace: demo spec: - version: "8.0" + version: "8.0-v1" storage: storageClassName: "standard" accessModes: @@ -155,71 +173,99 @@ Run the following command to deploy the above `MySQL` CRD object. ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/monitoring/coreos-operator/demo-1.yaml -mysql "mysql-mon-coreos" created +mysql.kubedb.com/mysql-mon-coreos created ``` Here, -- `spec.version` is the version of MySQL database. In this tutorial, a MySQL 8.0 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 `MySQL` objects using Kubernetes api. When a `MySQL` 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. +KubeDB will create a separate stats service with name `-stats` for monitoring purpose. KubeDB operator will configure this monitoring service once the MySQL is successfully running. ```console $ kubedb get my -n demo -NAME STATUS AGE -mysql-mon-coreos Running 36s - +NAME VERSION STATUS AGE +mysql-mon-coreos 8.0-v1 Creating 22s $ kubedb describe my -n demo mysql-mon-coreos -Name: mysql-mon-coreos -Namespace: demo -StartTimestamp: Mon, 12 Feb 2018 11:26:56 +0600 -Status: Running +Name: mysql-mon-coreos +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 16:29:36 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mysql-mon-coreos - Replicas: 1 current / 1 desired - CreationTimestamp: Mon, 12 Feb 2018 11:26:58 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mysql-mon-coreos - Type: ClusterIP - IP: 10.98.111.66 - Port: db 3306/TCP - Port: prom-http 56790/TCP + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mysql-mon-coreos + CreationTimestamp: Thu, 27 Sep 2018 16:29:39 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-coreos + Annotations: + Replicas: 824640215820 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mysql-mon-coreos + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-coreos + Annotations: + Type: ClusterIP + IP: 10.97.243.29 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.7:3306 + +Service: + Name: mysql-mon-coreos-stats + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-coreos + Annotations: monitoring.appscode.com/agent=prometheus.io/coreos-operator + Type: ClusterIP + IP: 10.109.38.68 + Port: prom-http 56790/TCP + TargetPort: prom-http/TCP + Endpoints: 172.17.0.7:56790 Database Secret: - Name: mysql-mon-coreos-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-mon-coreos-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-mon-coreos + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes Monitoring System: - Agent: prometheus.io/coreos-operator + Agent: prometheus.io/coreos-operator Prometheus: - Namespace: demo - Labels: app=kubedb - Interval: 10s + Port: 56790 + Namespace: demo + Labels: app=kubedb + Interval: 10s No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 31s 31s 1 MySQL operator Normal Successful Successfully patched StatefulSet - 31s 31s 1 MySQL operator Normal Successful Successfully patched MySQL - 34s 34s 1 MySQL operator Normal Successful Successfully created StatefulSet - 34s 34s 1 MySQL operator Normal Successful Successfully created MySQL - 49s 49s 1 MySQL operator Normal Successful Successfully created Service + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 1m MySQL operator Successfully created Service + Normal Successful 1m MySQL operator Successfully created StatefulSet + Normal Successful 1m MySQL operator Successfully created MySQL + Normal Successful 56s MySQL operator Successfully created stats service + Normal Successful 52s MySQL operator Successfully patched StatefulSet + Normal Successful 52s MySQL operator Successfully patched MySQL + Normal Successful 51s MySQL operator Successfully patched StatefulSet + Normal Successful 51s MySQL operator Successfully patched MySQL ``` Since `spec.monitoring` was configured, a ServiceMonitor object is created accordingly. You can verify it running the following commands: @@ -227,23 +273,22 @@ Since `spec.monitoring` was configured, a ServiceMonitor object is created accor ```yaml $ kubectl get servicemonitor -n demo NAME AGE -kubedb-demo-mysql-mon-coreos 51s - +kubedb-demo-mysql-mon-coreos 1m $ kubectl get servicemonitor -n demo kubedb-demo-mysql-mon-coreos -o yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: - clusterName: "" - creationTimestamp: 2018-02-12T05:27:13Z + creationTimestamp: 2018-09-27T10:30:20Z + generation: 1 labels: app: kubedb - monitoring.appscode.com/service: mysql-mon-coreos.demo + monitoring.appscode.com/service: mysql-mon-coreos-stats.demo name: kubedb-demo-mysql-mon-coreos namespace: demo - resourceVersion: "37184" + resourceVersion: "6257" selfLink: /apis/monitoring.coreos.com/v1/namespaces/demo/servicemonitors/kubedb-demo-mysql-mon-coreos - uid: 61bc7bf4-0fb5-11e8-a2d6-08002751ae8c + uid: 55a3ae53-c240-11e8-b2cc-080027d9f35e spec: endpoints: - interval: 10s @@ -267,23 +312,23 @@ Now, if you go the Prometheus Dashboard, you should see that this database endpo To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-mon-coreos -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-mon-coreos +kubectl patch -n demo mysql/mysql-mon-coreos -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-mon-coreos -$ kubectl patch -n demo drmn/mysql-mon-coreos -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-mon-coreos +kubectl patch -n demo drmn/mysql-mon-coreos -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-mon-coreos -$ kubectl delete clusterrolebindings prometheus-operator prometheus -$ kubectl delete clusterrole prometheus-operator prometheus +kubectl delete -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/coreos-operator/demo-1.yaml +kubectl delete -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/monitoring/coreos-operator/demo-0.yaml -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.md). - [Snapshot and Restore](/docs/guides/mysql/snapshot/backup-and-restore.md) process of MySQL databases using KubeDB. - Take [Scheduled Snapshot](/docs/guides/mysql/snapshot/scheduled-backup.md) of MySQL databases using KubeDB. - Initialize [MySQL with Script](/docs/guides/mysql/initialization/using-script.md). diff --git a/docs/guides/mysql/private-registry/using-private-registry.md b/docs/guides/mysql/private-registry/using-private-registry.md index 775aa7179..51bf070a2 100644 --- a/docs/guides/mysql/private-registry/using-private-registry.md +++ b/docs/guides/mysql/private-registry/using-private-registry.md @@ -9,6 +9,7 @@ menu: menu_name: docs_0.8.0 section_menu_id: guides --- + > New to KubeDB? Please start [here](/docs/concepts/README.md). # Deploy MySQL from private Docker registry @@ -17,23 +18,60 @@ KubeDB operator supports using private Docker registry. This tutorial will show ## 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/). - -You have to push the required images from KubeDB's [Docker hub account](https://hub.docker.com/r/kubedb/) into your private registry. For mysql, push the following images to your private registry. - -- [kubedb/operator](https://hub.docker.com/r/kubedb/operator) -- [kubedb/mysql](https://hub.docker.com/r/kubedb/mysql) -- [kubedb/mysql-tools](https://hub.docker.com/r/kubedb/mysql-tools) - -```console -$ export DOCKER_REGISTRY= - -$ docker pull kubedb/operator:0.9.0-beta.1 ; docker tag kubedb/operator:0.9.0-beta.1 $DOCKER_REGISTRY/operator:0.9.0-beta.1 ; docker push $DOCKER_REGISTRY/operator:0.9.0-beta.1 -$ docker pull kubedb/mysql:8.0 ; docker tag kubedb/mysql:8.0 $DOCKER_REGISTRY/mysql:8.0 ; docker push $DOCKER_REGISTRY/mysql:8.0 -$ docker pull kubedb/mysql-tools:8.0 ; docker tag kubedb/mysql-tools:8.0 $DOCKER_REGISTRY/mysql-tools:8.0 ; docker push $DOCKER_REGISTRY/mysql-tools:8.0 -``` +- Read [concept of MySQL Version Catalog](/docs/concepts/catalog/mysql.md) to learn detail concepts of `MySQLVersion` object. + +- 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/). + +- You have to push the required images from KubeDB's [Docker hub account](https://hub.docker.com/r/kubedb/) into your private registry. For mysql, push `DB_IMAGE`, `TOOLS_IMAGE`, `EXPORTER_IMAGE` of following MySQLVersions, where `deprecated` is not true, to your private registry. + + ```console + $ kubectl get mysqlversions -n kube-system -o=custom-columns=NAME:.metadata.name,VERSION:.spec.version,DB_IMAGE:.spec.db.image,TOOLS_IMAGE:.spec.tools.image,EXPORTER_IMAGE:.spec.exporter.image,DEPRECATED:.spec.deprecated + NAME VERSION DB_IMAGE TOOLS_IMAGE EXPORTER_IMAGE DEPRECATED + 5 5 kubedb/mysql:5 kubedb/mysql-tools:5 kubedb/operator:0.8.0 true + 5-v1 5 kubedb/mysql:5-v1 kubedb/mysql-tools:5-v1 kubedb/mysqld-exporter:v0.11.0 + 5.7 5.7 kubedb/mysql:5.7 kubedb/mysql-tools:5.7 kubedb/operator:0.8.0 true + 5.7-v1 5.7 kubedb/mysql:5.7-v1 kubedb/mysql-tools:5.7-v1 kubedb/mysqld-exporter:v0.11.0 + 8 8 kubedb/mysql:8 kubedb/mysql-tools:8 kubedb/operator:0.8.0 true + 8-v1 8 kubedb/mysql:8-v1 kubedb/mysql-tools:8-v1 kubedb/mysqld-exporter:v0.11.0 + 8.0 8.0 kubedb/mysql:8.0 kubedb/mysql-tools:8.0 kubedb/operator:0.8.0 true + 8.0-v1 8.0 kubedb/mysql:8.0-v1 kubedb/mysql-tools:8.0-v1 kubedb/mysqld-exporter:v0.11.0 + ``` + + Docker hub repositories: + + - [kubedb/operator](https://hub.docker.com/r/kubedb/operator) + - [kubedb/mysql](https://hub.docker.com/r/kubedb/mysql) + - [kubedb/mysql-tools](https://hub.docker.com/r/kubedb/mysql-tools) + - [kubedb/mysqld-exporter](https://hub.docker.com/r/kubedb/mysqld-exporter) + +- Update KubeDB catalog for private Docker registry. Ex: + + ```yaml + apiVersion: catalog.kubedb.com/v1alpha1 + kind: MySQLVersion + metadata: + name: "8.0-v1" + labels: + app: kubedb + spec: + version: "8.0" + db: + image: "PRIVATE_DOCKER_REGISTRY/mysql:8.0-v1" + exporter: + image: "PRIVATE_DOCKER_REGISTRY/mysqld-exporter:v0.11.0" + tools: + image: "PRIVATE_DOCKER_REGISTRY/mysql-tools:8.0-v1" + + ``` + +- 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 ns demo + namespace "demo" created + ``` ## Create ImagePullSecret @@ -42,13 +80,12 @@ ImagePullSecrets is a type of a Kubernete Secret whose sole purpose is to pull p Run the following command, substituting the appropriate uppercase values to create an image pull secret for your private Docker registry: ```console -$ kubectl create secret docker-registry myregistrykey \ +$ kubectl create secret docker-registry -n demo myregistrykey \ --docker-server=DOCKER_REGISTRY_SERVER \ --docker-username=DOCKER_USER \ --docker-email=DOCKER_EMAIL \ --docker-password=DOCKER_PASSWORD - -secret "myregistrykey" created. +secret/myregistrykey created ``` If you wish to follow other ways to pull private images see [official docs](https://kubernetes.io/docs/concepts/containers/images/) of kubernetes. @@ -59,22 +96,6 @@ NB: If you are using `kubectl` 1.9.0, update to 1.9.1 or later to avoid this [is 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. -## Create Demo namespace - -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 ns demo -namespace "demo" created - -$ kubectl get ns -NAME STATUS AGE -default Active 45m -demo Active 10s -kube-public Active 45m -kube-system Active 45m -``` - ## Deploy MySQL database from Private Registry While deploying `MySQL` from private repository, you have to add `myregistrykey` secret in `MySQL` `spec.imagePullSecrets`. @@ -87,7 +108,7 @@ metadata: name: mysql-pvt-reg namespace: demo spec: - version: "8.0" + version: "8.0-v1" doNotPause: true storage: storageClassName: "standard" @@ -96,51 +117,43 @@ spec: resources: requests: storage: 50Mi - imagePullSecrets: - - name: myregistrykey + podTemplate: + spec: + imagePullSecrets: + - name: myregistrykey ``` Now run the command to deploy this `MySQL` object: ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/private-registry/demo-2.yaml -mysql "mysql-pvt-reg" created +mysql.kubedb.com/mysql-pvt-reg created ``` To check if the images pulled successfully from the repository, see if the `MySQL` is in running state: ```console -$ kubectl get pods -n demo -w -NAME READY STATUS RESTARTS AGE -mysql-pvt-reg-0 0/1 Pending 0 0s -mysql-pvt-reg-0 0/1 Pending 0 0s -mysql-pvt-reg-0 0/1 ContainerCreating 0 1s -mysql-pvt-reg-0 1/1 Running 0 8s - - -$ kubedb get my -n demo -NAME STATUS AGE -mysql-pvt-reg Running 26s +$ kubectl get pods -n demo +NAME READY STATUS RESTARTS AGE +mysql-pvt-reg-0 1/1 Running 0 56s ``` ## Snapshot -We don't need to add `imagePullSecret` for `snapshot` objects. -Just create [snapshot object](/docs/guides/mysql/snapshot/backup-and-restore.md) and KubeDB operator will reuse the `ImagePullSecret` from `MySQL` object. +You can specify `imagePullSecret` for Snapshot objects in `spec.podTemplate.spec.imagePullSecrets` field of Snapshot object. If you are using scheduled backup, you can also provide `imagePullSecret` in `backupSchedule.podTemplate.spec.imagePullSecrets` field of MySQL crd. KubeDB also reuses `imagePullSecret` for Snapshot object from `spec.podTemplate.spec.imagePullSecrets` field of MySQL crd. ## Cleaning up To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-pvt-reg -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-pvt-reg +kubectl patch -n demo mysql/mysql-pvt-reg -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-pvt-reg -$ kubectl patch -n demo drmn/mysql-pvt-reg -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-pvt-reg +kubectl patch -n demo drmn/mysql-pvt-reg -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-pvt-reg -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps @@ -152,6 +165,7 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box CoreOS Prometheus Operator](/docs/guides/mysql/monitoring/using-coreos-prometheus-operator.md). - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/quickstart/quickstart.md b/docs/guides/mysql/quickstart/quickstart.md index 4c27e745a..832c67e50 100644 --- a/docs/guides/mysql/quickstart/quickstart.md +++ b/docs/guides/mysql/quickstart/quickstart.md @@ -16,50 +16,75 @@ section_menu_id: guides This tutorial will show you how to use KubeDB to run a MySQL database.

-  lifecycle +  lifecycle

-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: The yaml files used in this tutorial are stored in [docs/examples/mysql](https://github.com/kubedb/cli/tree/master/docs/examples/mysql) folder in github repository [kubedb/cli](https://github.com/kubedb/cli). ## 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). +- 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). + +- [StorageClass](https://kubernetes.io/docs/concepts/storage/storage-classes/) is required to run KubeDB. Check the available StorageClass in cluster. + + ```console + $ kubectl get storageclasses + NAME PROVISIONER AGE + standard (default) k8s.io/minikube-hostpath 4h + ``` + +- To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. This tutorial will also use a [phpMyAdmin](https://hub.docker.com/r/phpmyadmin/phpmyadmin/) deployment to connect and test MySQL database, once it is running. Run the following command to prepare your cluster for this tutorial: + + ```console + $ kubectl create ns demo + namespace "demo" created + + $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-1.yaml + deployment.extensions/myadmin created + service/myadmin created + + $ kubectl get pods -n demo --watch + NAME READY STATUS RESTARTS AGE + myadmin-c4db4df95-8lk74 0/1 ContainerCreating 0 27s + myadmin-c4db4df95-8lk74 1/1 Running 0 1m + + $ kubectl get service -n demo + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + myadmin LoadBalancer 10.105.73.16 80:30158/TCP 23m + + $ minikube ip + 192.168.99.100 + ``` + + Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. + You can also get this URl by running the following command: + + ```console + $ minikube service myadmin -n demo --url + http://192.168.99.100:30158 + ``` -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](https://hub.docker.com/r/phpmyadmin/phpmyadmin/) deployment to connect and test MySQL database, once it is running. Run the following command to prepare your cluster for this tutorial: - -```console -$ kubectl create ns demo -namespace "demo" created - -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-1.yaml -deployment "myadmin" created -service "myadmin" created - -$ kubectl get pods -n demo --watch -NAME READY STATUS RESTARTS AGE -myadmin-c4db4df95-8lk74 0/1 ContainerCreating 0 27s -myadmin-c4db4df95-8lk74 1/1 Running 0 1m - -$ kubectl get service -n demo -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -myadmin LoadBalancer 10.105.73.16 80:30158/TCP 23m +According to the above example, this URL will be [http://192.168.99.100:30158](http://192.168.99.100:30158). The login informations to phpMyAdmin _(host, username and password)_ will be retrieved later in this tutorial. -$ minikube ip -192.168.99.100 -``` +## Find Available MySQLVersion -Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. -You can also get this URl by running the following command: +When you have installed KubeDB, it has created `MySQLVersion` crd for all supported MySQL versions. Check 0 ```console -$ minikube service myadmin -n demo --url -http://192.168.99.100:30158 +$ kubectl get mysqlversions +NAME VERSION DB_IMAGE DEPRECATED AGE +5 5 kubedb/mysql:5 true 33s +5-v1 5 kubedb/mysql:5-v1 33s +5.7 5.7 kubedb/mysql:5.7 true 33s +5.7-v1 5.7 kubedb/mysql:5.7-v1 32s +8 8 kubedb/mysql:8 true 32s +8-v1 8 kubedb/mysql:8-v1 32s +8.0 8.0 kubedb/mysql:8.0 true 32s +8.0-v1 8.0 kubedb/mysql:8.0-v1 32s ``` -According to the above example, this URL will be [http://192.168.99.100:30158](http://192.168.99.100:30158). The login informations to phpMyAdmin _(host, username and password)_ will be retrieved later in this tutorial. - ## Create a MySQL database KubeDB implements a `MySQL` CRD to define the specification of a MySQL database. Below is the `MySQL` object created in this tutorial. @@ -71,8 +96,9 @@ metadata: name: mysql-quickstart namespace: demo spec: - version: "8.0" + version: "8.0-v1" doNotPause: true + storageType: Durable storage: storageClassName: "standard" accessModes: @@ -84,59 +110,80 @@ spec: ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/quickstart/demo-2.yaml -mysql "mysql-quickstart" created +mysql.kubedb.com/mysql-quickstart created ``` Here, -- `spec.version` is the version of MySQL database. In this tutorial, a MySQL 8.0 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.version` is the name of the MySQLVersion CRD where the docker images are specified. In this tutorial, a MySQL 8.0-v1 database is going to be created. +- `spec.doNotPause` prevents users from deleting this object if admission webhook is enabled.. This should be set to true for production databases to avoid accidental deletion. +- `spec.storageType` specifies the type of storage that will be used for MySQL database. It can be `Durable` or `Ephemeral`. Default value of this field is `Durable`. If `Ephemeral` is used then KubeDB will create MySQL database using `EmptyDir` volume. In this case, you don't have to specify `spec.storage` field. This is useful for testing purpose. - `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. Since release 0.8.0, a storage spec is required for MySQL. +> Note: spec.storage section is used to create PVC for database pod. It will create PVC with storage size specified instorage.resources.requests field. Don't specify limits here. PVC does not get resized automatically. + KubeDB operator watches for `MySQL` objects using Kubernetes api. When a `MySQL` object is created, KubeDB operator will create a new StatefulSet and a ClusterIP Service with the matching MySQL object name. KubeDB operator will also create a governing service for StatefulSets with the name `kubedb`, if one is not already present. No MySQL specific RBAC permission is required in [RBAC enabled clusters](/docs/setup/install.md#using-yaml). ```console $ kubedb describe my -n demo mysql-quickstart -Name: mysql-quickstart -Namespace: demo -StartTimestamp: Fri, 09 Feb 2018 15:55:42 +0600 -Status: Running +Name: mysql-quickstart +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 11:07:25 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mysql-quickstart - Replicas: 1 current / 1 desired - CreationTimestamp: Fri, 09 Feb 2018 15:55:44 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mysql-quickstart - Type: ClusterIP - IP: 10.104.50.139 - Port: db 3306/TCP + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mysql-quickstart + CreationTimestamp: Thu, 27 Sep 2018 11:07:26 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-quickstart + Annotations: + Replicas: 824635563004 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mysql-quickstart + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-quickstart + Annotations: + Type: ClusterIP + IP: 10.100.54.85 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.6:3306 Database Secret: - Name: mysql-quickstart-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-quickstart-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-quickstart + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 2m 2m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 2m 2m 1 MySQL operator Normal Successful Successfully patched MySQL - 2m 2m 1 MySQL operator Normal Successful Successfully created StatefulSet - 2m 2m 1 MySQL operator Normal Successful Successfully created MySQL - 9m 9m 1 MySQL operator Normal Successful Successfully created Service - + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 5m MySQL operator Successfully created Service + Normal Successful 2m MySQL operator Successfully created StatefulSet + Normal Successful 2m MySQL operator Successfully created MySQL + Normal Successful 2m MySQL operator Successfully patched StatefulSet + Normal Successful 2m MySQL operator Successfully patched MySQL + Normal Successful 2m MySQL operator Successfully patched StatefulSet + Normal Successful 2m MySQL operator Successfully patched MySQL $ kubectl get statefulset -n demo NAME DESIRED CURRENT AGE @@ -164,20 +211,28 @@ $ kubedb get my -n demo mysql-quickstart -o yaml apiVersion: kubedb.com/v1alpha1 kind: MySQL metadata: - clusterName: "" - creationTimestamp: 2018-02-09T09:55:42Z + creationTimestamp: 2018-09-27T05:07:25Z finalizers: - kubedb.com - generation: 0 + generation: 2 name: mysql-quickstart namespace: demo - resourceVersion: "25645" + resourceVersion: "2811" selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mysqls/mysql-quickstart - uid: 64388c9a-0d7f-11e8-9091-08002751ae8c + uid: 390009fb-c213-11e8-819c-08002760fa16 spec: databaseSecret: secretName: mysql-quickstart-auth doNotPause: true + podTemplate: + controller: {} + metadata: {} + spec: + resources: {} + replicas: 1 + serviceTemplate: + metadata: {} + spec: {} storage: accessModes: - ReadWriteOnce @@ -185,9 +240,13 @@ spec: requests: storage: 50Mi storageClassName: standard - version: 8 + storageType: Durable + terminationPolicy: Pause + updateStrategy: + type: RollingUpdate + version: 8.0-v1 status: - creationTime: 2018-02-09T09:55:43Z + observedGeneration: 2$4213139756412538772 phase: Running ``` @@ -199,40 +258,44 @@ Now, you can connect to this database from the phpMyAdmin dashboard using the da ```console $ kubectl get pods mysql-quickstart-0 -n demo -o yaml | grep IP - hostIP: 192.168.99.100 + hostIP: 10.0.2.15 podIP: 172.17.0.6 $ kubectl get secrets -n demo mysql-quickstart-auth -o jsonpath='{.data.\user}' | base64 -d root $ kubectl get secrets -n demo mysql-quickstart-auth -o jsonpath='{.data.\password}' | base64 -d -pefjWeXoAQ9PaRZv +8EisTcVchPiTSZOR ``` Now, open your browser and go to the following URL: _http://{minikube-ip}:{myadmin-svc-nodeport}_. To log into the phpMyAdmin, use host __`172.17.0.6`__ , username __`root`__ and password __`pefjWeXoAQ9PaRZv`__. -## Pause Database +## DoNotPause Property -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 MySQL object created in this tutorial has `spec.doNotPause` set to true, if you delete the MySQL 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 users from deleting the database as long as the `spec.doNotPause` is set to true. Since the MySQL object created in this tutorial has `spec.doNotPause` set to true, if you delete the MySQL object, KubeDB operator will nullify the delete operation. You can see this below: ```console $ kubedb delete my mysql-quickstart -n demo -error: MySQL "mysql-quickstart" can't be paused. To continue delete, unset spec.doNotPause and retry. +Error from server (BadRequest): admission webhook "mysql.validators.kubedb.com" denied the request: mysql "mysql-quickstart" can't be paused. To continue delete, unset spec.doNotPause and retry ``` -Now, run `kubedb edit my mysql-quickstart -n demo` to set `spec.doNotPause` to false or remove this field (which default to false). Then if you delete the MySQL object, KubeDB operator will delete the StatefulSet and its pods, but leaves the PVCs unchanged. In KubeDB parlance, we say that `mysql-quickstart` MySQL database has entered into dormant state. This is represented by KubeDB operator by creating a matching DormantDatabase object. +Now, run `kubedb edit my mysql-quickstart -n demo` to set `spec.doNotPause` to false or remove this field (which default to false). Then you will be able to delete/pause the database. + +## Pause Database + +When [TerminationPolicy](/docs/concepts/databases/mysql.md#specterminationpolicy) is set to `Pause`, it will pause the MySQL database instead of deleting it. Here, If you delete the MySQL object, KubeDB operator will delete the StatefulSet and its pods but leaves the PVCs unchanged. In KubeDB parlance, we say that `mgo-quickstart` MySQL database has entered into the dormant state. This is represented by KubeDB operator by creating a matching DormantDatabase object. ```console $ kubedb delete my mysql-quickstart -n demo -mysql "mysql-quickstart" deleted +mysql.kubedb.com "mysql-quickstart" deleted $ kubedb get drmn -n demo mysql-quickstart NAME STATUS AGE -mysql-quickstart Pausing 16s +mysql-quickstart Pausing 14s $ kubedb get drmn -n demo mysql-quickstart NAME STATUS AGE -mysql-quickstart Paused 31s +mysql-quickstart Paused 39s ``` ```yaml @@ -240,29 +303,36 @@ $ kubedb get drmn -n demo mysql-quickstart -o yaml apiVersion: kubedb.com/v1alpha1 kind: DormantDatabase metadata: - clusterName: "" - creationTimestamp: 2018-02-09T10:18:29Z + creationTimestamp: 2018-09-27T05:27:05Z finalizers: - kubedb.com - generation: 0 + generation: 1 labels: kubedb.com/kind: MySQL name: mysql-quickstart namespace: demo - resourceVersion: "26269" + resourceVersion: "4077" selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/dormantdatabases/mysql-quickstart - uid: 931ce051-0d82-11e8-9091-08002751ae8c + uid: f856b738-c215-11e8-819c-08002760fa16 spec: origin: metadata: - creationTimestamp: null + creationTimestamp: 2018-09-27T05:07:25Z name: mysql-quickstart namespace: demo spec: mysql: databaseSecret: secretName: mysql-quickstart-auth - resources: {} + podTemplate: + controller: {} + metadata: {} + spec: + resources: {} + replicas: 1 + serviceTemplate: + metadata: {} + spec: {} storage: accessModes: - ReadWriteOnce @@ -270,10 +340,14 @@ spec: requests: storage: 50Mi storageClassName: standard - version: "8" + storageType: Durable + terminationPolicy: Pause + updateStrategy: + type: RollingUpdate + version: 8.0-v1 status: - creationTime: 2018-02-09T10:18:30Z - pausingTime: 2018-02-09T10:18:48Z + observedGeneration: 1$5984877185736766566 + pausingTime: 2018-09-27T05:27:23Z phase: Paused ``` @@ -295,13 +369,15 @@ $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/doc mysql "mysql-quickstart" created ``` +Now, if you exec into the database, you can see that the datas are intact. + ## WipeOut DormantDatabase You can wipe out a DormantDatabase while deleting the objet by setting `spec.wipeOut` to true. KubeDB operator will delete any relevant resources of this `MySQL` database (i.e, PVCs, Secrets, Snapshots). It will also delete snapshot data stored in the Cloud Storage buckets. ```yaml $ kubedb delete my mysql-quickstart -n demo -mysql "mysql-quickstart" deleted +mysql.kubedb.com "mysql-quickstart" deleted $ kubedb edit drmn -n demo mysql-quickstart apiVersion: kubedb.com/v1alpha1 @@ -320,13 +396,13 @@ status: If `spec.wipeOut` is not set to true while deleting the `dormantdatabase` object, then only this object will be deleted and `kubedb-operator` won't delete related Secrets, PVCs and Snapshots. So, user still can access the stored data in the cloud storage buckets as well as PVCs. -## Delete Dormant Database +## Delete DormantDatabase As it is already discussed above, `DormantDatabase` can be deleted with or without wiping out the resources. To delete the `dormantdatabase`, ```console $ kubedb delete drmn mysql-quickstart -n demo -dormantdatabase "mysql-quickstart" deleted +dormantdatabase.kubedb.com "mysql-quickstart" deleted ``` ## Cleaning up @@ -334,16 +410,23 @@ dormantdatabase "mysql-quickstart" deleted To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-quickstart -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-quickstart +kubectl patch -n demo mysql/mysql-quickstart -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-quickstart -$ kubectl patch -n demo drmn/mysql-quickstart -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-quickstart +kubectl patch -n demo drmn/mysql-quickstart -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-quickstart -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` +## Tips for Testing + +If you are just testing some basic functionalities, you might want to avoid additional hassles due to some safety features that are great for production environment. You can follow these tips to avoid them. + +1. **Use `doNotPause: false`**. To avoid accidental deletion of database in production environment we recommend to use `spec.doNotPause: true`. It does not allow to delete MySQL crd. You have to update this to `false` first, then you will be able to delete MySQL crd. For testing purpose, you can just set `spec.donotPause: false`. You will not require to go through an additional step of updating to delete the MySQL crd. +2. **Use `storageType: Ephemeral`**. Databases are precious. You might not want to lose your data in your production environment if database pod fail. So, we recommend to use `spec.storageType: Durable` and provide storage spec in `spec.storage` section. For testing purpose, you can just use `spec.storageType: Ephemeral`. KubeDB will use [emptyDir](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) for storage. You will not require to provide `spec.storage` section. +3. **Use `terminationPolicy: WipeOut`**. It is nice to be able to resume database from previous one. So, we create `DormantDatabase` and preserve all your `PVCs`, `Secrets`, `Snapshots` etc. If you don't want to resume database, you can just use `spec.terminationPolicy: WipeOut`. It will not create `DormantDatabase` and it will delete everything created by KubeDB for a particular MySQL crd when you delete the crd. For more details about termination policy, please visit [here](/docs/concepts/databases/mysql.md#specterminationpolicy). + ## Next Steps - [Snapshot and Restore](/docs/guides/mysql/snapshot/backup-and-restore.md) process of MySQL databases using KubeDB. @@ -354,5 +437,6 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/snapshot/backup-and-restore.md b/docs/guides/mysql/snapshot/backup-and-restore.md index cb8b8aa38..b4dc3f306 100644 --- a/docs/guides/mysql/snapshot/backup-and-restore.md +++ b/docs/guides/mysql/snapshot/backup-and-restore.md @@ -15,30 +15,35 @@ section_menu_id: guides This tutorial will show you how to take snapshots of a KubeDB managed MySQL database. +> Note: The yaml files used in this tutorial are stored in [docs/examples/mysql](https://github.com/kubedb/cli/tree/master/docs/examples/mysql) folder in github repository [kubedb/cli](https://github.com/kubedb/cli). + ## 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). +- 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). +- Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). -A `MySQL` 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: +- [StorageClass](https://kubernetes.io/docs/concepts/storage/storage-classes/) is required to run KubeDB. Check the available StorageClass in cluster. -```console -$ kubectl create ns demo -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.9.0-beta.1/docs/examples/mysql/snapshot/demo-1.yaml -mysql "mysql-infant" created -``` + ```console + $ kubectl get storageclasses + NAME PROVISIONER AGE + standard (default) k8s.io/minikube-hostpath 4h + ``` -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). +- A `MySQL` 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 ns demo + namespace "demo" created + + $ kubectl get ns + NAME STATUS AGE + demo Active 1m + + $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/snapshot/demo-1.yaml + mysql.kubedb.com/mysql-infant created + ``` ## Instant Backups @@ -57,15 +62,15 @@ $ mv downloaded-sa-json.key > GOOGLE_SERVICE_ACCOUNT_JSON_KEY $ kubectl create secret generic my-snap-secret -n demo \ --from-file=./GOOGLE_PROJECT_ID \ --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY -secret "my-snap-secret" created +secret/my-snap-secret created ``` ```yaml $ kubectl get secret my-snap-secret -n demo -o yaml apiVersion: v1 data: - GOOGLE_PROJECT_ID: PHlvdXItcHJvamVjdC1pZD4= - GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== + GOOGLE_PROJECT_ID: PHlvdX....1pZD4= + GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInN...9tIgp9Cg== kind: Secret metadata: creationTimestamp: 2018-02-09T12:02:08Z @@ -91,16 +96,16 @@ spec: databaseName: mysql-infant storageSecretName: my-snap-secret gcs: - bucket: restic + bucket: kubedb ``` ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/snapshot/demo-2.yaml -snapshot "snap-mysql-infant" created +snapshot.kubedb.com/snap-mysql-infant created $ kubedb get snap -n demo -NAME DATABASE STATUS AGE -snap-mysql-infant my/mysql-infant Running 22s +NAME DATABASENAME STATUS AGE +snap-mysql-infant mysql-infant Running 13s ``` ```yaml @@ -108,28 +113,27 @@ $ kubedb get snap -n demo snap-mysql-infant -o yaml apiVersion: kubedb.com/v1alpha1 kind: Snapshot metadata: - clusterName: "" - creationTimestamp: 2018-02-09T12:03:50Z + creationTimestamp: 2018-09-27T06:12:37Z finalizers: - kubedb.com - generation: 0 + generation: 1 labels: kubedb.com/kind: MySQL kubedb.com/name: mysql-infant name: snap-mysql-infant namespace: demo - resourceVersion: "30488" + resourceVersion: "1754" selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/snapshots/snap-mysql-infant - uid: 4a507251-0d91-11e8-9091-08002751ae8c + uid: 54efc1fe-c21c-11e8-850e-080027517bbf spec: databaseName: mysql-infant gcs: - bucket: restic + bucket: kubedb storageSecretName: my-snap-secret status: - completionTime: 2018-02-09T12:04:52Z + completionTime: 2018-09-27T06:18:41Z phase: Succeeded - startTime: 2018-02-09T12:03:50Z + startTime: 2018-09-27T06:12:38Z ``` Here, @@ -143,50 +147,69 @@ You can also run the `kubedb describe` command to see the recent snapshots taken ```console $ kubedb describe my -n demo mysql-infant -Name: mysql-infant -Namespace: demo -StartTimestamp: Fri, 09 Feb 2018 18:00:23 +0600 -Status: Running +Name: mysql-infant +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 12:12:10 +0600 +Labels: +Annotations: +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mysql-infant - Replicas: 1 current / 1 desired - CreationTimestamp: Fri, 09 Feb 2018 18:00:24 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mysql-infant - Type: ClusterIP - IP: 10.103.94.148 - Port: db 3306/TCP + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mysql-infant + CreationTimestamp: Thu, 27 Sep 2018 12:12:11 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-infant + Annotations: + Replicas: 824641842156 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mysql-infant + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-infant + Annotations: + Type: ClusterIP + IP: 10.109.47.223 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.5:3306 Database Secret: - Name: mysql-infant-auth - Type: Opaque - Data - ==== - password: 16 bytes - user: 4 bytes + Name: mysql-infant-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-infant + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes Snapshots: - Name Bucket StartTime CompletionTime Phase - ---- ------ --------- -------------- ----- - snap-mysql-infant gs:restic Fri, 09 Feb 2018 18:03:50 +0600 Fri, 09 Feb 2018 18:04:52 +0600 Succeeded + Name Bucket StartTime CompletionTime Phase + ---- ------ --------- -------------- ----- + snap-mysql-infant gs:kubedb Thu, 27 Sep 2018 12:12:38 +0600 Thu, 27 Sep 2018 12:18:41 +0600 Succeeded Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 1m 1m 1 Job Controller Normal SuccessfulSnapshot Successfully completed snapshot - 2m 2m 1 Snapshot Controller Normal Starting Backup running - 5m 5m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 5m 5m 1 MySQL operator Normal Successful Successfully patched MySQL - 5m 5m 1 MySQL operator Normal Successful Successfully created StatefulSet - 5m 5m 1 MySQL operator Normal Successful Successfully created MySQL - 5m 5m 1 MySQL operator Normal Successful Successfully created Service + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 17m MySQL operator Successfully created Service + Normal Starting 17m Job Controller Backup running + Normal Successful 14m MySQL operator Successfully created StatefulSet + Normal Successful 14m MySQL operator Successfully created MySQL + Normal Successful 14m MySQL operator Successfully patched StatefulSet + Normal Successful 14m MySQL operator Successfully patched MySQL + Normal Successful 14m MySQL operator Successfully patched StatefulSet + Normal Successful 14m MySQL operator Successfully patched MySQL + Normal SuccessfulSnapshot 11m Job Controller Successfully completed snapshot ``` Once the snapshot Job is complete, you should see the output of the `mysql dump` command stored in the GCS bucket. @@ -199,6 +222,8 @@ From the above image, you can see that the snapshot output is stored in a folder You can create a new database from a previously taken Snapshot. Specify the Snapshot name in the `spec.init.snapshotSource` field of a new MySQL object. See the example `mysql-recovered` object below: +> Note: MySQL `mysql-recovered` must have same superuser credentials as MySQL `mysql-infant`. + ```yaml apiVersion: kubedb.com/v1alpha1 kind: MySQL @@ -206,7 +231,9 @@ metadata: name: mysql-recovered namespace: demo spec: - version: "8.0" + version: "8.0-v1" + databaseSecret: + secretName: mysql-infant-auth storage: storageClassName: "standard" accessModes: @@ -222,7 +249,7 @@ spec: ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/snapshot/demo-3.yaml -mysql "mysql-recovered" created +mysql.kubedb.com/mysql-recovered created ``` Here, @@ -233,58 +260,74 @@ Now, wait several seconds. KubeDB operator will create a new StatefulSet. Then K ```console $ kubedb get my -n demo -NAME STATUS AGE -mysql-infant Running 8m -mysql-recovered Initializing 21s +NAME VERSION STATUS AGE +mysql-infant 8.0-v1 Running 27m +mysql-recovered 8.0-v1 Initializing 5m $ kubedb get my -n demo -$ NAME STATUS AGE -mysql-infant Running 14m -mysql-recovered Running 6m +NAME VERSION STATUS AGE +mysql-infant 8.0-v1 Running 31m +mysql-recovered 8.0-v1 Running 9m $ kubedb describe my -n demo mysql-recovered -Name: mysql-recovered -Namespace: demo -StartTimestamp: Fri, 09 Feb 2018 18:08:23 +0600 -Status: Running -Annotations: kubedb.com/initialized= +Name: mysql-recovered +Namespace: demo +CreationTimestamp: Thu, 27 Sep 2018 12:34:07 +0600 +Labels: +Annotations: kubedb.com/initialized= +Replicas: 1 total +Status: Running + StorageType: Durable Volume: - StorageClass: standard - Capacity: 50Mi - Access Modes: RWO - -StatefulSet: - Name: mysql-recovered - Replicas: 1 current / 1 desired - CreationTimestamp: Fri, 09 Feb 2018 18:08:25 +0600 - Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed - -Service: - Name: mysql-recovered - Type: ClusterIP - IP: 10.105.110.215 - Port: db 3306/TCP + StorageClass: standard + Capacity: 50Mi + Access Modes: RWO + +StatefulSet: + Name: mysql-recovered + CreationTimestamp: Thu, 27 Sep 2018 12:34:09 +0600 + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-recovered + Annotations: + Replicas: 824640109500 desired | 1 total + Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed + +Service: + Name: mysql-recovered + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-recovered + Annotations: + Type: ClusterIP + IP: 10.99.66.59 + Port: db 3306/TCP + TargetPort: db/TCP + Endpoints: 172.17.0.6:3306 Database Secret: - Name: mysql-recovered-auth - Type: Opaque - Data - ==== - user: 4 bytes - password: 16 bytes + Name: mysql-infant-auth + Labels: kubedb.com/kind=MySQL + kubedb.com/name=mysql-infant + Annotations: + +Type: Opaque + +Data +==== + password: 16 bytes + user: 4 bytes No Snapshots. Events: - FirstSeen LastSeen Count From Type Reason Message - --------- -------- ----- ---- -------- ------ ------- - 5m 5m 1 Job Controller Normal SuccessfulSnapshot Successfully completed initialization - 10m 10m 1 MySQL operator Normal Successful Successfully patched StatefulSet - 10m 10m 1 MySQL operator Normal Successful Successfully patched MySQL - 10m 10m 1 MySQL operator Normal Initializing Initializing from Snapshot: "snap-mysql-infant" - 10m 10m 1 MySQL operator Normal Successful Successfully created StatefulSet - 10m 10m 1 MySQL operator Normal Successful Successfully created MySQL - 10m 10m 1 MySQL operator Normal Successful Successfully created Service + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal Successful 9m MySQL operator Successfully created Service + Normal Successful 9m MySQL operator Successfully created MySQL + Normal Successful 9m MySQL operator Successfully created StatefulSet + Normal Initializing 9m MySQL operator Initializing from Snapshot: "snap-mysql-infant" + Normal Successful 8m MySQL operator Successfully patched StatefulSet + Normal Successful 8m MySQL operator Successfully patched MySQL + Normal SuccessfulInitialize 3m Job Controller Successfully completed initialization ``` ## Cleaning up @@ -292,14 +335,13 @@ Events: To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-infant mysql/mysql-recovered -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-infant mysql/mysql-recovered +kubectl patch -n demo mysql/mysql-infant mysql/mysql-recovered -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-infant mysql/mysql-recovered -$ kubectl patch -n demo drmn/mysql-infant drmn/mysql-recovered -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-infant drmn/mysql-recovered +kubectl patch -n demo drmn/mysql-infant drmn/mysql-recovered -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-infant drmn/mysql-recovered -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps @@ -312,5 +354,6 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/snapshot/scheduled-backup.md b/docs/guides/mysql/snapshot/scheduled-backup.md index 8f72238af..8cc8ebb69 100644 --- a/docs/guides/mysql/snapshot/scheduled-backup.md +++ b/docs/guides/mysql/snapshot/scheduled-backup.md @@ -9,6 +9,7 @@ menu: menu_name: docs_0.8.0 section_menu_id: guides --- + > New to KubeDB? Please start [here](/docs/concepts/README.md). # Database Scheduled Snapshots @@ -17,25 +18,22 @@ This tutorial will show you how to use KubeDB to take scheduled snapshot of a My ## 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). +- 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). +- 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: +- 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 ns demo -namespace "demo" created - -$ kubectl get ns -NAME STATUS AGE -default Active 1h -demo Active 1m -kube-public Active 1h -kube-system Active 1h -``` + ```console + $ kubectl create ns demo + namespace "demo" created + + $ kubectl get ns + NAME STATUS AGE + demo Active 1m + ``` -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: The yaml files that are used in this tutorial are 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 @@ -54,7 +52,7 @@ $ mv downloaded-sa-json.key > GOOGLE_SERVICE_ACCOUNT_JSON_KEY $ kubectl create secret generic my-snap-secret -n demo \ --from-file=./GOOGLE_PROJECT_ID \ --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY -secret "my-snap-secret" created +secret/my-snap-secret created ``` ```yaml @@ -65,12 +63,9 @@ data: GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== kind: Secret metadata: - creationTimestamp: 2018-02-12T03:42:31Z name: my-snap-secret namespace: demo - resourceVersion: "32253" - selfLink: /api/v1/namespaces/demo/secrets/my-snap-secret - uid: c12eaa77-0fa6-11e8-a2d6-08002751ae8c + ... type: Opaque ``` @@ -83,7 +78,7 @@ metadata: name: mysql-scheduled namespace: demo spec: - version: "8.0" + version: "8.0-v1" storage: storageClassName: "standard" accessModes: @@ -91,21 +86,16 @@ spec: resources: requests: storage: 50Mi - init: - scriptSource: - gitRepo: - repository: "https://github.com/kubedb/mysql-init-scripts.git" - directory: . backupSchedule: cronExpression: "@every 1m" storageSecretName: my-snap-secret gcs: - bucket: restic + bucket: kubedb ``` ```console $ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0-beta.1/docs/examples/mysql/snapshot/demo-4.yaml -mysql "mysql-scheduled" created +mysql.kubedb.com/mysql-scheduled created ``` It is also possible to add backup scheduler to an existing `MySQL`. You just have to edit the `MySQL` CRD and add below spec: @@ -116,7 +106,7 @@ spec: backupSchedule: cronExpression: '@every 1m' gcs: - bucket: restic + bucket: kubedb storageSecretName: my-snap-secret ``` @@ -124,10 +114,11 @@ Once the `spec.backupSchedule` is added, KubeDB operator will create a new Snaps ```console $ kubedb get snap -n demo -NAME DATABASE STATUS AGE -mysql-scheduled-20180212-034954 my/mysql-scheduled Succeeded 2m -mysql-scheduled-20180212-035054 my/mysql-scheduled Succeeded 1m -mysql-scheduled-20180212-035154 my/mysql-scheduled Running 21s +NAME DATABASENAME STATUS AGE +mysql-scheduled-20180927-083539 mysql-scheduled Succeeded 3m +mysql-scheduled-20180927-083639 mysql-scheduled Succeeded 2m +mysql-scheduled-20180927-083739 mysql-scheduled Succeeded 1m +mysql-scheduled-20180927-083839 mysql-scheduled Succeeded 39s ``` you should see the output of the `mysql dump` command for each snapshot stored in the GCS bucket. @@ -152,7 +143,7 @@ spec: # backupSchedule: # cronExpression: '@every 1m' # gcs: -# bucket: restic +# bucket: kubedb # storageSecretName: my-snap-secret databaseSecret: secretName: mysql-scheduled-auth @@ -170,7 +161,6 @@ spec: storageClassName: standard version: 8 status: - creationTime: 2018-02-12T03:44:23Z phase: Running ``` @@ -179,14 +169,13 @@ status: To cleanup the Kubernetes resources created by this tutorial, run: ```console -$ kubectl patch -n demo mysql/mysql-scheduled -p '{"spec":{"doNotPause":false}}' --type="merge" -$ kubectl delete -n demo mysql/mysql-scheduled +kubectl patch -n demo mysql/mysql-scheduled -p '{"spec":{"doNotPause":false}}' --type="merge" +kubectl delete -n demo mysql/mysql-scheduled -$ kubectl patch -n demo drmn/mysql-scheduled -p '{"spec":{"wipeOut":true}}' --type="merge" -$ kubectl delete -n demo drmn/mysql-scheduled +kubectl patch -n demo drmn/mysql-scheduled -p '{"spec":{"wipeOut":true}}' --type="merge" +kubectl delete -n demo drmn/mysql-scheduled -$ kubectl delete ns demo -namespace "demo" deleted +kubectl delete ns demo ``` ## Next Steps @@ -198,5 +187,6 @@ namespace "demo" deleted - Monitor your MySQL database with KubeDB using [out-of-the-box builtin-Prometheus](/docs/guides/mysql/monitoring/using-builtin-prometheus.md). - Use [private Docker registry](/docs/guides/mysql/private-registry/using-private-registry.md) to deploy MySQL with KubeDB. - Detail concepts of [MySQL object](/docs/concepts/databases/mysql.md). +- Detail concepts of [MySQLVersion object](/docs/concepts/catalog/mysql.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/mysql/mysql-lifecycle.png b/docs/images/mysql/mysql-lifecycle.png index 6c785f89ff1beb29c7886196fe772f076028cd99..15045333bd043f4bc0890256a757d6443e1afdcd 100644 GIT binary patch literal 82540 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 literal 66555 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

FWfRl>i4`h3G+61h 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%0AFZh{ebCai{NYt#Q?tul(z}Oae#!wg4|a1k5r&D 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 CsKH18