Skip to content

Commit 8d9911a

Browse files
committed
add: 커스텀 리소스, 컨트롤러, 잡, 데몬셋, 스테이트풀셋
1 parent 84f2b56 commit 8d9911a

2 files changed

Lines changed: 254 additions & 0 deletions

File tree

documents/.vuepress/const.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,5 @@ exports.KubernetesList = [
5555
"Kubernetes/2.-네임스페이스,-컨피그맵,-시크릿,-인그레스.md",
5656
"Kubernetes/3.-pv와-pvc.md",
5757
"Kubernetes/4.-ServiceAccount와-RBAC.md",
58+
"Kubernetes/5.-커스텀-리소스,-컨트롤러,-잡,-데몬셋,-스테이트풀셋.md",
5859
];
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
# 커스텀 리소스, 컨트롤러, 잡, 데몬셋, 스테이트풀셋
2+
3+
## 커스텀 리소스
4+
* 쿠버네티스에서 자체적으로 제공하는 리소스 외에 직접 정의해 사용할 수 있는 리소스
5+
* 커스텀 리소스를 제대로 사용하려면 컨트롤러라는 별도 컴포넌트를 이해하고 구현할 수 있어야 함
6+
7+
> ## 쿠버네티스 컨트롤러
8+
> * 도커와 쿠버네티스는 리소스를 생성하는 방식이 다름
9+
> * 도커 : `docker run`처럼 특정 명령을 처리하는 주체와 통신해 그 작업을 수행하고 그 결괏값을 돌려 받는 방식 (**명령형**)
10+
> * 쿠버네티스 : `kubectl apply`처럼 최종적으로 도달해야 하는 상태(바람직한 상태, Desired State)를 정의한 뒤, 현재 상태가 바람직한 상태와 다를 경우 이를 일치시키는 방법 (**선언형**)
11+
> * 선언형 사용 시 최종적으로 완성되어야 하는 상태가 되기 위해 어떠한 동작을 하는지는 쿠버네티스에서 **컨트롤러**가 내부적으로 결정
12+
> * 이때 상태는 **etcd**에 저장되어 있으며, 컨트롤러는 쿠버네티스 API 서버의 **Watch API**를 통해 etcd에 저장된 상태를 받아와 동작 수행
13+
> * **etcd** : 클러스터 상태와 설정을 저장하는 오픈소스 분산 키-값 저장소
14+
> * **Watch API** : 리소스의 생성, 수정, 삭제 같은 변경 이벤트를 클라이언트나 다른 컨트롤러에게 실시간으로 알려주는 기능
15+
16+
* 커스텀 리소스는 직접 정의해 사용할 수 있는 사용자 정의 리소스
17+
* 디플로이먼트, 서비스 등의 오브젝트의 묶음을 커스텀 리소스로 추상화 함으로써 쿠버네티스 리소스를 묶어 놓은 패키지처럼 사용할 수도 있음
18+
![](https://velog.velcdn.com/images/temporary23571/post/1f0cb2bb-902f-45a9-b41e-c2a216f993fe/image.PNG)
19+
* 위 그림과 같이 여러 리소스를 한번에 생성할 수 있고, 각 리소스의 생애 주기를 쉽게 관리 가능
20+
* 많은 관리의 복잡성을 줄일 수 있고, 오브젝트를 원하는 대로 확장해 사용 가능
21+
22+
### Custom Resource Definition
23+
* crd라 하며 `kubectl get crd` 명령어를 통해 목록 확인 가능
24+
* 커스텀 리소스를 정의하는 역할, crd 자체가 커스텀 리소스를 의미하는건 아님
25+
26+
```yaml
27+
apiVersion: apiextensions.k8s.io/v1
28+
kind: CustomResourceDefinition
29+
metadata:
30+
name: managedredises.cloud.com # CRD 이름
31+
spec:
32+
group: cloud.com
33+
names: # CR 이름
34+
kind: ManagedRedis
35+
plural: managedredises
36+
shortNames:
37+
- mr
38+
singular: managedredis
39+
scope: Namespaced # 네임스페이스에 속하는지 여부
40+
versions:
41+
- name: v1
42+
schema:
43+
openAPIV3Schema:
44+
properties:
45+
spec:
46+
properties:
47+
image:
48+
description: The image of Redis cluster
49+
type: string
50+
replica:
51+
description: The number of Redis replica
52+
type: integer
53+
required: # 반드시 포함되어야 하는 spec 정의 부분
54+
- replica
55+
- image
56+
type: object
57+
status: # 해당 CRD를 관리하는 컨트롤러에 의해 채워지는 현재 상태 정보
58+
properties:
59+
message: # 현재 상태 설명
60+
description: A descriptive message about the cluster's status.
61+
type: string
62+
phase: # 현재 상태
63+
description: The current phase of the Redis cluster (e.g., Pending,
64+
Running, Failed).
65+
type: string
66+
primary_endpoint: # 쓰기 주소
67+
description: The Redis cluster's primary connection endpoint for writing.
68+
type: string
69+
secondary_endpoint: # 읽기 주소
70+
description: The Redis cluster's secondary connection endpoint for
71+
reading.
72+
type: string
73+
type: object
74+
x-kubernetes-preserve-unknown-fields: true # CRD 스키마에서 알 수 없는(정의되지 않은) 필드를 허용
75+
type: object
76+
subresources:
77+
status: {}
78+
```
79+
* 위와 같이 crd를 정의하는 것 외에 특정 동작을 수행하는 컨트롤러를 정의해줘야 함
80+
![](https://mblogthumb-phinf.pstatic.net/MjAxOTA3MDdfMjY2/MDAxNTYyNDkzNzIyMTcx.Sp9daHGfe5zryLIeKWA-GD4Lo4VSn8qJubjA8RT-RLQg.PVs-5vLc2zmt_Pd0rk37FsOjX7LTzqjFoo0yNDUFJxog.JPEG.alice_k106/crd.jpg?type=w420)
81+
* 컨트롤러는 Watch API를 통해 새로운 CR이 생성되었다는 것을 갑지하고, CR이 원하는 바람직한 상태가 되도록 특정 동작 수행
82+
* 이러한 바람직한 상태가 되도록 특정 동작을 수행하는 것을 **Reconcile**이라 부름
83+
* 이렇게 일련의 동작을 통해 CRD를 사용할 수 있도록 컨트롤러를 구현하는 방법을 오퍼레이터(Operator) 패턴이라 부름
84+
85+
## 잡
86+
* 잡(Job)은 특정 동작을 수행하고 종료해야 하는 작업을 위한 오브젝트
87+
* 잡에서 원하는 최종 상태는 **포드가 실행되어 정상적으로 종료되는 것**
88+
```yaml
89+
apiVersion: batch/v1
90+
kind: Job
91+
metadata:
92+
name: job-hello-world
93+
spec:
94+
template:
95+
spec:
96+
restartPolicy: Never # OnFailure 설정 시 spec.backoffLimit으로 재시도 횟수 설정 가능 (기본적으로는 6번)
97+
containers:
98+
- image: busybox
99+
args: ["sh", "-c", "echo Hello, World && exit 0"]
100+
name: job-hello-world
101+
```
102+
```bash
103+
> kubectl apply -f job-hello-world.yaml
104+
job.batch/job-hello-world created
105+
106+
> kubectl get pods
107+
NAME READY STATUS RESTARTS AGE
108+
job-hello-world-cj7lv 0/1 Completed 0 12s
109+
110+
> kubectl get jobs
111+
NAME STATUS COMPLETIONS DURATION AGE
112+
job-hello-world Complete 1/1 8s 9s
113+
```
114+
* 한 번 수행하고 종료되는 배치 작업에 사용됨
115+
* 잡은 동시성을 엄격하게 보장해야 하는 병렬 처리를 위해 사용하는 것이 아님
116+
* restartPolicy에 의해 재시작될 수도 있어서 잡이 처리하는 작업은 멱등성을 가져야 함
117+
* **멱등성** : 첫 번째 수행을 한 뒤 여러 차례 적용해도 결과를 변경시키지 않는 작업 또는 기능의 속성
118+
119+
### 잡의 세부옵션
120+
* spec.completions : 잡이 성공했다고 여겨지려면 몇 개의 포드가 성공해야 하는지
121+
* spec.parallelism : 동시에 생성될 포드의 개수 (기본값은 1)
122+
* spec.activeDeadlineSeconds : 포드가 실행될 수 있는 최대 시간. 더 오래 실행될 경우 강제로 종료되며, 잡은 실패함
123+
124+
### 크론잡으로 잡을 주기적으로 실행하기
125+
* 잡을 주기적으로 실행하는 쿠버네티스 오브젝트
126+
```yaml
127+
apiVersion: batch/v1
128+
kind: CronJob
129+
metadata:
130+
name: cronjob-ex
131+
spec:
132+
schedule: "*/1 * * * *"
133+
jobTemplate:
134+
spec:
135+
restartPolicy: Never
136+
containers:
137+
- image: busybox
138+
args: ["sh", "-c", "echo Hello, World && exit 0"]
139+
name: job-hello-world
140+
```
141+
* 리눅스의 크론 스케줄 방법을 사용하여 정의 가능
142+
143+
## 데몬셋
144+
* 데몬셋(DaemonSet)은 쿠버네티스의 모든 노드에 동일한 포드를 하나씩 생성하는 오브젝트
145+
* 로깅, 모니터링, 네트워킹 등을 위한 에이전트를 각 노드에 생성해야 할 때 사용
146+
```bash
147+
> kubectl get daemonsets -n kube-system
148+
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
149+
kube-proxy 1 1 1 1 1 kubernetes.io/os=linux 69d
150+
```
151+
* 쿠버네티스 네트워킹을 위한 kube-proxy 컴포넌트 등이 데몬셋으로 실행되고 있음
152+
```yaml
153+
apiVersion: apps/v1
154+
kind: DaemonSet
155+
metadata:
156+
name: daemonset-example
157+
spec:
158+
selector:
159+
matchLabels:
160+
name: my-daemonset-example # 포드를 생성하기 위한 셀렉터
161+
template:
162+
metadata:
163+
labels:
164+
name: my-daemonset-example # 포드 라벨
165+
spec:
166+
containers:
167+
- name: daemonset-example
168+
image: busybox
169+
args: ["tail", "-f", "/dev/null"]
170+
```
171+
* 특정 노드에만 데몬셋의 포드를 생성하고 싶다면 nodeSelector나 Node Affinity를 포드에 적용할 수도 있음
172+
173+
## 스테이트풀셋
174+
* 쿠버네티스에서 MSA 구조로 동작하는 애플리케이션은 대부분 Stateless인 경우가 많음
175+
* 데이터베이스처럼 Stateful한 애플리케이션은 스테이트풀셋(StatefulSet)으로 관리 가능
176+
![](https://blog.kakaocdn.net/dna/1UODm/btq74auZKMp/AAAAAAAAAAAAAAAAAAAAAHiZAJi0KrWFATpI1f1YDRODK3LT0g7XGcRnZBL8GqFB/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1767193199&allow_ip=&allow_referer=&signature=60VeFuKpkJCJ8Ua2Vax6JsMlsBw%3D)
177+
178+
```yaml
179+
apiVersion: apps/v1
180+
kind: StatefulSet
181+
metadata:
182+
name: statefulset-example
183+
spec:
184+
serviceName: statefulset-service
185+
selector:
186+
matchLabels:
187+
name: statefulset-example
188+
replicas: 3
189+
template:
190+
metadata:
191+
labels:
192+
name: statefulset-example
193+
spec:
194+
containers:
195+
- name: statefulset-example
196+
image: alicek106/rr-test:echo-hostname
197+
ports:
198+
- containerPort: 80
199+
name: web
200+
201+
---
202+
203+
apiVersion: v1
204+
kind: Service
205+
metadata:
206+
name: statefulset-service
207+
spec:
208+
ports:
209+
- port: 80
210+
name: web
211+
clusterIP: None
212+
selector:
213+
name: statefulset-example
214+
```
215+
216+
```bash
217+
> kubectl apply -f statefulset-example.yaml
218+
statefulset.apps/statefulset-example created
219+
220+
> kubectl get sts
221+
NAME READY AGE
222+
statefulset-example 3/3 18s
223+
224+
> kubectl get pods
225+
NAME READY STATUS RESTARTS AGE
226+
job-hello-world-cj7lv 0/1 Completed 0 54m
227+
statefulset-example-0 1/1 Running 0 25s
228+
statefulset-example-1 1/1 Running 0 13s
229+
statefulset-example-2 1/1 Running 0 12s
230+
```
231+
* 포드에 랜덤한 이름이 아닌 고유한 이름이 붙혀짐
232+
* spec.ServiceName을 정의하는 이유는 랜덤 포드가 아닌 개별 포드에 요청을 전달하기 위함
233+
![](https://blog.kakaocdn.net/dna/cJlbav/btq75DJQdWf/AAAAAAAAAAAAAAAAAAAAAFinXS3bvaaks7KG6bMaHMuX8wVRSGRyRYXphahoeGPr/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1767193199&allow_ip=&allow_referer=&signature=VXbWxJ2zfxgzfek4dKpYBNkYVCc%3D)
234+
* 각 포드는 고유하게 식별되어야 하며, 랜덤한 포드로 전달되는 동작은 스테이트풀셋이 원하는 동작이 아님
235+
* 이때 일반적인 서비스가 아닌 헤드리스 서비스 사용 가능
236+
237+
### 헤드리스 서비스
238+
* clusterIP의 항목이 None으로 되어 있음 → 헤드리스 서비스 의미
239+
* 로드 밸런싱을 수행하지 않고, 개별 파드에 직접 접근할 수 있는 경로를 제공하는 방식
240+
```bash
241+
> kubectl run -i --tty --image busybox:1.28 debug --restart=Never --rm \
242+
> nslookup statefulset-service
243+
Server: 10.96.0.10
244+
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
245+
246+
Name: statefulset-service
247+
Address 1: 10.1.1.186 statefulset-example-0.statefulset-service.default.svc.cluster.local
248+
Address 2: 10.1.1.188 statefulset-example-2.statefulset-service.default.svc.cluster.local
249+
Address 3: 10.1.1.187 statefulset-example-1.statefulset-service.default.svc.cluster.local
250+
```
251+
* 위와 같이 `<포드의 이름>.<서비스 이름>`을 통해서도 포드에 접근 가능
252+
* 포드의 데이터는 일반적으로 휘발성이기 때문에 스테이트풀셋에 PV를 마운트해서 데이터를 보존하는 것이 일반적임
253+
* PVC를 정의해두고 다이나믹 프로비저닝으로 PV 자동 생성 방식도 사용 가능

0 commit comments

Comments
 (0)