Kubernetes
Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications. Jolie microservices deployed inside a Docker container can be managed by Kubernetes as well. We are going to use what learnt in Docker section to deploy an easily-scalable application, with multiple containers running the same service behind a load balancer. To run the example a Kubernetes environment is needed, the easiest way to get it is to install Minikube.
Deploying "Hello" Jolie service in a container Docker
Let's make some modifications to helloservice.ol
used in the previous Docker example:
include "runtime.iol"
interface HelloInterface {
RequestResponse:
hello( string )( string )
}
execution{ concurrent }
inputPort Hello {
Location: "socket://localhost:8000"
Protocol: sodep
Interfaces: HelloInterface
}
init {
getenv@Runtime( "HOSTNAME" )( HOSTNAME )
}
main {
hello( request )( response ) {
response = HOSTNAME + ":" + request
}
}
The HOSTNAME environment variable is set by Kubernetes itself and it's printed out to show what microservice instance is answering the request.
Creating a docker image
The Dockerfile needed to create a docker image of this microservice is the same seen in the Docker section:
FROM jolielang/jolie
EXPOSE 8000
COPY helloservice.ol main.ol
CMD jolie main.ol
Typing the following command in the console actually creates the image:
docker build -t hello .
Creating a Kubernetes Deployment
This image can now be wrapped in Pods, the smallest deployable units of computing that can be created and managed in Kubernetes. A Deployment describes in a declarative way the desired state of a ReplicaSet having the purpose to maintain a stable set of replica Pods running at any given time:
apiVersion: apps/v1
kind: Deployment
metadata:
name: jolie-sample-deployment
labels:
app: jolie-sample
spec:
replicas: 2
selector:
matchLabels:
app: jolie-sample
template:
metadata:
labels:
app: jolie-sample
spec:
containers:
- name: jolie-k8s-sample
image: hello
ports:
- containerPort: 8000
imagePullPolicy: IfNotPresent
To create the Deployment save the text above in jolie-k8s-deployment.yml file and type this command:
kubectl apply -f jolie-k8s-deployment.yml
After a few seconds you can see your pods up and running using this command:
kubectl get pods
Exposing Deployment by a Service
Now we have 2 running Pods, each one listening on port 8000, but with 2 issues: 1. they're reachable only from the internal Kubernetes cluster network; 2. they're ephemeral. As explained here, a Service is needed to expose the application in the right way. Following the Minikube tutorial, just type:
kubectl expose deployment jolie-sample-deployment --type=LoadBalancer --port=8000
to create such Service. The result can be verified with this command:
kubectl get services
and the output should be something like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jolie-sample-deployment LoadBalancer 10.109.47.147 <pending> 8000:30095/TCP 13s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP
The last step is to make the Service visible from your host going through a "minikube service":
minikube service jolie-sample-deployment
|-----------|-------------------------|-------------|-----------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-------------|---------------------------|---------------|-------------------------------|
| default | jolie-sample-deployment | | http://<your_IP>:<ext_port> |
| ----------- | ------------------------- | ------------- | ----------------------------- |
Invoking microservices from client
Now we a stable access door to our application, and it can be invoked by a client:
include "console.iol"
interface HelloInterface {
RequestResponse:
hello( string )( string )
}
outputPort Hello {
Location: "socket://<your_IP>:<ext_port>"
Protocol: sodep
Interfaces: HelloInterface
}
main {
hello@Hello( "hello" )( response );
println@Console( response )()
}
Each time you make a request typing:
jolie client.ol
your local is hit and the LoadBalancer redirects the request to one of the 2 available Pods running the service. Printing out the HOSTNAME variable makes visible the load balancing, showing which Pod is serving the response:
$ jolie client.ol
jolie-sample-deployment-655f8b759d-mq8cn:hello
$ jolie client.ol
jolie-sample-deployment-655f8b759d-bmzk7:hello
$ jolie client.ol
jolie-sample-deployment-655f8b759d-mq8cn:hello
$ jolie client.ol
jolie-sample-deployment-655f8b759d-bmzk7:hello