This is a short guide to walk you through how to deploy and run Akka Cluster based application on Google Cloud Platform.
Note: This guide is about how to deploy Akka application to Google Container Engine (GKE). If you are interested in deploying Akka application to Google Compute Engine (GCE) instead, read the following article.
Creating Google Container cluster:
Google provides an excellent documentation how to signup to their platform, create and manage Container Clusters. For the rest of this guide, you will need:
- Signup to Google Container Engine. Documentation is here.
- Create a cluster with 3 nodes (default configuration should suffice). Documentation is here.
- To get familiar with Google Container Registry. Documentation is here.
Compiling and packaging sample Akka application:
Background: Our sample application is inspired by akka-sample-cluster. It has backend nodes that calculate factorial upon receiving messages from frontend nodes.
- Clone sample application: from here.
Compile and package sample components:
Dockerizing Akka application:
sbt backend:assembly # backend sbt frontend:assembly # frontend
We have 3 Dockerfiles:
Dockerfile-javais a file for base Docker image that contains Java installation. To build it:
docker build -t java -f Dockerfile-java .
Dockerfile-backend is file with a Backend component image. To build it:
docker build -t akka-sample-cluster-backend -f Dockerfile-backend .
Dockerfile-frontend is file with a Front component image. To build it:
docker build -t akka-sample-cluster-frontend -f Dockerfile-frontend .
- Testing locally with Docker:
- Running 2 backend nodes:
docker run -d -it -e "AKKA_THIS_IP=192.168.99.100" -e "AKKA_SAMPLE_SEED_IP_1=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_1=2551" -e "AKKA_SAMPLE_SEED_IP_2=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_2=2552" -p "2551:2551" --name akka-sample-cluster-backend-1 akka-sample-cluster-backend java -jar akka-sample-backend.jar 2551 docker run -d -it -e "AKKA_THIS_IP=192.168.99.100" -e "AKKA_SAMPLE_SEED_IP_1=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_1=2551" -e "AKKA_SAMPLE_SEED_IP_2=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_2=2552" -p "2552:2552" --name akka-sample-cluster-backend-2 akka-sample-cluster-backend java -jar akka-sample-backend.jar 2552
- Running a frontend:
docker run -d -it -e "AKKA_THIS_IP=192.168.99.100" -e "AKKA_SAMPLE_SEED_IP_1=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_1=2551" -e "AKKA_SAMPLE_SEED_IP_2=192.168.99.100" -e "AKKA_SAMPLE_SEED_PORT_2=2552" --name akka-sample-frontend akka-sample-cluster-frontend java -jar akka-sample-frontend.jar
192.168.99.100with IP of your Docker machine (
Verifying it works: check out frontend logs (
docker logs -f <container-id>). You should see stream of following:
[INFO] [10/22/2016 19:04:39.132] [AkkaSampleCluster-akka.actor.default-dispatcher-19] [akka.tcp://AkkaSampleCluster@192.168.99.100:36900/user/factorialFrontend] 10! = 3628800 sender: akka.tcp://AkkaSampleCluster@192.168.99.100:2552/user/factorialBackend
Note: If you change the source, you will need to repackage and then rebuild relevant docker image.
Deploy to Google Container Engine:
- Pushing images to Google Container Engine. Documentation how to push can be found here.
Note: Don’t forget to do
gcloud init if you haven’t done yet.
docker tag akka-sample-cluster-backend gcr.io/
docker tag akka-sample-cluster-frontend gcr.io/
gcloud docker push gcr.io/
gcloud docker push gcr.io/
Background: with Akka Cluster every node should know IPs/hostnames and ports of cluster seed nodes. Containers in Google Container Engine have dynamic IPs making it impossible to manage a list of static IPs for seed nodes. Some possible solutions are to use etcd directly or via ConstructR that utilizes etcd as Akka extension. However, Kubernetes also have headless services. We are going to use it to expose all seed node IPs via DNS by having a headless service, which will be attached to each seed node through selector.
Headless service and Akka seed: In our case in Discovery-service.yaml we create a headless service named
None and attach selector
name: seed-node to it. It means that any pod created from deployment marked by this selector will run instance of
discovery-svc service as well. Each instance of this service will register its IP under
discovery-svc.default.svc.cluster.local DNS entry, where
default.svc.cluster.local is a default Kubernetes namespace. We use this feature for managing centralized list of seed node IPs. However, the way Akka seed works, all nodes also need to see the same first node in list of seed nodes. So we split all backend nodes into 2 groups: backend seed nodes (Backend-seed.yaml) and backend regular nodes (Backend-node.yaml). Backend seed nodes should always have fixed number of replicas in its deployment that equals to
constructr.dns.num-of-seeds (conf) and selector
seed-node. We also use ConstructR with our implementation of DnsCoordination that makes sure that any node can join only after the number of IPs registered in DNS equals to number of seed nodes. Once this number is reached, it always returns list of seed nodes sorted so all nodes see the same first node as required.
Deploy headleass service:
kubectl create -f Discovery-service.yaml
Note: In our case we mark all backend nodes as seed nodes, in real use case you need to mark only some of them as seed and have two different deployments.
Deploy a sampe application components:
- Backend seed:
kubectl create -f Backend-seed.yaml
kubectl create -f Backend-node.yaml
kubectl create -f Frontend.yaml
- Verifying it works:
Check out frontend logs (
kubectl logs -f <container-id>). You should see stream of following:
[INFO] [10/22/2016 20:07:43.055] [AkkaSampleCluster-akka.actor.default-dispatcher-16] [akka.tcp://AkkaSampleCluster@10.0.2.14:34018/user/factorialFrontend] 50! = 30414093201713378043612608166064768844377641568960512000000000000 sender: akka.tcp://AkkaSampleCluster@10.0.2.12:2551/user/factorialBackend
Note Yaml deployment files declare 2 backend nodes and 1 frontend node to be started right away. It should be sifficient to see expected results. In general, to scale up/down:
kubectl scale --replicas=<target-number> deployment/cluster-backend-seed kubectl scale --replicas=<target-number> deployment/cluster-frontend
kubectl options such as listing pods, deplyoments etc: Kubernetes cheatsheet.
This guide shows how deploy and run Akka Cluster application on Google Container Engine. While more steps should be taken to harden it for production use, it is a successful proof-of-concept that demonstrates Akka Cluster working on Google Container Engine.