Skip to main content

GatewaySync CR Reference

The GatewaySync custom resource defines the git repository to sync from, authentication, polling behavior, gateway connection settings, sync profiles, and agent configuration.

apiVersion: stoker.io/v1alpha1
kind: GatewaySync
metadata:
name: my-gatewaysync
namespace: my-namespace
spec:
git:
repo: "https://github.com/org/repo.git"
ref: "main"
auth:
token:
secretRef:
name: git-token
key: token
polling:
enabled: true
interval: "60s"
gateway:
port: 8088
tls: false
api:
secretName: gw-api-key
sync:
defaults:
excludePatterns:
- "**/.git/"
- "**/.gitkeep"
- "**/.resources/**"
syncPeriod: 30
designerSessionPolicy: proceed
profiles:
standard:
mappings:
- source: "services/{{.GatewayName}}/projects/"
destination: "projects/"
type: dir
required: true
- source: "services/{{.GatewayName}}/config/"
destination: "config/"
type: dir
syncPeriod: 60
designerSessionPolicy: wait
agent:
image:
repository: ghcr.io/ia-eknorr/stoker-agent
tag: latest
pullPolicy: IfNotPresent
paused: false

spec.git

FieldTypeRequiredDefaultDescription
repostringYesGit repository URL (SSH or HTTPS)
refstringYesGit reference to sync — branch, tag, or commit SHA
authobjectNoGit authentication configuration

spec.git.auth

Exactly one authentication method should be specified. Omit entirely for public repositories.

Token authentication

auth:
token:
secretRef:
name: git-token
key: token
FieldTypeRequiredDescription
token.secretRef.namestringYesName of the Secret
token.secretRef.keystringYesKey within the Secret

SSH key authentication

auth:
sshKey:
secretRef:
name: ssh-key
key: id_ed25519
knownHosts: # optional — enables host key verification
secretRef:
name: ssh-known-hosts
key: known_hosts
FieldTypeRequiredDescription
sshKey.secretRef.namestringYesName of the Secret containing the SSH private key
sshKey.secretRef.keystringYesKey within the Secret
sshKey.knownHosts.secretRef.namestringNoName of a Secret containing SSH known_hosts data
sshKey.knownHosts.secretRef.keystringNoKey within the known_hosts Secret

When knownHosts is omitted, SSH connections use InsecureIgnoreHostKey (no MITM protection). The controller sets a SSHHostKeyVerification=False warning condition to flag this. See the Git Authentication guide for setup instructions.

GitHub App authentication

auth:
githubApp:
appId: 12345
installationId: 67890
privateKeySecretRef:
name: github-app-key
key: private-key.pem
apiBaseURL: "https://github.example.com/api/v3" # optional, for GitHub Enterprise
FieldTypeRequiredDefaultDescription
githubApp.appIdintegerYesGitHub App ID
githubApp.installationIdintegerYesGitHub App installation ID
githubApp.privateKeySecretRef.namestringYesName of the Secret containing the PEM key
githubApp.privateKeySecretRef.keystringYesKey within the Secret
githubApp.apiBaseURLstringNohttps://api.github.comGitHub API base URL (set for GitHub Enterprise Server)

The controller exchanges the PEM private key for a short-lived installation access token (1-hour expiry), caches it with a 5-minute pre-expiry refresh, and writes it to a controller-managed Secret (stoker-github-token-{crName}). The agent mounts this Secret at /etc/stoker/git-token/token. The PEM key never leaves the controller namespace — agent pods do not mount the PEM secret.

spec.polling

FieldTypeRequiredDefaultDescription
enabledboolNotrueWhether periodic polling for git changes is active
intervalstringNo"60s"Polling period (e.g., "60s", "5m")
tip

If you configure a webhook receiver for push-event-driven sync, you can set polling.enabled: false or increase the interval to reduce API calls.

spec.gateway

FieldTypeRequiredDefaultDescription
portint32No8088Ignition gateway API port
tlsboolNofalseEnable TLS for gateway API connections
api.secretNamestringYesName of the Secret containing the Ignition API key
api.secretKeystringNo"apiKey"Key within the Secret

spec.sync

The sync section contains baseline defaults and named profiles.

spec.sync.defaults

Baseline settings inherited by all profiles. Individual profiles can override these values.

FieldTypeRequiredDefaultDescription
excludePatterns[]stringNo["**/.git/", "**/.gitkeep", "**/.resources/**"]Glob patterns for files to exclude from sync
varsmap[string]stringNoDefault template variables inherited by all profiles. Profile vars override these per-key. Keys must be valid identifiers (letters, digits, underscores — no dashes).
syncPeriodint32No30Agent-side polling interval in seconds (min: 5, max: 3600)
designerSessionPolicystringNo"proceed"Behavior when Designer sessions are active: proceed, wait, or fail
dryRunboolNofalseSync to staging only — write diff to status ConfigMap without modifying /ignition-data/
pausedboolNofalseHalt sync for all profiles

