Fault Tolerance
Exploration of MySQL Operator
for Kubernetes in Python
October 29, 2022
Ivan Ma
MySQL Master principal Solution Engineer
The following is intended to outline our general product direction.
It is intended for information purposes only, and may not be
incorporated into any contract. It is not a commitment to deliver
any material, code, or functionality, and should not be relied upon
in making purchasing decisions. The development, release,
timing, and pricing of any features or functionality described for
Oracle’s products may change and remains at the sole discretion
of Oracle Corporation.
Safe harbor statement
2
MySQL Operator for Kubernetes
• Pod [ mysqloperator ]
• Dockerfile [ building the image ]
• https://github.com/mysql/mysql-operator/blob/trunk/docker-build/Dockerfile
• Installed with MySQL Shell
• mysqloperator package for Python
• COPY mysqloperator/ /usr/lib/mysqlsh/python-packages/mysqloperator
• Kopf
• Framework to build Kubernetes operators in Python
• https://kopf.readthedocs.io/en/stable/architecture/
kopf operator creation
• Manual Execution
• pip3 install kopf
• Create CRD
• Create the myoperator.py
• “Manually”
• kopf run myoprator.py
• Creating the resource object
External Reference Only : https://blog.baeke.info/2020/01/26/writing-a-kubernetes-
operator-with-kopf/
CRD - example
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: demowebs.mygroup.info
spec:
scope: Namespaced
group: mygroup.info
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
gitRepo:
type: string
replicas:
type: integer
names:
kind: DemoWeb
plural: demowebs
singular: demoweb
shortNames:
- dweb
Creation of crd
# kubectl apply –f demowebs-crd.yaml
# kubectl get crd demowebs.mygroup.info
NAME CREATED AT
demowebs.mygroup.info 2022-10-21T04:05:00Z
Creating the Resource Object
kubectl create ns mydemo
cat << EOF |kubectl apply -n mydemo -f -
apiVersion: mygroup.info/v1
kind: DemoWeb
metadata:
name: mydemoweb
spec:
replicas: 2
gitRepo: "https://github.com/ivanxma/staticweb.git"
EOF
Creation of the myoperator.py
The operator to be executed by “kopf”
import kopf
import kubernetes.client
from kubernetes.client.rest import ApiException
import yaml
@kopf.on.create('mygroup.info', 'v1', 'demowebs')
def create_fn(spec, **kwargs):
name = kwargs["body"]["metadata"]["name"]
print("Name is %sn" % name)
# Create the deployment spec
doc = yaml.safe_load(f"""
apiVersion: apps/v1
kind: Deployment
metadata:
name: {name}-deployment
labels:
app: {name}
spec:
replicas: {spec.get('replicas', 1)}
selector:
matchLabels:
app: {name}
template:
metadata:
labels:
app: {name}
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: workdir
mountPath: /usr/share/nginx/html
initContainers:
- name: install
image: alpine/git
command:
- git
- clone
- {spec.get('gitrepo', 'https://github.com/ivanxma/staticweb.git')}
- /work-dir
volumeMounts:
- name: workdir
mountPath: /work-dir
dnsPolicy: Default
volumes:
- name: workdir
emptyDir: {{}}
""")
# Adopt the Yaml and Apply
kopf.adopt(doc)
api = kubernetes.client.AppsV1Api()
try:
depl =
api.create_namespaced_deployment(namespace=doc['metadata']['nam
espace'], body=doc)
except ApiException as e:
print("Exception when calling AppsV1Api-
>create_namespaced_deployment: %sn" % e)
CRD : kind : DemoWeb
spec properties : replicas, gitRepos
The resource object
• The resource object DemoWeb [kind] is created - A definition ONLY
• What next : to execute the operator
• # kopf run --namespace=”<namespaces>” myoperator.py
How the MySQL Operator works
https://github.com/mysql/mysql-operator/blob/trunk/mysqloperator/controller/innodbcluster/operator_cluster.py
• @kopf.on.create(consts.GROUP, consts.VERSION, consts.INNODBCLUSTER_PLURAL)
• 1. prepare_initconf è2. prepare_secrets
• 3. prepare_router_secrets è 4. prepare_cluster_service
• 5. prepare-service_account è 6. prepare_role_binding
• 7. prepare_cluster_stateful_set è 8. prepare_cluster_pod_disruption_budget
• 9. prepare_router_service è 10 prepare_router_deployment
• 11 prepare_backup_secrets è
• Finally : set cluster status è online instance = 0, status as PENDING
• @kopf.on.delete(consts.GROUP, consts.VERSION,consts.INNODBCLUSTER_PLURAL)
• @kopf.on.filed(consts.GROUP, const.VERSION, consts.INNODBCLUSTER_PLURAL, filed=“….”)
• @kopf.on.field(consts.GROUP, consts.VERSION, consts.INNODBCLUSTER_PLURAL,field="spec.version") (spec.router.version)
• cluster_ctl.on_server_version_change(new)
• @kopf.on.create("", "v1", "pods",labels={"component": "mysqld"})
• @kopf.on.event ("", "v1", "pods",labels={"component": "mysqld"})
• @kopf.on.delete("", "v1", "pods", labels={"component": "mysqld"})
MySQL Operator
Creation of Innodb Cluster in K8s
11
mysql-2
mysql-1
mysql-0
Kubernetes Environment
MySQL InnoDB Cluster
application-0
apps-0
app-0 app-1
LB
Container
Bins  Libs
App
Container
Bins  Libs
App
mysql-mon-0
mem-0
Container
Bins  Libs
MySQL
Monitor
mysql-innodb-cluster-0
mysql-routers [Replicaset]
router-x
Container
Bins  Libs
MySQL
Router
router-y
Container
Bins  Libs
MySQL
Router
K8s
Service
mysql-servers [Statefulset]
mysql-0
Container
Bins  Libs
MySQL
mysql-1
Container
Bins  Libs
MySQL
mysql-2
Container
Bins  Libs
MySQL
GR GR
prim
ary
router-z
Container
Bins  Libs
MySQL
Router
Deployment
pod
Kopf framework
mysql-operator
Manifest Installation
MySQL Operator for Kubernetes
• https://github.com/mysql/mysql-operator
• https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-installation-kubectl.html
• 1- Apply Custom Resource Definition:
• $> kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-
crds.yaml
• 2- Deploy operator
• $> kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy-
operator.yaml
• 3- Describe operator
• $> kubectl get deployment mysql-operator --namespace mysql-operator
Helm installation
MySQL Operator for Kubernetes
• https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-installation-helm.html
• $> helm repo add mysql-operator https://mysql.github.io/mysql-operator/
• $> helm repo update
• $> helm install my-mysql-operator mysql-operator/mysql-operator --namespace mysql-operator --create-
namespace
Connecting to InnoDB Cluster with MySQL Operator Image
$> kubectl run --rm -it myshell -n <the ns> --image=mysql/mysql-operator – mysqlsh
If you don't see a command prompt, try pressing enter. MySQL JS >
More on Operations
MySQL Operator for Kubernetes
• Checking Innodb cluster status:
• kubectl get innodbcluster --watch –n <namespace>
• Retrieve IP address of cluster:
• kubectl get service mycluster –n <namespace>
• Describe the storage (PVC) for a MySQL server:
• kubectl describe pvc datadir-mycluster-[0|1|2|…] –n <namespace>
• Exposing ports (applications outside of Kubernetes):
• kubectl port-forward service/mycluster mysql –n <namespace>
• kubectl expose rs mycluster-router --port=6446 --target-port=6446 --type=LoadBalancer -
-name mycluster-lb –n <namespace>
Thank you

Exploring MySQL Operator for Kubernetes in Python

  • 1.
    Fault Tolerance Exploration ofMySQL Operator for Kubernetes in Python October 29, 2022 Ivan Ma MySQL Master principal Solution Engineer
  • 2.
    The following isintended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described for Oracle’s products may change and remains at the sole discretion of Oracle Corporation. Safe harbor statement 2
  • 3.
    MySQL Operator forKubernetes • Pod [ mysqloperator ] • Dockerfile [ building the image ] • https://github.com/mysql/mysql-operator/blob/trunk/docker-build/Dockerfile • Installed with MySQL Shell • mysqloperator package for Python • COPY mysqloperator/ /usr/lib/mysqlsh/python-packages/mysqloperator • Kopf • Framework to build Kubernetes operators in Python • https://kopf.readthedocs.io/en/stable/architecture/
  • 4.
    kopf operator creation •Manual Execution • pip3 install kopf • Create CRD • Create the myoperator.py • “Manually” • kopf run myoprator.py • Creating the resource object External Reference Only : https://blog.baeke.info/2020/01/26/writing-a-kubernetes- operator-with-kopf/
  • 5.
    CRD - example apiVersion:apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: demowebs.mygroup.info spec: scope: Namespaced group: mygroup.info versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: gitRepo: type: string replicas: type: integer names: kind: DemoWeb plural: demowebs singular: demoweb shortNames: - dweb
  • 6.
    Creation of crd #kubectl apply –f demowebs-crd.yaml # kubectl get crd demowebs.mygroup.info NAME CREATED AT demowebs.mygroup.info 2022-10-21T04:05:00Z
  • 7.
    Creating the ResourceObject kubectl create ns mydemo cat << EOF |kubectl apply -n mydemo -f - apiVersion: mygroup.info/v1 kind: DemoWeb metadata: name: mydemoweb spec: replicas: 2 gitRepo: "https://github.com/ivanxma/staticweb.git" EOF
  • 8.
    Creation of themyoperator.py The operator to be executed by “kopf” import kopf import kubernetes.client from kubernetes.client.rest import ApiException import yaml @kopf.on.create('mygroup.info', 'v1', 'demowebs') def create_fn(spec, **kwargs): name = kwargs["body"]["metadata"]["name"] print("Name is %sn" % name) # Create the deployment spec doc = yaml.safe_load(f""" apiVersion: apps/v1 kind: Deployment metadata: name: {name}-deployment labels: app: {name} spec: replicas: {spec.get('replicas', 1)} selector: matchLabels: app: {name} template: metadata: labels: app: {name} spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: workdir mountPath: /usr/share/nginx/html initContainers: - name: install image: alpine/git command: - git - clone - {spec.get('gitrepo', 'https://github.com/ivanxma/staticweb.git')} - /work-dir volumeMounts: - name: workdir mountPath: /work-dir dnsPolicy: Default volumes: - name: workdir emptyDir: {{}} """) # Adopt the Yaml and Apply kopf.adopt(doc) api = kubernetes.client.AppsV1Api() try: depl = api.create_namespaced_deployment(namespace=doc['metadata']['nam espace'], body=doc) except ApiException as e: print("Exception when calling AppsV1Api- >create_namespaced_deployment: %sn" % e) CRD : kind : DemoWeb spec properties : replicas, gitRepos
  • 9.
    The resource object •The resource object DemoWeb [kind] is created - A definition ONLY • What next : to execute the operator • # kopf run --namespace=”<namespaces>” myoperator.py
  • 10.
    How the MySQLOperator works https://github.com/mysql/mysql-operator/blob/trunk/mysqloperator/controller/innodbcluster/operator_cluster.py • @kopf.on.create(consts.GROUP, consts.VERSION, consts.INNODBCLUSTER_PLURAL) • 1. prepare_initconf è2. prepare_secrets • 3. prepare_router_secrets è 4. prepare_cluster_service • 5. prepare-service_account è 6. prepare_role_binding • 7. prepare_cluster_stateful_set è 8. prepare_cluster_pod_disruption_budget • 9. prepare_router_service è 10 prepare_router_deployment • 11 prepare_backup_secrets è • Finally : set cluster status è online instance = 0, status as PENDING • @kopf.on.delete(consts.GROUP, consts.VERSION,consts.INNODBCLUSTER_PLURAL) • @kopf.on.filed(consts.GROUP, const.VERSION, consts.INNODBCLUSTER_PLURAL, filed=“….”) • @kopf.on.field(consts.GROUP, consts.VERSION, consts.INNODBCLUSTER_PLURAL,field="spec.version") (spec.router.version) • cluster_ctl.on_server_version_change(new) • @kopf.on.create("", "v1", "pods",labels={"component": "mysqld"}) • @kopf.on.event ("", "v1", "pods",labels={"component": "mysqld"}) • @kopf.on.delete("", "v1", "pods", labels={"component": "mysqld"})
  • 11.
    MySQL Operator Creation ofInnodb Cluster in K8s 11
  • 12.
    mysql-2 mysql-1 mysql-0 Kubernetes Environment MySQL InnoDBCluster application-0 apps-0 app-0 app-1 LB Container Bins Libs App Container Bins Libs App mysql-mon-0 mem-0 Container Bins Libs MySQL Monitor mysql-innodb-cluster-0 mysql-routers [Replicaset] router-x Container Bins Libs MySQL Router router-y Container Bins Libs MySQL Router K8s Service mysql-servers [Statefulset] mysql-0 Container Bins Libs MySQL mysql-1 Container Bins Libs MySQL mysql-2 Container Bins Libs MySQL GR GR prim ary router-z Container Bins Libs MySQL Router Deployment pod Kopf framework mysql-operator
  • 13.
    Manifest Installation MySQL Operatorfor Kubernetes • https://github.com/mysql/mysql-operator • https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-installation-kubectl.html • 1- Apply Custom Resource Definition: • $> kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy- crds.yaml • 2- Deploy operator • $> kubectl apply -f https://raw.githubusercontent.com/mysql/mysql-operator/trunk/deploy/deploy- operator.yaml • 3- Describe operator • $> kubectl get deployment mysql-operator --namespace mysql-operator
  • 14.
    Helm installation MySQL Operatorfor Kubernetes • https://dev.mysql.com/doc/mysql-operator/en/mysql-operator-installation-helm.html • $> helm repo add mysql-operator https://mysql.github.io/mysql-operator/ • $> helm repo update • $> helm install my-mysql-operator mysql-operator/mysql-operator --namespace mysql-operator --create- namespace
  • 15.
    Connecting to InnoDBCluster with MySQL Operator Image $> kubectl run --rm -it myshell -n <the ns> --image=mysql/mysql-operator – mysqlsh If you don't see a command prompt, try pressing enter. MySQL JS >
  • 16.
    More on Operations MySQLOperator for Kubernetes • Checking Innodb cluster status: • kubectl get innodbcluster --watch –n <namespace> • Retrieve IP address of cluster: • kubectl get service mycluster –n <namespace> • Describe the storage (PVC) for a MySQL server: • kubectl describe pvc datadir-mycluster-[0|1|2|…] –n <namespace> • Exposing ports (applications outside of Kubernetes): • kubectl port-forward service/mycluster mysql –n <namespace> • kubectl expose rs mycluster-router --port=6446 --target-port=6446 --type=LoadBalancer - -name mycluster-lb –n <namespace>
  • 17.