v1.40.0
Upgrade OPM version to v1.55.0 in the Makefile
Update the OPM version in your Makefile to v1.55.0
:
-const opmVersion = "v1.23.0"
+const opmVersion = "v1.55.0"
- curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
+ curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.55.0/$${OS}-$${ARCH}-opm ;\
See #6953 for more details.
Add a devcontainer for Go-based operators
Create the devcontainer configuration in the root of the repository
under .devcontainer
.
- Create a new directory called
.devcontainer
in the root of your project. - Copy the contents of the testdata/go/v4/memcached-operator/.devcontainer
available in the Operator SDK repository for the tag release
v1.40.0
.
See #6928 for more details.
Add new GitHub actions for Go-based operators
Add the actions configuration in the .github/workflows
directory.
The new actions are:
- lint.yaml: Lint the code using golangci-lint
- test.yaml: Run the tests using go test
- test-e2e.yaml: Run the e2e tests using go test
You can obtain this configuration to be added
to your project by looking at the files available
in
testdata/go/v4/memcached-operator/.github/workflows
for this release. testdata/go/v4/memcached-operator/.github/workflows
See #6928 for more details.
Update your project to properly support TLS certificates for webhooks and metrics server
- Update the
main.go
file in your project to support TLS certificates for webhooks and metrics server.
-
Add the new flag definitions to accept custom certificate file paths and names:
func main() { ... var metricsCertPath, metricsCertName, metricsCertKey string var webhookCertPath, webhookCertName, webhookCertKey string ... flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.") flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.") flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.") flag.StringVar(&metricsCertPath, "metrics-cert-path", "", "The directory that contains the metrics server certificate.") flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.") flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
-
After this conditional check:
if !enableHTTP2 { tlsOpts = append(tlsOpts, disableHTTP2) }
Insert the following code to configure certificate watchers for webhooks and metrics:
var metricsCertWatcher, webhookCertWatcher *certwatcher.CertWatcher webhookTLSOpts := tlsOpts if len(webhookCertPath) > 0 { setupLog.Info("Initializing webhook certificate watcher using provided certificates", "webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey) var err error webhookCertWatcher, err = certwatcher.New( filepath.Join(webhookCertPath, webhookCertName), filepath.Join(webhookCertPath, webhookCertKey), ) if err != nil { setupLog.Error(err, "Failed to initialize webhook certificate watcher") os.Exit(1) } webhookTLSOpts = append(webhookTLSOpts, func(config *tls.Config) { config.GetCertificate = webhookCertWatcher.GetCertificate }) }
-
Update the webhook server TLS options:
Replace:
TLSOpts: tlsOpts,
With:
TLSOpts: webhookTLSOpts,
-
Before initializing the manager, configure the metrics certificate watcher if metrics certs are provided:
if len(metricsCertPath) > 0 { setupLog.Info("Initializing metrics certificate watcher using provided certificates", "metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey) var err error metricsCertWatcher, err = certwatcher.New( filepath.Join(metricsCertPath, metricsCertName), filepath.Join(metricsCertPath, metricsCertKey), ) if err != nil { setupLog.Error(err, "Failed to initialize metrics certificate watcher") os.Exit(1) } metricsServerOptions.TLSOpts = append(metricsServerOptions.TLSOpts, func(config *tls.Config) { config.GetCertificate = metricsCertWatcher.GetCertificate }) } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ ... })
-
Before calling
AddHealthzCheck
, ensure the certificate watchers are registered with the manager:if metricsCertWatcher != nil { setupLog.Info("Adding metrics certificate watcher to manager") if err := mgr.Add(metricsCertWatcher); err != nil { setupLog.Error(err, "Unable to add metrics certificate watcher to manager") os.Exit(1) } } if webhookCertWatcher != nil { setupLog.Info("Adding webhook certificate watcher to manager") if err := mgr.Add(webhookCertWatcher); err != nil { setupLog.Error(err, "Unable to add webhook certificate watcher to manager") os.Exit(1) } } if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "Unable to set up health check") os.Exit(1) }
Note that you can use as reference the main.go
file available in the
Operator SDK repository for the tag release v1.40.0
to see how the code should look like,
see: testdata/go/v4/memcached-operator/cmd/main.go
- Add the new certificates in the
config/certmanager
directory:
-
Add the new files:
certificate-metrics.yaml
with the content: testdata/go/v4/memcached-operator/config/certmanager/certificate-metrics.yamlissuer.yaml
with the content: testdata/go/v4/memcached-operator/config/certmanager/issuer.yaml
-
Rename certificate.yaml to
certificate-webhook.yaml
-
Update the
kustomization.yaml
file to include the new files and remove the old ones: Replace:- certificate.yaml
With:
resources: - certificate-metrics.yaml - certificate-webhook.yaml - issuer.yaml
NOTE: You can see the complete file in the repository for the tag release
v1.40.0
: testdata/go/v4/memcached-operator/config/certmanager/kustomization.yaml
- Update the
config/default/kustomization.yaml
to allow work with the new options:
Under patches
ensure that you have:
patches:
...
# Uncomment the patches line if you enable Metrics and CertManager
# [METRICS-WITH-CERTS] To enable metrics protected with certManager, uncomment the following line.
# This patch will protect the metrics with certManager self-signed certs.
- path: cert_metrics_manager_patch.yaml
target:
kind: Deployment
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
- path: manager_webhook_patch.yaml
target:
kind: Deployment
...
Under the replacements section, replace:
- source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs
kind: Certificate
group: cert-manager.io
version: v1
name: serving-cert # this name should match the one in certificate.yaml
fieldPath: .metadata.namespace # namespace of the certificate CR
targets:
- select:
kind: ValidatingWebhookConfiguration
fieldPaths:
- .metadata.annotations.[cert-manager.io/inject-ca-from]
options:
delimiter: '/'
index: 0
create: true
- select:
kind: MutatingWebhookConfiguration
fieldPaths:
- .metadata.annotations.[cert-manager.io/inject-ca-from]
options:
delimiter: '/'
index: 0
create: true
- select:
kind: CustomResourceDefinition
fieldPaths:
- .metadata.annotations.[cert-manager.io/inject-ca-from]
options:
delimiter: '/'
index: 0
create: true
With: the code from Kubebuilder samples testdata/project-v4/config/default/kustomization.yaml
NOTE: You can see the complete file in the repository for the tag release v1.40.0
: testdata/go/v4/memcached-operator/config/default/kustomization.yaml
- Add the new file to allow patch the certs for the metrics: testdata/go/v4/memcached-operator/config/default/cert_metrics_manager_patch.yaml
- Replace the content of
config/default/manager_webhook_patch.yaml
with: testdata/go/v4/memcached-operator/config/default/config/default/manager_webhook_patch.yaml - Update the
config/manager/manager.yaml
to include the ports and volumes to allow the patch to work properly:
...
env:
- name: MEMCACHED_IMAGE
value: memcached:1.4.36-alpine
+ ports: []
...
...
requests:
cpu: 10m
memory: 64Mi
+ volumeMounts: []
+ volumes: []
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10
...
See #6928 for more details.
Update your project to properly support TLS for Prometheus scraping
Changes required under the hood config/prometheus/
-
- Update the
config/prometheus/kutomization.yaml
add at the bottom:
- Update the
# [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus
# to securely reference certificates created and managed by cert-manager.
# Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml
# to mount the "metrics-server-cert" secret in the Manager Deployment.
#patches:
# - path: monitor_tls_patch.yaml
# target:
# kind: ServiceMonitor
-
- Add the file config/prometheus/monitor_tls_patch.yaml to do the patch for the ServiceMonitor.
See #6928 for more details.
Update your project to properly support CA injection for CRDs with conversion webhooks
Changes required under the hood config/crd/
-
- Update the
config/crd/kustomization.yaml
for the file to include the new marker+kubebuilder:scaffold:crdkustomizewebhookpatch
for the tool be able to inject the path for any new CRD that is created with the--conversion
flag.
- Update the
-
- Ensure that under the patches section you have only patches for the CRDs which
are created with the
--conversion
flag.
- Ensure that under the patches section you have only patches for the CRDs which
are created with the
-
- Remove the files prefixed with
cainjection_<kind>.yaml
. You should have only the files prefixed withwebhookpatch_<kind>.yaml
for the CRDs that have the--conversion
flag. (example)
- Remove the files prefixed with
Changes required under the hood config/default/
-
- Update the
config/default/kustomization.yaml
for the file to include the new marker+kubebuilder:scaffold:crdkustomizecainjectionns
for the tool be able to inject for any new CRD that is created with the--conversion
flag as well to have commented the default replacement. For further information see an example in Kubebuilder testdata samples testdata/project-v4/config/default/kustomization.yaml.
- Update the
NOTE: You can see the complete file in the repository for the tag release v1.40.0
: testdata/go/v4/memcached-operator/config/default/kustomization.yaml
See #6928 for more details.
Use .Named("<Kind>")
in SetupWithManager for controller registration
To improve clarity and avoid naming collisions in multi-group Go-based operator projects,
each controller’s SetupWithManager
call now includes an explicit .Named("<Kind>")
declaration.
Example change:
func (r *DeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&appsv1.Deployment{}).
Named("apps-deployment").
Complete(r)
}
This ensures controller names are unique and consistent across different APIs in multi-group scenarios, which improves controller lifecycle management and logging.
See #6928 for more details.
ENVTEST version automation and improved test binary discovery
The SDK now automates the setup of ENVTEST for Go-based operators by dynamically deriving
the required versions from go.mod
rather than requiring manual updates in the Makefile.
- Update the
Makefile
:
- The variables
ENVTEST_VERSION
andENVTEST_K8S_VERSION
are now computed usinggo list
:ENVTEST_VERSION := $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller-runtime | awk -F'[v.]' '{printf "release-%d.%d", $$2, $$3}') ENVTEST_K8S_VERSION := $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
- A new target
setup-envtest
was introduced to automatically install the binaries:.PHONY: setup-envtest setup-envtest: @$(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path || { \ echo "Error setting up envtest"; exit 1; }
- The
test
target now depends onsetup-envtest
to ensure binaries are ready before running tests.
- Update the suite_test.go files for controllers and webhooks:
In each
internal/controller/suite_test.go
andinternal/webhook/<version>/webhook/suite_test.go
file:
- A new helper function
getFirstFoundEnvTestBinaryDir()
was added:func getFirstFoundEnvTestBinaryDir() string { basePath := filepath.Join("..", "..", "..", "bin", "k8s") entries, err := os.ReadDir(basePath) if err != nil { logf.Log.Error(err, "Failed to read directory", "path", basePath) return "" } for _, entry := range entries { if entry.IsDir() { return filepath.Join(basePath, entry.Name()) } } return "" }
testEnv.BinaryAssetsDirectory
now uses this helper to locate installed ENVTEST binaries:testEnv = &envtest.Environment{ BinaryAssetsDirectory: getFirstFoundEnvTestBinaryDir(), ... }
See #6928 for more details.
Replace exportloopref
with copyloopvar
in .golangci.yaml
The exportloopref
linter has been deprecated in recent versions of GolangCI-Lint.
It is now replaced with the more accurate and actively maintained copyloopvar
linter.
Update your .golangci.yaml
file by replacing:
- exportloopref
With:
- copyloopvar
See #6928 for more details.
Add lint-config
target to Makefile to verify linter configuration
The target uses the config verify
subcommand provided by golangci-lint
:
.PHONY: lint-config
lint-config: golangci-lint ## Verify golangci-lint linter configuration
$(GOLANGCI_LINT) config verify
See #6928 for more details.
Upgrade to Go 1.23 and Kubernetes v0.32.1 dependencies
- Update your
go.mod
to reflect the new versions:
go 1.23
require (
github.com/onsi/ginkgo/v2 v2.22.0
github.com/onsi/gomega v1.36.1
k8s.io/api v0.32.1
k8s.io/apimachinery v0.32.1
k8s.io/client-go v0.32.1
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
sigs.k8s.io/controller-runtime v0.20.4
)
- Update the Go toolchain in your
Dockerfile
to match:
FROM golang:1.23 AS builder
See #6928 for more details.
You must change your webhooks implementation to be able to use controller-runtime v0.20.0+
If you have no webhooks, you can skip this migration. Otherwise, ensure that you check the described
steps to update your project in the release notes of Kubebuilder v4.3.0
release: https://github.com/kubernetes-sigs/kubebuilder/releases/tag/v4.3.0
See #6928 for more details.
Add app.kubernetes.io/name
label to your manifests
The Operator SDK now adds the app.kubernetes.io/name
label to scaffolded Kubernetes
manifests such as Deployments, Services, and RBAC resources. This label aligns with
Kubernetes labeling conventions and improves compatibility with observability and automation tools.
If upgrading from a previous version, you may want to add the following label manually to your existing manifests:
metadata:
labels:
app.kubernetes.io/name: <your-app-name>
See #6928 for more details.
With you wish manually add those roles to your project
See the permissions and RBAC generate as an example to know how properly
create those files for each CRD you have in your project by looking at the
sample in the repository for the tag release v1.40.0
: testdata/go/v4/memcached-operator/config/rbac
See #6928 for more details.
With you wish manually add those roles to your project
See the permissions and RBAC generate as an example to know how properly
create those files for each CRD you have in your project by looking at the
sample in the repository for the tag release v1.40.0
: testdata/go/v4/memcached-operator/config/rbac
See #6928 for more details.