Run a service locally
Running a service locally is helpful to test and debug. The following sections provide commands for starting and stopping a single service locally.
Prerequisites
In order to run your service locally, you’ll need to have the following prerequisites:
-
Docker 20.10.14 or higher
-
Access to the
gcr.io/kalix-public
container registry. This is a public container registry that provides a Kalix Proxy container suited for local development. Make sure this registry is not blocked by your firewall.
The samples provided with the Kalix SDKs all have |
Starting your service
To start your service locally, run the following command from the root of your project:
mvn kalix:runAll
This command will start your Kalix service and a Kalix Proxy using the included docker-compose.yml
file.
If you prefer, you can instead start docker-compose
manually by running docker-compose up
in one terminal and in another terminal start your Kalix service with:
mvn kalix:run
Invoking your service
After you start the service it will accept invocations on localhost:9000
. You can use cURL to invoke your service.
As an example, we will use the customer-registry
sample.
Using cURL
Create a customer:
- Linux or macOS
-
curl localhost:9000/customer/one/create \ --header "Content-Type: application/json" \ -XPOST \ --data '{"email":"test@example.com","name":"Test","address":{"street":"Test street 25","city":"Test City"}}'
- Windows 10+
-
curl localhost:9000/customer/one/create ^ --header "Content-Type: application/json" ^ -XPOST ^ --data '{"email":"test@example.com","name":"Test","address":{"street":"Test street 25","city":"Test City"}}'
Retrieve an existing customer:
curl -XGET localhost:9000/customer/one
Shut down the service
Use Ctrl+C
to shut down the service. When stopping your service, it will also shutdown the Kalix Proxy container and any other container you have defined in docker-compose.yml
. Unless you have chosen to start docker-compose
manually in a separate terminal, in which case you will need to stop it manually as well.
Running multiple services locally
A typical Kalix application is composed of one or more services deployed to the same Kalix project. When deployed under the same Kalix project, two different services can make calls to each other or subscribe to each other’s event streams by simply using their logical names.
The same can be done on your local machine by configuring the services to run on different ports and by configuring them to "discover" each other using some extra configurations.
In this section, we will show you how to configure your local development environment to run two services and have them call each other.
For that we will use two of our existing samples: customer-registry
and customer-registry-subscriber
.
The customer-registry sample provides a service to register customers and the customer-registry-subscriber subscribes to an event stream produced by the customer-registry service, building a View from it.
Customer Registry Sample
The docker-compose.yml
file from customer-registry is left untouched and use the usual default ports. The user function will run on port 8080 and the Kalix Proxy on port 9000.
version: "3"
services:
kalix-proxy:
image: gcr.io/kalix-public/kalix-proxy:1.1.18
ports:
- "9000:9000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
JAVA_TOOL_OPTIONS: >
-Dconfig.resource=dev-mode.conf
-Dlogback.configurationFile=logback-dev-mode.xml
USER_FUNCTION_HOST: ${USER_FUNCTION_HOST:-host.docker.internal}
USER_FUNCTION_PORT: ${USER_FUNCTION_PORT:-8080}
Customer Registry Subscriber Sample
On the other hand, in the customer-registry-subscriber we will use port 8081 and 9001 respectively to avoid port conflicts with the customer-registry service.
Moreover, since customer-registry-subscriber needs to subscribe to customer-registry and since we will be running it on our local machine, we need to show it where to find the customer-registry service.
This is done by passing an extra property (kalix.dev-mode.service-port-mappings.customer-registry
) to its Kalix Proxy to let it create a mapping between the logical name customer-registry and the host and port where the customer-registry service is running.
Note that you need to add service port mappings to the Kalix Proxy configuration for the service that depends on the other service. Here, customer-registry-subscriber depends on customer-registry, therefore we add the service port mapping to the Kalix Proxy associated with the customer-registry-subscriber.
version: "3"
services:
kalix-proxy:
image: gcr.io/kalix-public/kalix-proxy:1.1.18
ports:
- "9001:9000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
JAVA_TOOL_OPTIONS: >
-Dconfig.resource=dev-mode.conf
-Dlogback.configurationFile=logback-dev-mode.xml
-Dkalix.dev-mode.service-port-mappings.customer-registry=host.docker.internal:9000
USER_FUNCTION_HOST: ${USER_FUNCTION_HOST:-host.docker.internal}
USER_FUNCTION_PORT: "8081"
With both services configured, we can start them independently by running mvn kalix:runAll
in two separate terminals.
From a third terminal, we can create a customer on customer-registry service.
- Linux or macOS
-
curl localhost:9000/customer/one/create \ --header "Content-Type: application/json" \ -XPOST \ --data '{"email":"test@example.com","name":"Test","address":{"street":"Test street 25","city":"Test City"}}'
- Windows 10+
-
curl localhost:9000/customer/one/create ^ --header "Content-Type: application/json" ^ -XPOST ^ --data '{"email":"test@example.com","name":"Test","address":{"street":"Test street 25","city":"Test City"}}'
While watching the logs in customer-registry-subscriber service, we will see it receiving the customer created event. After that we can query its View.
curl localhost:9001/customers/by_name/Test
Running other services with Docker
In the previous example, we run two services independently with mvn kalix:runAll
. Each time, the service is started together with a Kalix Proxy running in a Docker container.
An alternative is to build a larger docker-compose
file containing dependent services. In the case of customer-registry-subscriber, we can have a second docker-compose
file containing a Kalix Proxy for customer-registry-subscriber, a Kalix Proxy for customer-registry and the customer-registry itself.
At the root of the customer-registry-subscriber service, we can find an alternative docker-compose
file called docker-compose-integration.yml
.
version: "3"
services:
kalix-proxy:
image: gcr.io/kalix-public/kalix-proxy:1.1.18
depends_on:
- kalix-proxy-customer-registry
ports:
- "9001:9000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
JAVA_TOOL_OPTIONS: >
-Dconfig.resource=dev-mode.conf
-Dlogback.configurationFile=logback-dev-mode.xml
-Dkalix.dev-mode.service-port-mappings.customer-registry=host.docker.internal:9000
USER_FUNCTION_HOST: ${USER_FUNCTION_HOST:-host.docker.internal}
USER_FUNCTION_PORT: "8081"
kalix-proxy-customer-registry:
image: gcr.io/kalix-public/kalix-proxy:1.1.18
ports:
- "9000:9000"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
JAVA_TOOL_OPTIONS: >
-Dconfig.resource=dev-mode.conf
-Dlogback.configurationFile=logback-dev-mode.xml
USER_FUNCTION_HOST: ${USER_FUNCTION_HOST:-host.docker.internal}
USER_FUNCTION_PORT: "8080"
customer-registry:
image: my-docker-repo/eventsourced-customer-registry:latest
ports:
- "8080:8080"
environment:
HOST: customer-registry
But first, we need to build an image for customer-registry. For local development, we don’t need to publish it to a remote container registry. It suffices to build it locally.
We can build the image by calling the following command at the root of customer-registry:
mvn package docker:build
Next we can run customer-registry-subscriber and instead pass docker-compose-integration.yml
to it.
Run the following command at the root of customer-registry-subscriber:
mvn -Dkalix.dev-mode.docker-compose-file=docker-compose-integration.yml kalix:runAll
This time, kalix:runAll
will start docker-compose-integration.yml
instead. The customer-registry service and its companion Kalix Proxy will run alongside customer-registry-subscriber and its own Kalix Proxy.
Note that the configuration is exactly the same except that now we are running one single mvn kalix:runAll
command and the docker-compose
file we are using contains all the dependencies required by customer-registry-subscriber.
This approach can be extended to any service you might want to integrate with. It can be any other Kalix service that you plan to deploy to the same Kalix project or even external services. The only requirement is to have a Docker image for it.