Container Orchestration/Kubernetes

Kubernetes Operator(CRD, CR) 생성(With kubebuilder)

Somaz 2024. 12. 17. 10:25
728x90
반응형

Overview

Kubebuilder를 활용해서 Kubernetes Operator를 생성해본다.

 

 


 

Kubebuilder란?

Kubebuilder는 Kubernetes 운영자를 구축하기 위한 강력한 프레임워크이다. scaffolding, 코드 생성 및 Kubernetes 도구와의 통합을 제공하여 맞춤형 컨트롤러 및 API 개발을 단순화한다.

Kubernetes Operator는 커스텀 리소스(CRD)를 관리하고 애플리케이션 배포, 확장, 관리를 자동화하는 커스텀 컨트롤러이다.

 

Kubebuilder를 사용하는 이유는 무엇일까?

  • 코드 생성: CRD 및 컨트롤러에 대한 상용구 코드를 자동으로 생성한다.
  • 표준 기반: Kubernetes API 패턴을 준수하는 controller-runtime 라이브러리를 기반으로 구축되었다.
  • scaffolding: 구성 파일, Dockerfile, Makefile을 포함하여 프로젝트의 구조를 제공한다.
  • 테스트: Kubernetes용 'envtest'와 같은 테스트 도구와의 통합을 지원한다.
  • 확장성: 특정 요구 사항에 맞게 컨트롤러를 쉽게 확장하고 사용자 정의할 수 있다.

 

Kubebuilder 워크플로

 

Kubebuilder 설치

curl -L -o kubebuilder <https://github.com/kubernetes-sigs/kubebuilder/releases/latest/download/kubebuilder_>_
chmod +x kubebuilder && sudo mv kubebuilder /usr/local/bin/

 

 

프로젝트 초기화(생성)

mkdir my-operator
cd my-operator
kubebuilder init --domain example.com --repo my-operator
  • -domain: API 도메인(예: example.com)을 지정
  • --repo: 프로젝트의 Go 모듈 경로를 설정

 

새로운 API 및 컨트롤러에 대한 코드를 생성한한다.

kubebuilder create api --group apps --version v1 --kind MyApp
  • -group: API 그룹(예: apps).
  • --version: API 버전(예: v1).
  • --kind: 사용자 정의 리소스의 이름(예: MyApp).
  • config/crd/에 CRD 정의
  • api/ 및 controllers/의 API 및 컨트롤러 파일

 

프로젝트 구조

tree -d
.
├── api
│   └── v1
├── bin
├── cmd
├── config
│   ├── crd
│   ├── default
│   ├── manager
│   ├── network-policy
│   ├── prometheus
│   ├── rbac
│   └── samples
├── hack
├── internal
│   └── controller
└── test
    ├── e2e
    └── utils

 

 

Kubebuilder 사용하여 Operator 생성

 

내가 만든 Kubernetes Operator이다.

https://github.com/somaz94/k8s-namespace-sync

 

GitHub - somaz94/k8s-namespace-sync: k8s-namespace-sync

k8s-namespace-sync. Contribute to somaz94/k8s-namespace-sync development by creating an account on GitHub.

github.com

https://github.com/somaz94/helios-lb

 

GitHub - somaz94/helios-lb: helios-lb

helios-lb. Contribute to somaz94/helios-lb development by creating an account on GitHub.

github.com

 

 

사전 작업

# kubebuilder 설치
brew install kubebuilder

# git repo 생성 후 clone
git clone git@github.com-somaz94:somaz94/k8s-namespace-sync.git

# kube builder 프로젝트 초기화
kubebuilder init --domain nsync.dev --repo github.com/somaz94/k8s-namespace-sync

# api 생성
kubebuilder create api --group sync --version v1 --kind NamespaceSync

 

 

파일 설명 및 구조 설명

 

crd 스키마 정의는 아래의 파일에 해준다.

  • `api/v1/namespacesync_types.go`

 

main.go는 아래의 경로에 정의 되어있다.

  • `cmd/main.go`

 

controller는 해당 파일에 정의해준다. 필자는 해당 파일 이외에도 다양한 기능을 위한 파일들을 구성하였다.

  • `internal/controller/namespacesync_controller.go`
