Skip to content

Helm values

This page lists every value of the agent-kourier Helm chart, with its default and the comment charts/agent-kourier/values.yaml gives it.

replicaCount

Defaults for the Agent Kourier chart.

This chart runs ONE replica by default, with its state in SQLite on a PersistentVolumeClaim (store.type sqlite, the default) or in Postgres (store.type postgres). A SQLite file may be open in one pod, and the session manager keeps per-thread state in memory, so SQLite is one replica: the render refuses replicaCount above 1 with it. With Postgres, replicaCount 2 gives an active/passive pair: the replicas elect a leader with a Kubernetes Lease (leaderElection below), the leader does all of Agent Kourier's work, and the standby is Ready and idle until the leader's lease lapses or it stops. Every write is fenced by an epoch in the database, so a leader that has been paused past its lease cannot write when it wakes. Postgres at replicaCount 1 elects too, and is a standby-less leader. replicaCount 0 is the kill switch: Agent Kourier stops, and the volume (or the database) stays.

Default: 1

image

Key Default Description
image.repository "" Required. A released chart has it stamped (ghcr.io/skyarksolutions/agent-kourier), with digest; in the source tree it is empty. Locally: agent-kourier (the image make image builds is agent-kourier:dev).
image.tag "" A tag, which defaults to the chart's appVersion. Ignored when digest is set: a released chart sets the digest, so to run another tag with it, set image.digest="" as well (or set image.digest to the other release's digest).
image.digest "" Pin production to a digest (sha256:...), which wins over tag.
image.pullPolicy IfNotPresent

imagePullSecrets

Default: []

fullnameOverride

Resource names are <release>-agent-kourier (or the release name when it contains "agent-kourier"). The label app.kubernetes.io/name=agent-kourier is fixed either way: NetworkPolicies elsewhere trust pods by it.

Default: ""

serviceAccount

Key Default Description
serviceAccount.create true
serviceAccount.name "" Defaults to the fullname. Agent Kourier reads Secrets through the API, so the token stays mounted.
serviceAccount.annotations {}

listen

Agent Kourier's process settings. These are the environment cmd/agent-kourier reads (its package comment lists all of them).

Key Default Description
listen.port 8080 The port of /healthz, /readyz and /metrics (AGENTKOURIER_LISTEN). The alert webhook receiver is not served yet.

logLevel

Default: info

debug, info, warn or error (AGENTKOURIER_LOG_LEVEL)

klogVerbosity

client-go's verbosity (AGENTKOURIER_KLOG_V). Keep it 0: at 8 and above client-go logs response bodies, Secret lists included.

Default: 0

syncTimeout

How long to wait for the Secret caches before startup fails (AGENTKOURIER_SYNC_TIMEOUT). Empty is Agent Kourier's default, 30s.

Default: ""

auditRetention

How long audit entries are kept (AGENTKOURIER_AUDIT_RETENTION): empty or "keep" is for ever, which is what runs until you set one; a duration of at least 24h (8760h is a year) purges the entries older than it, hourly, in batches. The audit holds IDs and outcomes, never message text. The purge is the only way an entry leaves the table.

Default: ""

extraEnv

Extra container environment, in Kubernetes' own form. This is where the OpenTelemetry settings go (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_TRACES_EXPORTER, ...); take a header or other credential from a Secret with valueFrom.secretKeyRef, never as a value.

Default: []

config

What Agent Kourier reads. Either the resources below, which the chart writes into a ConfigMap mounted at /etc/agent-kourier, or existingConfigMap, the name of a ConfigMap you manage (one key per file, each ending .yaml). Not both.

Each entry is keyed by its name and holds the resource's spec exactly as the resource reference describes it (the chart does not interpret it) and, optionally, the namespace (default: the release's). Secrets are referenced by name (credentialsSecretRef, tokenSecretRef, valueSecretRef) and live in the cluster, made by you or Sealed Secrets: no token value belongs in this file or in any values file (the render refuses a Slack token, and a header value whose name looks like a credential).

