akua / examples / 01-hello-webapp

Example 01 — hello-webapp

The smallest possible akua Package. One local-path chart dep, an `Input` schema with two fields, raw-manifest output. Teaches the three regions of `package.k` — imports, schema, body — and the `charts

The smallest possible akua Package. One local-path chart dep, an Input schema with two fields, raw-manifest output. Teaches the three regions of package.k — imports, schema, body — and the charts.* typed-import pattern that Phase 2a landed.

Read this first. Every other example adds exactly one concept over this one.

Layout

01-hello-webapp/
├── akua.toml                  declared deps (one local-path chart)
├── akua.lock                  digest ledger (machine-maintained)
├── package.k                  the Package itself
├── inputs.yaml                sample inputs satisfying the Input schema
├── vendor/nginx/              the vendored chart — see Phase 2b for OCI pulls
│   ├── Chart.yaml
│   ├── values.yaml
│   └── templates/
└── README.md

The three regions in package.k

  1. Importsakua.ctx (reads user inputs) and charts.nginx

(resolved from akua.toml — a per-render stub module akua's chart resolver synthesizes, exposing template/Values/TemplateOpts). No import akua.helm at the call site — the stub dispatches.

  1. SchemaInput with two fields. Both have defaults; docstrings

will become UI labels once the schema-extraction path ships.

  1. Body — one call to nginx.template(nginx.TemplateOpts{...})

wiring public schema into chart values. Resources are aggregated into top-level resources. akua writes one YAML file per resource under --out.

Run

akua add                                 # resolve deps → writes akua.lock
akua render --inputs inputs.yaml         # render to ./deploy/
ls deploy/                               # 000-deployment-hello.yaml, 001-service-hello.yaml

Under --strict, akua rejects raw-string chart paths — every chart must be declared in akua.toml and imported as charts.<name>:

akua render --strict --inputs inputs.yaml

Vendored chart vs OCI pull

This example vendors nginx into vendor/nginx/ so the Package is self-contained and rendering works offline. To point at a registry instead, swap the akua.toml dep for:

[dependencies]
nginx = { oci = "oci://registry-1.docker.io/bitnamicharts/nginx", version = "18.2.0" }

akua pulls the chart into $XDG_CACHE_HOME/akua/oci/ on first akua add / akua render, verifying the blob digest against akua.lock on subsequent renders. See Phase 2b in docs/roadmap.md.

Local fork override

While iterating on a chart, point a real oci:// dep at a local clone without losing the canonical source-of-record:

nginx = { oci = "oci://registry-1.docker.io/bitnamicharts/nginx", version = "18.2.0", replace = { path = "../nginx-fork" } }

akua.lock still records the oci:// digest; files resolve from ../nginx-fork. Drop the replace clause to switch back.

See also

package.k

# Example 01 — hello-webapp
#
# Smallest useful akua Package. One local-path chart dep, a few public
# inputs, raw-manifest output.
#
# Render:
#   akua render --inputs inputs.yaml      # render to ./rendered by default

import akua.ctx
import charts.nginx as nginx    # Phase 2a: resolved from akua.toml

schema Input:
    """Public inputs for the hello-webapp Package."""

    @ui(order=10, group="Identity")
    name: str = "hello"
    """Internal name used as a resource-name prefix. Lowercase, hyphen-separated."""

    @ui(order=20, widget="slider", min=1, max=20)
    replicas: int = 2
    """Replica count for the Deployment."""

    check:
        replicas >= 1, "replicas must be at least 1"

input: Input = ctx.input()

# Phase 2b slice C: the generated `charts.nginx` module exposes a
# `template()` callable pre-filled with the resolved chart path, so
# the Package only restates the options that matter.
resources = nginx.template(nginx.TemplateOpts {
    values = {
        replicaCount = input.replicas
        fullnameOverride = input.name
    }
    release = input.name
})

Rendered output

000-deployment-hello.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/instance: hello
    app.kubernetes.io/managed-by: akua
    app.kubernetes.io/name: nginx
  name: hello
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/instance: hello
      app.kubernetes.io/name: nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/instance: hello
        app.kubernetes.io/managed-by: akua
        app.kubernetes.io/name: nginx
    spec:
      containers:
      - image: nginx:1.27
        name: nginx
        ports:
        - containerPort: 80
          name: http
          protocol: TCP

001-service-hello.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: hello
    app.kubernetes.io/managed-by: akua
    app.kubernetes.io/name: nginx
  name: hello
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: http
  selector:
    app.kubernetes.io/instance: hello
    app.kubernetes.io/name: nginx
  type: ClusterIP

Source: examples/01-hello-webapp/