runtime package

runtime is a standard library package. It talks to the hidden engine that actually runs your Go program — goroutines, the scheduler, memory, and garbage collection.

import "runtime"

Why is it used?

You want to know / do Use
Which OS / CPU is this binary on? runtime.GOOS, runtime.GOARCH
How many CPUs? How many workers? NumCPU(), GOMAXPROCS()
Are we leaking goroutines? NumGoroutine()
How much heap? Force a GC? ReadMemStats(), GC()

OS and CPU (constants)

These are set at compile time. Same values you would pass as GOOS / GOARCH when cross-compiling.

package main

import (
    "fmt"
    "runtime"
)

func main() {
    fmt.Println(runtime.GOOS)   // linux, windows, darwin
    fmt.Println(runtime.GOARCH) // amd64, arm64
}

Kubernetes runtime.NewScheme() (different package)

scheme := runtime.NewScheme() is not from Go’s standard library. It comes from k8s.io/apimachinery/pkg/runtime — the package controller-runtime and client-go use to encode and decode Kubernetes objects.

import (
    "k8s.io/apimachinery/pkg/runtime"
)

What does “Scheme” mean?

A Scheme is a phone book of types. Kubernetes talks in YAML/JSON using apiVersion + kind. Go talks in structs. The Scheme maps one to the other:

YAML/JSON                         Go struct
---------                         ---------
apiVersion: v1             <-->   *corev1.Pod
kind: Pod

apiVersion: apps/v1        <-->   *appsv1.Deployment
kind: Deployment

apiVersion: demo.io/v1     <-->   *demov1.Widget   (your CRD)
kind: Widget

Without a Scheme, the client sees kind: Widget and does not know which Go type to put the bytes into. Typical error: no kind "Widget" is registered for version "demo.io/v1".

What runtime.NewScheme() does

It creates an empty phone book. Nothing is registered yet — not even Pod. You then fill it with AddToScheme(scheme) for every API group you will read or write.

scheme := runtime.NewScheme() // empty book

// Register built-in types (Pod, Service, Deployment, ...)
utilruntime.Must(clientgoscheme.AddToScheme(scheme))

// Register your CRD types
utilruntime.Must(demov1.AddToScheme(scheme))

After that you pass scheme into the Manager or client so every Get / List / Update can encode and decode those types.

Very simple example

Goal: decode this YAML into a real Go Pod struct. That works only after Pod is registered on the Scheme.

package main

import (
    "fmt"

    corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/serializer"
    clientgoscheme "k8s.io/client-go/kubernetes/scheme"
)

func main() {
    // 1. Empty phone book
    scheme := runtime.NewScheme()

    // 2. Teach it: kind Pod + apiVersion v1 → *corev1.Pod
    if err := clientgoscheme.AddToScheme(scheme); err != nil {
        panic(err)
    }

    yamlBytes := []byte(`
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
`)

    // 3. Decoder uses the Scheme to pick the Go type
    decoder := serializer.NewCodecFactory(scheme).UniversalDeserializer()
    obj, gvk, err := decoder.Decode(yamlBytes, nil, nil)
    if err != nil {
        panic(err)
    }

    pod := obj.(*corev1.Pod)
    fmt.Println("decoded kind:", gvk.Kind) // Pod
    fmt.Println("pod name:", pod.Name)     // nginx
}

Comment out AddToScheme and the same YAML fails — the empty Scheme does not know what a Pod is.

Same Scheme in a controller

Operators do the same thing once at startup, then hand the Scheme to controller-runtime:

var scheme = runtime.NewScheme()

func init() {
    utilruntime.Must(clientgoscheme.AddToScheme(scheme))
    utilruntime.Must(demov1.AddToScheme(scheme)) // your CRD
}

func main() {
    mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme: scheme, // Manager + cache + client all share this book
    })
    // ...
}