config:
  chatConnections:
    slack-main:
      spec:
        platform: slack
        mode: socket
        credentialsSecretRef: {name: slack-main}   # keys botToken and appToken
  agentBackends:
    agents:
      spec: {dialect: kagent-v1, url: "http://kagent-frontdoor.kagent.svc.cluster.local:4180"}
  bindings:
    sre-alerts:
      spec:
        agent: {backendRef: {name: agents}, namespace: kagent, name: k8s-agent}
        identity: {userId: agent-kourier-sre, tokenSecretRef: {name: agent-kourier-agent-token}}
        chat: {connectionRef: {name: slack-main}, channel: C0123456789, output: live, threadReplies: all}  # all (default) | mention
Key Default Description
config.existingConfigMap ""
config.agentBackends {}
config.chatConnections {}
config.bindings {}
config.rollOnChange true Roll the pod when the rendered ConfigMap changes. Agent Kourier reloads its files in place, but a reload that adds a Secret namespace fails until the process restarts. Has no effect with existingConfigMap.

store

Where Agent Kourier keeps its state. SQLite is one file on a volume (persistence below), for one replica. Postgres is a database you run (the chart does not install one), for more than one replica: they elect a leader (leaderElection below).

Key Default Description
store.type sqlite sqlite or postgres (AGENTKOURIER_STORE)
store.postgres.dsnSecret The Secret that holds the DSN, a postgres:// URL or key/value string, in the release namespace: required with store.type postgres, and refused with sqlite. Make it yourself (by hand, Sealed Secrets, an external operator); the DSN, password included, never goes in a values file (the render refuses a postgres:// URL with a password anywhere in them). Agent Kourier reads it through the API like its other Secrets, which the Role below grants: list and watch on every Secret of the release namespace, so keep Agent Kourier's Secrets in a namespace of their own when it is shared. Percent-encode the reserved characters of a password in a URL. The role in the DSN needs the right to create tables in its schema: agent-kourier applies its own migrations at start.
store.postgres.dsnSecret.name ""
store.postgres.dsnSecret.key ""
store.postgres.timeouts agent-kourier Who sets the idle-in-transaction and statement timeouts, which end a stalled leader's transaction and free its locks. "agent-kourier" (the default) sends them as startup parameters on every connection. Connect to Postgres directly or through a pooler in SESSION mode. A pooler in TRANSACTION mode (PgBouncer's pool_mode = transaction) refuses startup parameters ("unsupported startup parameter"), and listing them in its ignore_startup_parameters silently drops the protection: there, set both on the database role (ALTER ROLE agentkourier SET idle_in_transaction_session_timeout = '10s'; ALTER ROLE agentkourier SET statement_timeout = '30s') and set this to "role", which turns Agent Kourier's own off.

leaderElection

Leader election, which runs with store.type postgres only (with sqlite none of this is allowed). The replicas hold one Lease, named <fullname>-leader in the release namespace, which the chart's Role grants (rbac.create). The leader renews it every retryPeriod. A standby takes it leaseDuration after the last renewal it saw, so the worst case before work resumes after a crash or a lost node is the lease duration plus Agent Kourier's start-up (a few seconds). A leader that cannot renew for renewDeadline gives up and exits at once, which is 5 s before a standby may take over with the defaults. The leader hands the lease over when it stops on a signal (a rolling update), so that takeover is quick. Empty is Agent Kourier's default; each is a Go duration, and leaseDuration > renewDeadline > 1.2 x retryPeriod. See also docs/explanation/high-availability.md.

Key Default Description
leaderElection.leaseDuration "" 15s
leaderElection.renewDeadline "" 10s
leaderElection.retryPeriod "" 2s

livenessProbe

How often the kubelet asks /healthz, and how many misses in a row make it restart the container. The defaults restart a process that does not answer for about 30 seconds. A process that is frozen answers nothing, so this is also how long a paused pod is left before it is restarted.

Key Default Description
livenessProbe.periodSeconds 10
livenessProbe.failureThreshold 3

persistence

SQLite lives here (store.type sqlite; with postgres none of this is used or rendered). The claim is ReadWriteOnce and the Deployment's strategy is Recreate, so the old pod has released the volume before the new one starts.

