From e2b18d2d8440a5b89d870e665e38304778e1357d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my-Christophe=20Schermesser?= Date: Fri, 24 May 2019 12:08:28 +0200 Subject: [PATCH] feat: add operators (#50) --- 20-operators/01-mysql-operator.yml | 235 +++++++++++++++++++++++++++++ 20-operators/02-mysql-cluster.yml | 28 ++++ 20-operators/README.md | 115 +++++++++++++- 3 files changed, 375 insertions(+), 3 deletions(-) create mode 100644 20-operators/01-mysql-operator.yml create mode 100644 20-operators/02-mysql-cluster.yml diff --git a/20-operators/01-mysql-operator.yml b/20-operators/01-mysql-operator.yml new file mode 100644 index 0000000..c9b3070 --- /dev/null +++ b/20-operators/01-mysql-operator.yml @@ -0,0 +1,235 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: operator +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-operator + namespace: operator +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-agent + namespace: operator +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: mysql-operator +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: [""] + resources: ["secrets"] + verbs: + - create + - apiGroups: [""] + resources: + - services + verbs: + - create + - get + - list + - watch + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - update + - patch + - apiGroups: ["apps"] + resources: ["statefulsets"] + verbs: + - create + - get + - list + - patch + - update + - watch + - apiGroups: ["mysql.oracle.com"] + resources: + - mysqlbackups + - mysqlbackupschedules + - mysqlclusters + - mysqlclusters/finalizers + - mysqlrestores + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: ["mysql.oracle.com"] + resources: ["mysqlbackups"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: mysql-agent +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - update + - patch + - apiGroups: ["mysql.oracle.com"] + resources: + - mysqlbackups + - mysqlbackupschedules + - mysqlclusters + - mysqlclusters/finalizers + - mysqlrestores + verbs: + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: mysql-operator + namespace: operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-operator +subjects: + - kind: ServiceAccount + name: mysql-operator + namespace: operator +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: mysql-agent + namespace: operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-agent +subjects: + - kind: ServiceAccount + name: mysql-agent + namespace: operator +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlclusters.mysql.oracle.com + labels: + release: mysql-operator + chart: mysql-operator-0.2.1 +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Cluster + singular: mysqlcluster + plural: mysqlclusters +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlbackups.mysql.oracle.com + labels: + release: mysql-operator + chart: mysql-operator-0.2.1 +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Backup + singular: mysqlbackup + plural: mysqlbackups +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlrestores.mysql.oracle.com + labels: + release: mysql-operator + chart: mysql-operator-0.2.1 +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: Restore + singular: mysqlrestore + plural: mysqlrestores +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: mysqlbackupschedules.mysql.oracle.com + labels: + release: mysql-operator + chart: mysql-operator-0.2.1 +spec: + group: mysql.oracle.com + version: v1alpha1 + scope: Namespaced + names: + kind: BackupSchedule + singular: mysqlbackupschedule + plural: mysqlbackupschedules +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: mysql-operator + namespace: operator + labels: + release: mysql-operator + chart: mysql-operator-0.2.1 + app: mysql-operator +spec: + replicas: 1 + selector: + matchLabels: + app: mysql-operator + template: + metadata: + labels: + app: mysql-operator + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + spec: + serviceAccountName: mysql-operator + containers: + - name: mysql-operator-controller + imagePullPolicy: Always + image: iad.ocir.io/oracle/mysql-operator:0.3.0 + ports: + - containerPort: 10254 + args: + - --v=4 + - --mysql-agent-image=iad.ocir.io/oracle/mysql-agent diff --git a/20-operators/02-mysql-cluster.yml b/20-operators/02-mysql-cluster.yml new file mode 100644 index 0000000..265cbc3 --- /dev/null +++ b/20-operators/02-mysql-cluster.yml @@ -0,0 +1,28 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mysql-agent + namespace: default +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: mysql-agent + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: mysql-agent +subjects: + - kind: ServiceAccount + name: mysql-agent + namespace: default +--- +apiVersion: mysql.oracle.com/v1alpha1 +kind: Cluster +metadata: + name: my-app-db + namespace: default +spec: + members: 1 diff --git a/20-operators/README.md b/20-operators/README.md index 0d77e8f..9567026 100644 --- a/20-operators/README.md +++ b/20-operators/README.md @@ -2,14 +2,123 @@ ## Introduction -## Exercices +In the previous section we saw what a controller is and what it does: interact with the Kubernetes API to act on it. -Nothing to see here. +In fact, the Kubernetes API is more powerful. You can enhance it with your own objects. That's what is called Custom Resource Definition or CRD for short. When you add your own CRDs and your own controllers you get an operator. + +We will not build on operator in this chapter, but we will rely on an existing operation, the [mysql-operator](https://github.com/oracle/mysql-operator). + +Start by [deploying the operator](https://github.com/oracle/mysql-operator/blob/master/docs/tutorial.md). For ease of installation, the operator is included in this repo in the file [`01-mysql-operator.yml`](./01-mysql-operator.yml). + +```sh +$ kubectl apply -f 20-operators/01-mysql-operator.yml +serviceaccount/mysql-operator created +serviceaccount/mysql-agent created +clusterrole.rbac.authorization.k8s.io/mysql-operator created +clusterrole.rbac.authorization.k8s.io/mysql-agent created +clusterrolebinding.rbac.authorization.k8s.io/mysql-operator created +clusterrolebinding.rbac.authorization.k8s.io/mysql-agent created +customresourcedefinition.apiextensions.k8s.io/mysqlclusters.mysql.oracle.com created +customresourcedefinition.apiextensions.k8s.io/mysqlbackups.mysql.oracle.com created +customresourcedefinition.apiextensions.k8s.io/mysqlrestores.mysql.oracle.com created +customresourcedefinition.apiextensions.k8s.io/mysqlbackupschedules.mysql.oracle.com created +deployment.apps/mysql-operator created +``` + +## CRDs + +This operator creates multiple CRDs automatically, you can see it by: + +```sh +$ kubectl describe crds mysqlclusters.mysql.oracle.com +Name: mysqlclusters.mysql.oracle.com +[...] +API Version: apiextensions.k8s.io/v1beta1 +Kind: CustomResourceDefinition +Metadata: + [...] +Spec: + [...] + Group: mysql.oracle.com + Names: + Kind: Cluster + List Kind: ClusterList + Plural: mysqlclusters + Singular: mysqlcluster + Scope: Namespaced + Version: v1alpha1 + Versions: + Name: v1alpha1 + Served: true + Storage: true +Status: + [...] +Events: [...] +``` + +We see that is created a new "kind" named `Cluster`, with a name `mysqlcluster`. And this new "kind" is completely integrated with Kubernetes and all the tooling try to do a: + +```sh +kubectl get mysqlcluster +``` + +Magically it is also integrated with `kubectl` but only when connected to your cluster. So now we can write a [manifest](./02-mysql-cluster.yml) of kind `Cluster`: + +```yml +apiVersion: mysql.oracle.com/v1alpha1 +kind: Cluster +metadata: + name: my-app-db + namespace: default +spec: + members: 1 +``` + +We won't go into the details of what each option does. The only important part is that each of those options was declared in the CRD. Here we specify a mysql cluster with 1 node or `members` + +## Operator + +Now let's apply this manifest: + +```sh +kubectl apply -f 20-operators/02-mysql-cluster.yml +``` + +And see what it did: + +```sh +kubectl get mysqlcluster my-app-db +``` + +Look around in pods, deployments, services, stateful sets, secrets, etc. What can you see? + +The operator creates a root password for mysql automatically, let's get it by + +```sh +kubectl get secret my-app-db-root-password -o jsonpath="{.data.password}" | base64 --decode +``` + +Use it to connect to your mysql instance: + +```sh +$ kubectl run mysql-client --image=mysql:5.7 -it --rm --restart=Never -- mysql -h my-app-db -uroot -p -e 'SELECT 1' +If you don't see a command prompt, try pressing enter. +Error attaching, falling back to logs: Internal error occurred: error attaching to container: container not running (ce62ea67ace6b65020d75646e3d31cad41f275ff51a05964a100ed8a87bf77c7) +mysql: [Warning] Using a password on the command line interface can be insecure. ++---+ +| 1 | ++---+ +| 1 | ++---+ +pod "mysql-client" deleted +``` + +Change the number of `members` from `1` to `2` in the manifest of `02-mysql-cluster.yml`. Reapply it, what can you see? Try reconnecting to the mysql. ## Clean up ```sh -kubectl delete service,deployment,pod --all +kubectl delete mysqlclusters,service,deployment,crds,pod --all ``` ## Links