Development Kubernetes Docker Cloud
(updated 2017-03-16)
I’ve been using different volume types for storage in my kubernetes-on-arm
cluster. I wrote two posts about it: GlusterFS On Kubernetes ARM and Storage for your cluster a year ago. All solutions adds complexity
to the cluster, the one that’s been easiest to handle is nfs. But nfs isn’t transparent enough. I always seems to end up in strange corner cases where it’s
not working as expected. The emptyDir volume type let’s you mount an empty
directory from the host in to your Pod. But when the Pod goes away, so does your
volume, leaving you with nothing.
There is now beta features in Kubernetes v1.5 for StatefulSet and
init-containers that got me started thinking. If one could use something
like Minio for storage in combination with emptyDir
volumes, maybe we could end up with a good enough solution that lowers the
technology stack.
The plan was to have an init-container running minio mc to mirror
in files from minio server using the mirror command to an
emptyDir volume in a pod defined by a StatefulSet. Once the pod is up
and running, file changes needs to be mirrored back to the minio server, so
that we don’t lose any data. The minio server is also a pod defined by a
StatefulSet but uses a nfs persistentVolume for storage.
The plan was to use the mc mirror --watch command for mirroring changes back
to the minio server, and that is probably the most suitable solution, but there
was a bug in the arm64 version so I
had to create a work around.
The work around is a simple script that for every # seconds checks for changes
and copies them using the mc cp command back to the server.
If you wan’t to try it out your self there’s multiarch images for arm, arm64
and amd64 and a mysql example at volumizr.
minio serverThe accessKey and secretKey is only for demo, you should create your own
config files using kubectl create secret generic and mount it to your container at
/app/config.json.
$ # the minio server expects a persistentVolume of at least 5Gi
$ kubectl create -f https://raw.githubusercontent.com/TheNatureOfSoftware/volumizr/master/minio.yml
service "minio" created
statefulset "minio" created
$
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
minio-0 1/1 Running 0 22s
Once the minio server is started you can access the ui using port-forward:
$ # port-forward to your minio server and create a store0 bucket
$ kubectl port-forward minio-0 9000:9000
Forwarding from 127.0.0.1:9000 -> 9000
Forwarding from [::1]:9000 -> 9000
Now you can login to minio server: http://localhost:9090 and create a bucket
named store0.
mysql example
$ kubectl create -f https://raw.githubusercontent.com/TheNatureOfSoftware/volumizr/master/example/mysql-example.yml
service "mysql" created
statefulset "mysql" created
$
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
minio-0 1/1 Running 0 3m
mysql-0 0/2 Init:0/2 0 8s
$ # you can see above, the two init containers has not yet run
$
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
minio-0 1/1 Running 0 4m
mysql-0 0/2 PodInitializing 0 28s
$ # here you can see the pod is initializing
$
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
minio-0 1/1 Running 0 4m
mysql-0 2/2 Running 0 49s
$ # and finally our mysql database is up and running
If you go back to your minio server: http://localhost:9090 and take
a look at the store0 bucket, you should see all mysql files mirrored back.
Here you can se that our mysql example has two init-containers.
They are executed in order and the first (setup) mirrors all files
to the persistentdata volume. The second container restores the file
ownership.
annotations:
pod.beta.kubernetes.io/init-containers:
'[{
"name": "volumizr-in",
"image": "thenatureofsoftware/volumizr:latest",
"args": ["in", "minio/mysql", "/var/lib/mysql"],
"volumeMounts": [{
"mountPath": "/var/lib/mysql",
"name": "persistentdata"
}]
},
{
"name": "chown",
"image": "tobi312/rpi-mysql:5.6",
"command": ["chown", "-R", "mysql:mysql", "/var/lib/mysql"],
"volumeMounts": [{
"mountPath": "/var/lib/mysql",
"name": "persistentdata"
}]
}]'
The last pice of the puzzle is the sidecar container to mysql that mirrors
changes back:
- image: thenatureofsoftware/volumizr:latest
imagePullPolicy: Always
name: volumizr-out
args:
- out
- /var/lib/mysql
- minio/mysql
volumeMounts:
- mountPath: "/var/lib/mysql"
name: persistentdata
The solution has it’s pros and cons. The pros are that it uses the nodes
local disk when using volume type emptyDir. Once the volume is setup then there
should be very few surprises. The problem is of course that you need to
mirror everything back and the size of the local disk.
16 Mar 2017 #Development #Docker #Kubernetes #Minio #Storage