
This week is KubeCon in Detroit, and in preparation for attending I have been polishing up my Kubernetes skills. This big rush to put software in containers and have Kubernetes run everything is getting a lot of push in the industry. Many software applications run perfectly well in ready-made packages from a container made for ephemeral consumption much like a can of Campell’s tomato soup. But generally, relational databases like permanence, stability, and a consistent presence. Databases like to run to stock caches and build statistics, so they are not great at running well after being started. But this article is the first in a series for ‘us’ database folks to learn how to keep our databases happy in a containerized world.
With the trip to the Motor City on my calendar, it was time to answer the question “What is the minimalist Kubernetes installation that I can use to run MySQL?”. I am sharing my steps hoping that others wondering similar questions will find this blog post helpful if not more palatable than a recent can of Campbell’s tomato soup. I pulled out my trusty test mule laptop and installed Ubuntu 22.04.1 LTS with updates. My plan was to run everything needed for a single MySQL instance on the laptop itself.
Googling Kubernetes offerings was exhausting as there are so many different options. Orchestrating Docker containers is what Kubernetes does and there are many choices, most of which are extremely complicated to set up. What was desired was a simple installation with the least number of “moving parts” to get working. I ended up using Minikube as it runs very well running a single-node Kubernetes cluster in a virtual machine on a laptop.
Installing Minikube
Minikube is a “local Kubernetes engine” so we need minimal preparation time and hardware. There are some prerequisite software packages needed when installing Minikube.
$ sudo apt install -y curl wget apt-transport-https
We will also need Docker for our container.
sudo apt-get install ca-certificates curl gnupg lsb-release $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg $ echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Then we can get the latest Minikube and kubectl binaries.
$ wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 $ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
Those binaries need to be given a good home and made executable.
$ sudo cp minikube-linux-amd64 /usr/local/bin/minikube $ sudo chmod +x /usr/local/bin/minikube $ sudo cp kubectl /usr/local/bin $ sudo chmod +x /usr/local/bin/kubectl
Now that the required software is in place, we start our cluster.
minikube start --driver=docker
So it looks like all the various components are functional. Now the containerized applications can be deployed.
Okay, now how do we get MySQL to run?
Putting MySQL into a container will seem a bit off for those used to the popular open source database. The first step is to create a file with the MySQL server’s root password. We create a simple password by sending a simple phrase through the base64 program.
echo -n 'hidave' | base64 aGlkYXZl
And we have to put that password into a file named mysql-secret.yaml
$ cat mysql-secret.yaml apiVersion: v1 kind: Secret metadata: name: mysql-pass type: Opaque data: password: aGlkYXZl
Double-check that the password you received out of base64 is the same as in your file. That yaml file is called a ‘manifest’ and it needs to be applied.
$ kubectl create -f mysql-secret.yaml secret/mysql-pass created $ kubectl get secrets NAME TYPE DATA AGE mysql-pass Opaque 1 97m
This creates the mysql-pass object. Now we need a manifest for the MySQL object that tells what is needed to run MySQL. Read through it to double-check paths, ports, and mount points.
apiVersion: v1 kind: Pod metadata: name: k8s-mysql labels: name: lbl-k8s-mysql spec: containers: - name: mysql image: mysql:latest env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-pass key: password ports: - name: mysql containerPort: 3306 protocol: TCP volumeMounts: - name: k8s-mysql-storage mountPath: /var/lib/mysql volumes: - name: k8s-mysql-storage emptyDir: {}
This manifest also needs to be applied.
$ kubectl create -f mysql-pod.yaml pod/k8s-mysql created $kubectl get pod NAME READY STATUS RESTARTS AGE k8s-mysql 1/1 Running 0 99m
At this point in time, we can bash shell to the MySQL container.
$ kubectl exec k8s-mysql -it -- bash bash-4.4# mysql --user=root --password=$MYSQL_ROOT_PASSWORD mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 8.0.31 MySQL Community Server - GPL Copyright (c) 2000, 2022, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
We will also need an object to allow other objects to reach MySQL.
Create a mysql-service.yaml with the following contents to make the k8s-mysql pod be reachable:
apiVersion: v1 kind: Service metadata: name: mysql-service labels: name: lbl-k8s-mysql spec: ports: - port: 3306 selector: name: lbl-k8s-mysql type: ClusterIP
And activate it too.
kubectl create -f mysql-service.yaml
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 443/TCP 127m mysql-service ClusterIP 10.100.110.78 3306/TCP 3m10s
At this point, we could add something like a WordPress website and continue (I do hope to build on this at a later date and do just that) to improve our Kubernetes cluster. But for now, we can look back at starting with nothing and building a small cluster using Minikube to support MySQL.
What I hope to do is build on this and discover how the various “tinker toys” communicate as well as how they are controlled. Then we can explore persistent data in a world of short-lived containers and how we can manage them.
For those who want to experiment more with this while I am in Detroit, I refer you to these two articles that I have borrowed liberally from and acknowledge them as great resources: