Skip to content

Commit d357dd3

Browse files
authored
Merge pull request #106 from ContainerSolutions/mysqlsample-improvements
Checking if schema exists before trying to delete or create. Fix README More generic deployment.yaml
2 parents 351a528 + e1530e9 commit d357dd3

File tree

7 files changed

+103
-78
lines changed

7 files changed

+103
-78
lines changed

samples/mysql-schema/README.md

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,77 @@
1-
# WebServer Operator
1+
# MySQL Schema Operator
22

3-
This is a more complex example of how a Custom Resource backed by an Operator can serve as
4-
an abstraction layer. This Operator will use an webserver resource, which mainly contains a
5-
static webpage definition and creates a nginx Deployment backed by a ConfigMap which holds
6-
the html.
3+
This example shows how an operator can control resources outside of the Kubernetes cluster. In this case it will be
4+
managing MySQL schemas in an existing database server. This is a common scenario in many organizations where developers
5+
need to create schemas for different applications and environments, but the database server itself is managed by a
6+
different team. Using this operator a dev team can create a CR in their namespace and have a schema provisioned automatically.
7+
Access to the MySQL server is configured in the configuration of the operator, so admin access is restricted.
78

89
This is an example input:
910
```yaml
10-
apiVersion: "sample.javaoperatorsdk/v1"
11-
kind: WebServer
11+
apiVersion: "mysql.sample.javaoperatorsdk/v1"
12+
kind: MySQLSchema
1213
metadata:
13-
name: mynginx-hello
14+
name: mydb
1415
spec:
15-
html: |
16-
<html>
17-
<head>
18-
<title>Webserver Operator</title>
19-
</head>
20-
<body>
21-
Hello World!!
22-
</body>
23-
</html>
16+
encoding: utf8
2417
```
2518
19+
Creating this custom resource will prompt the operator to create a schema named `mydb` in the MySQL server and update
20+
the resource status with its URL. Once the resource is deleted, the operator will delete the schema. Obviously don't
21+
use it as is with real databases.
22+
2623
### Try
2724