Key Default Description
persistence.existingClaim "" Use a claim you manage instead of creating one.
persistence.dbFile courier.db The SQLite file in the volume (AGENTKOURIER_DB_PATH is /data/<dbFile>). Change it to start a fresh database beside an old one. The default predates the project's rename and is kept so that the file in an existing volume keeps its name (upgrading across the rename: docs/how-to/upgrade.md, "Upgrade across the rename").
persistence.size 1Gi
persistence.storageClassName "" Empty is the cluster's default class; "-" is an explicitly empty one.
persistence.accessModes [ReadWriteOnce]
persistence.retainOnUninstall true Keep the claim (helm.sh/resource-policy: keep) when the release is uninstalled: it holds sessions, the outbox and the dedup record. Delete it by hand when you mean to.

terminationGracePeriodSeconds

Kubernetes gives Agent Kourier up to this long after SIGTERM; its ordered shutdown takes up to 25 s.

Default: 40

podAnnotations

Default: {}

podLabels

Added to the pod. app.kubernetes.io/name and /instance cannot be changed.

Default: {}

priorityClassName

Default: ""

nodeSelector

Default: {}

tolerations

Default: []

affinity

Default: {}

podSecurityContext

Key Default Description
podSecurityContext.runAsNonRoot true
podSecurityContext.runAsUser 65532
podSecurityContext.runAsGroup 65532
podSecurityContext.fsGroup 65532
podSecurityContext.seccompProfile {type: RuntimeDefault}

securityContext

Key Default Description
securityContext.allowPrivilegeEscalation false
securityContext.readOnlyRootFilesystem true
securityContext.capabilities {drop: [ALL]}

resources

Key Default Description
resources.requests {cpu: 50m, memory: 64Mi}
resources.limits {memory: 256Mi}

rbac

Agent Kourier reads the Secrets that its config names, and the Postgres DSN's, through the API (list and watch, in a namespace-scoped Role; it never issues a get). Roles are made in each namespace that holds a referenced Secret, found from config.* above, and the release namespace with store.type postgres.

Key Default Description
rbac.create true
rbac.secretNamespaces [] More namespaces to grant that Role in. Needed with config.existingConfigMap, which the chart cannot read.

service

A ClusterIP Service on the metrics port (/metrics, and the health paths). Never published; there is nothing else to serve yet.

Key Default Description
service.enabled false
service.port 8080
service.annotations {}

serviceMonitor

A prometheus-operator ServiceMonitor for the Service (needs service.enabled).

Key Default Description
serviceMonitor.enabled false
serviceMonitor.namespace "" The namespace of the ServiceMonitor; default is the release's.
serviceMonitor.labels {} Labels your Prometheus selects ServiceMonitors by (for kube-prometheus-stack, release: <its release>).
serviceMonitor.interval 30s
serviceMonitor.scrapeTimeout 10s

networkPolicy

Fences Agent Kourier's network. Egress is the Kubernetes API server, DNS, Slack on 443 and what extraEgress adds (the agent backend, an OTLP collector); ingress is the metrics scrape and nothing else. Needs a CNI that enforces NetworkPolicy.