The **/.resources/** pattern is always enforced by the agent even if omitted from excludePatterns.

spec.sync.profiles

A map of named sync profiles. Each key is the profile name, referenced by the stoker.io/profile pod annotation. Gateways without a stoker.io/profile annotation use the profile named default if one exists.

sync:
profiles:
standard:
mappings:
- source: "services/{{.GatewayName}}/projects/"
destination: "projects/"
type: dir
required: true
syncPeriod: 60
minimal:
mappings:
- source: "config/"
destination: "config/"
type: dir

Each profile supports the following fields:

FieldTypeRequiredDefaultDescription
mappings[]objectYesOrdered list of source-to-destination file mappings
excludePatterns[]stringNoAdditional glob patterns merged with spec.sync.defaults.excludePatterns
varsmap[string]stringNoCustom template variables available as {{.Vars.key}}. Keys must be valid identifiers (letters, digits, underscores — no dashes).
syncPeriodint32NoinheritedOverrides spec.sync.defaults.syncPeriod
dryRunboolNoinheritedOverrides spec.sync.defaults.dryRun
designerSessionPolicystringNoinheritedOverrides spec.sync.defaults.designerSessionPolicy
pausedboolNoinheritedOverrides spec.sync.defaults.paused

Mappings

An ordered list of source-to-destination file mappings. Applied top to bottom; later mappings overlay earlier ones.

FieldTypeRequiredDefaultDescription
sourcestringYesRepo-relative path to copy from
destinationstringYesPath relative to the Ignition data directory (/ignition-data/)
typestringNoinferredEntry type — "dir" or "file". When omitted the agent infers the type from the filesystem at sync time.
requiredboolNofalseFail sync if the source path doesn't exist
templateboolNofalseResolve Go template variables inside file contents at sync time. Binary files (null bytes) are rejected. See Content Templating.
patches[]objectNoTargeted JSON field updates applied at sync time. See JSON Patches.
note

type is inferred from os.Stat on the source path — no default value is required in the CR. If you set it explicitly, it acts as a validation hint: the agent errors if the actual filesystem type doesn't match. A source that doesn't exist (when required: false) defaults to "dir" and is silently skipped.

patches

Each entry in patches applies one set of JSON field updates to files matched by the file glob:

FieldTypeRequiredDescription
filestringNoPath relative to the mapping's destination. Supports doublestar globs (**/*.json). For file mappings (type: file), omit to target the mapped file itself.
setmap[string]stringYessjson dot-notation paths to values. Values support Go template syntax (same variables as template: true).
mappings:
- source: "config/resources/ignition/core"
destination: "config/resources/ignition/core"
patches:
- file: "system-properties/config.json"
set:
systemName: "{{ .GatewayName }}"
httpPort: "{{ .Vars.gatewayPort }}"
- file: "db-connections/*.json"
set:
connection.host: "{{ .Vars.dbHost }}"

See the JSON Patches guide for full examples, type inference rules, and path syntax.

Template variables

Both source and destination support Go template variables:

VariableDescriptionExample
{{.GatewayName}}Gateway identity from the stoker.io/gateway-name annotation (or app.kubernetes.io/name label)sites/{{.GatewayName}}/projects
{{.PodName}}Kubernetes pod namesystem-{{.PodName}}
{{.PodOrdinal}}StatefulSet replica index (0, 1, 2, ...). Always 0 for non-StatefulSet pods. Sourced from the apps.kubernetes.io/pod-index label (K8s 1.27+) with pod-name fallback."{{.Vars.projectName}}-{{.PodOrdinal}}"
{{.CRName}}Name of the GatewaySync CR that owns this syncconfig/{{.CRName}}/resources
{{.Labels.key}}Any label on the gateway pod — key must be a simple identifier (letters, digits, underscores). See note below.sites/{{.Labels.site}}/projects
{{.Vars.key}}Custom variable from profile or defaults vars (profile overrides default per-key)site{{.Vars.siteNumber}}/scripts
{{.Namespace}}Pod namespaceconfig/{{.Namespace}}/overlay
{{.Ref}}Resolved git ref
{{.Commit}}Full commit SHA

Using {{.GatewayName}} or {{.Labels.key}} in source paths lets a single profile serve multiple gateways, each syncing from its own directory in the repo.

Example: StatefulSet replica systemName with {{.PodOrdinal}}

For StatefulSets with multiple replicas, use {{.PodOrdinal}} to produce a unique, stable name per replica:

sync:
defaults:
vars:
projectName: "my-gateway" # key must be a valid identifier
profiles:
frontend:
mappings:
- source: "config/system-properties"
destination: "config/system-properties"
type: dir
patches:
- file: "config.json"
set:
systemName: "{{.Vars.projectName}}-{{.PodOrdinal}}"
# → my-gateway-0, my-gateway-1, my-gateway-2, ...

