Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add CUE walkthrough and module dev guides #301

Merged
merged 17 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ packaged as [Modules](https://timoni.sh/module/), using type-safe
Kubernetes templates and rich customisation options for end-users.

The app configuration packaged in a Module is
[distributed](https://timoni.sh/module-distribution/) as an
[distributed](https://timoni.sh/cue/module/publishing/) as an
Open Container Initiative (OCI) artifact, next to the app images,
in a container registry. Timoni Modules are semantically versioned
and cryptographically [signed](https://timoni.sh/module-sign/).
and cryptographically [signed](https://timoni.sh/cue/module/signing/).

With Timoni, platform engineers can manage the lifecycle of Kubernetes
controllers, including the upgrade of CRDs. Module authors can
[import CRD schemas](https://timoni.sh/module/#kubernetes-crds)
[import CRD schemas](https://timoni.sh/cue/module/custom-resources/)
from YAML files and incorporate Kubernetes custom resources
in their app deployments.

Expand Down
2 changes: 1 addition & 1 deletion docs/bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ where the module is published. The `url` field must be in the format `oci://<reg
#### Version

The `instance.module.version` is an optional field that specifies the version number of the module.
The version number must follow [Timoni's semantic versioning](module-distribution.md).
The version number must follow [Timoni's semantic versioning](cue/module/publishing.md#version-format).
When not specified, the version defaults to `latest`, which pulls the module OCI artifact tagged as latest.

```cue
Expand Down
13 changes: 2 additions & 11 deletions docs/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@ with an opinionated structure.
A module accepts a set of values supplied by users,
and outputs a set of Kubernetes objects that Timoni deploys on Kubernetes clusters.

Module structure:
```sh
app
├── cue.mod # Kubernetes APIs and CRDs schemas
├── templates # Workloads and app config schema
├── timoni.cue # Timoni entry point
└── values.cue # Default config values
```

Commands for working with local modules:

- `timoni mod init <module-name>`
Expand All @@ -38,8 +29,8 @@ Commands for vendoring Kubernetes APIs and CRDs:
- `timoni mod vendor k8s --version latest`
- `timoni mod vendor crds -f <path/to/crds.yaml>`

Timoni modules are distributed as OCI artifacts that can be cryptographically [signed and verified](module-sign.md).
Modules are versioned using strict [semantic versioning](module-distribution.md#version-format),
Timoni modules are distributed as OCI artifacts that can be cryptographically [signed and verified](cue/module/signing.md).
Modules are versioned using strict [semantic versioning](cue/module/publishing.md#version-format),
the version of a module is used as the OCI artifact tag.

To learn more about modules, please see the [module documentation](module.md).
Expand Down
64 changes: 64 additions & 0 deletions docs/cue/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# CUE Language

[CUE](https://cuelang.org) is the configuration language used by Timoni. We chose CUE
due to its expressive syntax, powerful data validation model, and ability to generate
Kubernetes configuration while ensuring the result is consistent and unambiguous.

Timoni embeds the CUE engine enabling software vendors to define complex application
deployments packaged as CUE modules. Kubernetes' operators can then refer to these
modules in their own CUE definitions, allowing them to deploy and manage the lifecycle
of applications in a reliable manner.

## What is CUE?

CUE stands for Configure, Unify, Execute. The CUE language is a superset of JSON,
it reduces the verbosity of JSON and allows C-style comments.

While JSON is a data format, CUE is a data constraint language, allowing embedding logic
within the data using if statements, for loops, comprehensions, string interpolation,
arithmetic operations, regular expressions, and more.

CUE can be used for data validation, data templating, configuration, querying,
code generation and even scripting.

## Why CUE for Kubernetes?

What sets CUE apart from other configuration languages is that CUE merges
types, values and constraints into a single concept, think of JSON and JSONSchema all-in-one.

What makes CUE the ideal configuration language for Kubernetes is its ability to
import the Kubernetes OpenAPI schema (both for the builtin Kinds and CRDs)
and use it to validate the generated YAML configuration. When writing templates for Kubernetes
with CUE, you can be sure that the generated YAML is valid and will not be rejected by the API server.

!!! tip "Timoni vendor commands"

Timoni streamlines the process of importing Kubernetes schemas with the `timoni mod vendor` commands:

- `timoni mod vendor k8s` imports the schema of Kubernetes builtin Kinds
- `timoni mod vendor crd` imports the schema of Kubernetes CRDs

CUE makes it easy to define complex Kubernetes objects and build abstractions on top of them.
To reduce the boilerplate, CUE allows defining common schemas, constraints and default values
that can be reused across multiple Kubernetes objects.

!!! tip "Timoni CUE definitions"

Timoni comes with a set of CUE definitions for the most common Kubernetes constructs, such as
Metadata, Label Selectors, Resource Requirements, Container Images, Image Pull Secrets, and more.

## Who maintains CUE?

The CUE language was originally developed at Google by [Marcel van Lohuizen](https://github.com/mpvl)
who co-created the Borg Configuration Language (BCL). Although CUE is very different from BCL, it
incorporates many of the lessons learned from 15 years of GCL usage.

Nowadays, CUE is an independent open source project maintained by a dedicated team,
with a growing community of contributors and users.

CUE is licensed under the Apache 2.0 license, the source code is hosted on [GitHub](https://github.com/cue-lang/cue)
and accepts contributions from the community, for more information see the
[contributing guidelines](https://github.com/cue-lang/cue/blob/master/CONTRIBUTING.md).

Everyone is welcome to join the CUE community,
for more information please see the [community page](https://cuelang.org/community/).
101 changes: 101 additions & 0 deletions docs/cue/module/apply-behavior.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Control the Apply Behavior

Timoni allows changing the default apply behaviour of Kubernetes resources
with the `action.timoni.sh` annotations.

## Annotations

| CUE | Generated YAML |
|--------------------------|-------------------------------------|
| `timoniv1.Action.Force` | `action.timoni.sh/force: enabled` |
| `timoniv1.Action.OneOff` | `action.timoni.sh/one-off: enabled` |
| `timoniv1.Action.Keep` | `action.timoni.sh/prune: disabled` |

### Force Apply

To recreate immutable resources such as Kubernetes Jobs,
these resources can be annotated with `action.timoni.sh/force: "enabled"`.

Example:

```cue
package templates

import (
batchv1 "k8s.io/api/batch/v1"
timoniv1 "timoni.sh/core/v1alpha1"
)

#TestJob: batchv1.#Job & {
#config: #Config
apiVersion: "batch/v1"
kind: "Job"
metadata: timoniv1.#MetaComponent & {
#Meta: #config.metadata
#Component: "test"
}
metadata: annotations: timoniv1.Action.Force
spec: {...}
}

```

### One-Off Apply

To apply resources only if they don't exist on the cluster,
these resources can be annotated with `action.timoni.sh/one-off: "enabled"`.

Example:

```cue
package templates

import (
batchv1 "k8s.io/api/batch/v1"
timoniv1 "timoni.sh/core/v1alpha1"
)

#InstallJob: batchv1.#Job & {
#config: #Config
apiVersion: "batch/v1"
kind: "Job"
metadata: timoniv1.#MetaComponent & {
#Meta: #config.metadata
#Component: "install"
}
metadata: annotations: timoniv1.Action.OneOff
spec: {...}
}

```

### Disable Pruning

To prevent Timoni's garbage collector from deleting certain
resources such as Kubernetes Persistent Volumes,
these resources can be annotated with `action.timoni.sh/prune: "disabled"`.


Example:

```cue
package templates

import (
corev1 "k8s.io/api/core/v1"
timoniv1 "timoni.sh/core/v1alpha1"
)

#DatabasePVC: corev1.#PersistentVolumeClaim & {
#config: #Config
apiVersion: "v1"
kind: "PersistentVolumeClaim"
metadata: timoniv1.#MetaComponent & {
#Meta: #config.metadata
#Component: "database"
}
metadata: annotations: timoniv1.Action.Keep
spec: {...}
}

```
114 changes: 114 additions & 0 deletions docs/cue/module/custom-resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Kubernetes Custom Resources

Timoni allows defining Kubernetes Custom Resources (CRs) in modules and can ensure
that these are validated against their Kubernetes Custom Resource Definitions (CRDs).

To enable validation for custom resources, you have to generate the CUE schemas from
the Kubernetes CRDs OpenAPI validation spec with the `timoni mod vendor crds` command.

## Example

To demonstrate this feature, we'll use the
[Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator) CRDs,
and we'll add a `ServiceMonitor` custom resource to a Timoni module.

### Vendor Prometheus Operator CRDs

From the root dir of your module, run the `timoni mod vendor crds` command, and pass the URL
to the YAML file which contains the Prometheus Operator CRDs:

```shell
timoni mod vendor crds -f https://github.com/prometheus-operator/prometheus-operator/releases/download/v0.68.0/stripped-down-crds.yaml
```

The above command will generate the CUE schemas corresponding to the Kubernetes CRDs
inside the `cue.mod/gen` directory:

```text
cue.mod/gen/
└── monitoring.coreos.com
├── alertmanager
├── alertmanagerconfig
├── podmonitor
├── probe
├── prometheus
├── prometheusagent
├── prometheusrule
├── scrapeconfig
├── servicemonitor
└── thanosruler
```

### Create the `ServiceMonitor` template

In the `templates` directory, create a `servicemonitor.cue` file with the following content:

```cue
package templates

import (
promv1 "monitoring.coreos.com/servicemonitor/v1"
)

#ServiceMonitor: promv1.#ServiceMonitor & {
#config: #Config
metadata: #config.metadata
spec: {
endpoints: [{
// Change this to match the Service port where
// your app exposes the /metrics endpoint
port: "http-metrics"
path: "/metrics"
interval: "\(#config.monitoring.interval)s"
}]
namespaceSelector: matchNames: [#config.metadata.namespace]
selector: matchLabels: #config.selector.labels
}
}
```

Make sure to replace the `port` and `path` values with the ones used by your app.
The port name must match one of the ports exposed in the Kubernetes Service template.

!!! tip "API Version and Kind"

Note that for Kubernetes custom resources, you don't need to specify the
`apiVersion` and `kind`, these fields are set by Timoni in the generated schema.

### Add the `monitoring` configuration

In the `templates/config.cue` file, add the `monitoring` configuration:

```cue
#Config: {

// Promethues service monitor (optional)
monitoring: {
enabled: *false | bool
interval: *15 | int & >=5 & <=3600
}

}

```

### Add the `ServiceMonitor` to the instance

In the `templates/config.cue` file, add the `ServiceMonitor` resource to the instance objects:

```cue
#Instance: {
config: #Config

if config.monitoring.enabled {
objects: servicemonitor: #ServiceMonitor & {#config: config}
}

}

```

### Document the `monitoring` configuration

Finally, document the `monitoring` configuration in the `README.md` file, so that users
know how to enable monitoring if they have Prometheus Operator installed.
Loading