Reference kix helpers
expose
Add an Ingress or Gateway API HTTPRoute for one Service or a set of path backends.
kix.expose returns a package build function. Add it to the package’s build
list after the function that creates the backend Services:
build = [ ({ self, scope, ... }: { service = scope.mkResource { /* ... */ }; root = self.service; }) (kix.expose { service = "service"; })];The helper has optional gateway, ingressNginx, and clusterIssuer build
arguments. It emits an HTTPRoute when a Gateway provider is resolved, or an
Ingress when an ingress-nginx provider is resolved. Resolving both exposure
providers is an evaluation error; wire exactly one with the instance’s
deps when both are available. The HTTPRoute depends on a CRD reference
marker for httproutes.gateway.networking.k8s.io, so kix deploy waits for
the Gateway API CRDs before applying it.
No route is emitted when neither provider is available or when no host can be
resolved. The host comes from config.ingress.host, then falls back to
<instance>.<cluster.domain>. With deriveHost = false there is no
fallback: the instance gets a route only when it sets ingress.host.
The helper adds two parts to the package: the Ingress or HTTPRoute, named
route by default, and exposure, a record that describes it. A
Deployment in the same package can read self.exposure.url.
Backend modes
Section titled “Backend modes”Set exactly one of service and paths.
service names one part in the package’s returned attrset:
kix.expose { service = "service"; port = 8080;}paths routes several paths, possibly to different Service parts:
kix.expose { paths = [ { path = "/api"; service = "apiService"; } { path = "/"; service = "frontendService"; port = 80; } ];}Each path accepts path, service, optional port, and optional pathType.
The default path type is Prefix. In Gateway mode it is translated to
PathPrefix; Exact is supported in both modes. A missing port is read from
the Service’s out.port, and evaluation fails when neither is available.
Arguments
Section titled “Arguments”| Argument | Default | Meaning |
|---|---|---|
service | null | Name of the single backend Service part. Mutually exclusive with paths. |
paths | null | Path records for one Ingress or HTTPRoute. Mutually exclusive with service. |
partName | "route" | Part name for the generated Ingress or HTTPRoute. Derived network-policy part names also start with this value. In Gateway mode a second part, <partName>Crd, holds the scope.mkCRDRef for HTTPRoute that the route is built from (routeCrd by default). |
exposurePart | "exposure" | Part name for the exposure record. A package that calls kix.expose twice sets partName and exposurePart on the second call; two build entries that define the same part are an evaluation error. |
defaultAnnotations | { } | Base Ingress annotations. config.ingress.annotations takes precedence on duplicate keys. Ignored in Gateway mode. |
port | null | Single-backend Service port. null reads out.port. |
timeouts | null | Gateway API rule timeouts. Copied to every rule and ignored in Ingress mode. |
deriveHost | true | When false, the host comes only from config.ingress.host. Without it there is no route and exposure.via is null. Use it for a package that should not be public unless the instance names a host. |
Ingress mode enables TLS when a clusterIssuer dependency is resolved. The
issuer helper annotates the Ingress, and Kix adds a TLS entry for the host
with the Secret <instance>-tls. Gateway mode leaves TLS to the Gateway
listener.
Public URL
Section titled “Public URL”The exposure part is a record of the route this call renders:
| Field | Value |
|---|---|
via | "gateway", "ingress", or null when no route is rendered |
host | The route’s host, or null |
scheme | "https" or "http", or null when Kix cannot tell |
url | <scheme>://<host>, with :<port> when the port is not the scheme’s default. Reading it when scheme is null is an evaluation error that names the instance and the cause: no route, no host, or a Gateway without listeners |
urlOrNull | url, or null when scheme is null, for a package that works without a public URL |
In Ingress mode the scheme is https when a clusterIssuer is wired and
http otherwise.
In Gateway mode Kix finds the listener the HTTPRoute attaches to, as
Gateway API does. A listener qualifies when its protocol is HTTP or
HTTPS, its hostname is unset, equal to the host, or a wildcard such as
*.example.com that covers it, and its allowedRoutes.namespaces.from is
All, or Same (the default) with the application in the Gateway’s
namespace. Among qualifying listeners Kix prefers HTTPS, then the scheme’s
default port, then list order. When no listener qualifies, evaluation
fails and the message lists each listener with the reason it was skipped.
Kix does not evaluate a Selector namespace policy. Such a listener is
chosen only when no other qualifies, and Kix warns that it assumed the
application’s namespace matches.
A Gateway that does not publish its listeners, such as one declared with
kix.mkImport, gives scheme = null, so reading url fails.
A package that needs its public URL reads url, so an instance without a
route fails evaluation instead of starting with a wrong address. A package
that works without one, such as Metabase, which then records the URL of
the first administrator’s request, reads urlOrNull and handles null.
TLS that terminates outside Kix, for example at cloudflared or at a load
balancer in front of ingress-nginx, is not visible to Kix, so the record
says http. Packages that read the URL take an override for that case
(vaultwarden’s domain, for one).
Generated network policy
Section titled “Generated network policy”With ingress-nginx and a network-policy provider, Kix derives an ingress rule
from the controller pods to each backend. The ingress controller package must
export out.podSelector and out.podNamespace; Kix warns when it cannot
derive the rule. In Gateway mode the rule comes from the gateway’s
out.podSelector and out.podNamespace: traefik publishes its pods, and
envoy-gateway publishes null because Envoy Gateway’s controller places the
proxy pods, so its backends get no rule.