ls
backup					filters.go				namespacesync_controller.go		namespacesync_controller_target_test.go	resources.go				sync.go
events.go				metrics.go				namespacesync_controller_filter_test.go	namespacesync_controller_test.go	suite_test.go				utils.go

 

 

테스트 코드도 동일한 경로에 정의해주면 되고 make test 명령어를 사용하여 test 가능하다.

자세한 내용이 궁금하다면, makefile을 확인해주면 된다.

 

모든 기능 구현이 끝났다면, 이미지를 빌드 후 업로드 할 dockerhub 계정을 만들어준다.

  • Docker Hub 웹사이트에서 Access Token 생성
  • https://hub.docker.com/settings/security 접속
  • "New Access Token" 클릭
  • 토큰 이름 입력 (예: "k8s-namespace-sync")
  • 토큰이 생성되면 복사 (이 토큰은 한 번만 표시되므로 잘 저장해두세요)

 

터미널에서 로그인해준다.

docker login -u somaz940
# token을 비밀번호로 입력한다.
  • make test를 진행하기 전에 설명해야 할 내용이 남아있다.

 

kubebuilder 마커

Kubernetes CRD(Custom Resource Definition)의 스키마와 표시 방식을 정의하는 kubebuilder 마커(marker)이다.

 

`namespacesync_types.go` 파일을 확인해보면 아래와 같이 마커가 정의되어 있다.

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Source",type="string",JSONPath=".spec.sourceNamespace"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status"
// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message"
  • +kubebuilder:object:root=true
    • 이 타입이 CRD의 루트 객체임을 나타낸다.
  • +kubebuilder:subresource:status
    • status 서브리소스를 활성화한다.
    • 상태 업데이트를 위한 별도의 엔드포인트를 제공한다.
  • +kubebuilder:printcolumn:...
    • kubectl get 명령어 실행 시 표시될 커스텀 컬럼을 정의합니다.
    • 정의된 컬럼들
      • Source: spec.sourceNamespace 값을 표시
      • Age: 생성 시간 표시
      • Status: Ready 컨디션의 상태 표시
      • Message: Ready 컨디션의 메시지 표시

 

make manifests 사용 시

  • controller-gen이 Go 코드의 마커들을 읽어서 CRD YAML 파일을 생성
  • RBAC 권한 설정 파일 생성
  • config/crd/bases 디렉토리에 결과물 생성

 

make generate 사용 시

  • Go 타입에 대한 DeepCopy 메서드 생성
  • 쿠버네티스 클라이언트 코드에 필요한 타입 변환 코드 생성

 

makefile을 확인해보면 아래와 같이 정의되어있다. 모든 필요한 작업을 수행한 후 test 까지 진행해준다.

.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 $$(go list ./... | grep -v /e2e) -coverprofile cover.out

 

 

그리고 makefile에서 IMG 업로드 경로와 K8S 테스트 버전을 지정해 줄 수 있다.

# Image URL to use all building/pushing image targets
IMG ?= somaz940/k8s-namespace-sync:v0.1.6
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.31.0

 

 

테스트가 성공적으로 끝낫다면, make dokcer-buildx 를 사용해서 다양한 플랫폼으로 동시에 build 해준다.

필자는 makefile을 수정해서, latest, versiontag 그리고 latest+versiontag 환경으로 build 할 수 있게 makefile을 수정했다.

PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx-tag
docker-buildx-tag: ## Build and push docker image for the manager for cross-platform support with specific version
	# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross
	sed -e '1 s/\\(^FROM\\)/FROM --platform=\\$$\\{BUILDPLATFORM\\}/; t' -e ' 1,// s//FROM --platform=\\$$\\{BUILDPLATFORM\\}/' Dockerfile > Dockerfile.cross
	- $(CONTAINER_TOOL) buildx create --name k8s-namespace-sync-builder
	$(CONTAINER_TOOL) buildx use k8s-namespace-sync-builder
	# Build and push version-specific tag
	- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) \\
		--tag ${IMG} \\
		-f Dockerfile.cross .
	- $(CONTAINER_TOOL) buildx rm k8s-namespace-sync-builder
	rm Dockerfile.cross