28-
The quickest way to try the operator is to run it on your local machine, while it connects to a local or remote
29-
Kubernetes cluster. When you start it it will use the current kubectl context on your machine to connect to the cluster.
25+
To try how the operator works you will need the following:
26+
* JDK installed (minimum version 8, tested with 1.8, 12, 13)
27+
* Maven installed (tested with 3.6.3)
28+
* A working Kubernetes cluster (tested with v1.15.9-gke.24)
29+
* kubectl installed (tested with v1.15.5)
30+
* Docker installed (tested with 19.03.8)
31+
* Container image registry
32+
How to configure all the above depends heavily on where your Kubernetes cluster is hosted.
33+
If you use [minikube](https://minikube.sigs.k8s.io/docs/) you will need to configure kubectl and docker differently
34+
than if you'd use [GKE](https://cloud.google.com/kubernetes-engine/). You will have to read the documentation of your
35+
Kubernetes provider to figure this out.
36+
37+
Once you have the basics you can build and deploy the operator.
3038

31-
Before you run it you have to install the CRD on your cluster by running `kubectl apply -f crd/crd.yaml`
39+
### Build & Deploy
40+
41+
1. We will be building the Docker image from the source code using Maven, so we have to configure the Docker registry
42+
where the image should be pushed. Do this in your ~/.m2/settings.xml. In the example below I'm setting it to
43+
the [Container Registry](https://cloud.google.com/container-registry/) in Google Cloud Europe.
44+
45+
```xml
46+
<properties>
47+
<docker-registry>eu.gcr.io/my-gcp-project</docker-registry>
48+
</properties>
49+
```
3250

33-
When the Operator is running you can create some Webserver Custom Resources. You can find a sample custom resource in
34-
`crd/webserver.yaml`. You can create it by running `kubectl apply -f webserver.yaml`
51+
1. The following Maven command will build the jar file, package it as a Docker image and push it to the registry.
3552

36-
After the Operator has picked up the new webserver resource (see the logs) it should create the nginx server in the
37-
same namespace where the webserver resource is created. To connect to the server using your browser you can
38-
run `kubectl get service` and view the service created by the Operator. It should have a NodePort configured. If you are
39-
running a single-node cluster (e.g. Docker for Mac or Minikube) you can connect to the VM on this port to access the
40-
page.
53+
`mvn package dockerfile:build dockerfile:push`
4154

42-
You can also try to change the html code in `crd/webserver.yaml` and do another `kubectl apply -f crd/webserver.yaml`.
43-
This should update the actual nginx deployment with new configuration.
55+
1. Deploy the test MySQL on your cluster if you want to use it. Note that if you have an already running MySQL server
56+
you want to use, you can skip this step, but you will have to configure the operator to use that server.
57+
58+
`kubectl apply -f k8s/mysql.yaml`
59+
1. Deploy the CRD:
4460

45-
### Build
61+
`kubectl apply -f k8s/crd.yaml`
62+
1. Set up RBAC:
4663

47-
You can build the sample using `mvn package dockerfile:build` this will produce a Docker image you can push to the registry
48-
of your choice. The jar file is built using your local Maven and JDK and then copied into the Docker image.
64+
`kubectl apply -f k8s/rbac.yaml`
65+
1. Make a copy of `k8s/deployment.yaml` and replace ${DOCKER_REGISTRY} and ${OPERATOR_VERSION} to the
66+
right values. You will want to set `OPERATOR_VERSION` to the one used for building the Docker image. `DOCKER_REGISTRY` should
67+
be the same as you set the docker-registry property in your `settings.xml`.
68+
If you look at the environment variables you will notice this is where the access to the MySQL server is configured.
69+
The default values assume the server is running in another Kubernetes namespace (called `mysql`), uses the `root` user
70+
with a not very secure password. In case you want to use a different MySQL server, this is where you configure it.
4971

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

52-
1. Deploy the CRD: kubectl apply -f crd/crd.yaml
53-
2. Deploy the operator: kubectl apply -f k8s/deployment.yaml
76+
1. Now you are ready to create some databases! To create a database schema called `mydb` just apply the `k8s/example.yaml`
77+
file with kubectl: `kubectl apply -f k8s/example.yaml`. You can modify the database name in the file to create more schemas.
File renamed without changes.

samples/mysql-schema/k8s/deployment.yaml

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ spec:
1313
matchLabels:
1414
app: mysql-schema-operator
1515
replicas: 1
16+
strategy:
17+
type: Recreate
1618
template:
1719
metadata:
1820
labels:
@@ -21,8 +23,8 @@ spec:
2123
serviceAccount: mysql-schema-operator
2224
containers:
2325
- name: operator
24-
image: mysql-schema-operator
25-
imagePullPolicy: Never
26+
image: ${DOCKER_REGISTRY}/mysql-schema-operator:${OPERATOR_VERSION}
27+
imagePullPolicy: Always
2628
ports:
2729
- containerPort: 80
2830
env:
@@ -43,42 +45,4 @@ spec:
4345
path: /health
4446
port: 8080
4547
initialDelaySeconds: 30
46-
timeoutSeconds: 1
47-
---
48-
apiVersion: rbac.authorization.k8s.io/v1beta1
49-
kind: ClusterRole
50-
metadata:
51-
name: mysql-schema-operator
52-
rules:
53-
- apiGroups:
54-
- mysql.sample.javaoperatorsdk
55-
resources:
56-
- schemas
57-
verbs:
58-
- "*"
59-
- apiGroups:
60-
- apiextensions.k8s.io
61-
resources:
62-
- customresourcedefinitions
63-
verbs:
64-
- "get"
65-
- "list"
66-
---
67-
apiVersion: v1
68-
kind: ServiceAccount
69-
metadata:
70-
name: mysql-schema-operator
71-
namespace: mysql-schema-operator
72-
---
73-
apiVersion: rbac.authorization.k8s.io/v1
74-
kind: ClusterRoleBinding
75-
metadata:
76-
name: operator-admin
77-
subjects:
78-
- kind: ServiceAccount
79-
name: mysql-schema-operator
80-
namespace: mysql-schema-operator
81-
roleRef:
82-
kind: ClusterRole
83-
name: mysql-schema-operator
84-
apiGroup: ""
48+
timeoutSeconds: 1

samples/mysql-schema/k8s/mysql.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ spec:
1313
- port: 3306
1414
selector:
1515
app: mysql
16-
type: NodePort
16+
type: LoadBalancer
1717
---
1818
apiVersion: apps/v1
1919
kind: Deployment

samples/mysql-schema/k8s/rbac.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
apiVersion: rbac.authorization.k8s.io/v1beta1
2+
kind: ClusterRole
3+
metadata:
4+
name: mysql-schema-operator
5+
rules:
6+
- apiGroups:
7+
- mysql.sample.javaoperatorsdk
8+
resources:
9+
- schemas
10+
verbs:
11+
- "*"
12+
- apiGroups:
13+
- apiextensions.k8s.io
14+
resources:
15+
- customresourcedefinitions
16+
verbs:
17+
- "get"
18+
- "list"
19+
---
20+
apiVersion: v1
21+
kind: ServiceAccount
22+
metadata:
23+
name: mysql-schema-operator
24+
namespace: mysql-schema-operator
25+
---
26+
apiVersion: rbac.authorization.k8s.io/v1
27+
kind: ClusterRoleBinding
28+
metadata:
29+
name: mysql-schema-operator
30+
subjects:
31+
- kind: ServiceAccount
32+
name: mysql-schema-operator
33+
namespace: mysql-schema-operator
34+
roleRef:
35+
kind: ClusterRole
36+
name: mysql-schema-operator
37+
apiGroup: ""

samples/mysql-schema/src/main/java/com/github/containersolutions/operator/sample/SchemaController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class SchemaController implements ResourceController<Schema> {
2424
@Override
2525
public Optional<Schema> createOrUpdateResource(Schema schema) {
2626
try (Connection connection = getConnection()) {
27-
if (schemaExists(connection, schema.getMetadata().getName())) {
27+
if (!schemaExists(connection, schema.getMetadata().getName())) {
2828
connection.createStatement().execute(format("CREATE SCHEMA `%1$s` DEFAULT CHARACTER SET %2$s",
2929
schema.getMetadata().getName(),
3030
schema.getSpec().getEncoding()));

0 commit comments

Comments
 (0)