Open-Source Wikis

/

Kubernetes

/

How to contribute

/

Patterns and conventions

kubernetes/kubernetes

Patterns and conventions

Cross-cutting style and design conventions used everywhere in the repo. New code is expected to follow them.

Go style

  • gofmt-clean, goimports-ordered. Enforced by verify-gofmt.sh and verify-imports.sh.
  • Standard library first, then external imports, then k8s.io/... imports, then the local module. The goimports configuration in hack/ enforces this.
  • Receiver names are short (c *Controller, not controller *Controller).
  • Exported types use full English (PodStatus, not PdSt).
  • No global state except for registries (feature gate, scheme, codec, plugin registry).
  • Error wrapping uses fmt.Errorf("...: %w", err). Use errors.Is / errors.As to unwrap, never type assertions.

API conventions

The Kubernetes API has its own conventions document. The most important rules:

  • Every object has metadata, spec, and status. spec is desired state; status is observed state. Controllers reconcile spec → status.
  • Objects are versioned per API group (apiVersion: apps/v1). Version bumps require a KEP and conversion functions.
  • Every field has a // +k8s: tag controlling codegen. Read existing types in staging/src/k8s.io/api/core/v1/types.go for the pattern.
  • Booleans are forbidden when a string enum could be used. The reason: enums grow gracefully; booleans don't.
  • omitempty on optional fields. Pointers (*string, *int32) when "unset" needs to be distinguishable from "zero".

Controller pattern

Every controller in pkg/controller/ follows this skeleton:

type FooController struct {
    client    clientset.Interface
    fooLister fooListers.FooLister
    fooSynced cache.InformerSynced
    queue     workqueue.RateLimitingInterface
}

func (c *FooController) Run(ctx context.Context, workers int) {
    defer c.queue.ShutDown()
    if !cache.WaitForCacheSync(ctx.Done(), c.fooSynced) {
        return
    }
    for i := 0; i < workers; i++ {
        go wait.UntilWithContext(ctx, c.worker, time.Second)
    }
    <-ctx.Done()
}

func (c *FooController) worker(ctx context.Context) {
    for c.processNextItem(ctx) {}
}

func (c *FooController) processNextItem(ctx context.Context) bool {
    key, quit := c.queue.Get()
    if quit {
        return false
    }
    defer c.queue.Done(key)
    err := c.syncHandler(ctx, key.(string))
    if err == nil {
        c.queue.Forget(key)
        return true
    }
    c.queue.AddRateLimited(key)
    return true
}

controller_utils.go and controller_ref_manager.go in pkg/controller/ contain helpers for Pod creation, ownership management, and expectation tracking that every controller eventually needs.

Error handling

  • Wrap, don't replace. Always preserve the underlying error so callers can errors.Is(err, ...).
  • Type a domain error when the caller will switch on it. apierrors.IsNotFound(err) from staging/src/k8s.io/apimachinery/pkg/api/errors is the canonical example.
  • Never panic in steady-state code. Bugs that should panic use runtime.HandleError or klog.Fatalf at startup.
  • Return early. Stack-arrowed code is rejected in review.

Concurrency

  • Use context.Context for cancellation and timeouts. Never time.AfterFunc for cancelling work.
  • Channels for coordination, mutexes for protecting state. Never both for the same field.
  • sync.RWMutex over sync.Mutex only when the read/write ratio is heavily skewed.
  • Goroutines must be cancelable. Bare go func(){...}() without a way to stop is a review red flag.
  • wait.UntilWithContext, wait.PollUntilContextTimeout, and wait.NonSlidingUntil from k8s.io/apimachinery/pkg/util/wait are the project's preferred polling primitives.

Logging

  • klog.V(N).InfoS("message", "key", value, ...). Use structured logging (InfoS/ErrorS), not the legacy formatted variant (Infof/Errorf).
  • klog.FromContext(ctx) to inherit context-scoped logger fields. Many controllers attach pod, namespace, and name keys to the context-bound logger.
  • Avoid logging at level 0 from steady-state loops; that's reserved for genuine errors.

Metrics

  • Use k8s.io/component-base/metrics (the metrics.Gauge, metrics.Counter, metrics.Histogram constructors). Don't import Prometheus directly except in code that wires up the registry.
  • New metrics need a STABLE/BETA/ALPHA stability marker.
  • Metrics names must follow the existing pattern (apiserver_request_duration_seconds, kubelet_pod_start_duration_seconds). Lower snake_case, base-unit suffix.

Feature gates

  • Add a constant in pkg/features/kube_features.go (or the equivalent file in staging/src/k8s.io/apiserver/pkg/features).
  • Wrap the new code path in utilfeature.DefaultFeatureGate.Enabled(features.MyFeature).
  • Default false for alpha; flip to true and document graduation at beta.
  • Remove the gate (and the unconditional code path) at GA.

Cross-cutting concerns

  • Don't import from k8s.io/kubernetes/pkg/... into staging modules. The dependency arrow only goes the other way. The lint script staging/publishing/... enforces this.
  • Don't import pkg/api/v1 directly. Use k8s.io/api/core/v1. The pkg/api/ tree is the internal hub-and-spoke versioning surface, not a public type set.
  • Don't add new top-level directories. New code finds a home under pkg/, cmd/, staging/src/k8s.io/, or test/.
  • Don't break existing compatibility. Field renames, enum reorderings, and serialization changes are forbidden on stable types.

Imports

  • _ "time/tzdata" is imported by cmd/kube-apiserver/apiserver.go and cmd/kube-controller-manager/controller-manager.go to embed the time-zone database for CronJobs.
  • _ "k8s.io/component-base/logs/json/register" registers the JSON log format on every binary.
  • _ "k8s.io/component-base/metrics/prometheus/clientgo" registers client-go Prometheus collectors.

These blank imports are part of the boot ritual and must be present in every new component binary.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Kubernetes wiki | Factory