.PHONY: docker-buildx-latest
docker-buildx-latest: ## Build and push docker image for the manager for cross-platform support with latest tag
	# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross
	sed -e '1 s/\\(^FROM\\)/FROM --platform=\\$$\\{BUILDPLATFORM\\}/; t' -e ' 1,// s//FROM --platform=\\$$\\{BUILDPLATFORM\\}/' Dockerfile > Dockerfile.cross
	- $(CONTAINER_TOOL) buildx create --name k8s-namespace-sync-builder
	$(CONTAINER_TOOL) buildx use k8s-namespace-sync-builder
	# Build and push latest tag
	- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) \\
		--tag $(shell echo ${IMG} | cut -f1 -d:):latest \\
		-f Dockerfile.cross .
	- $(CONTAINER_TOOL) buildx rm k8s-namespace-sync-builder
	rm Dockerfile.cross

.PHONY: docker-buildx
docker-buildx: ## Build and push both version-specific and latest tags
docker-buildx: docker-buildx-tag docker-buildx-latest

 

 

build가 성공적으로 완료되었다면 make deploy 명령어를 사용해서 app을 배포해준다.

✔ ~/PrivateWork/k8s-namespace-sync [main|✔] 
18:40 $ make deploy 
/Users/somaz/PrivateWork/k8s-namespace-sync/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
cd config/manager && /Users/somaz/PrivateWork/k8s-namespace-sync/bin/kustomize edit set image controller=somaz940/k8s-namespace-sync:v0.1.6
/Users/somaz/PrivateWork/k8s-namespace-sync/bin/kustomize build config/default | kubectl apply -f -
namespace/k8s-namespace-sync-system created
customresourcedefinition.apiextensions.k8s.io/namespacesyncs.sync.nsync.dev created
serviceaccount/k8s-namespace-sync-controller-manager created
role.rbac.authorization.k8s.io/k8s-namespace-sync-leader-election-role created
clusterrole.rbac.authorization.k8s.io/k8s-namespace-sync-manager-role created
clusterrole.rbac.authorization.k8s.io/k8s-namespace-sync-metrics-auth-role created
clusterrole.rbac.authorization.k8s.io/k8s-namespace-sync-metrics-reader created
clusterrole.rbac.authorization.k8s.io/k8s-namespace-sync-namespacesync-editor-role created
clusterrole.rbac.authorization.k8s.io/k8s-namespace-sync-namespacesync-viewer-role created
rolebinding.rbac.authorization.k8s.io/k8s-namespace-sync-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/k8s-namespace-sync-manager-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/k8s-namespace-sync-metrics-auth-rolebinding created
service/k8s-namespace-sync-controller-manager-metrics-service created
deployment.apps/k8s-namespace-sync-controller-manager created

 

 

api와 crd를 확인해준다.

k get apiservices.apiregistration.k8s.io |grep nsync
v1.sync.nsync.dev                      Local                        True        25s

k get crd |grep nsync
namespacesyncs.sync.nsync.dev                2024-12-16T09:41:00Z

 

 

필자는 다양한 sample crd를 생성하였다.

ls config/samples/
kustomization.yaml			sync_v1_namespacesync_exclude.yaml	sync_v1_namespacesync_target.yaml	test-configmap2.yaml			test-secret2.yaml
sync_v1_namespacesync.yaml		sync_v1_namespacesync_filter.yaml	test-configmap.yaml			test-secret.yaml

 

 

App 기능이 궁금한다면 아래의 링크를 확인해주길 바란다.

https://github.com/somaz94/k8s-namespace-sync

 

GitHub - somaz94/k8s-namespace-sync: k8s-namespace-sync

k8s-namespace-sync. Contribute to somaz94/k8s-namespace-sync development by creating an account on GitHub.

github.com

https://github.com/somaz94/helios-lb

 

GitHub - somaz94/helios-lb: helios-lb

helios-lb. Contribute to somaz94/helios-lb development by creating an account on GitHub.

github.com

 

 

app의 시작로그를 확인해보면 아래와 같다.

