๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ”Ž Kubernetes

Kubernetes Operator (feat. Operator SDK)

by Seongpyo Hong 2020. 12. 18.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” Operator ํŒจํ„ด์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ณ , ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ผ ๊ฐ„๋‹จํ•œ Custom Operator๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Operator๋ž€?

Operator๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๊ธฐ ์ด์ „์— Controller๋ผ๋Š” ๊ฐœ๋…์— ๋Œ€ํ•ด ๋จผ์ € ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Controller

Kubernetes Patterns ์ฑ…์„ ์ฐธ๊ณ ํ•˜๋ฉด Kubernetes์—์„œ ๋ฆฌ์†Œ์Šค์˜ Status๋ฅผ ๊ฐ์‹œํ•˜๋ฉฐ ์›ํ•˜๋Š” ์ƒํƒœ(Spec)๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ Controller๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Controller์˜ ๊ธฐ๋Šฅ ์ด์™ธ์—๋„ ๋” ๋ณต์žกํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ด€๋ฆฌ ๋กœ์ง์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋ถ„๋ช… ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์„ ์ปค๋ฒ„ํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๊ฒƒ์ด Operator์ž…๋‹ˆ๋‹ค.

Operator

Kubernetes Patterns ์ฑ…์—์„œ ์ •ํ™•ํ•œ ์ •์˜๋ฅผ ์‚ดํŽด๋ณด๋ฉด Operator๋Š” CRD(Custom Resource Definitions)์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ์ •๊ตํ•œ Reconcil ๊ณผ์ •์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์šด์˜์ž๋Š” ๋ณต์žกํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋„๋ฉ”์ธ ๋กœ์ง์„ ์บก์Šํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Develop Custom Operator

๊ทธ๋ ‡๋‹ค๋ฉด Operator๋ฅผ ์–ด๋–ป๊ฒŒ ๊ฐœ๋ฐœํ• ๊นŒ์š”?

Operator๋ฅผ ๊ฐœ๋ฐœํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ๋กœ๋Š” KUDO, kubebuilder, Operator Framework๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. Operator ๊ฐœ๋ฐœ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด Custom Resource๋‚˜ Controller๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ Boiler Plate๋ฅผ ์ œ๊ณตํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๋Š” ํ•ต์‹ฌ ๋กœ์ง ๊ฐœ๋ฐœ์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ Operator Framework๊ฐ€ ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Operator Framework๋ฅผ ์‚ฌ์šฉํ•ด Operator๋ฅผ ์ƒ์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Operator Framework๋Š” Operator ๊ฐœ๋ฐœ ํ”Œ๋กœ์šฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” Operator SDK์™€ Operator์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ๊ด€๋ฆฌํ•˜๋Š” Operator OLM์œผ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

Operator SDK

Operator SDK ๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด Golang, Ansible, Helm์„ ์‚ฌ์šฉํ•˜์—ฌ Operator ๊ฐœ๋ฐœ ํ”Œ๋กœ์šฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Golang์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Golang Operator๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœํ•œ Controller๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์š” ํŒจํ‚ค์ง€๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • Runtime Controller Package
    Controller๊ฐ€ ๊ด€๋ฆฌํ•  CR์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ  SDK Controller Package์˜ Reconcile Loop๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  • Runtime Manager Package
    Kubernetes Client ๋ฐ Cache๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • SDK Controller Package
    ์‹ค์ œ Controller ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” Reconcile Loop์™€ Runtime Manager Package๋กœ ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ Kubernetes Client๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ๋ฌธ์„œ : https://ssup2.github.io/programming/Kubernetes_Operator_SDK_Golang/

Operator SDK Tutorial

Operator SDK Tutorial์— ์žˆ๋Š” Memcached Operator๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž. ๋จผ์ € working directory๋ฅผ ์ƒ์„ฑํ•œ ํ›„, ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

โ–ถ operator-sdk init --repo=github.com/seongpyoHong/memcached-operator
โ–ถ ls
Dockerfile Makefile   PROJECT    bin        config     go.mod     go.sum     hack       main.go

operator๋ฅผ ์œ„ํ•œ main program์€ main.go๋กœ Manager์˜ ์ดˆ๊ธฐํ™” ๋ฐ ์‹คํ–‰์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

[main.go]

mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
        Scheme:             scheme,
        MetricsBindAddress: metricsAddr,
        Port:               9443,
        LeaderElection:     enableLeaderElection,
        LeaderElectionID:   "9dd21db1.my.domain",
        //Namespace: namespace
    })

๋งŒ์•ฝ Controller๊ฐ€ ๊ด€์ฐฐํ•  ๋ฆฌ์†Œ์Šค์˜ Namespace๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด Options์— Namespace ๊ด€๋ จ ์„ค์ •์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ Memcached Operator๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌํ•  Memcached CRD์™€ Controller๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

โ–ถ operator-sdk create api --group=cache --version=v1alpha1 --kind=Memcached
Create Resource [y/n]
y
Create Controller [y/n]
y
...
...

 

Memcached CRD

์œ„์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์ƒ์„ฑํ•œ CRD๊ฐ€ ๊ฐ€์ ธ์•ผ ํ•˜๋Š” ์ •๋ณด๋Š” api/v1alpha1 ์•„๋ž˜์— memcached-types.go์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Spec์˜ Size๋Š” ๋™์ž‘ํ•ด์•ผํ•˜๋Š” Memcached Pod์˜ ๊ฐœ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , Status์˜ Nodes๋Š” ๋™์ž‘ํ•˜๋Š” Memcached Pod์˜ ์ด๋ฆ„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

package v1alpha1

import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// MemcachedSpec defines the desired state of Memcached
type MemcachedSpec struct {
    Size int32 `json:"size"`
}

