This is a go-based Kubernetes operator built with operator-sdk, which manages MySQL databases, schema, users, permissions in existing MySQL servers. This operator DOES NOT manage MySQL cluster like other MySQL operators such as vitess, mysql/mysql-operator.
Reduce human operations:
- User management: When creating a MySQL user for an application running on Kubernetes, it's necessary to create a MySQL user and create a Secret manually or with a script, which can be replaced with a Kubernetes operator. The initial idea is from KafkaUser and KafkaTopic in Strimzi Kafka Operator. With a custom resource for MySQL user, we can manage MySQL users with Kubernetes manifest files as a part of dependent application. Benefits from such a custom resource and operator:
- Kubernetes manifest files for an application and its dependent resources (including MySQL user) can be managed together with Kustomize or Helm chart, with which we can easily duplicate whole environment.
- There's no chance to require someone to check the raw password as it's stored directly to Secret by the operator, and read by the dependent application from the Secret.
- Database migration: Reduce manual operations but keep changelog. When any schema migration or database operation is required, we needed a human operation, which has potential risk of human errors that should be avoided. With a Kubernetes operator, we can execute each database operation in the standard way with traceable changlog.
- Go: 1.24.0
- Custom Resource
MySQL: MySQL connection (host,port,adminUser,adminPasswordholding the credentials to connect to MySQL.adminUserandadminPasswordcan be given by GSM or k8s Secret other than plaintext.)MySQLUser: MySQL user (mysqlNameandhost)MySQLDB: MySQL database (mysqlName,dbName,schemaMigrationFromGitHub)
- Reconciler
MySQLReconcileris responsible for managingMySQLClientsbased onMySQLandMySQLDBresourcesMySQLUserReconcileris responsible for creating/deleting MySQL users defined inMySQLUserusingMySQLClients, and creating Secret to store MySQL user's passwordMySQLDBReconcileris responsible for creating/deleting database and schema migration defined inMySQLDBusingMySQLClients
Install (Create CRD and operator objects) With kustomize:
kubectl apply -k https://github.com/nakamasato/mysql-operator/config/installWith Helm:
helm repo add nakamasato https://nakamasato.github.io/helm-charts helm repo update helm install mysql-operator nakamasato/mysql-operator(Optional) prepare MySQL.
kubectl apply -k https://github.com/nakamasato/mysql-operator/config/mysqlApply custom resources (
MySQL,MySQLUser,MySQLDB).mysql.yamlcredentials to connect to the MySQL:apiVersion: mysql.nakamasato.com/v1alpha1kind: MySQLmetadata: name: mysql-samplespec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint.adminUser: name: roottype: rawadminPassword: name: passwordtype: raw
mysqluser.yaml: MySQL userapiVersion: mysql.nakamasato.com/v1alpha1kind: MySQLUsermetadata: name: sample-userspec: mysqlName: mysql-samplehost: '%'
mysqldb.yaml: MySQL databaseapiVersion: mysql.nakamasato.com/v1alpha1kind: MySQLDBmetadata: name: sample-db # this is not a name for MySQL database but just a Kubernetes object namespec: dbName: sample_db # this is MySQL database namemysqlName: mysql-sample
kubectl apply -k https://github.com/nakamasato/mysql-operator/config/samples-on-k8sCheck
MySQLUserandSecretfor the MySQL userkubectl get mysqluser NAME PHASE REASON sample-user Ready Both secret and mysql user are successfully created.kubectl get secret NAME TYPE DATA AGE mysql-mysql-sample-sample-user Opaque 1 10sConnect to MySQL with the secret
kubectl exec -it $(kubectl get po | grep mysql | head -1 | awk '{print $1}') -- mysql -usample-user -p$(kubectl get secret mysql-mysql-sample-nakamasato -o jsonpath='{.data.password}' | base64 --decode)Delete custom resources (
MySQL,MySQLUser,MySQLDB). Example:kubectl delete -k https://github.com/nakamasato/mysql-operator/config/samples-on-k8sNOTICE
custom resources might get stuck if MySQL is deleted before (to be improved). → Remove finalizers to forcifully delete the stuck objects:
kubectl patch mysqluser <resource_name> -p '{"metadata":{"finalizers": []}}' --type=mergekubectl patch mysql <resource_name> -p '{"metadata":{"finalizers": []}}' --type=mergekubectl patch mysqldb <resource_name> -p '{"metadata":{"finalizers": []}}' --type=merge(Optional) Delete MySQL
kubectl delete -k https://github.com/nakamasato/mysql-operator/config/mysqlUninstall
mysql-operatorkubectl delete -k https://github.com/nakamasato/mysql-operator/config/install
Instead of writing raw password in MySQL.Spec.AdminPassword, you can get the password for root user from an external secret manager (e.g. GCP) (ref: Authenticate to Google Cloud using a service account)
Create
SecretManagerecho -n "password" | gcloud secrets create mysql-password --data-file=- echo -n "root" | gcloud secrets create mysql-user --data-file=-Create a
Secretfor credentials json for service account withroles/secretm anager.secretAccessorpermissionkubectl create secret generic gcp-sa-private-key --from-file=sa-private-key.jsonInstall mysql-operator with
--set adminUserSecretType=gcp --set gcpProjectId=$PROJECT_IDhelm repo add nakamasato https://nakamasato.github.io/helm-charts helm repo update helm install mysql-operator nakamasato/mysql-operator --set adminUserSecretType=gcp --set gcpProjectId=$PROJECT_IDYou can specify
type: gcpforadminUserandadminPassword.apiVersion: mysql.nakamasato.com/v1alpha1kind: MySQLmetadata: name: mysql-samplespec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint.adminUser: name: mysql-user # secret name in SecretManagertype: gcpadminPassword: name: mysql-password # secret name in SecretManagertype: gcp
Example: (you need to run
kubectl apply -k config/mysql)kubectl apply -k config/samples-on-k8s-with-gcp-secretmanager
Read credentials from GCP SecretManager
Instead of writing raw password in MySQL.Spec.AdminPassword, you can get the password for root user from an external secret manager (e.g. K8s)
Create Kubernetes Secret.
kubectl create secret generic mysql-user --from-literal=key=root kubectl create secret generic mysql-password --from-literal=key=passwordInstall mysql-operator with
--set adminUserSecretType=k8s --set adminUserSecretNamespace=defaulthelm repo add nakamasato https://nakamasato.github.io/helm-charts helm repo update helm install mysql-operator nakamasato/mysql-operator --set adminUserSecretType=k8s --set adminUserSecretNamespace=defaultYou can specify
type: k8sforadminUserandadminPassword.apiVersion: mysql.nakamasato.com/v1alpha1kind: MySQLmetadata: name: mysql-samplespec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint.adminUser: name: mysql-user # secret name in SecretManagertype: k8sadminPassword: name: mysql-password # secret name in SecretManagertype: k8s
Example: (you need to run
kubectl apply -k config/mysql)kubectl apply -k config/samples-on-k8s-with-k8s-secret
mysql_user_created_totalmysql_user_deleted_total