The - between }} and {{ is literal text outside the template delimiters — this is valid syntax even though dashes cannot appear inside {{ }}.

Example: label-based routing

Add a site label to each gateway pod and use it in the profile:

sync:
profiles:
standard:
mappings:
- source: "services/{{.Labels.site}}/projects/"
destination: "projects/"
type: dir
required: true
- source: "services/{{.Labels.site}}/config/"
destination: "config/"
type: dir

A pod with label site: ignition-blue syncs from services/ignition-blue/, while site: ignition-red syncs from services/ignition-red/ — same profile, different files.

note

Label and var key naming constraint: Go's template engine requires map keys to be valid identifiers when accessed with dot notation. Keys must use only letters, digits, and underscores — dashes, dots, and slashes are not supported.

  • {{.Labels.site}} ✅ — simple identifier
  • {{.Labels.my-label}} ❌ — parse error (bad character '-')
  • {{.Labels.app.kubernetes.io}} ❌ — silently looks up key "app", not "app.kubernetes.io"

For K8s system labels with dots or slashes (e.g., apps.kubernetes.io/pod-index), use {{.PodOrdinal}} or a vars entry instead of {{.Labels.*}}.

The same constraint applies to vars keys: {{.Vars.myVar}} ✅, {{.Vars.my-var}} ❌. The controller rejects CRs with invalid var keys at reconcile time with a clear status condition.

{{.Labels.key}} reads from the pod's Kubernetes labels at sync time. The agent needs get permission on pods (included in the agent ClusterRole).

Designer session policy

Controls sync behavior when Ignition Designer sessions are active on the gateway. Can be set at the defaults level or overridden per profile.

ValueBehavior
proceed (default)Logs a warning and continues the sync
waitRetries until sessions close (up to 5 minutes)
failAborts the sync

spec.agent

FieldTypeRequiredDefaultDescription
image.repositorystringNoghcr.io/ia-eknorr/stoker-agentAgent container image repository
image.tagstringNolatestAgent container image tag
image.pullPolicystringNoIfNotPresentImage pull policy
resourcesobjectNoAgent container resource requirements

spec.paused

When set to true, halts all sync operations. The controller continues to reconcile and resolve refs, but agents will not perform syncs.

Pod Annotations

Gateways are discovered by pod annotations. These are typically set via podAnnotations in the Ignition Helm chart values:

AnnotationRequiredDescription
stoker.io/injectYesSet to "true" to trigger sidecar injection
stoker.io/cr-nameYesName of the GatewaySync CR to sync from
stoker.io/profileNoName of the sync profile to use (from spec.sync.profiles). Falls back to default if unset.
stoker.io/gateway-nameNoOverride gateway identity (defaults to pod label app.kubernetes.io/name)

Status

The GatewaySync CR status is managed by the controller and reports:

FieldDescription
lastSyncRefThe git ref that was last resolved
lastSyncCommitFull 40-character git commit SHA
lastSyncCommitShortAbbreviated 7-character commit SHA (used in printer columns)
lastSyncTimeTimestamp of the last commit change (only updates when the resolved commit changes)
refResolutionStatusNotResolved, Resolving, Resolved, or Error
profileCountNumber of profiles defined in spec.sync.profiles
discoveredGatewaysList of gateway pods with per-gateway sync status, commit, projects synced
conditionsStandard Kubernetes conditions: RefResolved, AllGatewaysSynced, and Ready

Printer columns

kubectl get gs shows these columns by default:

NAME         REF    GATEWAYS     READY   STATUS              AGE
my-gateway main 1/1 synced True All gateways synced 5m

kubectl get gs -o wide adds COMMIT, PROFILES, and LAST SYNC.

Sync status lifecycle

Gateways progress through these sync states:

  1. Pending — initial sync completes (files written) but gateway hasn't been validated yet
  2. Synced — the Ignition scan API confirmed both /scan/projects and /scan/config returned HTTP 200
  3. Error — the scan API returned a non-200 status or was unreachable

The AllGatewaysSynced condition is True only when all discovered gateways report Synced.

Conditions

TypeDescription
RefResolvedThe controller successfully resolved the git ref to a commit SHA
ProfilesValidAll embedded profiles pass validation (no path traversal, no absolute paths)
AllGatewaysSyncedAll discovered gateway pods report Synced status
SidecarInjectedAll discovered gateway pods have the stoker-agent sidecar container
SSHHostKeyVerificationSSH host key verification status — True when knownHosts is configured, False (warning) when SSH auth is used without it. Only present on CRs using SSH key authentication.
ReadyRefResolved, ProfilesValid, and AllGatewaysSynced are all True