Using Compound Promises
This is Part 3 of a series illustrating how Kratix works.
ππΎ Previous: Install a Kratix Promise
ππΎ Next: Part II
In this tutorial, you will:
What's a Compound Promise?β
Imagine that you want to provide your users with a simpler way to deploy their applications. You do your research and notice that most teams use a similar stack: PostgreSQL as database, Redis for caching, Grafana for monitoring, etc. You also find out that the majority of users don't care about a lot of the configuration options of those services, as long as they come with sane defaults.
However, not all teams are created equal. Some teams need specific versions of those services, configured with specific parameters, on specific regions and resources.
You want the platform to cater for both: it should be simple to get the simple services, and it should be possible to get the specialised ones. You decide to provide each of the individual services as a Promise. Specialist teams can then use the API to get the exact service they need.
To deliver the simpler experience though, you want to orchestrate those Promises in a higher-level Promise. In Kratix terms, this is a Compound Promise: a Promise that defines other Promises as its Dependencies.
In this tutorial, you will install and use a Compound Promise.
Installing a Compound Promiseβ
The Compound Promise you will install can be found on the Kratix repository,
under samples/easy-app
. This Compound Promise encapsulate the Nginx
and the Postgres Promises.
Compound Promises work by including, in their list of Dependencies, other Promises. Those Promises need to be scheduled to the platform cluster itself. That means you will need to include the platform cluster to the list of clusters where workloads can be scheduled to.
Validate the state of your platform clusterβ
Before jumping in, verify that Kratix is still up and running on your platform cluster:
kubectl --context $PLATFORM get pods --namespace kratix-platform-system
The above command will give an output similar to:
NAME READY STATUS RESTARTS AGE
kratix-platform-controller-manager-7cc49f598b-zqkmz 2/2 Running 0 4h4m
If the command above does not include a ready kratix-platform-controller-manager, please refer back to previous guides.
Install the Promiseβ
Since the EasyApp Promise declares two other Promises as its Dependencies, installing it will add a total of three Promises to the platform:
- The EasyApp Promise itself
- The EasyApp Promise dependencies: NGINX and PostgreSQL
From the Kratix directory, install the EasyApp Promise:
kubectl --context $PLATFORM apply --filename samples/easy-app/promise.yaml
Validate the EasyApp promises are successfully installed:
kubectl --context $PLATFORM get promises --watch
The above command will eventually include the following output:
easyapp Unavailable EasyApp example.promise.syntasso.io/v1
easyapp Unavailable EasyApp example.promise.syntasso.io/v1
easyapp Unavailable EasyApp example.promise.syntasso.io/v1
easyapp Available EasyApp example.promise.syntasso.io/v1
Once the EasyApp promise becomes "Available", you should see the sub-Promises getting automatically installed. If you haven't killed the watch command, you should see the following output appearing:
nginx-ingress
postgresql
nginx-ingress Unavailable deployment marketplace.kratix.io/v1alpha1
postgresql Unavailable postgresql marketplace.kratix.io/v1alpha1
...
nginx-ingress Available deployment marketplace.kratix.io/v1alpha1
postgresql Available postgresql marketplace.kratix.io/v1alpha1
Once all promises are "Available", press Ctrl+C to exit the watch mode.
The dependencies for the sub-Promises, on the other hands, are installed on the Worker destination. You can validate that by checking the deployments on the Worker:
kubectl --context $WORKER get deployments --watch
The above command will give an output similar to (it may take a few minutes for it to appear and to start):
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-nginx-ingress 1/1 1 1 1m
postgres-operator 1/1 1 1 1m
When the deployments eventually complete, press Ctrl+C to exit.
Understanding Destination Selectorsβ
You may be asking yourself: how did Kratix know it should install the sub-promises on the Platform cluster? And how did it know to install the NGINX and the PostgreSQL Promises dependencies on the Worker cluster?
The answer is: Destination Selectors.
Destination Selectors are a powerful feature in Kratix that allows Promises to specify where their dependencies and resources should be scheduled to. Similar to how Kubernetes uses labels to select resources, Kratix uses Destination Selectors to select Destinations.
You can verify the EasyApp Destination Selectors by describing the Promise:
kubectl --context $PLATFORM describe promise easyapp | tail -n 30 | \
grep "Destination Selectors" --after-context 2 --max-count 1
The above command will give an output similar to:
Destination Selectors:
Match Labels:
Environment: platform
This tells Kratix:
Only install the EasyApp Dependencies (i.e., the NGINX and the PostgreSQL Promises) in Destinations with the label environment=platform.
So, on the Platform Destination, you should have a label environment=platform
. Verify:
kubectl --context $PLATFORM get destination platform-cluster --show-labels
The above command will give an output similar to:
NAME AGE LABELS
platform-cluster 1h environment=platform
That explains why the NGINX and the PostgreSQL Promises were installed on the Platform cluster. But how did the dependencies of those Promises end up on the Worker cluster?
Once again, Destination Selectors are the answer. Check the destination selectors defined in the NGINX and the PostgreSQL Promises:
kubectl --context $PLATFORM describe promise nginx-ingress | grep "Destination Selectors:" -A 2 -m 1
kubectl --context $PLATFORM describe promise postgresql | grep "Destination Selectors:" -A 2 -m 1
The above command will give an output similar to:
Destination Selectors:
Match Labels:
Environment: dev
The NGINX and the PostgreSQL Promises are telling Kratix:
Only install my Dependencies (which include, the NGINX Ingress Controller and the PostgreSQL operator) in Destinations with the label environment=dev.
Similarly, if you check the Worker Destination, you should see the label
environment=dev
:
kubectl --context $PLATFORM get destination worker-cluster --show-labels
The above command will give an output similar to:
NAME AGE LABELS
worker-cluster 1h environment=dev
The entire installation process is summarised in the diagram below:
The mechanism described above is one of the most powerful features in Kratix: the ability platform teams have to fully control the scheduling of works across Destinations.
When a Destination is registered, Kratix will use the destination selectors to determine what should be immediately installed on the new Destination. When a Promise gets updated or upgraded, its Dependencies are seamlessly propagated across the fleet. If a Destination's labels change, Kratix will automatically converge on the expected system state.
If you are curious to learn more about Kratix scheduling, check the Multi-cluster Management docs.
Your Platform is now ready to deploy EasyApps!
Request an EasyAppβ
As a platform user, you now have a few choices of Promises. Verify the available Promises:
kubectl --context $PLATFORM get promises
The above command will give an output similar to:
NAME STATUS KIND API VERSION VERSION
easyapp Available EasyApp example.promise.syntasso.io/v1
nginx-ingress Available deployment marketplace.kratix.io/v1alpha1
postgresql Available postgresql marketplace.kratix.io/v1alpha1
You could request each one of those services individually if you needed fine-grained control of how they ought to be deployed, or you can use the EasyApp Promise to get an opinionated deployment of each of those. In this example, all you want is to run your application without much fuss.
Create a request for a new EasyApp Resource:
cat <<EOF | kubectl --context $PLATFORM apply --filename -
---
apiVersion: example.promise.syntasso.io/v1
kind: EasyApp
metadata:
name: example
namespace: default
spec:
name: todo
image: syntasso/sample-todo-app:v0.1.2
dbDriver: postgres
EOF
The above command will give an output similar to:
easyapp.example.promise.syntasso.io/example created
The EasyApp Promise will take that request and generate the necessary requests for the sub-Promises, wiring up the application to the Postgres service.
Verify the Workflows running on the platform cluster:
kubectl --context $PLATFORM get pods --watch
The above command will give an output similar to:
NAME READY STATUS RESTARTS AGE
kratix-easyapp-example-instance-configure-43a5e-x7sdg 0/1 Completed 0 45s
kratix-nginx-ingress-todo-instance-configure-0907d-8zs5m 0/1 Completed 0 13s
kratix-postgresql-todo-instance-configure-6b25f-chtj6 0/1 Completed 0 13s
Once the Status column reports Completed
for all three request pipelines,
press Ctrl+C to exit the watch mode. It may take a few
seconds for the Postgres and Nginx pipelines to start.
Similar to last time, Kratix will store the Pipeline outputs (i.e. the desired state) in the State Store for the worker cluster, and that will be picked up by the GitOps toolkit running on the worker.
Verify that the requested pods start on the worker cluster (it may take a few minutes):
kubectl --context $WORKER get pods --watch
The above command will give an output similar to:
NAME READY STATUS RESTARTS AGE
acid-todo-postgresql-0 1/1 Running 0 110s
nginx-nginx-ingress-58c4dcb47d-49fd8 1/1 Running 0 10m
postgres-operator-79754946d-nmkhr 1/1 Running 0 10m
todo-84f6b6698-vqxqm 1/1 Running 0 74s
It will take a couple of minutes for the Todo App to start, and it may cycle through a few states, including Error, before it eventually succeeds.
Once you see the todo
and the acid-todo-postgresql-0
pods reporting Ready 1/1
, press Ctrl+C to exit the watch mode.
The app is now fully deployed! You can now access it on http://todo.local.gd:31338/.
Clean upβ
Delete the EasyApp Promise:
kubectl --context $PLATFORM delete promise easyapp
The above command will give an output similar to:
promise.platform.kratix.io "easyapp" deleted
π Congratulationsβ
You have installed a Compound Promise and created an EasyApp Resource!
β
Β Β This tutorial concludes the Introduction to Kratix.
ππΎΒ Β You can go ahead and start the next module to learn how to write your own
Promises or jump to What's next to learn about
what else you can achieve with Kratix.