1. DaemonSet
- 지속적으로 돌아야 하는 어떤 프로세스를 실행하고 싶을 때 사용하는 워크로드 리소스
- 지속적으로 모니터링을 하고, PV / PVC를 붙여서 데이터를 저장해야 할 때 사용
- 노드가 추가되거나 제거되더라도 자동으로 해당 노드에 파드가 배포되거나 삭제됨
- 모든 서버에서 동일하게 작업되어야 하는 기준을 가지고 있다면 데몬셋이 가장 적당함
- 일반적으로 모든 노드에 하나씩 실행해 spec.replicas 필드가 필요하지 않음
1) DaemonSet vs Static Pod
비교 항목 | DaemonSet | Static Pod |
생성 방식 | YAML로 생성, kubectl로 관리 가능 | 노드의 로컬 파일(/etc/kubernetes/manifests/)에 직접 배치 |
관리 주체 | Kubernetes API Server | Kubelet (API Server와 무관) |
배포 대상 | 모든 노드 또는 특정 조건에 맞는 노드 | 특정 노드 |
유스케이스 | 클러스터 전체 모니터링, 로그 수집 | 노드 개별 관리, 단독 실행 필요 시 |
자동화 | 노드 추가 시 자동 배포 | 자동화되지 않음, 직접 파일 배치 필요 |
선택 기준 예시 :
100개의 노드가 존재하는 클러스터
- 클러스터 관리 목적(노드 모니터링)으로 각 노드에 1개씩 파드 실행 => 데몬셋
- 클러스터 관리 목적으로 특정한 30개의 노드에서만 2개씩의 파드 실행 => 정적 파드
- 클러스터 관리 목적으로 각 노드에 모두 다른 파드를 1개씩 실행 => 데몬셋
2) [실습] DaemonSet
# vi daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
annotations:
kubernetes.io/change-cause: "update to nginx 1.15"
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: webui
template:
metadata:
labels:
app: webui
spec:
containers:
- name: nginx-container
image: nginx:1.15
파드를 하나 삭제해보자.
노드 제거하기.
노드에 있는 파드를 안전하게 다른 노드로 옮기고 스케줄링을 막음
- --ignore-daemonsets : 데몬셋파드는 제거 하지 않음
- --force : 시스템 파드가 있어도 강제로 진행
- --delete-emptydir-data : emptyDir 볼륨 사용 중인 파드도 삭제
node2로 넘어가서 kubectl reset
클러스터 조인시 충돌을 방지하기 위해 삭제
# iptables -F && iptables -t nat && iptables -t mangle -F && iptables -X
노드 삭제
롤아웃을 위한 파일 생성하기
# vi nginx-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
annotations:
kubernetes.io/change-cause: "Initial rollout with nginx 1.15"
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: webui
template:
metadata:
labels:
app: webui
spec:x
containers:
- name: nginx-container
image: nginx:1.15
토큰을 이용해 node2에서 조인 수행하기
이미지 버전을 1.14로 낮추기 위한 파일 생성
# vi nginx-ds-ver1.14.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ds
annotations:
kubernetes.io/change-cause: "Updated to nginx 1.14"
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: webui
template:
metadata:
labels:
app: webui
spec:
containers:
- name: nginx-container
image: nginx:1.14
# kubectl create -f nginx-ds-ver1.14.yaml
2. StatefulSet
- 애플리케이션의 스테이트풀을 관리하는데 사용하는 워크로드 리소스
- Deployment처럼 Pod 집합을 관리하지만, 각 파드의 고유한 ID와 상태(데이터, 네트워크 정체성 등)를 유지하는 것이 차이
- 고유한 Pod 이름유지
- 고유한 볼륨 유지
- 순차적 배포/종료/업데이트 지원
- 스케일 업/다운도 순서대로 처리
- 롤링 업데이트도 순차적으로 진행 (기존 파드 종료 -> 새 파드 생성 순서)
- 개별 장애에 취약하지만, 고유한 식별자와 Persistent Volume을 유지하므로 동일한 이름의 새 파드가 생성되면 기존 데이터를 그대로 이어받아 복구가 용이
1) Stateful Apps vs Stateless Apps
애플리케이션이 안정적인 식별자 또는 순차적인 배포, 삭제 또는 스케일링이 필요하다면 스테이트풀셋을 사용하고, 그렇지 않으면 디플로이먼트를 사용해서 애플리케이션을 배포한다.
- 상태가 없는 파드(Stateless Apps)들을 관리하는 용도라면 디플로이먼트(Deployment)를 사용
- 예: 웹 파드, 앱 파드 등
- 상태가 있는 파드(Stateful Apps)들을 관리하는 용도라면 스테이트풀셋(StatefulSet)을 사용
- 예: DB(MySQL, Redis, MongoDB) 파드 등
2) 주의 사항
- 스토리지 준비 필수
- PersistentVolume 또는 StorageClass를 미리 선언해야 함
- Pod가 삭제돼도 볼륨은 유지됨
- DNS로 파드에 접근하기 위해 Headless Service 필요
- 삭제 시 바로 삭제하지 말고 replicas를 0으로 줄여 순차 종료 후 삭제하는 것이 안전함
3) [실습] StatefulSet
# vi nginx-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-sts
spec:
replicas: 3
serviceName: nginx
selector:
matchLabels:
app: webui
template:
metadata:
labels:
app: webui
spec:
containers:
- name: nginx-container
image: nginx:1.14
Pod 삭제와 scale 변경 등을 수행해보자.
3. Service
- 파드에 안정적으로 접근할 수 있도록 해주는 네트워크 창구
- 파드는 IP가 바뀌지만 서비스는 고정된 IP와 이름을 제공
- 필드 재시작시 IP가 바뀌므로 직접 접근이 어려운데, 서비스는 고정된 Cluster IP와 DNS로 파드에 접근 가능하기 때문에 로드밸런싱도 자동 수행
1) 구성 요소
- Selector : 어떤 파드에 트래픽을 보낼지 결정 (라벨 기준)
- Port : 서비스가 외부에 노출하는 포트
- TargetPort : 파드 내부 컨테이너가 실제로 수신하는 포트
서비스는 80 포트로 요청을 받고, 내부 파드의 8080 포트로 전달할 수 있음
2) 서비스 종류
- Cluster IP : 클러스터 내부 전용 (기본값)
- NodePort : 노드 외부 포트로 접근 가능
- LoadBalancer : 클라우드 외부 로드 밸런서 연결
- Headless : 파드 IP 직접 노출, StatefulSet에 사용
4. Job
반드시 실행하고 완료되어야 하는 일회성 작업을 처리할 때 사용하는 워크로드 리소스
하나 이상의 파드를 생성하고 지정된 수의 파드가 성공적으로 종료될 때까지 계속해서 파드의 실행을 재시도
1) 재기동 정책 (restartPolicy)
- Never : 파드가 종료되면 다시 생성하지 않음
- OnFailure : 파드 안 컨테이너가 비정상 종료했거나 다양한 이유로 실행이 정상 종료되지 않았을 때 컨테이너를 다시 시작
Always는 Job에서 사용할 수 없다.
기본값이 Always이기 때문에 반드시 Never 또는 OnFailure로 명시적 설정이 필요하다.
2) 일회성 작업인 Job에 필요한 또 다른 옵션 : ttlSecondsAfterFinished
- 기본적으로 Job은 완료된 후에도 클러스터에 계속 남아 있음
- 일회성 작업을 많이 실행하는 환경에서는 불필요한 Job이 계속 쌓이고 리소스 낭비가 발생할 수 있음
- 이 옵션을 사용하면 완료된 Job을 자동으로 정리할 수 있어 클러스터를 깔끔하게 유지 가능
3) [실습] 예시 코드
apiVersion: batch/v1
kind: Job
metadata:
name: os-job
spec:
ttlSecondsAfterFinished: 60
template:
spec:
containers:
- name: os-container
image: rockylinux:9.2
command: ["bash"]
args:
- "-c"
- "echo 'Hello, OS'; sleep 30; echo 'Bye, OS'"
restartPolicy: Never
5. CronJob
- 정기적인 작업을 예약 실행할 수 있도록 도와주는 리소스
- Job 컨트롤러로 실행할 애플리케이션 파드를 주기적으로 반복해서 실행
- 리눅스 시스템의 crontab 스케줄링 기능을 잡 컨트롤러에 추가한 API
- 백업, 리포트 생성, 메일 보내기, 작업 정리 등에 사용됨
- 추가적으로 크론잡 스케줄 표현을 위해 crontab.guru 웹 도구를 사용할 수도 있음
- spec.schedule, spec.jobTemplate 필드에 크론잡에 대한 값을 추가하면 됨
1) [실습] 예시 코드
apiVersion: batch/v1
kind: CronJob
metadata:
name: os-cj
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: os-container
image: busybox
args:
- "/bin/sh"
- "-c"
- "echo Hello; sleep 5; echo Bye"
restartPolicy: OnFailure
6. Volume
1) 컨테이너의 데이터
- Default는 상태 없음
- Container 장애시 자유롭게 옮길 수 있음
- Container에서 저장했던 데이터는 삭제
- Container의 Volume은 기본적으로 Temp 방식
- 보통 Container는 Application을 쓰고 버리는 거라 데이터 유지를 안하는 편이지만 DB 같은 곳에선 Data의 유지가 필수
- Data 유지가 필요한 경우엔 영구 볼륨을 사용해야 함
2) emptyDir
- Pod가 실행될 때 자동으로 생성되는 임시 디스크 볼륨
- 해당 디렉토리는 Pod가 스케줄링된 노드의 디스크를 활용하며, Pod가 삭제되면 함께 사라짐
- Pod가 실행하는 Host의 Disk를 임시로 Contianer 내부의 볼륨으로 할당
- 컨테이너 장애로 인해 재시작하더라도 Pod는 살아 있기 때문에 emtpyDir은 사용 가능
- Mem과 Disk를 동시에 사용하는 App(ex: No-SQL)에서 사용
3) hostPath
- 호스트 노드의 파일 시스템에 있는 파일이나 디렉터리를 Pod에 마운트
- 가능하면 HostPath를 사용하지 않는 것을 권장
- 사용한다면 필요한 파일 또는 디렉토리로 범위를 한정하고 Read-Only Mount 수행
3-1) hostPath Field
타입 | 설명 |
"" (빈 문자열) | 아무 조건 없이 마운트 (가장 위험) |
DirectoryOrCreate | 디렉터리가 없으면 새로 생성 (권한 755) |
Directory | 디렉터리가 있어야 함, 없으면 Pod 생성 실패 |
FileOrCreate | 파일이 없으면 새로 생성 (권한 644) |
File | 파일이 존재해야 함 |
Socket | Unix 소켓 파일이어야 함 |
CharDevice | 문자 디바이스 파일이어야 함 |
BlockDevice | 블록 디바이스 파일이어야 함 |
4) NFS
- 네트워크 상에서 여러 노드와 파드가 동시에 접근할 수 있는 공유 파일 시스템
- 쿠버네티스에서 NFS 서버를 외부에 구성한 뒤, 이를 파드에 마운트하여 공유 스토리지를 활용할 수 있음
- 하나의 스토리지를 여러 파드에서 동시에 읽고 쓸 수 있다는 것이 가장 큰 장점
- 로그 저장소, 데이터 공유 버퍼, 웹 서버 콘텐츠 디렉터리 등으로 사용됨
4-1) [실습]
[root@master ~]# dnf -y install nfs-utils
[root@master ~]# vi /etc/exports
/tmp/share 10.10.10.0/24(rw,sync,no_root_squash,no_subtree_check)
[root@master ~]# mkdir -p /tmp/share
[root@master ~]# chmod 777 /tmp/share
[root@master ~]# systemctl enable --now nfs-server.service
[root@master ~]# firewall-cmd --permanent --add-service=nfs
[root@master ~]# firewall-cmd --reload
[root@master ~]# cd /tmp/share/
[root@master share]# ls
[root@master share]# echo 'master /tmp/share webpage' > index.html
node1과 node2에도 dnf로 nfs-utils 설치
[root@node1 ~]# mount -t nfs 10.10.10.10:/tmp/share /mnt/nfs
[root@node1 ~]# cd /mnt/nfs
[root@node1 nfs]# cat index.html
master /tmp/share webpage
[root@node1 nfs]# cd
[root@node1 ~]# umount /mnt/nfs
[root@master ~]# vi nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-example
spec:
replicas: 1
selector:
matchLabels:
app: nfs-example
template:
metadata:
labels:
app: nfs-example
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nfs-vol
volumes:
- name: nfs-vol
nfs:
server: 10.10.10.10
path: /tmp/share
readOnly: true
[root@master ~]# kubectl port-forward nfs-example-f6598fb4-h89st 8080:80
[root@master ~]# curl http://localhost:8080
master /tmp/share webpage
5) Persistent Volume
Container는 기본적으로 임시 Volume을 사용하며, 영구 볼륨이 필요한 경우에는 Persistent Volume을 사용해야 한다.
5-1) PV와 PVC
- PV (Persistent Volume)
- Storage의 물리 볼륨 -> LVM의 PV와 동일
- PV는 서버 내 파티션일 수도 있고, NFS, iSCSI, Cloud 환경에서의 Storage Class일 수도 있음
- 서버측에서 제공해주는 스토리지
- PVC (Persistent Volume Claim)
- 실제 PV에 연결하기 위한 요청서
- 예 : 사용 용량, 읽기/쓰기 모드 등
- 구조 : 사용자 요청 -> PVC에서 해석
5-2) Access Mode
- ReadWirteOnce : 하나의 노드에서 해당 볼륨이 읽기-쓰기로 마운트될 수 있음
- 해당 모드에서도 Pod가 동일 노드에서 구동되는 경우에는 복수의 Pod에서 볼륨에 접근할 수 있음
- ReadOnlyMany : 볼륨이 다수의 노드에서 읽기 전용으로 마운트 가능
- ReadWriteMany : 볼륨이 다수의 노드에서 읽기-쓰기로 마운트 가능
- ReadWriteOncePod : 볼륨이 단일 파드에서 읽기-쓰기로 마운트 가능
- 전체 클러스터에서 단 하나의 Pod만 해당 PVC를 읽거나 쓸 수 있어야 하는 경우 ReadWriteOncePod 접근 모드 사용
- CSI 볼륨과 쿠버네티스 버전 1.22+ 에서만 지원
6-3) Lifecycle
1. Provisioning
- 정적 : Cluster Admin이 적정한 용량의 PV를 생성하고 USer의 요청이 있으면 PV 할당
- 동적 : Cluser User가 생성한 PV가 PVC와 일치하지 않을 때 User가 PVC를 거쳐서 PV 요청시 PV의 용량에 관계 없이 할당. StorageClass를 사용하여 Cluster Admin이 kube-apiserver를 통해 Admission Controller를 사용하도록 설정하고 이를 PV로 생성
2. Binding
- 프로비저닝으로 생성한 PV를 PVC와 연결
- PVC에서 원하는 PV가 없으면 할당 실패 -> 원하는 PV가 발생할 때까지 대기 -> 용량 확보 시 PVC 바인딩
3. Using
- PVC는 Pod에 설정하고 Pod는 PVC를 Volume으로 인식
- 할당된 PVC는 Pod를 유지하는 동안 계속 사용 -> 삭제 시도 시 사용중인 스토리지 오브젝트 보호 모드 작동
4. Reclaming
- 사용이 끝난 PVC를 삭제하고 PVC를 PV로 초기화하는 과정
- Retain : PVC 삭제 시 사용중이던 PV는 해제상태로 전환하고, PV와 PV 내부 데이터는 그대로 보존
- Delete : PV 삭제 후 외부 Storage Volume도 같이 삭제. 동적 볼륨으로 생성된 PV의 기본 정책
- Recycle : PV의 Data를 삭제하고 새로운 PVC에서 생성하는 방법 (현재는 권장되지 않음)
6-4) [실습] PV와 PVC
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0002 # PV 이름
spec:
capacity:
storage: 2Gi # PV 용량 지정(이진법 접두어 방식)
volumeMode: Filesystem # Volume을 FileSystem 형식으로 지정
accessModes: # Volume의 읽기/쓰기 모드 지정
- ReadWriteMany # 노드 1대에만 Volume의 읽기/쓰기 가능
persistentVolumeReclaimPolicy: Retain # PV 해제 시 초기화 옵션
storageClassName: slow # Storage Class가 있는 PV는 해당 Storate Class에 맞는 PVC만 연결
mountOptions: # 추가 옵션 사용이 가능한 Volume Mount Option (예시 : NFS v4.1)
- hard
- nfsvers=4.1
nfs: # PV의 Volume Plugin (예시 : nfs)
path: /tmp/share # Mount를 수행할 NFS Server 경로
server: 10.10.10.10 # NFS Server 주소
✍️ 하루 회고
저번 주에 이어 이번 수업에서는 Kubernetes의 워크로드 리소스 중 나머지 항목들에 대해 배웠다.
각 리소스는 목적에 따라 사용하는 방식이 조금씩 다르기 때문에, 특성에 맞게 적절히 선택하고 사용하는 것이 중요하다는 점을 다시 한번 느꼈다.
특히 Job, CronJob, StatefulSet, DaemonSet 등은 실습을 통해 개념이 한층 더 명확해졌다.
이번에는 볼륨에 대해서도 다뤘는데, 리눅스에서 파일 시스템과 마운트 개념을 배운 경험이 있어서 그런지 보다 직관적으로 이해할 수 있었다.
emptyDir, hostPath, NFS, PVC/PV의 차이와 각각의 쓰임새를 구분할 수 있어 유익한 시간이었다.
실습을 통해 체득한 내용을 바탕으로, 앞으로는 어떤 워크로드 구조를 선택해야 할지 판단하는 감각을 키워가고 싶다.
'TIL' 카테고리의 다른 글
[에스넷시스템 부트캠프] TIL Day 36 - VMware Tools, vCenter Server (2) | 2025.07.09 |
---|---|
[에스넷시스템 부트캠프] TIL Day 35 - SDDC, ESXi, vCenter Server (1) | 2025.07.08 |
[에스넷시스템 부트캠프] TIL Day 33 - ReplicationController, ReplicaSet, Deployment, RollingUpdate & RollingBack, Label, Selector, ConfigMap (0) | 2025.07.04 |
[에스넷시스템 부트캠프] TIL Day 32 - 쿠버네티스 Pod 2 (0) | 2025.07.03 |
[에스넷시스템 부트캠프] TIL Day 31 - 쿠버네티스 Pod 1 (1) | 2025.07.02 |