Skip to content

Commit

Permalink
Kubebuilder 3.7.0 (#63)
Browse files Browse the repository at this point in the history
* set kubebuilder 3.7.0 style, upgrade dependencies and upgrade go version to 1.19

* add contribution documentation

* fix typo
  • Loading branch information
vincentmrg authored Oct 25, 2022
1 parent 026b8da commit f94b065
Show file tree
Hide file tree
Showing 16 changed files with 718 additions and 409 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ jobs:
GCP_PROJECT_ID: quortex-registry-public

steps:
- name: Set up Go 1.16
- name: Set up Go 1.19
uses: actions/setup-go@v3
with:
go-version: 1.16
go-version: 1.19

# This step uses Github's checkout-action: https://github.com/actions/checkout
- name: Check out code
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ jobs:

- uses: actions/setup-go@v3
with:
go-version: 1.16
go-version: 1.19

# Instead of using our own CI, we uses https://golangci-lint.run/
# It combines 48 linters and execute them in parallel
- name: Lint with golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.32
version: v1.49
args: --timeout 5m

test:
Expand All @@ -31,7 +31,7 @@ jobs:

- uses: actions/setup-go@v3
with:
go-version: 1.16
go-version: 1.19

- name: Execute tests
run: make test
Expand Down
98 changes: 98 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# How to contribute

This project is maintained with **golang v1.19** and **kubebuilder v3.7.0**, please use these versions to ensure the integrity of the project.

## Introduction to Kubebuilder

This operator is build upon [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder), a framework for building Kubernetes APIs using [custom resource definitions (CRDs)](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).

Kubebuilder is developed on top of the controller-runtime and controller-tools libraries.

- [Quickstart](https://book.kubebuilder.io/quick-start.html)
- [Installation instructions](https://book.kubebuilder.io/quick-start.html#installation)

Useful additional resources :

- A [tutorial](https://book.kubebuilder.io/cronjob-tutorial/cronjob-tutorial.html).
- A list of [best practices](https://www.openshift.com/blog/kubernetes-operators-best-practices) for operators development.
- A complete [ebook](https://book.kubebuilder.io/introduction.html).

## How to create a new CRD / API

### 1. Bootstrap files

To create a new API, you need first to bootstrap it with Kubebuilder.
Here is an example to create an object `Frigate` in the group `ship` in version `v1beta1` :

```bash
kubebuilder create api --group ship --version v1beta1 --kind Frigate
```

Versions numbers must follows [kubernetes naming scheme](https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning). Object are namespaced by default, to create a cluster-wide object add the parameter `--namespaced=false`.

### 2. Define API and implement controller

The next step is to complet API declaration and controller. For a multigroup project like this one :

- The API is in `apis/ship/v1beta1`
- The controller is in `controllers/ship/v1beta1`

Refer to the kubebuilder [API documentation](https://book.kubebuilder.io/cronjob-tutorial/new-api.html) and [controller documentation](https://book.kubebuilder.io/cronjob-tutorial/controller-overview.html) for advanced documentation on these parts.

After modifying files, don't forget to run `make` in order to update generated files, format and lint everything.

### 3. Create a validating or mutating Admission Webhook (Optional)

To create mutating (defaulting) or / and validating webhooks for your API you need to bootstrap it with Kubebuilder.
Here is an example to create defaulting and validation webhooks for `Frigate` in the group `ship` in version `v1beta1` :

```bash
kubebuilder create webhook --group ship --version v1beta1 --kind Frigate --defaulting --programmatic-validation
```

The next step is to fill generated code following [kubebuilder documentation](https://book.kubebuilder.io/cronjob-tutorial/webhook-implementation.html)

### 4. Testing

You can then run your operator in different ways :

#### Locally

Assuming you have a cluster connected, you can install the _CustomResourceDefinition_ by running `make install` (which can also be removed with `make uninstall`).

Then, run the operator locally against the configured Kubernetes cluster in ~/.kube/config.

```sh
make run ENABLE_WEBHOOKS=false
```

#### With kind

You can test on a local cluster with [kind](https://kind.sigs.k8s.io/), this method will allow you to build an image of your operator and run it on a local cluster. This way you can test more like a real deployment and you can use webhooks.

Create a cluster :

`kind create cluster`

Build the operator locally e.g. :

`make docker-build`

Load your image in kind nodes :

`kind load docker-image $IMG`

Deploy the operator in the cluster :

`make deploy`

## Contribution rules

- As this project uses kubebuilder 3.7.0, you should use [golang](https://go.dev/) v1.19.
- It is advised to use vendoring to avoid using packages not in the `go mod` or mixing versions.
To do so, run the command `go mod vendor`.
- Before commiting, run `make` to generate files and format files. You should also run `make lint` to do the same linting done in CI, and `go mod tidy` to tidy up the `go.mod` and `go.sum` files.

## Versioning

We use [SemVer](http://semver.org/) for versioning.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.16 as builder
FROM golang:1.19 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
Expand Down
123 changes: 79 additions & 44 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

# Image URL to use all building/pushing image targets
IMG ?= controller:latest
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true,preserveUnknownFields=false"
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.25.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand Down Expand Up @@ -37,34 +37,39 @@ help: ## Display this help.

##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...

.PHONY: vet
vet: ## Run go vet against code.
go vet ./...

lint: ## Run the linter used in CI against code.
.PHONY: lint
lint: golangci-lint ## Run the linter used in CI against code.
$(GOLANG_CI_LINT) run -v

ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
test: manifests generate fmt vet ## Run tests.
mkdir -p ${ENVTEST_ASSETS_DIR}
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.7.2/hack/setup-envtest.sh
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out

.PHONY: doc
doc: crd-ref-docs ## Build api documentation.
$(CRD_REF_DOCS) --source-path=api \
--renderer=asciidoctor \
--config=hack/doc-generation/config.yaml \
--templates-dir=hack/doc-generation/templates/asciidoctor \
--output-path=docs/api-docs.asciidoc

.PHONY: charts
charts: yq kustomize ## Generate helm chart crds, rbac from kustomize files and doc from helm values.
@TMPFILE=$$(mktemp) && \
${YQ} -y '.metadata.name = ("PREFIX-" + .metadata.name)' config/rbac/role.yaml | \
Expand All @@ -77,66 +82,96 @@ charts: yq kustomize ## Generate helm chart crds, rbac from kustomize files and

##@ Build

.PHONY: build
build: generate fmt vet ## Build manager binary.
go build -o bin/manager main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go

# If you wish built the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: test ## Build docker image with the manager.
docker build -t ${IMG} .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
docker push ${IMG}

##@ Deployment

ifndef ignore-not-found
ignore-not-found = false
endif

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | kubectl apply -f -

uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | kubectl delete -f -
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | kubectl apply -f -

undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/default | kubectl delete -f -


CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
controller-gen: ## Download controller-gen locally if necessary.
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1)

CRD_REF_DOCS = $(shell pwd)/bin/crd-ref-docs
crd-ref-docs: ## Download crd-ref-docs locally if necessary.
$(call go-get-tool,$(CRD_REF_DOCS),github.com/elastic/crd-ref-docs@v0.0.5)

GOLANG_CI_LINT = $(shell pwd)/bin/golangci-lint
golangci-lint: ## Download golangci-lint locally if necessary.
$(call go-get-tool,$(GOLANG_CI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1)

KUSTOMIZE = $(shell pwd)/bin/kustomize
kustomize: ## Download kustomize locally if necessary.
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7)
.PHONY: undeploy
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f -

##@ Build Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
CRD_REF_DOCS ?= $(LOCALBIN)/crd-ref-docs
GOLANG_CI_LINT?= $(LOCALBIN)/golangci-lint

## Tool Versions
KUSTOMIZE_VERSION ?= v4.5.5
CONTROLLER_TOOLS_VERSION ?= v0.9.2
CRD_REF_DOCS_VERSION ?= v0.0.8
GOLANG_CI_LINT_VERSION ?= v1.49.0

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); }

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)

.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

.PHONY: crd-ref-docs
crd-ref-docs: $(CRD_REF_DOCS) ## Download crd-ref-docs locally if necessary.
$(CRD_REF_DOCS): $(LOCALBIN)
test -s $(LOCALBIN)/crd-ref-docs || GOBIN=$(LOCALBIN) go install github.com/elastic/crd-ref-docs@$(CRD_REF_DOCS_VERSION)

.PHONY: golangci-lint
golangci-lint: $(GOLANG_CI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANG_CI_LINT): $(LOCALBIN)
test -s $(LOCALBIN)/golangci-lint || GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANG_CI_LINT_VERSION)

yq: ## Download yq if necessary.
ifeq (, $(shell which yq))
@pip3 install yq
endif
YQ=$(shell which yq)

# go-get-tool will 'go get' any package $2 and install it to $1.
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
define go-get-tool
@[ -f $(1) ] || { \
set -e ;\
TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Downloading $(2)" ;\
GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\
rm -rf $$TMP_DIR ;\
}
endef
4 changes: 2 additions & 2 deletions api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ limitations under the License.
*/

// Package v1alpha1 contains API Schema definitions for the v1alpha1 API group
//+kubebuilder:object:generate=true
//+groupName=kubestatic.quortex.io
// +kubebuilder:object:generate=true
// +groupName=kubestatic.quortex.io
package v1alpha1

import (
Expand Down
9 changes: 1 addition & 8 deletions config/crd/bases/kubestatic.quortex.io_externalips.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.1
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: externalips.kubestatic.quortex.io
spec:
Expand Down Expand Up @@ -82,9 +81,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
9 changes: 1 addition & 8 deletions config/crd/bases/kubestatic.quortex.io_firewallrules.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.1
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
name: firewallrules.kubestatic.quortex.io
spec:
Expand Down Expand Up @@ -132,9 +131,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
1 change: 0 additions & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
Expand Down
Loading

0 comments on commit f94b065

Please sign in to comment.