Deploy a https REST service on Kubernetes in 5 minutes with Ballerina

Ballerina is a new programming language with built in support for docker and kubernetes. In this article we will be deploying a REST service in a kubernetes cluster.

Pre-requisites:

  1. Install a recent version of Docker for Mac/Windows and enable Kubernetes OR Minikube is installed and running.
  2. Nginx backend and controller deployed (Optional).
  3. Ballerina Platfrom installed.
  4. If you you are running on windows, please ensure you have switched to linux containers and enable remote access to the API.

We will be deploying a simple ballerina hello-world service in kubernetes. Copy and paste the following code in file named hello.bal.

import ballerina/http;
endpoint http:Listener helloEP {
port:9090,
secureSocket:{
keyStore:{
path:"${ballerina.home}/bre/security/ballerinaKeystore.p12",
password:"ballerina"
}
}};


@http:ServiceConfig {
basePath:"/helloWorld"
}
service<http:Service> helloWorld bind helloEP {
sayHello(endpoint outboundEP, http:Request request) {
http:Response response = new;
response.setTextPayload("Hello, World from service helloWorld ! \n");
_ = outboundEP->respond(response);
}
}

This is a simple ballerina program which creates a REST service. Let’s make sure the service is working by running following commands.

$ ballerina run hello.bal
ballerina: initiating service(s) in 'hello.bal'
ballerina: started HTTPS/WSS endpoint 0.0.0.0:9090

Now the ballerina service is up and running, let’s invoke the service with curl.

$ curl https://localhost:9090/HelloWorld/sayHello -k
Hello, World from service helloWorld !

Now lets deploy the same service in kubernetes. Stop the service and open hello.bal file in an editor.

Ballerina provides annotations to generate kubernetes artifacts. Let’s Import ballerinax/kubernetes package and add annotations to source.

import ballerina/http;
import ballerinax/kubernetes;
//Endpoint annotations
@kubernetes:Ingress {
hostname:"abc.com"
}
@kubernetes:Service {
name:"hello",
serviceType:"NodePort"
}

endpoint http:Listener helloEP {
port:9090,
secureSocket:{
keyStore:{
path:"${ballerina.home}/bre/security/ballerinaKeystore.p12",
password:"ballerina"
}
}};
//Service annotations
@kubernetes:Deployment {
enableLiveness:true
}

@http:ServiceConfig {
basePath:"/helloWorld"
}
service<http:Service> helloWorld bind helloEP {
sayHello(endpoint outboundEP, http:Request request) {
http:Response response = new;
response.setTextPayload("Hello, World from service helloWorld ! \n");
_ = outboundEP->respond(response);
}
}

We have added three kubernetes annotations to the service.

  1. @kubernetes:Deployment{} — This an optional annotation that allows users to modify deployment.yaml. We have enable liveness for deployment.
  2. @kubernetes:Service{} — This annotation allows to modify the kubernetes service yaml. We have given a name(“hello”) and changed service type as NodePort.
  3. @kubernetes:Ingress{} — This annotation generates a ingress resource for our service. We have exposed the service from “abc.com” hostname.

Check here for list of supported annotations: https://github.com/ballerinax/kubernetes#supported-annotations.

If you are using minikube please add following attributes to the @kubernetes:Deployment{} annotation. The dockerHost and dockerCertPath must be changed accordingly.

@kubernetes:Deployment {
dockerHost:"tcp://192.168.99.100:2376",
dockerCertPath:"/Users/anuruddha/.minikube/certs"
}

Let’s compile the ballerina file.

$ ballerina build hello.bal
@kubernetes:Service - complete 1/1
@kubernetes:Ingress - complete 1/1
@kubernetes:Secret - complete 1/1
@kubernetes:Docker - complete 3/3
@kubernetes:Deployment - complete 1/1
Run following command to deploy kubernetes artifacts:
kubectl apply -f /Users/anuruddha/workspace/ballerinax/kubernetes/samples/sample2/kubernetes/

The compiler generates kubernetes artifacts and docker image:

$ tree
├── hello_world_k8s.balx
└── kubernetes
├── docker
│ └── Dockerfile
├── hello_deployment.yaml
├── hello_ingress.yaml
├── hello_secret.yaml
└── hello_svc.yaml
$ docker images
hello latest 35dd9d2081da 17 minutes ago 132MB

Let’s go ahead and deploy the artifacts in kubernetes.

$ kubectl apply -f /Users/anuruddha/workspace/ballerinax/kubernetes/samples/sample2/kubernetes/
deployment "hello-deployment" created
ingress "helloep-ingress" created
secret "helloep-keystore" created
service "hello" created

Let’s verify everything is deployed.

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-deployment-77894bc54b-7mxnd 1/1 Running 0 18s

$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello NodePort 10.99.21.185 <none> 9090:31229/TCP 38s
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
helloep-ingress abc.com 80, 443 1m
$ kubectl get secrets
NAME TYPE DATA AGE
helloep-keystore Opaque 1 2m

That’s it !

Let’s access the service via nodeport :D (Note that the port 312291 should be changed according to kubectl get svc output.

$ curl https://localhost:31229/HelloWorld/sayHello -k
Hello, World from service helloWorld !

Let’s access the service via ingress ;)

This requires nginx ingress to be deployed.

First add /etc/hosts entry to match hostname. (127.0.0.1 is only applicable to docker for mac users. Other users should map the hostname with correct ip address from kubectl get ingresscommand.)

127.0.0.1 abc.com

Use curl command with hostname to access the service.

$ curl https://abc.com/HelloWorld/sayHello -k
Hello, World from service helloWorld !

Conclusion:

With ballerina it is just a matter of adding annotations to the service, to generate kubernetes artifacts. Ballerina is capable of generating kubernetes and docker artifacts without user having to worry about yaml or Dockerfile.

Refer the ballerinax/kuberenetes repo for more advanced samples.

Following k8s functionality are map to ballerina language

  1. K8s pod
  2. K8s deployment
  3. K8s service
  4. K8s ingress
  5. K8s horizontal pod autoscaling
  6. K8s secrets
  7. K8s config maps
  8. K8s persistent volume claims
  9. K8s liveness probe
  10. Docker image creation support
  11. Remote docker registry support
  12. Docker push support