An API written in Ballerina and deployed to Kubernetes that returns website rankings
- Check your environment
- Install Minikube
- Create a Kubernetes cluster
- Setup a Docker Client
- Install, run and test Kubectl
- Run Ballerina and deploy to minikube
The setup described here used a standard laptop with 8GB of RAM running
Microsoft Windows [Version 10.0.18362.357]
Hyper-V should be enabled and we need to add a Virtual Switch using the Hyper-V Manager. My switch was named minikube. There was an issue with IPV6 addressing (race condition or something like that) I disabled ipv6 and started over. When using CLI tools I prefer bash and have Windows Subsystem for Linux (WSL) setup wit 18.04 LTS (Bionic)
Initially minikube was installed on WSL but then I realised that this won't work
# systemctl status docker
Because WSL does not have systemd. It tells you it can't operate. So following this tutorial I installed minikube on Windows. And then I ran straight into:
>minikube start --vm-driver=none
* minikube v1.5.0 on Microsoft Windows 10 Enterprise 10.0.18362 Build 18362
X The driver 'none' is not supported on windows
Ah well. Here is a summary of what I found out about where to run minikube with what driver.
WSL Ubuntu | Windows | Ubuntu | |
---|---|---|---|
VM | no | yes | yes |
Native | no | no | yes |
But then anyway it turned out that minikube on Windows was necessary aaaanyway. Because when Docker Desktop and minikube are running simultaneously Windows ran out of RAM. To side-step this I used the docker daemon that runs inside minikube and stopped Docker Desktop.
In this design, I also like the separation between WSL and Windows. It means that when I come to actually deploy to a cloud, I only need to reconfigure the clients on WSL. Windows is acting like a fake cloud :)
Run the windows cmd as Administrator and run the following.
>minikube start --vm-driver hyperv --hyperv-virtual-switch minikube
Check what just happened by asking for the IP address.
>minikube ip
192.168.1.67
Although we're not going to run a docker daemon on WSL we need a client so Ballerina can prepare the image.
# sudo apt install docker.io
$ docker --version
Docker version 18.09.7, build 2d0083d
Now back in Windows I grab the values for the environment vars.
>minikube docker-env
The vars are used to create the following entries in .bashrc on WSL.
export DOCKER_HOST="tcp://192.168.1.67:2376"
export DOCKER_TLS_VERIFY=0
export DOCKER_CERT_PATH="/c/Users/gavin/.minikube/certs"
A couple of changes that were made. The DOCKER_TLS_VERIFY is turned off as we are working on a private network. Also note that the path has no /mnt/. This is because in /etc/wsl.conf I have set the root as /.
To check if the client is talking nicely to the daemon try this from WSL.
$ docker info
This will return a lot of output, check for the line Name: minikube. See set up docker for wsl for more.
Kubectl will communicate with the Kubernetes cluster that was created using minikube. Kubectl version v1.16.2 was set up in WSL.
curl -LO "https://storage.googleapis.com/kubernetes-release/release/$ver/bin/linux/amd64/kubectl"
mv kubectl /usr/local/bin
Now to confgure the client I did the same as docker and used the windows config.
>kubectl config view
These values were used in this bash script
#!/bin/bash -x
minikubeip='192.168.1.67:8443'
winuser='gavin'
kubectl config set-cluster minikube \
--server="https://$minikubeip" \
--certificate-authority="/c/Users/$winuser/.minikube/ca.crt" \
kubectl config set-credentials minikube \
--client-certificate="/c/Users/$winuser/.minikube/client.crt" \
--client-key="/c/Users/$winuser/.minikube/client.key" \
kubectl config set-context minikube --cluster=minikube --user=minikube
This is the output of running the shell script.
+ minikubeip=192.168.1.67:8443
+ winuser=gavin
+ kubectl config set-cluster minikube --server=https://192.168.1.67:8443 --certificate-authority=/c/Users/gavin/.minikube/ca.crt
Cluster "minikube" set.
+ kubectl config set-credentials minikube --client-certificate=/c/Users/gavin/.minikube/cert.crt --client-key=/c/Users/gavin/.minikube/client.key
User "minikube" set.
+ kubectl config set-context minikube --cluster=minikube --user=minikube
Context "minikube" created.
Now that we have switch our kubectl to use the minikube context let's test it.
$ kubectl cluster-info
Kubernetes master is running at https://192.168.1.67:8443
Almost there! I learnt most of this from minkube on win with wsl
Using ballerina I defined a Rankings API to deploy to my new cluster. This is a simple test service based on data sourced from Alexa.
The following shows how the artifacts built by ballerina were applied to minikube and tested. First I tested the container that Ballerina built.
$ docker run -d -p 9090:9090 snow6oy/fnarg:rankingsApiBal
Now the container is running, check the service
$ curl http://localhost:9090/rankings/status
ok
Looks good, so let's publish to the cluster.
$ kubectl apply -f /home/gavin/fnarg/target/kubernetes/rankingsApiBal
service/rankings-svc created
ingress.extensions/rankings-ingress created
secret/rankings-secure-socket created
deployment.apps/rankingsapibal-deployment created
And to see what just happened
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 81m
rankings-svc NodePort 10.104.84.120 <none> 9090:30191/TCP 44s
Using the minikube IP and the NodePort I can run an HTTP query.
$ curl https://192.168.1.67:30191/rankings/?query=goo -k
[{
"rank": "1",
"domain": "google.com"
}, {
"rank": "7",
"domain": "google.co.in"
}]
Hooray!