Key Default Description
networkPolicy.enabled false
networkPolicy.kubeApiServer.cidrs [] The API server's addresses, as the pod sees them after the Service's translation: required when enabled. A NetworkPolicy cannot select the API server by pod. Where the control plane is yours (kind, kubeadm), the addresses of kubectl get endpoints kubernetes, as /32s. On EKS those are control-plane ENI addresses that change when AWS upgrades or replaces the control plane, so give the CIDRs of the control-plane subnets instead (aws eks describe-cluster --name <cluster>, resourcesVpcConfig.subnetIds, then each subnet's CIDR). The VPC CNI enforces NetworkPolicy only with enableNetworkPolicy=true on the vpc-cni add-on; without it this policy does nothing.
networkPolicy.kubeApiServer.ports [443, 6443]
networkPolicy.dns.namespaceSelector {matchLabels: {kubernetes.io/metadata.name: kube-system}}
networkPolicy.dns.podSelector {matchLabels: {k8s-app: kube-dns}}
networkPolicy.slack.cidrs ["0.0.0.0/0"] A NetworkPolicy cannot name a host, so Slack (slack.com, wss-*.slack.com, files.slack.com) is port 443 to anywhere outside the private ranges. Put an egress proxy's address in extraEgress and narrow this to [] to close it.
networkPolicy.slack.except ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "169.254.0.0/16"]
networkPolicy.postgres The Postgres database (store.type postgres), as NetworkPolicyPeers: required when this policy is enabled with Postgres, since the Slack rule excludes private ranges and is 443 only. An ipBlock for a managed database, or the pods of an in-cluster one: to: [{namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: db}}, podSelector: {matchLabels: {app: postgres}}}] Egress is on port (the server's, 5432 by default). Behind a pooler, name the pooler.
networkPolicy.postgres.to []
networkPolicy.postgres.port 5432
networkPolicy.metricsFrom [] Who may scrape the metrics port: NetworkPolicyPeers, for example the Prometheus pods: - namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: monitoring}} podSelector: {matchLabels: {app.kubernetes.io/name: prometheus}} Empty admits nobody. Kubelet's probes are node traffic, which the CNIs we know admit regardless.
networkPolicy.extraEgress [] More egress rules, in Kubernetes' own form. The agent backend goes here, for example the front door: - to: [{namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: kagent}}, podSelector: {matchLabels: {app: kagent-frontdoor}}}] ports: [{port: 4180}]

podDisruptionBudget

Off, and meaningful with the standby (replicaCount 2 on Postgres): minAvailable: 1 keeps a drain from taking both replicas, and renders there. At one replica a budget that keeps the pod (minAvailable 1 or 100%, maxUnavailable 0) blocks every voluntary eviction, a node drain included, so the render refuses it. Set exactly one of minAvailable and maxUnavailable; with one replica only maxUnavailable: 1 renders, and that permits what it was meant to stop. A minAvailable that renders at replicaCount 0 (the kill switch) is refused again on scaling back to 1: switch the budget off, or to maxUnavailable, before scaling to zero.

Key Default Description
podDisruptionBudget.enabled false
podDisruptionBudget.minAvailable null
podDisruptionBudget.maxUnavailable null

tokenRefresh

Keeps a Binding's identity token fresh when the AgentBackend sits behind a verifying front door that takes Dex ID tokens (the sandbox tier does this, with ci/sandbox-values.yaml). An hourly CronJob asks Dex for a token with the password grant and patches it into one Secret through the API, with its own ServiceAccount, whose Role allows patch on that Secret and nothing else. The Dex credentials are read from a Secret into the Job's environment; they never pass through an argument list or this file.

The target Secret is the Binding's identity.tokenSecretRef: its name, key and namespace (the Binding's), which the render checks against the inline config. It must exist before Agent Kourier starts. After install, run the first refresh by hand:

kubectl -n <ns> create job --from=cronjob/<fullname>-token-refresh first-token
Key Default Description
tokenRefresh.enabled false
tokenRefresh.schedule 0 * * * *
tokenRefresh.targetSecret "" The Secret to patch, its key and its namespace (default: the release's), which are the Binding's identity.tokenSecretRef and the Binding's namespace. The Job's Role, in that namespace, allows patch on this one Secret.
tokenRefresh.targetKey token
tokenRefresh.targetNamespace ""
tokenRefresh.dex.tokenURL "" for example http://dex.dex.svc.cluster.local:5556/dex/token
tokenRefresh.dex.clientId ""
tokenRefresh.dex.scope openid email
tokenRefresh.dex.credentialsSecret "" A Secret in the release namespace with the keys clientSecret, username and password.
tokenRefresh.image.repository curlimages/curl
tokenRefresh.image.tag 8.11.1
tokenRefresh.image.digest sha256:c1fe1679c34d9784c1b0d1e5f62ac0a79fca01fb6377cdd33e90473c6f9f9a69
tokenRefresh.resources.requests {cpu: 10m, memory: 16Mi}
tokenRefresh.resources.limits {memory: 64Mi}

Generated by hack/docs/refgen from charts/agent-kourier/values.yaml. Do not edit this page; change the source and run make docs-ref.