
쿠버네티스에서 기본적으로 정의된 리소스 외에 Custom Resource를 활용하여 관리자가 원하는 리소스를 정의하고 사용할 수 있다.
쿠버네티스에서 기본으로 제공되지 않는 리소스, 쿠버네티스 API의 Extension
kubectl apply -f mycrd.yaml 실행/registry/apiextensions.k8s.io/customresourcedefinitions/...apis/example.com/v1/mycrNamecert-manager는 쿠버네티스에서 SSL 인증서를 자동으로 발급하고 갱신하는 컨트롤러로, 이를 위해 Issuer, Certificate 같은 Custom Resource를 사용한다.
1. cert-manager 설치
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
# 다음 CRDs를 자동 등록
# issuers.cert-manager.io
# certificates.cert-manager.io
# clusterissuers.cert-manager.io
# issuers.cert-manager.io 중 일부
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: issuers.cert-manager.io
spec:
group: cert-manager.io
names:
kind: Issuer
plural: issuers # 복수형, kubectl 명령어나 REST API 요청 시 사용될 이름
singular: issuer # 단수형
scope: Namespaced # 해당 CR이 특정 네임스페이스에 귀속된다는 뜻이며
# ClusterIssuer 같은 리소스는 scope: Cluster로 정의한다.
...
2. Issuer & Certificate 리소스 정의 (자체 서명 CA 사용)
# issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: example-issuer
namespace: default
spec:
selfSigned: {} # 자체 서명 방식
# Let's Encrypt를 이용하려면 ClusterIssuer 리소스를 생성하고
# ACME 프로토콜을 통한 도메인 검증 설정 필요
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-cert
namespace: default
spec:
secretName: example-tls
duration: 2160h # 90일
renewBefore: 360h # 15일 전 자동 갱신
subject:
organizations:
- example.org
dnsNames:
- example.com
issuerRef:
name: example-issuer
kind: Issuer
3. Issuer & Certificate 리소스 등록
kubectl apply -f issuer.yaml
kubectl apply -f certificate.yaml
4. 확인
# 인증서 발급 상태 확인
kubectl describe certificate example-cert
# 생성된 Secret 확인 (TLS 키/인증서 포함)
kubectl get secret example-tls -o yaml
ConfigMap은 단순한 설정 데이터를 저장하고 전달하는 데 사용되며,
Custom Resource는 구조화된 선언형 리소스로서 설정뿐 아니라 해당 설정에 따라 동작하는 자동화 로직의 입력으로 사용된다.
mysql.cnf 또는 pom.xml과 같이 잘 문서화된 기존 구성 파일 형식이 있다.kubectl get [Resource_NAME].spec, .status 및 .metadata와 같은 쿠버네티스 API 규칙을 사용하려고 한다.CR은 단지 구조만 정의된 YAML 객체일 뿐 자체적인 동작은 없지만, Custom Controller가 이를 감시하면서 사용자가 선언한 상태(spec)를 실제 상태(status)와 동기화(Reconcile)하는 로직을 수행한다.
1. Controller 코드 작성
// HelloReconciler: Hello 리소스를 감시하고 반응하는 Reconciler 구조체
// ctx: Context 객체 (타임아웃, 취소 등 처리 가능)
// req: 어떤 네임스페이스의 어떤 이름의 리소스가 변경되었는지 정보가 담긴 요청 객체
func (r *HelloReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// example.com/v1 API 그룹에서 정의된 Hello 리소스
var hello examplev1.Hello
// req.NamespacedName으로 지정된 Hello 리소스를 클러스터에서 읽어옴
// 리소스가 이미 삭제된 경우, 에러가 아니라 무시하고 종료
if err := r.Get(ctx, req.NamespacedName, &hello); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 사용자가 정의한 Custom Resource(Hello)의 spec.message 필드를 로그에 출력
log.Info("Reconciling", "Message", hello.Spec.Message)
// 원하는 상태를 클러스터에 반영
return ctrl.Result{}, nil
}
2. Docker 이미지로 빌드
docker build -t myrepo/my-controller:v1 .
docker push myrepo/my-controller:v1
3. Deployment로 배포
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-controller
spec:
replicas: 1
selector:
matchLabels:
app: hello-controller
template:
metadata:
labels:
app: hello-controller
spec:
containers:
- name: controller
image: myrepo/hello-controller:v1
kubectl apply -f hello-deployment.yaml
이 조합은 도메인 지식을 포함한 고급 자동화가 가능한 Operator Pattern으로 이어진다.
조금 더 퀄리티 있는 Custom Resource 예제는 이 포스트를 참고하자. 쿠버네티스 커스텀 리소스 정의하고 관리하기 (feat. 컨트롤러)