2024-12-16T09:41:01.541Z        ESC[34minfoESC[0m       setup   creating controller     {"controller": "NamespaceSync", "scheme": "pkg/runtime/scheme.go:100"}
2024-12-16T09:41:01.541Z        ESC[34minfoESC[0m       namespacesync-controller        Setting up controller manager
2024-12-16T09:41:01.545Z        ESC[34minfoESC[0m       setup   controller created successfully {"controller": "NamespaceSync"}
2024-12-16T09:41:01.545Z        ESC[34minfoESC[0m       setup   starting manager
2024-12-16T09:41:01.545Z        ESC[34minfoESC[0m       controller-runtime.metrics      Starting metrics server
2024-12-16T09:41:01.545Z        ESC[34minfoESC[0m       setup   disabling http/2
2024-12-16T09:41:01.545Z        ESC[34minfoESC[0m       starting server {"name": "health probe", "addr": "[::]:8081"}
I1216 09:41:01.645802       1 leaderelection.go:254] attempting to acquire leader lease k8s-namespace-sync-system/47c2149c.nsync.dev...
I1216 09:41:01.659829       1 leaderelection.go:268] successfully acquired lease k8s-namespace-sync-system/47c2149c.nsync.dev
2024-12-16T09:41:01.659Z        ESC[35mdebugESC[0m      manager.events  k8s-namespace-sync-controller-manager-5874b756c8-h9ng6_2a3d0c37-b1f0-46c3-bcff-e28ccc2750e9 became leader       {"type": "Normal", "object": {"kind":"Lease","namespace":"k8s-namespace-sync-system","name":"47c21
49c.nsync.dev","uid":"385be981-f090-4b4e-a341-7888c2858e4b","apiVersion":"coordination.k8s.io/v1","resourceVersion":"12611207"}, "reason": "LeaderElection"}
2024-12-16T09:41:01.660Z        ESC[34minfoESC[0m       manager Starting EventSource    {"controller": "namespacesync", "controllerGroup": "sync.nsync.dev", "controllerKind": "NamespaceSync", "source": "kind source: *v1.NamespaceSync"}
2024-12-16T09:41:01.660Z        ESC[34minfoESC[0m       manager Starting EventSource    {"controller": "namespacesync", "controllerGroup": "sync.nsync.dev", "controllerKind": "NamespaceSync", "source": "kind source: *v1.Namespace"}
2024-12-16T09:41:01.660Z        ESC[34minfoESC[0m       manager Starting EventSource    {"controller": "namespacesync", "controllerGroup": "sync.nsync.dev", "controllerKind": "NamespaceSync", "source": "kind source: *v1.Secret"}
2024-12-16T09:41:01.660Z        ESC[34minfoESC[0m       manager Starting EventSource    {"controller": "namespacesync", "controllerGroup": "sync.nsync.dev", "controllerKind": "NamespaceSync", "source": "kind source: *v1.ConfigMap"}
2024-12-16T09:41:01.660Z        ESC[34minfoESC[0m       manager Starting Controller     {"controller": "namespacesync", "controllerGroup": "sync.nsync.dev", "controllerKind": "NamespaceSync"}

 

 

마치며

이렇게 kubebuilder 를 사용해 간단한 app을 생성해보았다. 프레임워크를 제공해주기 때문에 개발하기 상당히 용이하다. 다들 한번쯤 간단한 app이라도 생성해보길 바란다. 생성해보면, 복잡한 Kubernetes Application들이 어떤 구조로 개발되었는지에 대하여 약간이나마 알 수 도움이 될 것이다.

다음시간에는 생성한 app에 대하여 release 그리고 helm 패키징하여 github에 hosting 하는 방법에 대해서 알아보려고 한다.

 


Reference

https://github.com/kubernetes-sigs/kubebuilder

https://github.com/somaz94/k8s-namespace-sync

https://medium.com/@SabujJanaCodes/building-a-kubernetes-operator-in-go-reconciling-our-pdfdoc-crd-for-converting-text-to-pdf-files-d0c0c7da98be

https://github.com/somaz94/helios-lb

728x90
반응형