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
- Imports —
akua.ctx(reads user inputs) andcharts.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.
- Schema —
Inputwith two fields. Both have defaults; docstrings
will become UI labels once the schema-extraction path ships.
- 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-format.md — canonical Package spec
- cli.md
render— render verb + flags - roadmap.md Phase 2 — chart dep resolver design
- 02-webapp-postgres/ — next example: cross-source wiring
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/