Fading Coder

An Old Coder’s Final Dance

Home > Tech > Content

Generating CRDs with Kubebuilder and k8s.io/code-generator

Tech 3

This guide shows how to combine two toolchains to build CustomResourceDefinitions (CRDs) and typed clients:

  • Use Kubebuilder to scaffold API types and CRD/manifests
  • Use k8s.io/code-generator to produce clientsets, listers, and informers

This workflow is useful when you don’t need a controller/operator but still want Kubernetes-style APIs and typed clients.

Prerequisites

  • Go 1.18+
  • Kubebuilder installed
  • A working Kubernetes cluster or kubeconfig for applying CRDs

1. Initialize a project with Kubebuilder

MODULE=example.com/gb-controller

go mod init "$MODULE"
kubebuilder init --domain example.com
kubebuilder edit --multigroup=true

You should see a structure similar to:

.
├── Dockerfile
├── Makefile
├── PROJECT
├── bin
│   └── manager
├── config
│   ├── certmanager
│   ├── default
│   ├── manager
│   ├── prometheus
│   ├── rbac
│   └── webhook
├── hack
│   └── boilerplate.go.txt
└── main.go

2. Create API types and manifests

Scaffold the API group/version and kind without a controller:

kubebuilder create api --group webapp --version v1 --kind Guestbook
# Create Resource: y
# Create Controller: n

New files will be created under apis and config:

.
├── apis
│   └── webapp
│       └── v1
│           ├── groupversion_info.go
│           ├── guestbook_types.go
│           └── zz_generated.deepcopy.go
└── config
    ├── crd
    │   ├── kustomization.yaml
    │   ├── kustomizeconfig.yaml
    │   └── patches
    │       ├── cainjection_in_guestbooks.yaml
    │       └── webhook_in_guestbooks.yaml
    ├── rbac
    │   ├── guestbook_editor_role.yaml
    │   ├── guestbook_viewer_role.yaml
    └── samples
        └── webapp_v1_guestbook.yaml

Add RBAC markers for aggregated RBAC generasion:

Create apis/webapp/v1/rbac.go:

// +kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks,verbs=list;watch;get;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.example.com,resources=guestbooks/status,verbs=get;patch;update

package v1

Generate CRD and RBAC manifests:

make manifests

You should see:

config
├── crd
│   └── bases
│       └── webapp.example.com_guestbooks.yaml
└── rbac
    └── role.yaml

Note: When you edit apis/webapp/v1/guestbook_types.go, regenerate code and manifests:

make generate && make manifests

3. Produce clients, listers, and informers with code-generator

3.1 Create codegen helper scripts

Add the folllowing files under hack:

./hack
├── tools.go
├── update-codegen.sh
└── verify-codegen.sh

hack/tools.go:

//go:build tools
// +build tools

package tools

import (
	_ "k8s.io/code-generator"
)

hack/update-codegen.sh (adjust variables to match your module and package layout):

#!/usr/bin/env bash
set -euo pipefail

# Go module path (same value used in: go mod init <module>)
MODULE_PATH=example.com/gb-controller

# API package containing your types
API_PKG=apis

# Where to write generated client code (import path will be ${MODULE_PATH}/${OUT_PKG})
OUT_PKG=generated/webapp

# Space-separated list of group:version pairs to generate for
gv_list=("webapp:v1")
GVs=$(IFS=' '; echo "${gv_list[*]}")

ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${ROOT_DIR}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}

# Ensure the generator is runnable
chmod +x "${CODEGEN_PKG}/generate-groups.sh"

# Write generated code next to the repo to avoid touching GOPATH
bash "${CODEGEN_PKG}/generate-groups.sh" "client,lister,informer" \
  "${MODULE_PATH}/${OUT_PKG}" "${MODULE_PATH}/${API_PKG}" \
  ${GVs} \
  --go-header-file "${ROOT_DIR}/hack/boilerplate.go.txt" \
  --output-base "${ROOT_DIR}"

hack/verify-codegen.sh can simply check for a clean git tree after running update-codegen.sh.

3.2 Add code-generator and align dependencies

Choose a Kubernetes release and use the same version for client-go, apimachinery, and code-generator. For example:

K8S_VERSION=v0.18.5

go get k8s.io/code-generator@${K8S_VERSION}
go get k8s.io/client-go@${K8S_VERSION}
go get k8s.io/apimachinery@${K8S_VERSION}

go get sigs.k8s.io/controller-runtime@v0.6.0

go mod vendor

If needed, ensure generate-groups.sh is executable inside vendor:

chmod +x vendor/k8s.io/code-generator/generate-groups.sh

3.3 Annotate types and add supporting files

In apis/webapp/v1/guestbook_types.go, add the genclient marker to the top-level type:

// +genclient
// +kubebuilder:object:root=true

// Guestbook is the Schema for the guestbooks API
type Guestbook struct {
    // ... existing fields
}

Create apis/webapp/v1/doc.go with the group name:

// +groupName=webapp.example.com

package v1

Create apis/webapp/v1/register.go to support client code:

package v1

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

// SchemeGroupVersion is used to register these objects with a scheme.
var SchemeGroupVersion = GroupVersion

// Resource returns a GroupResource for the given resource name.
func Resource(res string) schema.GroupResource {
	return SchemeGroupVersion.WithResource(res).GroupResource()
}

3.4 Generate clients, listers, and informers

Run the codegen script:

./hack/update-codegen.sh

The generated code will appear under your module path, for example:

example.com
└── gb-controller
    └── generated
        └── webapp
            ├── clientset
            ├── informers
            └── listers

You may move the generated directory too your preferred location (e.g., project root or pkg/generated) and update imports accordingly.

4. Try it out

Apply the CRD and a sample instance:

kubectl apply -f config/crd/bases/webapp.example.com_guestbooks.yaml
kubectl apply -f config/samples/webapp_v1_guestbook.yaml

Run you're main program or integrate the generated client into your application to list or watch Guestbook resources.

Tags: Kubernetes

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.