// MemcachedStatus defines the observed state of Memcached
type MemcachedStatus struct {
    Nodes []string `json:"nodes"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status

// Memcached is the Schema for the memcacheds API
type Memcached struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   MemcachedSpec   `json:"spec,omitempty"`
    Status MemcachedStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// MemcachedList contains a list of Memcached
type MemcachedList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []Memcached `json:"items"`
}

func init() {
    SchemeBuilder.Register(&Memcached{}, &MemcachedList{})
}

 

CRD ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ๋‹ค์Œ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , Manifest๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด config/crd ์•„๋ž˜์— CRD๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

> make generate
> make manifest

 

Memcached Controller

controllers/memcached-controller.go์— controller boilerplate๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. Memcached CR์„ ์œ„ํ•ด Controller๊ฐ€ ์‹คํ–‰ํ•ด์•ผํ•  ํ•ต์‹ฌ ๋กœ์ง์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. Memcached Deployment ์ƒ์„ฑ
  2. Deployment Replica๊ฐ€ Spec์˜ Size์™€ ๋™์ผํ•˜๋„๋ก ๋ณด์žฅ
  3. Memcached CR์˜ status ์—…๋ฐ์ดํŠธ

 

์ด์ œ controller.go์— ์กด์žฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ € SetupWithManagerํ•จ์ˆ˜๋Š” Controller๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” CR ๋ฐ ๊ธฐํƒ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ์‹œํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ป๊ฒŒ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๊ตฌ์ถ•๋˜๋Š”์ง€๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&cachev1alpha1.Memcached{}).
        Owns(&appsv1.Deployment{}).
        WithOptions(controller.Options{
            MaxConcurrentReconciles: 2,
        }).Complete(r)
}

์œ„์˜ ์ฝ”๋“œ์—์„œ ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • NewControllerManagedBy() ๋Š” ๋‹ค์–‘ํ•œ ์ปจํŠธ๋กค๋Ÿฌ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋Š” controller builder๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • For(&cachev1alpha1.Memcached{})์€ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๊ด€์ฐฐํ•˜๊ธฐ ์œ„ํ•œ ์šฐ์„ ์ ์ธ ๋ฆฌ์†Œ์Šค๋ฅผ Memcached ํƒ€์ž…์œผ๋กœ ํŠน์ •ํ•ฉ๋‹ˆ๋‹ค. Memcached ํƒ€์ž…์˜ Add/Update/Delete ์ด๋ฒคํŠธ์— ๋Œ€ํ•ด Reconcil ๋ฃจํ”„๊ฐ€ ํ•ด๋‹น Memcached ๊ฐœ์ฒด์— ๋Œ€ํ•œ Reconcil ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

  • Owns(&appsv1.Deployment{}) ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๊ด€์ฐฐํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค๋กœ Deployments๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ๋Š” Memcached Object๊ฐ€ ์ƒ์„ฑํ•œ Deployment๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค

  • WithOptions ๋ฅผ ํ†ตํ•ด Controller์— ์ ์šฉํ•  ๋‹ค์–‘ํ•œ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์ฝ”๋“œ๋Š” Reconcil์„ ๋™์‹œ์— ์ตœ๋Œ€ 2๊ฐœ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

๋‹ค์Œ์œผ๋กœ Reconcile(req ctrl.Request) ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” Request๋ฅผ ๋ฐ›์•˜์„ ๋•Œ, ์–ด๋–ค ๋™์ž‘์„ ์ˆ˜ํ–‰ํ• ์ง€ ์ •์˜ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ์ฝ”๋“œ๋Š” https://github.com/operator-framework/operator-sdk/blob/master/example/memcached-operator/memcached_controller.go.tmpl ์— ์กด์žฌํ•˜๋ฉฐ, ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด ์œ„์—์„œ ์„ค๋ช…ํ•œ Controller๊ฐ€ ์‹คํ–‰ํ•  ํ•ต์‹ฌ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Build

์ด์ œ Operator๋ฅผ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋นŒ๋“œ ์ดํ›„ crd๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

> make install
go: creating new go.mod: module tmp
go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.3.0
/Users/seongpyo/workspace/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
go: creating new go.mod: module tmp
/Users/seongpyo/workspace/go/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/memcacheds.cache.my.domain created

> kubectl get crd
NAME                                        CREATED AT
managedcertificates.networking.gke.io       2020-10-02T05:32:57Z

Run

Operator๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ 2๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  1. Local์—์„œ Go Program์œผ๋กœ ์‹คํ–‰
  2. Cluster์— Deployment๋กœ ๋ฐฐํฌ

์ด๋ฒˆ์—๋Š” Local์—์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง„ํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

โ–ถ make run ENABLE_WEBHOOKS=false
go: creating new go.mod: module tmp
go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.3.0
/Users/seongpyo/workspace/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
/Users/seongpyo/workspace/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
go run ./main.go
2020-10-02T15:07:51.303+0900    INFO    controller-runtime.metrics    metrics server is starting to listen    {"addr": ":8080"}
2020-10-02T15:07:51.304+0900    INFO    setup    starting manager
2020-10-02T15:07:51.304+0900    INFO    controller-runtime.manager    starting metrics server    {"path": "/metrics"}
2020-10-02T15:07:51.304+0900    INFO    controller    Starting EventSource    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "source": "kind source: /, Kind="}
2020-10-02T15:07:51.406+0900    INFO    controller    Starting EventSource    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "source": "kind source: /, Kind="}
2020-10-02T15:07:51.508+0900    INFO    controller    Starting Controller    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached"}
2020-10-02T15:07:51.508+0900    INFO    controller    Starting workers    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "worker count": 1}

Operator๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜์—ˆ์œผ๋ฉด ๋‹ค์Œ์œผ๋กœ Operator๊ฐ€ ๊ด€์ฐฐํ•  CR์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

โ–ถ kubectl apply -f cache_v1alpha1_memcached.yaml
memcached.cache.my.domain/memcached-sample created

CR์„ ์ƒ์„ฑํ•˜๋ฉด Operator๋ฅผ ์‹คํ–‰ํ–ˆ๋˜ ์‰˜์—์„œ ์ด๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๋กœ๊ทธ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

2020-10-02T15:09:07.588+0900    INFO    controllers.Memcached    Creating a new Deployment    {"memcached": "default/memcached-sample", "Deployment.Namespace": "default", "Deployment.Name": "memcached-sample"}
2020-10-02T15:09:08.243+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:08.256+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:08.256+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:14.221+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:14.254+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:14.263+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:14.263+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}
2020-10-02T15:09:15.818+0900    DEBUG    controller    Successfully Reconciled    {"reconcilerGroup": "cache.my.domain", "reconcilerKind": "Memcached", "controller": "memcached", "name": "memcached-sample", "namespace": "default"}

๋‹ค์Œ ๊ธ€์—์„œ๋Š” Operator SDK๋ฅผ ์ด์šฉํ•ด์„œ Elasticsearch Operator๋ฅผ ๊ฐœ๋ฐœํ•ด๋ณด๋Š” ๊ฒƒ์„ ์ง„ํ–‰ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ๋‚ด์šฉ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“ ์ง€ ํ”ผ๋“œ๋ฐฑ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

์ฐธ๊ณ  ์ž๋ฃŒ


๋Œ“๊ธ€