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.21
- Custom Resource
MySQL
: MySQL cluster (host
,port
,adminUser
,adminPassword
hoding the credentials to connect to MySQL)MySQLUser
: MySQL user (mysqlName
andhost
)MySQLDB
: MySQL database (mysqlName
,dbName
,schemaMigrationFromGitHub
)
- Reconciler
MySQLReconciler
is responsible for managingMySQLClients
based onMySQL
andMySQLDB
resourcesMySQLUserReconciler
is responsible for creating/deleting MySQL users defined inMySQLUser
usingMySQLClients
, and creating Secret to store MySQL user's passwordMySQLDBReconciler
is responsible for creating/deleting database and schema migration defined inMySQLDB
usingMySQLClients
-
Install (Create CRD and operator objects) With kustomize:
kubectl apply -k https://github.com/nakamasato/mysql-operator/config/install
With 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/mysql
-
Apply custom resources (
MySQL
,MySQLUser
,MySQLDB
).mysql.yaml
credentials to connect to the MySQL:apiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQL metadata: name: mysql-sample spec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint. adminUser: name: root type: raw adminPassword: name: password type: raw
mysqluser.yaml
: MySQL userapiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQLUser metadata: name: sample-user spec: mysqlName: mysql-sample host: '%'
mysqldb.yaml
: MySQL databaseapiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQLDB metadata: name: sample-db # this is not a name for MySQL database but just a Kubernetes object name spec: dbName: sample_db # this is MySQL database name mysqlName: mysql-sample
kubectl apply -k https://github.com/nakamasato/mysql-operator/config/samples-on-k8s
-
Check
MySQLUser
andSecret
for 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 10s
-
Connect 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-k8s
NOTICE
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=merge
kubectl patch mysql <resource_name> -p '{"metadata":{"finalizers": []}}' --type=merge
kubectl patch mysqldb <resource_name> -p '{"metadata":{"finalizers": []}}' --type=merge
-
(Optional) Delete MySQL
kubectl delete -k https://github.com/nakamasato/mysql-operator/config/mysql
-
Uninstall
mysql-operator
kubectl 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
SecretManager
echo -n "password" | gcloud secrets create mysql-password --data-file=- echo -n "root" | gcloud secrets create mysql-user --data-file=-
-
Create a
Secret
for credentials json for service account withroles/secretm anager.secretAccessor
permissionkubectl create secret generic gcp-sa-private-key --from-file=sa-private-key.json
-
Install mysql-operator with
--set adminUserSecretType=gcp --set gcpProjectId=$PROJECT_ID
helm 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_ID
-
You can specify
type: gcp
foradminUser
andadminPassword
.apiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQL metadata: name: mysql-sample spec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint. adminUser: name: mysql-user # secret name in SecretManager type: gcp adminPassword: name: mysql-password # secret name in SecretManager type: 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=password
-
Install mysql-operator with
--set adminUserSecretType=k8s --set adminUserSecretNamespace=default
helm repo add nakamasato https://nakamasato.github.io/helm-charts helm repo update helm install mysql-operator nakamasato/mysql-operator --set adminUserSecretType=k8s --set adminUserSecretNamespace=default
-
You can specify
type: k8s
foradminUser
andadminPassword
.apiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQL metadata: name: mysql-sample spec: host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint. adminUser: name: mysql-user # secret name in SecretManager type: k8s adminPassword: name: mysql-password # secret name in SecretManager type: k8s
Example: (you need to run
kubectl apply -k config/mysql
)kubectl apply -k config/samples-on-k8s-with-k8s-secret
mysql_user_created_total
mysql_user_deleted_total