Axon (Spring Boot) demo application - Deploy to Kubernetes via Docker Stack API and/or `kubectl` and `skaffold` - Scale out
This Axon demo project demonstrates two different deployment strategies:
command
(CQRS) and query
(CQRS) are activated within one application/service, the final result is one application/service running: axon-scale-demo
)command
or query
), the final result are two applications/services running: axon-scale-demo-command
and axon-scale-demo-command
)with two different versions:
Spring profiles are used to separate
command
fromquery
components in a simple way, for demo purposes. In real world scenarios you would split your code in more (maven) modules, or in more dedicated git repositories.
This scenario covers running of Spring Boot application/s directly on the host machine. There is no cluster, and only one instance of the application/service is running at the same time.
There are two deployment strategies:
You can download a ZIP file with AxonServer as a standalone JAR. This will also give you the AxonServer CLI and information on how to run and configure the server.
command
and query
Spring profiles are activated, grouping command and query components into one monolithic application.
You can run the following command to start monolithic version locally:
$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.profiles.active=command,query"
We use H2 SQL database. Web console is enabled, and it should be available on
/h2-console
URL (eg.http://localhost:8080/h2-console
). Datasource URL:jdbc:h2:mem:axon-scale-demo-command,query
Verify:
$ curl -i -X POST -H 'Content-Type:application/json' -d '{"value" : "1000"}' 'http://localhost:8080/commandcards'
$ curl http://localhost:8080/querycards
Axon Server dashboard is available here http://localhost:8024/
command
and query
services/applications are separately deployed. Each service activated appropriate Spring profile (command
or query
).
You can run the following commands to start microservices version locally:
$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.profiles.active=command -Dserver.port=8081"
$ ./mvnw spring-boot:run -Dspring-boot.run.jvmArguments="-Dspring.profiles.active=query -Dserver.port=8082"
Each application use its own H2 SQL database. H2 Web console of command application is enabled, and it should be available on
/h2-console
URL (eg.http://localhost:8081/h2-console
). Datasource URL:jdbc:h2:mem:axon-scale-demo-command
. H2 Web console of query application is enabled, and it should be available on/h2-console
URL (eg.http://localhost:8082/h2-console
). Datasource URL:jdbc:h2:mem:axon-scale-demo-query
.
Verify:
$ curl -i -X POST -H 'Content-Type:application/json' -d '{"value" : "1000"}' 'http://localhost:8081/commandcards'
$ curl http://localhost:8082/querycards
Axon Server dashboard is available here http://localhost:8024/
This scenario covers deployment of our containerized (Docker) applications/services to the Kubernetes cluster, so we can scale services better.
There are two deployment strategies:
Build the application image with Jib directly to a Docker daemon. ‘Jib’ uses the docker
command line tool and requires that you have docker available on your PATH.
$ ./mvnw compile jib:dockerBuild -Dimage=axon-scale-demo
‘Jib’ separates your application into multiple layers, splitting dependencies from classes. Now you don’t have to wait for Docker to rebuild your entire Java application - just deploy the layers that changed.
You typically use docker-compose for local development because it can build and works only on a single docker engine. Docker stack and docker service commands require a Docker Swarm (configured by defaut)
or Kubernetes cluster
, and they are step towards production.
Docker Desktop comes with Kubernetes and the Compose controller built-in, and enabling it is as simple as ticking a box in the settings.
Now, we can use Docker Compose file and native Docker API for stacks
to manage applications/services on local Kubernetes cluster.
command
and query
Spring profiles are activated, grouping command and query components into one monolithic application.
$ docker stack deploy --orchestrator=kubernetes -c .docker/docker-compose.monolith.yml axon-scale-demo-stack
When you scale an application, you increase or decrease the number of replicas (we set 2). Each replica of your application represents a Kubernetes Pod that encapsulates your application’s container(s).
services:
axon-scale-demo:
image: axon-scale-demo
environment:
- SPRING_PROFILES_ACTIVE=command,query
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-db:5432/axon-scale-demo
- SPRING_DATASOURCE_USERNAME=demouser
- SPRING_DATASOURCE_PASSWORD=thepassword
- SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.PostgreSQLDialect
- AXON_AXONSERVER_SERVERS=axon-server
ports:
- 8080:8080
deploy:
replicas: 2
Verify
$ curl -i -X POST -H 'Content-Type:application/json' -d '{"value" : "1000"}' 'http://localhost:8080/commandcards'
$ curl http://localhost:8080/querycards
Axon Server dashboard is available here http://localhost:8024/
command
and query
services/applications are separately deployed. Each service is activating appropriate Spring profile (command
or query
).
$ docker stack deploy --orchestrator=kubernetes -c .docker/docker-compose.microservices.yml axon-scale-demo-stack
When you scale an application, you increase or decrease the number of replicas (we set 2). Each replica of your application represents a Kubernetes Pod that encapsulates your application’s container(s).
services:
axon-scale-demo-command:
image: axon-scale-demo
environment:
- SPRING_PROFILES_ACTIVE=command
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-db-command:5432/axon-scale-demo-command
- SPRING_DATASOURCE_USERNAME=demouser
- SPRING_DATASOURCE_PASSWORD=thepassword
- SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.PostgreSQLDialect
- AXON_AXONSERVER_SERVERS=axon-server
- SERVER_PORT=8081
ports:
- 8081:8081
deploy:
replicas: 2
axon-scale-demo-query:
image: axon-scale-demo
environment:
- SPRING_PROFILES_ACTIVE=query
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-db-query:5432/axon-scale-demo-query
- SPRING_DATASOURCE_USERNAME=demouser
- SPRING_DATASOURCE_PASSWORD=thepassword
- SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.PostgreSQLDialect
- AXON_AXONSERVER_SERVERS=axon-server
- SERVER_PORT=8082
ports:
- 8082:8082
deploy:
replicas: 2
Verify
$ curl -i -X POST -H 'Content-Type:application/json' -d '{"value" : "1000"}' 'http://localhost:8081/commandcards'
$ curl http://localhost:8082/querycards
Axon Server dashboard is available here http://localhost:8024/
Feel free to use kubectl
CLI to explore your Kubernetes cluster:
$ kubectl get all
There are several different types of volumes that are handled by Compose for Kubernetes.
The following Compose snippet declares a service that uses a persistent volume:
services:
axon-server:
image: axoniq/axonserver
hostname: axon-server
environment:
- AXONSERVER_EVENTSTORE=/eventstore
- AXONSERVER_CONTROLDB=/controldb
volumes:
- axonserver-eventstore:/eventstore
- axonserver-controldb:/controldb
ports:
- '8024:8024'
- '8124:8124'
volumes:
axonserver-eventstore:
axonserver-controldb:
A persistentVolumeClaim volume is used to mount a PersistentVolume into a Pod. PersistentVolumes are a way for users to “claim” durable storage (such as a GCE PersistentDisk or an iSCSI volume) without knowing the details of the particular cloud environment.
This demo is focusing on scaling axon (spring boot) application/s itself. Infrastructure components like AxonServer and Postgres are not in the focus. Nevertheless it is fair to say that the data that this components collect is saved in a durable way via
PersistentVolume
s keeping us closer to Production.
$ docker stack rm --orchestrator=kubernetes axon-scale-demo-stack
kubectl
and skaffold
Skaffold is a command line tool that facilitates continuous development for Kubernetes applications.
skaffold
Use skaffold dev
to build and deploy your app every time your code changes:
$ skaffold dev
Use skaffold run
to build and deploy your app once, similar to a CI/CD pipeline:
$ skaffold run
skaffold
Use skaffold dev
to build and deploy your apps every time your code changes:
$ skaffold dev -p microservices
Use skaffold run
to build and deploy your apps once, similar to a CI/CD pipeline:
$ skaffold run -p microservices
The skaffold debug
command runs your application with a continuous build and deploy loop, and forwards any required debugging ports to your local machine.
This allows Skaffold to automatically attach a debugger to your running application.
Skaffold also takes care of any configuration changes dynamically, giving you a simple yet powerful tool for developing Kubernetes-native applications. ‘Skaffold debug’ powers the debugging features in Cloud Code for IntelliJ and Cloud Code for Visual Studio Code.
If you don’t like
skaffold
, you can usekubectl
directly. Please follow the instructions here.
This project comes with some rudimentary tests as a good starting point for writing your own. Use the following command to execute the tests using Maven:
$ ./mvnw test
Created with :heart: by Ivan Dugalic