Skip to content

feature: move mysql operator to this repo #737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions sample-operators/mysql-schema/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# MySQL Schema Operator

This example shows how an operator can control resources outside of the Kubernetes cluster. In this case it will be
managing MySQL schemas in an existing database server. This is a common scenario in many organizations where developers
need to create schemas for different applications and environments, but the database server itself is managed by a
different team. Using this operator a dev team can create a CR in their namespace and have a schema provisioned automatically.
Access to the MySQL server is configured in the configuration of the operator, so admin access is restricted.

This is an example input:
```yaml
apiVersion: "mysql.sample.javaoperatorsdk/v1"
kind: MySQLSchema
metadata:
name: mydb
spec:
encoding: utf8
```

Creating this custom resource will prompt the operator to create a schema named `mydb` in the MySQL server and update
the resource status with its URL. Once the resource is deleted, the operator will delete the schema. Obviously don't
use it as is with real databases.

### Try

To try how the operator works you will need the following:
* JDK installed (minimum version 11, tested with 11 and 15)
* Maven installed (tested with 3.6.3)
* A working Kubernetes cluster (tested with v1.15.9-gke.24)
* kubectl installed (tested with v1.15.5)
* Docker installed (tested with 19.03.8)
* Container image registry

How to configure all the above depends heavily on where your Kubernetes cluster is hosted.
If you use [minikube](https://minikube.sigs.k8s.io/docs/) you will need to configure kubectl and docker differently
than if you'd use [GKE](https://cloud.google.com/kubernetes-engine/). You will have to read the documentation of your
Kubernetes provider to figure this out.

Once you have the basics you can build and deploy the operator.

### Build & Deploy

1. We will be building the Docker image from the source code using Maven, so we have to configure the Docker registry
where the image should be pushed. Do this in mysql-schema/pom.xml. In the example below I'm setting it to
the [Container Registry](https://cloud.google.com/container-registry/) in Google Cloud Europe.

```xml
<to>
<image>eu.gcr.io/my-gcp-project/mysql-operator</image>
</to>
```

1. The following Maven command will build the JAR file, package it as a Docker image and push it to the registry.

`mvn jib:dockerBuild`

1. Deploy the test MySQL on your cluster if you want to use it. Note that if you have an already running MySQL server
you want to use, you can skip this step, but you will have to configure the operator to use that server.

`kubectl apply -f k8s/mysql-db.yaml`
1. Deploy the CRD:

`kubectl apply -f k8s/crd.yaml`

1. Make a copy of `k8s/operator.yaml` and replace ${DOCKER_REGISTRY} and ${OPERATOR_VERSION} to the
right values. You will want to set `OPERATOR_VERSION` to the one used for building the Docker image. `DOCKER_REGISTRY` should
be the same as you set the docker-registry property in your `pom.xml`.
If you look at the environment variables you will notice this is where the access to the MySQL server is configured.
The default values assume the server is running in another Kubernetes namespace (called `mysql`), uses the `root` user
with a not very secure password. In case you want to use a different MySQL server, this is where you configure it.

1. Run `kubectl apply -f copy-of-operator.yaml` to deploy the operator. You can wait for the deployment to succeed using
this command: `kubectl rollout status deployment mysql-schema-operator -w`. `-w` will cause kubectl to continuously monitor
the deployment until you stop it.

1. Now you are ready to create some databases! To create a database schema called `mydb` just apply the `k8s/schema.yaml`
file with kubectl: `kubectl apply -f k8s/schema.yaml`. You can modify the database name in the file to create more schemas.
25 changes: 25 additions & 0 deletions sample-operators/mysql-schema/k8s/mysql-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
# Use secret in real usage
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
10 changes: 10 additions & 0 deletions sample-operators/mysql-schema/k8s/mysql-service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
type: LoadBalancer
101 changes: 101 additions & 0 deletions sample-operators/mysql-schema/k8s/operator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
apiVersion: v1
kind: Namespace
metadata:
name: mysql-schema-operator
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-schema-operator
namespace: mysql-schema-operator
spec:
selector:
matchLabels:
app: mysql-schema-operator
replicas: 1 # we always run a single replica of the operator to avoid duplicate handling of events
strategy:
type: Recreate # during an upgrade the operator will shut down before the new version comes up to prevent two instances running at the same time
template:
metadata:
labels:
app: mysql-schema-operator
spec:
serviceAccountName: mysql-schema-operator # specify the ServiceAccount under which's RBAC persmissions the operator will be executed under
containers:
- name: operator
image: ${DOCKER_REGISTRY}/mysql-schema-operator:${OPERATOR_VERSION}
imagePullPolicy: Always
ports:
- containerPort: 80
env:
- name: MYSQL_HOST
value: mysql.mysql # assuming the MySQL server runs in a namespace called "mysql" on Kubernetes
- name: MYSQL_USER
value: root
- name: MYSQL_PASSWORD
value: password # sample-level security
readinessProbe:
httpGet:
path: /health # when this returns 200 the operator is considered up and running
port: 8080
initialDelaySeconds: 1
timeoutSeconds: 1
livenessProbe:
httpGet:
path: /health # when this endpoint doesn't return 200 the operator is considered broken and get's restarted
port: 8080
initialDelaySeconds: 30
timeoutSeconds: 1

---
apiVersion: v1
kind: ServiceAccount
metadata:
name: mysql-schema-operator
namespace: mysql-schema-operator

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: mysql-schema-operator
rules:
- apiGroups:
- mysql.sample.javaoperatorsdk
resources:
- schemas
verbs:
- "*"
- apiGroups:
- mysql.sample.javaoperatorsdk
resources:
- schemas/status
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- "get"
- "list"
- apiGroups:
- ""
resources:
- secrets
verbs:
- "*"

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: mysql-schema-operator
subjects:
- kind: ServiceAccount
name: mysql-schema-operator
namespace: mysql-schema-operator
roleRef:
kind: ClusterRole
name: mysql-schema-operator
apiGroup: ""
6 changes: 6 additions & 0 deletions sample-operators/mysql-schema/k8s/schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: "mysql.sample.javaoperatorsdk/v1"
kind: MySQLSchema
metadata:
name: mydb
spec:
encoding: utf8
96 changes: 96 additions & 0 deletions sample-operators/mysql-schema/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>sample-operators</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>

<artifactId>sample-mysql-schema-operator</artifactId>
<name>Operator SDK - Samples - MySQL Schema</name>
<description>Provisions Schemas in a MySQL database</description>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<jib-maven-plugin.version>3.1.4</jib-maven-plugin.version>
</properties>

<dependencies>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.takes</groupId>
<artifactId>takes</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>crd-generator-apt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>${jib-maven-plugin.version}</version>
<configuration>
<from>
<image>gcr.io/distroless/java:11</image>
</from>
<to>
<image>mysql-schema-operator</image>
</to>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.javaoperatorsdk.operator.sample;

import org.apache.commons.lang3.ObjectUtils;

public class MySQLDbConfig {

private final String host;
private final String port;
private final String user;
private final String password;

public MySQLDbConfig(String host, String port, String user, String password) {
this.host = host;
this.port = port != null ? port : "3306";
this.user = user;
this.password = password;
}

public static MySQLDbConfig loadFromEnvironmentVars() {
if (ObjectUtils.anyNull(System.getenv("MYSQL_HOST"),
System.getenv("MYSQL_USER"), System.getenv("MYSQL_PASSWORD"))) {
throw new IllegalStateException("Mysql server parameters not defined");
}
return new MySQLDbConfig(System.getenv("MYSQL_HOST"),
System.getenv("MYSQL_PORT"),
System.getenv("MYSQL_USER"),
System.getenv("MYSQL_PASSWORD"));
}

public String getHost() {
return host;
}

public String getPort() {
return port;
}

public String getUser() {
return user;
}

public String getPassword() {
return password;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.javaoperatorsdk.operator.sample;

import io.fabric8.kubernetes.api.model.Namespaced;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Version;

@Group("mysql.sample.javaoperatorsdk")
@Version("v1")
public class MySQLSchema extends CustomResource<SchemaSpec, SchemaStatus> implements Namespaced {
}
Loading