
사용자 정의 리소스는 쿠버네티스 API를 사용자가 원하는대로 확장한 리소스를 말한다. 예를 들어, 쿠버네티스 코어 API에 Pod라는 리소스가 있지만 사용자가 원하는 특별한 기능을 더한 MyPod라는 리소스를 새롭게 정의할 수 있다. 쿠버네티스에는 사용자가 쉽게 API를 확장할 수 있도록 CustomResourceDefinition(CRD)라는 리소스를 제공한다.
CRD는 바로 새로운 리소스를 정의하는 리소스이다.
# mypod-crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: mypods.crd.example.com
spec:
group: crd.example.com
version: v1
scope: Namespaced
names:
plural: mypods # 복수 이름
singular: mypod # 단수 이름
kind: MyPod # kind 이름
shortNames: # 축약 이름
- mp
kubectl apply -f mypod-crd.yaml
kubectl get crd | grep mypods
apiVersion: crd.example.cop/v1
kind: MyPod
metadata:
name: mypod-test
spec:
uri: "any uri"
customCommand: "custom command"
image: nginx
kubectl get mypod
kubectl get mp
새로운 리소스를 만들었지만, 어떤 동작을 수행해야 하는지에 대해 아무런 정보가 없다.
실제 동작을 수행하기 위해서는 Custom Controller의 도움이 필요하다.
쿠버네티스에서는 적절한 권한만 가지고 있다면 쿠버네티스 API를 통해 특정 리소스의 상태를 조회할 수 있다. Controller는 쿠버네티스 클러스터 내에 Pod 형태로 존재하면서 주기적으로 특정 리소스의 이벤트를 모니터링하다가 해당 리소스의 상태 변화에 따라 사전에 정의된 동작을 수행하는 주체이다. 예를 들어, Deployment Controller는 쿠버네티스 내부 리소스인 Deployment의 생성, 삭제 이벤트와 같은 상태 변화를 지속적으로 관찰(watching)하여 새로운 Deployment 리소스 생성 시 Deployment에 정의된 정보에 맞게 Pod들을 배포하는 역할을 담당한다.
GO
아래는 Go 언어 기반의 MyPod 컨트롤러 예시 코드이다:
package main
import (
"context"
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
panic(err)
}
dynClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err)
}
gvr := schema.GroupVersionResource{
Group: "crd.example.com",
Version: "v1",
Resource: "mypods",
}
for {
mypods, err := dynClient.Resource(gvr).Namespace("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
fmt.Println("Error listing MyPods:", err)
} else {
for _, pod := range mypods.Items {
fmt.Printf("Found MyPod: %s\n", pod.GetName())
}
}
time.Sleep(10 * time.Second)
}
}
위 코드는 간단한 Dynamic 클라이언트를 활용해 "mypods" 리소스를 10초마다 조회하며, 감지된 리소스를 출력한다.
Python
아래는 Python 언어 기반의 MyPod 컨트롤러 예시 코드이다:
from kubernetes import client, config
import time
def main():
config.load_kube_config()
custom_api = client.CustomObjectsApi()
group = "crd.example.com"
version = "v1"
namespace = "default"
plural = "mypods"
while True:
try:
response = custom_api.list_namespaced_custom_object(
group=group,
version=version,
namespace=namespace,
plural=plural
)
for item in response.get('items', []):
print(f"Found MyPod: {item['metadata']['name']}")
except Exception as e:
print(f"Error retrieving MyPods: {e}")
time.sleep(10)
if __name__ == "__main__":
main()
위 코드는 Kubernetes Python 클라이언트를 활용하여 "mypods" 리소스를 주기적으로 조회하고, 이름을 출력한다.
Operator 패턴이란 Custom Resource와 그에 대응하는 컨트롤러의 조합을 이용하여 특정 애플리케이션이나 서비스의 생성과 삭제를 관리하는 패턴을 말한다.
Operator패턴을 이용해서 쿠버네티스 코어 API에 포함되지 않은 애플리케이션을 마치 쿠버네티스 native리소스처럼 동작하게끔 만들 수 있다.
💡 신규 프로젝트를 시작할때마다 CI/CD를 위한 Jenkins 애플리케이션을 매번 새로 생성하고 프로젝트가 완료된 이후 jenkins를 삭제하는 시나리오
#!/bin/bash
# 1. Jenkins Custom Resource 배포
echo "📦 Jenkins Custom Resource 배포 중..."
cat <<EOF | kubectl apply -f -
apiVersion: jenkins.io/v1alpha1
kind: Jenkins
metadata:
name: jenkins-ci
namespace: ci-namespace
spec:
master:
image: jenkins/jenkins:lts
resources:
limits:
memory: "1Gi"
cpu: "500m"
service:
type: ClusterIP
EOF
echo "✅ Jenkins 배포 완료"
# 2. 프로젝트 완료 후 Jenkins 삭제
read -p "❓ 프로젝트가 완료되었습니까? [y/N]: " confirm
if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
echo "🗑 Jenkins 삭제 중..."
kubectl delete jenkins jenkins-ci -n ci-namespace
echo "✅ Jenkins 삭제 완료"
else
echo "⏸ Jenkins 삭제를 취소했습니다."
fi
이 스크립트는 다음과 같은 목적에 맞춰 구성되어 있다:
Operator를 쿠버네티스 API를 이용하여 처음부터 개발하는 것도 가능하지만, Operator를 편리하게 만들 수 있게 제공하는 툴들이 이미 있다.