Install a local platform¶
A complete ankka platform runs on a laptop in a kind cluster. One script,
kustomization/deploy-local.sh in the ankka repository, builds the platform's images, loads them into
the cluster, installs everything the platform depends on and starts it. The result answers at
https://api.127.0.0.1.sslip.io:8443, over TLS, with no port-forward.
The local platform is the same platform a cloud cluster runs, with three local choices: images are loaded
into the node rather than pulled from a registry, certificates come from a certificate authority created
inside the cluster, and the base domain resolves to 127.0.0.1.
Inside the cluster, every name under the base domain resolves to the gateway instead, on the same port
as on your machine. A service can therefore call another at its public hostname, such as
https://cart-checkout.127.0.0.1.sslip.io:8443, and the call goes through the gateway with the same
routes and certificates a browser meets. The deploy script adds this to the cluster's DNS, CoreDNS, with
a stable ankka-gateway Service in envoy-gateway-system for the names to resolve to. A cloud
installation's domain resolves publicly to its load balancer and needs neither.
Prerequisites¶
- Docker, with enough memory for several JVMs; 8 GB for Docker is comfortable.
- kind 0.24 or later, and
kubectl. Earlier versions of kind do not enforce network policy, which the platform relies on. - A JDK 21 and sbt, because the script builds the platform's images from source.
- A checkout of the ankka repository. Every command on this page runs from its root.
- Optionally just, for the short forms of the commands.
Nothing more is needed for services built to WebAssembly modules. A wasm service's pod copies its module into a shared volume by running the service's own image as an init container, so it works on any container runtime kind ships; the runtime that loads the module is the platform's own image, which the script already builds.
Create the cluster¶
kind create cluster --name ankka --config kustomization/kind.yaml
The configuration file matters. It publishes the gateway's node ports on your machine, container port 30080 on host port 8080 and 30443 on 8443, and kind decides port mappings only when it creates a cluster: they cannot be added later. The deploy script checks for them and refuses a cluster created without them, naming the fix, because such a cluster would deploy cleanly and then fail every request by hostname.
Before it deploys anything, the script also proves the cluster enforces network policy: it starts two throwaway pods, puts a deny-all policy on one, and requires a connection to it to fail. On a cluster that stores the policy and ignores it, the script stops with:
refusing to deploy: this cluster accepted a NetworkPolicy and did not enforce it; ankka needs a
network that does (kind 0.24 or later does; see docs/platform/install-local.md).
On kind, a cluster that passed this probe before can fail it later: kind's network, kindnet, stops
enforcing new policies once its informers have died of API timeouts, which the load of a first install
can cause. The script restarts kindnet once and probes again before it refuses; by hand, that is
kubectl -n kube-system rollout restart daemonset/kindnet.
A first run also pulls every image the platform's databases, broker and identity provider need, so its waits are long, up to ten minutes for a database. If a wait still runs out, run the script again once the cluster has caught up: every step is idempotent.
Deploy the platform¶
./kustomization/deploy-local.sh
Or, with just, create the cluster if it is not there and deploy in one step:
just up
The script takes several minutes on its first run. In order, it:
- Checks where it is pointed. It refuses to run unless the current
kubectlcontext iskind-ankka, and unless that cluster publishes the gateway's ports. It never deploys to whatever context happens to be current. - Installs the controllers the platform builds on, each with server-side apply and waiting for each to be ready: CloudNativePG for Postgres, cert-manager for certificates, Envoy Gateway for the gateway, and the Keycloak operator for the identity provider. Their custom resource definitions must exist before anything that uses them is applied.
- Builds the platform's images with
sbt docker:publishLocal: the operator, the control plane, the sidecar that hosts services in other languages, and the shopping cart sample. - Loads them into the cluster's node with
kind load docker-image. No registry is involved. - Applies the
AnkkaServicecustom resource definition, then the control plane's namespace. - Applies everything else with one
kubectl apply -kof the local overlay: the operator, the control plane with its own Postgres cluster and the schema that cluster is created with, the installation's gateway with a local certificate authority and a wildcard certificate, Keycloak with its database and theankkarealm's import, and the telemetry store every service exports its traces and metrics to, with an agent on the node that gathers what every pod printed. The store's image is about a gigabyte, pulled the first time. The overlay is the whole platform, so applying it any other way — by hand, or from a GitOps tool — installs the same thing. - Restarts the operator and the control plane so they run the images just loaded, even when nothing in their manifests changed.
- Waits for the control plane's database, the operator, the control plane's three instances, the gateway and its certificate, and Keycloak.
- Waits for the
ankkarealm to be imported into Keycloak, then creates a development userdevwith passworddevand theplatform-adminrole, and a clientankka-local-smokefor scripts on this machine. The user and the client are the only things the script adds beyond the overlay, and they exist only on a local cluster. - Exports the local certificate authority's root to
~/.ankka/local-ca.crt. - Checks the platform end to end: it obtains a token from the identity provider and lists organizations through the gateway, which exercises DNS, TLS, both routes, token verification and the control plane's database. Then it asks the telemetry store, through Grafana, for a trace from the control plane. A problem is printed as a warning naming the likely cause.
It ends by printing the control plane's address and the commands to use it.
Add the model server¶
The local installation runs no model server unless asked. To add one, deploy with the flag set:
ANKKA_LOCAL_MODELS=on ./kustomization/deploy-local.sh
just deploy-models # the same
The script then applies the local-models overlay, which is the local overlay with the models
component added, loads the keeper's image into the node, and waits for the model server to be ready. The
first run fetches every declared model, so it is as slow as the download. The component declares one
small model that runs on a laptop's processor; see
Models served by the installation for changing the declaration and naming a
model from a service. Adding the model server restarts every running service once, because each is given
the server's address.
Deploying again without the flag applies the local overlay, which has no model server. The model server's namespace and the models it fetched stay until the cluster is deleted.
Point the CLI at it¶
ankka config set url https://api.127.0.0.1.sslip.io:8443
ankka config set ca ~/.ankka/local-ca.crt
ankka login # user dev, password dev, in a browser
Nothing on your machine is asked to trust the local certificate authority. The CLI is told about it
with config set ca, and curl with --cacert. There is no option anywhere to skip certificate
verification.
Open the console¶
The console is at https://console.127.0.0.1.sslip.io:8443; sign in as dev
with password dev. A browser shows it only once it trusts the local certificate authority, which the
deploy script exported to ~/.ankka/local-ca.crt. On macOS, open that file in Keychain Access and mark it
trusted for SSL; remove it from the keychain when you tear the platform down.
Open the telemetry store¶
Every service's traces, metrics and logs are at https://grafana.127.0.0.1.sslip.io:8443, as admin
with password admin, in the same browser that trusts the local certificate authority. The control
plane's own traces are there before anything is deployed. The store keeps what it holds only until it
restarts. See Telemetry.
The identity provider¶
The identity provider's console is at https://auth.127.0.0.1.sslip.io:8443/admin/, as admin with
password admin. Those credentials are public and belong to the local platform only; a cloud
installation removes them. Add users there. See Identity and machine accounts.
From here, Deploy to a local platform deploys the sample.
Use another base domain¶
The base domain 127.0.0.1.sslip.io relies on a public DNS service that resolves any name ending in an
address to that address. If your resolver blocks it, add hosts-file entries and deploy with a matching
base domain:
echo '127.0.0.1 api.ankka.local auth.ankka.local cart-checkout.ankka.local' | sudo tee -a /etc/hosts
ANKKA_BASE_DOMAIN=ankka.local ./kustomization/deploy-local.sh
A hosts file has no wildcards, so every hostname you use, including auth.<base domain> for logins and
each exposed service, needs a line.
Run it again¶
The script is safe to run again, and running it again is how the platform picks up a change to its
source: it rebuilds and reloads the images and restarts the operator and the control plane onto them.
Without that restart a re-run would change nothing running, because the manifests and the latest tags
are the same as before and Kubernetes sees no difference.
Some things are created once and not updated by a re-run. The Keycloak realm is imported only if it does not exist, so a change to the realm file on an existing cluster is made in Keycloak's console.
Tear it down¶
just down # delete the kind cluster and stop the local compose services
kind delete cluster --name ankka # the same, without just
Deleting the cluster deletes every service and every database in it.
The shortcuts¶
| Command | Does |
|---|---|
just up |
create the cluster if it does not exist, then deploy |
just deploy |
run deploy-local.sh |
just deploy-models |
run deploy-local.sh with the model server added |
just cluster-create |
create the cluster from kustomization/kind.yaml |
just cluster-status |
whether the cluster exists and what platform pods are running |
just down |
delete the cluster and stop the local compose services |
just render |
print the local overlay's manifests without applying them |
Each is one command, or a call to the script, which holds the guards. Everything works without just
installed.