Skip to content

Commit 1b1d6d3

Browse files
authored
Add a tutorial that uses cue-lang to generate larger configuration files (#149)
1 parent f0cf899 commit 1b1d6d3

File tree

7 files changed

+168
-2
lines changed

7 files changed

+168
-2
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ learn using it with the step by step tutorial:
5454
1. [Two services](./docs/tutorial/1-two-services.md)
5555
2. [A database and more services](./docs/tutorial/2-a-database-and-more-services.md)
5656
3. [Errors and randomness](./docs/tutorial/3-errors-and-randomness.md)
57-
4. [Observability with OpenTelemetry](./docs/tutorial/4-observability-with-opentelemetry.md)
57+
4. [Observability with cilium Hubble](./docs/tutorial/4-observability-with-cilium-hubble.md)
58+
5. [Observability with OpenTelemetry](./docs/tutorial/5-observability-with-opentelemetry.md)
59+
6. [Large deployments with cue](./docs/tutorial/5-large-deployments-with-cue/README.md)
5860

5961
## Configuration specification
6062

docs/tutorial/1-two-services.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,4 @@ simulation:
6767
kubectl apply -f deployments/
6868
```
6969

70-
In both cases you will be see three containers being started.
70+
In both cases you will be see three containers being started.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Tutorial 4: Observability with cilium hubble
2+
3+
> [!NOTE]
4+
>
5+
> This tutorial is work in progress.
6+
7+
If you run your application simulation on kubernetes you can use [cilium Hubble's ui](https://github.com/cilium/hubble).
8+
9+
Follow the instructions to install [cilium](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/) and [enable the Hubble UI](https://docs.cilium.io/en/stable/observability/hubble/hubble-ui/#hubble-ui).
10+
11+
If you already have deployed your application simulation in a previous tutorial (for example the [two services from tutorial 1](./1-two-services.md)), you can navigate to `http://localhost:12000/?namespace=app-sim-tutorial1`
12+
in your browser, and you will see the interaction between the load generator, and the two services.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Tutorial 4: Observability with OpenTelemetry
2+
3+
> [!NOTE]
4+
>
5+
> This tutorial is work in progress.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Tutorial 5: Large deployments with cue
2+
3+
> [!NOTE]
4+
>
5+
> This tutorial is work in progress.
6+
7+
With application simulator you are able to describe a complex multi-service architecture without thinking about the business logic of each service that is part of your setup.
8+
This allows you to create arbitrarily large deployments for your purposes, e.g. if you'd like to generate lots of telemetry data for your observability backend.
9+
10+
The only limitation that remains, is that YAML does not provide you with a level of programmability, that allows you to write a lot of similar services in one place. You have
11+
to write them down one by one.
12+
13+
Instead of enriching the application simulation configuration file format with such a functionality, you can leverage configuration languages like [`pkl`](https://pkl-lang.org/), [`dhall`](https://dhall-lang.org/) or [`cue`](https://cuelang.org/).
14+
In this tutorial we will use `cue` to demonstrate this use case.
15+
16+
## Requirements
17+
18+
Make sure you have `cue` installed locally, following [these instructions](https://cuelang.org/docs/introduction/installation/)
19+
20+
## Create cue file
21+
22+
To get started create the following file named [`large-application.cue`](../../examples/cue/large-application.cue) in an empty folder:
23+
24+
```cue
25+
import "list"
26+
import "math"
27+
28+
#depth: int @tag(depth,type=int)
29+
#adjectives: ["swift", "happy", "brave", "clever", "silent", "bold", "lucky", "fierce", "gentle", "mighty", "shy", "curious", "wise", "playful", "proud", "loyal"]
30+
#nouns: ["lion", "tiger", "eagle", "panda", "fox", "wolf", "hawk", "bear", "otter", "falcon", "rabbit", "panther", "deer", "owl", "cheetah", "dolphin"]
31+
32+
loaders: {
33+
"user1": {
34+
type: "curl",
35+
wait: 5,
36+
sleep: 2,
37+
urls: [ "http://swift-lion/next" ]
38+
}
39+
}
40+
41+
services: {
42+
for x in list.Range(0, #depth+1, 1) {
43+
for y in list.Range(0, x+1, 1) {
44+
"\(#adjectives[x])-\(#nouns[y])": {
45+
type: "java"
46+
endpoints: {
47+
http: {
48+
"/next": list.Concat([[
49+
for i in [y, y+1] if x < #depth {
50+
"http://\(#adjectives[x+1])-\(#nouns[i])/next"
51+
}
52+
], ["sleep,\(math.Exp2(x)+(y*10))"]])
53+
}
54+
}
55+
}
56+
}
57+
}
58+
}
59+
```
60+
61+
## Export cue to YAML
62+
63+
Run the following command to generate a YAML file:
64+
65+
```shell
66+
cue -t depth=3 export large-application.cue --out yaml > config.yaml
67+
```
68+
69+
This will generate an application simulation configuration file with 10 services, since the `for` loop within the `services` block creates a tree of services, where each node talks to two children, until `depth` is reached:
70+
71+
```mermaid
72+
flowchart TD
73+
user1 --> swift-lion
74+
swift-lion --> happy-lion
75+
swift-lion --> happy-tiger
76+
happy-lion --> brave-lion
77+
happy-lion --> brave-tiger
78+
happy-tiger --> brave-tiger
79+
happy-tiger --> brave-eagle
80+
brave-lion --> clever-lion
81+
brave-lion --> clever-tiger
82+
brave-tiger --> clever-tiger
83+
brave-tiger --> clever-eagle
84+
brave-eagle --> clever-eagle
85+
brave-eagle --> cleaver-panda
86+
```
87+
88+
By increasing the `depth` parameter, you can add additional layers, e.g. `depth=4` will create 15 services, `depth=5` will create 21 services and `depth=6` will create 28 services.
89+
90+
Additionally, each service will introduce some milliseconds of delay using `sleep` depending on their position in the tree.
91+
92+
We recommend that you continue the tutorial with `depth=3`. Afterwards you can increase the value step by step and check how many nodes you can run simultaneously.
93+
94+
## Create your k8s deployment files
95+
96+
To turn the application simulation configuration file from the last step into manifests for kubernetes, run the generator:
97+
98+
```
99+
docker run --rm -t -i -v ${PWD}/deployments:/app/deployments -v ${PWD}:/mnt ghcr.io/cisco-open/app-simulator-generators-k8s:latest --config /mnt/config.yaml
100+
```
101+
102+
This will create a folder `deployments` that will continue all the files you need to run your simulation on your cluster, using the following command:
103+
104+
```
105+
kubectl create namespace app-sim-cue
106+
kubectl apply -f deployments/ --namespace app-sim-cue
107+
```
108+
109+
This will spin up your sample application. You can now use [OpenTelemetry](./5-observability-with-opentelemetry.md) or [cilium hubble](./4-observability-with-cilium-hubble.md to visualize your application.
110+
111+
For example, the following image shows an application with `depth=4` in cilium hubble ui:
112+
113+
![](./depth-4-in-hubble-ui.png)
211 KB
Loading

examples/cue/large-application.cue

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import "list"
2+
import "math"
3+
4+
#depth: int @tag(depth,type=int)
5+
#adjectives: ["swift", "happy", "brave", "clever", "silent", "bold", "lucky", "fierce", "gentle", "mighty", "shy", "curious", "wise", "playful", "proud", "loyal"]
6+
#nouns: ["lion", "tiger", "eagle", "panda", "fox", "wolf", "hawk", "bear", "otter", "falcon", "rabbit", "panther", "deer", "owl", "cheetah", "dolphin"]
7+
8+
loaders: {
9+
"user1": {
10+
type: "curl",
11+
wait: 5,
12+
sleep: 2,
13+
urls: [ "http://swift-lion/next" ]
14+
}
15+
}
16+
17+
services: {
18+
for x in list.Range(0, #depth+1, 1) {
19+
for y in list.Range(0, x+1, 1) {
20+
"\(#adjectives[x])-\(#nouns[y])": {
21+
type: "java"
22+
endpoints: {
23+
http: {
24+
"/next": list.Concat([[
25+
for i in [y, y+1] if x < #depth {
26+
"http://\(#adjectives[x+1])-\(#nouns[i])/next"
27+
}
28+
], ["sleep,\(math.Exp2(x)+(y*10))"]])
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)