Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: impl mutator using KRM KCL spec. #9

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ go.work
/vendor
.tools
.gopath
.DS_store
45 changes: 16 additions & 29 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,33 +1,20 @@
# Build the manager binary
FROM golang:1.19 as builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot

ENV GO111MODULE=on \
GOPROXY=https://goproxy.cn,direct

WORKDIR /

COPY . .

RUN GOOS=linux GOARCH=amd64 go build -o manager

FROM kcllang/kcl

WORKDIR /
COPY --from=builder /workspace/manager .
USER 65532:65532
COPY --from=builder /manager .

ENV KCL_GO_DISABLE_ARTIFACT=on
ENV LANG="en_US.UTF-8"

ENTRYPOINT ["/manager"]
104 changes: 77 additions & 27 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ ifeq ($(USE_IMAGE_DIGESTS), true)
endif

# Image URL to use all building/pushing image targets
IMG ?= controller:latest
IMG ?= kcllang/webhookserver
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.26.0
ENVTEST_K8S_VERSION = 1.28.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand All @@ -63,6 +63,31 @@ endif
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

# Current Webhook version
VERSION ?= 1.0
# Default bundle image tag
BUNDLE_IMG ?= controller-bundle:$(VERSION)
# Options for 'bundle-build'
ifneq ($(origin CHANNELS), undefined)
BUNDLE_CHANNELS := --channels=$(CHANNELS)
endif
ifneq ($(origin DEFAULT_CHANNEL), undefined)
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
endif
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)

# Image URL to use all building/pushing image targets
IMG ?= controller:latest

WEBHOOK_NAME ?=$(shell basename -z `pwd`)

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

.PHONY: all
all: build

Expand Down Expand Up @@ -108,9 +133,21 @@ test: manifests generate fmt vet envtest ## Run tests.
##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
build: ## Build binaries.
make manager

.PHONY: build
build-linux: ## Build binaries.
make manager-linux

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

.PHONY: manager-linux
manager-linux: generate fmt vet
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o build/bin/manager main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
Expand All @@ -119,14 +156,14 @@ run: manifests generate fmt vet ## Run a controller from your host.
# (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} .
docker-build: ## Build docker image with the manager.
docker build -t $(IMG) .

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

# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple
# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/
# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/
Expand Down Expand Up @@ -155,12 +192,13 @@ install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~

.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 -
$(KUSTOMIZE) build config/crd | kubectl delete -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 -
deploy: #manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/webhook && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > config/all.yaml
kubectl apply -f config/all.yaml

.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.
Expand Down Expand Up @@ -276,13 +314,20 @@ CONTROLLER_TOOLS_VERSION ?= v0.11.1

KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading.
$(KUSTOMIZE): $(LOCALBIN)
@if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \
echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \
rm -rf $(LOCALBIN)/kustomize; \
fi
test -s $(LOCALBIN)/kustomize || { curl -Ss $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN); }
kustomize:
ifeq (, $(shell which kustomize))
@{ \
set -e ;\
KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$KUSTOMIZE_GEN_TMP_DIR ;\
go mod init tmp ;\
go get sigs.k8s.io/kustomize/kustomize/[email protected] ;\
rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\
}
KUSTOMIZE=$(GOBIN)/kustomize
else
KUSTOMIZE=$(shell which kustomize)
endif

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten.
Expand All @@ -298,18 +343,10 @@ $(ENVTEST): $(LOCALBIN)
.PHONY: bundle
bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files.
operator-sdk generate kustomize manifests -q
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle $(BUNDLE_GEN_FLAGS)
cd config/webhook && $(KUSTOMIZE) edit set image controller=$(IMG)
$(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
operator-sdk bundle validate ./bundle

.PHONY: bundle-build
bundle-build: ## Build the bundle image.
docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .

.PHONY: bundle-push
bundle-push: ## Push the bundle image.
$(MAKE) docker-push IMG=$(BUNDLE_IMG)

.PHONY: opm
OPM = ./bin/opm
opm: ## Download opm locally if necessary.
Expand Down Expand Up @@ -432,3 +469,16 @@ codegen-applyconfigurations: $(APPLYCONFIGURATION_GEN) ## Generate apply configu

.PHONY: codegen-client-all
codegen-client-all: codegen-register codegen-defaulters codegen-applyconfigurations codegen-client-clientset codegen-client-listers codegen-client-informers ## Generate clientset, listers and informers

.PHONY: codegen-webhook
codegen-webhook:
operator-sdk create webhook --group krm.kcl.dev --version v1alpha1 --kind KCLRun --defaulting --programmatic-validation

# Generate helm chart
helmchart: kustomize
mkdir -p ./charts/${WEBHOOK_NAME}/templates
cp ./config/helmchart/templates/* ./charts/${WEBHOOK_NAME}/templates
$(KUSTOMIZE) build ./config/helmchart | sed 's/release-namespace/{{.Release.Namespace}}/' > ./charts/${WEBHOOK_NAME}/templates/rbac.yaml
version=${VERSION} envsubst < ./config/helmchart/Chart.yaml.tpl > ./charts/${WEBHOOK_NAME}/Chart.yaml
version=${VERSION} image_repo=$${IMG%:*} envsubst < ./config/helmchart/values.yaml.tpl > ./charts/${WEBHOOK_NAME}/values.yaml
helm lint ./charts/${WEBHOOK_NAME}
69 changes: 58 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,74 @@ KCL Operator provides cluster integration, allowing you to use Access Webhook to

![architecture](./images/arch.png)

## CR Example
## Developing

+ Install Go 1.20+
+ Install Kubectl and Kustomize
+ Install [Operator SDK](https://sdk.operatorframework.io/)
+ Prepare a Kubernetes Cluster e.g., K3d

Run `make help` to get the help.

## Quick Start

1. Deploy the KCL Operator.

```shell
make deploy
```

Use the following command to watch and wait the pod status is Running.

```shell
kubectl get po
```

```yaml
2. Deploy the KCL source

```shell
kubectl apply -f- << EOF
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: set-annotation
spec:
params:
annotations:
config.kubernetes.io/local-config: "true"
source: oci://ghcr.io/kcl-lang/set-annotation
source: |
items = [item | {
metadata.annotations: {
"managed-by" = "kcl-operator"
}
} for item in option("items")]
EOF
```

## Developing
3. Validate the mutation result by creating a nginx Pod YAML.

+ Install Go 1.20+
+ Install [Operator SDK](https://sdk.operatorframework.io/)
```shell
kubectl apply -f- << EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
annotations:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF
kubectl get po nginx -o yaml | grep kcl-operator
```

Run `make help` to get the help.
The output is

```shell
managed-by: kcl-operator
```

We can find the annotation `managed-by=kcl-operator` is added on the pod.

## Guides for Developing KCL

Expand All @@ -57,4 +105,3 @@ See [here](https://kcl-lang.io/docs/reference/lang/tour) to study more features
## Examples

See [here](https://github.com/kcl-lang/krm-kcl/tree/main/examples) for more examples.

Loading
Loading