Rendering a Baseline from git

A Baseline either declares its services inline in spec.services or points at a repository in spec.source. Given a source the operator clones the repository. It renders the deployment definition and derives the service list. Inline entries then act as per-service overrides by name.

spec:
  application: shop
  source:
    url: https://git.acme.internal/retail/shop.git
    ref: release/2026.09        # branch, tag or commit sha
    path: deploy/chart
    kind: helm                  # helm | kustomize | manifests
    secretRef: {name: shop-git}
    helm:
      valuesFiles: [values-prod.yaml]
      values: {logLevel: info}
    pollInterval: 5m            # optional; re-resolve the ref this often
  services:
    - name: shop-postgres       # override: rendered as StatefulSet, keep it shared
      shared: true

Credentials Secret

Key Use
token HTTPS token or password. username is optional and defaults to nezal.
ssh-privatekey SSH key. known_hosts is required. passphrase optional.
ca.crt PEM bundle for a private certificate authority on the git server.

The operator contacts nothing but this git server.

Formats

Docker Compose is not a supported format. A compose file describes a laptop and leaves out most of what a cluster needs. Converting one meant guessing. Describe the application as a Helm chart or a Kustomize overlay or plain manifests. A Baseline still of kind compose reports that on its status and deploys nothing new.

How Kubernetes objects become services

Each Service that selects a Deployment or StatefulSet becomes one nezal service named after the Service. Image and command and args and env come from the first container. So do resources and replicas and the working directory and the numeric uid. Port protocol comes from appProtocol or the nezal.dev/protocol annotation and is otherwise http. Well-known database ports default to tcp instead. The annotation nezal.dev/shared: "true" marks a shared dependency and so does being a StatefulSet.

Health checks

A readiness probe in the source is carried over.

Nothing is ever rendered as a liveness probe. A liveness probe restarts the pod. A check written for production or for a laptop will restart a half-built preview environment forever. A readiness probe only decides whether traffic is sent and that is recoverable. When a workload declares only a liveness probe that probe becomes the readiness check and a warning says so.

Without any declared check nezal infers a TCP probe on the service's first port. The first request after nezal up then does not reach a process that has not started listening yet.

Volumes and mounted files

In the source Becomes Note
emptyDir emptyDir Ephemeral. Nothing survives a restart.
configMap or secret file mount The object must already exist in the namespace.
persistentVolumeClaim emptyDir with a warning Mark the service shared if it owns real data.

Two rules behind that table. A preview environment is rebuilt from the repository. State that survived a rebuild would make it irreproducible so nezal never provisions persistent storage for one. And nezal never copies secret material out of a git repository into the cluster: a mounted Secret is one that an admin creates.

A ConfigMap or Secret mounted as a whole directory is not carried over because its keys are only known at deploy time. List them under items in the source or use subPath.

Every rendered pod has a read-only root filesystem so a service that writes outside a declared scratch path will fail. Add an emptyDir mount in the source for the paths it needs.

Ordering

Kubernetes has no start order. Everything starts at once and a service restarts until its dependencies answer. That usually converges within seconds. A service that reads its database once at startup and exits rather than retrying will crash-loop instead. Make startup connections retry.

What to look at

Failures retry every two minutes. Rendered output is cached by commit so restarting the operator or re-applying the same Baseline does not re-render.