[Kubernetes] 기본 리소스

식빵·2026년 1월 11일

kubernetes

목록 보기
8/8

쿠버네티스가 조금 약한 거 같아서 최근 강의를 하나 들었고,
해당 내용을 좀 길지만 머릿속으로 정리해볼 겸 작성해 본 글입니다.


쿠버네티스

필요성

컨테이너를 돌리기 위해서는 하나의 서버와 컨테이너 런타임이 있어야 한다.
하지만 가용성과 확장성 측면 때문에 결국은 이중화를 진행해야 된다.

이런 이중화된 서버에 실행될 컨테이너들을 관리하기 위한
자동화된 소프트웨어가 필요하게 됐고, 그게 바로 쿠버네티스(kubernetes)다.


Kubernetes?

Kubernetes(쿠버네티스) 는 컨테이너 오케스트레이션 소프트웨어이다.
물리적으로 분리된 여러 서버와 그 위에서 실행될 여러 컨테이너들을
일괄적으로 관리하는 게 핵심 목표이다.

  • 주요기능
    • 오케스트레이션: 다중 서버 환경의 컨테이너 운영 기능
    • 셀프 힐링: 컨테이너 문제 발생 시 자동복구
    • 오토 스케일링: 트래픽 증가/감소 시 컨테이너 개수 자동 조절

참고: Kubernetes 는 k8s 로 줄여서 부르기도 한다.
이하에서는 모두 k8s 로 줄여 부르겠다.



Node / Cluster

k8s여러 서버 에 컨테이너 동작할 컨테이너들을 관리/조율하는게 목표이다.
이때 이 서버들을 묶어서 Cluster (클러스터) 라고 표현한다.
이렇게 하나로 묶음으로써 통합 관리가 가능케 한다.

그리고 각각의 서버는 또 노드(Node)라고 표현한다.



동작원리

사용자는 원하는 상태를 정의 하여 k8s 를 건내주고,
k8s 는 이 상태에 맞게 동작되도록 지속적으로 조정하게 된다.

여기서 말하는 "지속적인 조정" 을 컨트롤 루푸(Control Loop) 라고 한다.
컨트롤 루프는 크게 3가지 절차로 이루어진다.

  1. Cluster 의 정보를 지속적으로 관찰 한다. (=정보수집)
  2. 사용자의 "원하는 상태"와 Cluster 의 "현재 상태"를 비교 한다.
  3. 다르면 조치 한다.

즉 관찰, 비교, 조치로 이루어진다.




리소스

k8s 의 리소스

위에서는 간단하게 "사용자가 정의한 상태"라고 모호하게 표현했지만,
정확히 네트워크, 스토리지, 환경변수 등의 상태를 의미한다.
즉, 상태라는 말은 정확히는 애플리케이션이 실행될 환경의 구성 요소들 을 의미한다.

k8s 에서 리소스란 애플리케이션이 실행될 환경의 구성요소들을
정의하기 위해 사용하는 구성 단위이다.
k8s 에서는 다음과 같은 리소스가 존재한다.

  • Namespace
  • Pod
  • ReplicaSet
  • Deployment
  • Service
  • ConfigMap
  • Secret
  • 등등..

이러한 모든 리소스는 yaml 로 표현이 가능하다.

ex:

apiVersion: v1    # 리소스 버전 (필수값)
kind: Pod         # 리소스 타입 명 (필수값)
metadata:              # 리소스의 부가 정보
  name: my-pod          # (리소스 이름, 필수값)
  namespace: my-ns      # 리소스가 속한 Namespace
  labels: 
  	app: my-app         # 그룹화를 위한 Label
spec:                   # 리소스의 속성
 (...생략...)



kubectl 명령어

kubectl 은 k8s 를 사용하기 위한 프로그램이고,
이 kubectl 을 통해서 k8s 클러스터와 상호작용을 할 수 있다.

kubectl get pod # 리소스 목록조회

kubetl get pod my-pod -o yaml # 이렇게 하면 특정 리소스 하나에 대해서 yaml 형태로 정보를 조회할 수 있다.

kubectl describe pod my-pod # 리소스 상세 내역

kubectl apply -f my-pod.yaml # yaml 을 통한 리소스 생성 (더 일반적)
kubectl create deployment m-nginx --image=nginx # 명령어를 통한 리소스 생성

kubectl apply -f my-pod.yaml # 리소스 수정, 똑같으면 변경 X
kubectl edit pod my-pod # vim 같은 에디터로 리소스 수정

kubectl delete -f my-pod.yaml # yaml 을 통한 리소스 삭제
kubectl delete pod my-pod # 리소스 타입과 명칭으로 직접 삭제

참고: apply 와 delete 는 yaml 파일이 여러개 있는 디렉토리에도 사용할 수 있다.
ex: kubectl apply -f 디렉토리_경로
ex: kubectl delete -f 디렉토리_경로
이러면 디렉토리에 안에 있던 각각의 yaml apply/delete 된다.



📁 NameSpace

다양한 리소스들을 논리적으로 분리하기 위한 일종의 폴더이다.
NameSpace (=ns) 안에 있는 리소스들은 Namespace 를 삭제하면 한번에 다 같이 지워진다.

yaml 형태

apiVersion: v1
kind: Namespace
metadata:
  name: my-ns

명령어 활용

kubectl get pods -n my-namespace
# 참고로 -n 으로 지정 안하면 default 네임스페이스를 뒤져본다.

# 전체 NameSpace 에 대해서 리소스 조회
kubectl get pods -A


🐳 Pod

  • k8s 에서 컨테이너를 실행하기 위해 사용하는 리소스이다.
  • Pod 는 하나 이상의 컨테이너를 담을 수 있다.
    다만 한 개의 Pod 에 한 개의 컨테이너만 사용하는 것이 일반적
  • Pod 가 생성되면 클러스터 내의 하나의 Node 에 실제 컨테이너가 실행

주의:
실제 컨테이너를 실행할 Node 에서는 Pod 라는 개념은 없다! 그냥 컨테이너 밖에 모른다.
Pod 는 k8s 가 컨테이너를 관리하기 위한 논리적인 단위이다!

yaml

## 파일명: toast-pod.yaml

# # toast 네임스페이스도 같이 생성
# apiVersion: v1
# kind: Namespace
# metadata:
#  name: toast
#---

# Pod 를 생성
apiVerion: v1
kind: Pod
metadata:
  name: toast-pod
  namespace: toast # 필수는 아님! 지정 안하면 default ns 들어감
spec:
  containers:
  - name: nginx
    image: nginx:alpine-slim
    # name, image 는 필수값!
    
# 위처럼 yaml 로 하는 게 정석이지만, 귀찮다면 bash 에서 명령어로도 할 수 있다.
# kubectl run nginx --image=nginx:alpine-slim -n toast

명령어 활용

# POD 생성
kubectl apply -f toast-pod.yaml

# POD 조회
kubectl get pod -n toast

# 상세조회
kubectl describe pod toast-pod -n toast

# yaml 뽑애나기
kubectl get pod -n toast -o yaml

# 로그 조회
kubectl logs -f toast-pod -n toast # ctrl+c 로 탈출 가능

# 삭제
kubectl delete pod toast-pod -n toast

# 가끔은 Pod 를 띄우지는 않지만, 템플릿 yaml 파일이 필요할 때가 있다.
# 이때 쓰면 좋은게 "--dry-run=client" 옵션이다
# 이러면 실제 실행은 안되고, yaml 을 뽑아낼 수 있다.
kubectl run sample-pod --image=nginx:slim-alpine \
  --dry-run=client -n toast -o yaml > some-pod.yaml
  
# 출력 결과:
# apiVersion: v1
# kind: Pod
# metadata:
#   labels:
#     run: sample-pod
#   name: sample-pod
#   namespace: toast
# spec:
#   containers:
#   - image: nginx:alpine-slim
#     name: sample-pod
#     resources: {}
#   dnsPolicy: ClusterFirst
#   restartPolicy: Always
# status: {}

참고: kubectl describe 명령어 결과물

Name:             toast-pod
Namespace:        toast
Priority:         0
Service Account:  default
Node:             worker-node-3/172.22.0.4
Start Time:       Sat, 20 Dec 2025 10:41:04 +0900
Labels:           <none>
Annotations:      <none>
Status:           Running
IP:               10.244.3.2
IPs:
  IP:  10.244.3.2
Containers:
  nginx:
    Container ID:   containerd://(...생략...)
    Image:          nginx:alpine-slim
    Image ID:       (...생략...)
    Port:           <none>
    Host Port:      <none>

... (생략)...

Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  8m18s  default-scheduler  Successfully assigned toast/toast-pod to worker-node-3
  Normal  Pulled     8m17s  kubelet            Container image "nginx:alpine-slim" already present on machine
  Normal  Created    8m17s  kubelet            Created container nginx
  Normal  Started    8m17s  kubelet            Started container nginx



파드의 라이프 사이클

7 개가 있다.

# kubectl run some-app ... 명령어 입력 후...
- [Pending]
     |
     |
     V
- [ContainerCreating] --> !! ImagePullBackOff !!
     |
     |
     V
- [Running] --> [Succeeded] (실행됐고, 정상 종료. 주로 1회성 배치 컨테이너에서 활용)
     |              |   
     |              |
     -->  [Failed]  -->  (성공이든 실패든 짧은 시간 내에 지속적으로 반복 실행되면...)
                               |
                               |
      [CrashLoopBackOff] <------

요약:

  • Pending :
    • Pod 를 실행할 Node 를 찾는 중이다.
    • 참고로 Pod 를 실행할 Node 를 지정하는 것을 Scheduling 이라고 한다.
      Pod 가 스케줄링됐다 라고도 표현한다.
  • ContainerCreating : Scheduling 완료, 컨테이너 생성을 위한 시간을 갖는다.
    • 이때 Image 다운로드 에러가 발생하면 ImagePullBackOff 상태가 된다.
    • 주로 Image 이름 오타, 또는 platform 지원이 안되는 경우 발생
  • Running: 컨테이너 생성이 됐고, 실제 실행을 한 상태이다.
    • 재시도 정책 (Restart Policy) : Never, OnFailure, Always 지정 가능
      • Always : Succceed/Failed 뭘로 끝나던 간에 재실행한다. Web 서버에 적합.
      • OnFailure : 오로지 Failed 했을 때만 다시 실행한다.
      • Never : Succceed/Failed 뭘로 끝나던 재실행하지 않는다. Batch 에 적합.
    • SUCCEEDED : 실행된 후 exit code = 0 으로 종료된 상태
    • FAILED :
      • 실행됐고 어떤 이유로 exit code != 0 으로 종료된 상태
      • PodRestart Policy 에 따라 다시 실행될 수도 있다
    • SUCCEEDFAILED 이든 짧은 시간 내에 계속 재시도 되면 CrashLoopBackOff 상태가 된다.

SUCCEED 인데 CrashLoopBackOff 가 발생하는게 의아할 수 있다.
이건 1회성 앱을 마치 서버처럼 실행해서 그런 것이다.
이때는 restart policyNever 또는 OnFailure 로 지정하면 된다.
그외에도 Job/CronJob 으로 실행해도 된다.




ReplicaSet

Pod 의 이중화, 즉 고가용성을 위한 리소스이고,
사용자의 상태 정의(=yaml)를 통해서 Pod 의 수를 정해진 갯수대로
유지해주는 리소스가 바로 ReplicaSet (=rs)
이다.

Replica 라는 건 복제본을 의미한다. 이 복제본은 각각의 Pod 를 의미한다.
이렇게 복제본 Pod 를 관리한다고 해서 Set 을 붙인다.


동작방식

Pod 의 수를 정해진 갯수대로 유지해주는 것이 바로 ReplicaSet 의 주요 기능이다.
이를 위해서 rs 는 아래와 같은 동작을 한다.

  1. 주기적으로 실행중인 Pod 개수 체크
  2. 실제 Pod 의 개수가 정의된 개수보다 적을 때는 새로운 Pod 생성
  3. 실제 Pod 의 개수가 정의된 개수보다 많을 때는 기본 Pod 제거

이때 자기가 관리할 파드를 구분 짓는 방법이 중요한데,
레이블(=label) 을 기준으로 관리대상을 타겟팅한다.


yaml

# 파일명: toast-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: toast-rs
spec:
  # 유지할 POD 의 갯수 지정
  replicas: 3
  
  # 관리 대상 POD 를 지정하기 위한 레이블 설정
  selector:
    matchLabels:
      app: toast-proxy
      
  # ReplicaSet 이 관리할 POD 정의
  # 참고로 POD 의 이름은 toast-rs-????? 처럼 자동 생성된다.
  template:
    metadata:
      labels:
        app: toast-proxy
    spec:
      containers:
      - name: toast-nginx
        image: nginx:alpine-slim

이렇게 지정하고 yaml 을 kubectl apply 하면 다음과 같은 일이 벌어진다.

  1. ReplicaSet 생성
  2. app: backend label 이 붙은 Pod 갯수 체크
  3. 기존에 실행 중인 Pod 가 하나도 없으므로 Pod 생성
  4. Pod 3개가 정상적으로 실행

명령어 활용

kubectl apply -f toast-rs.yaml
replicaset.apps/toast-rs created

ToastBread → kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
toast-rs   3         3         3       4m27s

ToastBread → kubectl get pods --show-labels
NAME                         READY   STATUS    RESTARTS        AGE    LABELS
toast-rs-7jhrz               1/1     Running   0               43s    app=toast-proxy
toast-rs-9zb8l               1/1     Running   0               43s    app=toast-proxy
toast-rs-zgk29               1/1     Running   0               43s    app=toast-proxy

## 자동으로 pod 명이 rs 의 name 을 활용하는 것을 볼 수 있다.
## 레이블 또한 template > metadata > labels 에 지정한 것과 동일하다. 


ToastBread → kubectl describe rs toast-rs
Name:         toast-rs
Namespace:    default
Selector:     app=toast-proxy
Labels:       <none>
Annotations:  <none>
Replicas:     3 current / 3 desired
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=toast-proxy
  Containers:
   toast-nginx: # 앞서 yaml 에 지정했던 container 이름이 보인다.
    Image:         nginx:alpine-slim

(... 생략 ...)

Events:
  Type    Reason            Age   From                   Message
  ----    ------            ----  ----                   -------
  Normal  SuccessfulCreate  5m9s  replicaset-controller  Created pod: toast-rs-zgk29
  Normal  SuccessfulCreate  5m9s  replicaset-controller  Created pod: toast-rs-7jhrz
  Normal  SuccessfulCreate  5m9s  replicaset-controller  Created pod: toast-rs-9zb8l
  
  
## 참고: replicaSet 갯수 늘리기
## kubectl scale rs toast-rs --scale=5

## 레이블 추가
## kubectl label pod toast-rs-zgk29 creator=something

## 레이블 수정
kubectl label pod toast-rs-zgk29 app=toast-proxy2 --overwrite

kubectl get po,rs --show-labels
pod/toast-rs-9wfgz               1/1     Running   0             5m39s   app=toast-proxy
pod/toast-rs-x9glv               1/1     Running   0             5m39s   app=toast-proxy
pod/toast-rs-xlvxf               1/1     Running   0             5m39s   app=toast-proxy2
pod/toast-rs-zd65r               1/1     Running   0             6s      app=toast-proxy

## -> 다시 생성

## 다시 지우기...
kubectl delete -f .\toast-rs.yaml
kubectl delete pod -l app=toast-proxy2




Deployment

애플리케이션의 버전관리와 배포를 담당하는 리소스이다.
여러개의 ReplicaSet 을 관리하며, 각 ReplicaSet 을 하나의 버전(=Revision)으로 관리한다.
Deployment -> ReplicaSet -> Pod 순으로 계층적 리소스 구조를 갖는다.

ReplicaSet 버전이 여러 개 있으면 가장 최신 버전의 rs 의 Pod 만 남기고, 이전 rs 의 Pod 는 없앤다.
다만 이 과정에서 배포 전략(Strategy)에 따라서 생성/삭제의 방식이 조금씩 다르다.

배포전략은 대표적으로 Recreate 와 RollingUpdate 가 있다.
Recreate 은 그냥 기존 Pod 모두 삭제 후 신규 Pod 를 띄운다. 이러면 무중단 배포가 안된다.
RollingUpdate 는 점진적으로 Pod 를 교체한다.


yaml

## 파일명 toast-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: toast-deploy
spec:
  # 배포전략 지정 (생략 가능!)
  strategy:
    type: RollingUpdate # default 임.
    rollingUpdate:
      maxSurge: 2 # 새로운 버전 배포할 때 한번에 배포하는 Pod 갯수
      maxUnavailable: 1 # 기존 Pod 삭제 시 동시 삭제 갯수 지정
  
  # ReplicaSet 정의
  replicas: 3
  selector:
    matchLabels:
      app: backend
  
  # Pod 정의 
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: my-nginx
        image: nginx:alpine

# 참고로 Pod 정의가 수정될 때만 새로운 리비전이 생성된다!
# 즉 아래처럼 명령어로 deployment 의 pod 정보를 수정할 때 새로운 리비전이 생성된다.
# kubectl set image deploy my-app nginx=nginx:alpine-slim
# 일반적으로는 이미지의 버전이 바뀌어서 리비전이 생성된다.

명령어 활용

ToastBread → kubectl apply -f .\toast-deploy.yaml
deployment.apps/toast-deploy created

# 참고: 명령어로도 생성가능
# kubectl create deployment toast-deploy --image=nginx:alpine-slim --replicas=3

# 참고: replicas 변경방법, 이건 하더라도 리비전 생성 X
# kubectl scale deploy toast-deploy --replicas=5

# ------------------------------------------------

ToastBread → kubectl get deploy,rs,pod --show-labels
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   LABELS
deployment.apps/toast-deploy   3/3     3            3           74s   <none>

NAME                                      DESIRED   CURRENT   READY   AGE   LABELS
replicaset.apps/toast-deploy-5ccd56fb5d   3         3         3       74s   app=backend,pod-template-hash=5ccd56fb5d

NAME                                READY   STATUS    RESTARTS      AGE    LABELS
pod/toast-deploy-5ccd56fb5d-8lz7t   1/1     Running   0             74s    app=backend,pod-template-hash=5ccd56fb5d
pod/toast-deploy-5ccd56fb5d-tt56f   1/1     Running   0             74s    app=backend,pod-template-hash=5ccd56fb5d
pod/toast-deploy-5ccd56fb5d-vdkkk   1/1     Running   0             74s    app=backend,pod-template-hash=5ccd56fb5d

deployment 의 배포 이력 관리

명령어

# 배포 상태 확인 (실시간)
kubectl rollout status deploy 리소스명

# 배포 이력
kubectl rollout history deploy 리소스명

# 변경 이력 기록 (deployment 배포 후에 이렇게 처리하면 더 쉽게 변경 추적이 가능)
kubectl annotate deploy 리소스명 Kubernetes.io/change-cause="변경이력"

# 이전 버전(=revision)으로 롤백, 롤백 대상 리비전이 가장 큰 수의 리비전으로 바뀐다. 
# 즉 롤백 된 리비전이 가장 최신 리비전으로 변경되는 것이다.
kubectl rollout undo deploy 리소스명 [--revision=1]

# 참고: 배포 일시 중지
# kubectl rollout pause deploy 리소스명

# 참고: 배포 재개
kubectl rollout resume deploy 리소스명

RollingUpdate 의 maxUnavailable 과 maxSurge

  • maxSurge:
    replicaset 의 지정된 갯수 외에도
    교체 작업도중 추가분으로 생성할 수 있는 Pod 의 수
  • maxUnavailabe:
    교체 도중에 실행될 필요가 없는 갯수
    replicas=3 이더라도 maxUnavailabe=1 이면 교체 도중에는 2개까지만 유지되면 된다.




Service

서비스는 Pod 간에 네트워크를 연결해주는 리소스이다.
이에 대한 이해를 위해서 먼저 이중화화 로드밸런싱을 좀 알아보자.

이중화 구조와 로드 밸런싱

  • 서버 이중화 구성 시 사용자는 특정 서버를 선택해서 접속 X
    • 서버마다 IP 가 다름, 파드가 재시작되면 새로운 IP 가 생성
  • 사용자가 접속할 수 있는 주소(엔드포인트)는 하나여야 한다.
  • 이때 로드밸러서가 필요하다! 로드밸런서는 "동일한 역할을 하는 서버"를
    묶어 한 개의 공통된 접속 주소를 제공한다.

k8s 로드밸런싱

  • k8s 는 Pod 가 여러 노드에서 실행된다.
  • 그리고 각 Pod 는 고유한 IP 를 가진다.
  • 동일한 역할을 하는 Pod 에 접근하기 위한 로드밸런서가 필요하다.

k8s 는 Service(서비스) 가 바로 이 로드밸런서의 역할을 수행한다
Service 는 다음과 같은 특성/기능을 갖는다.

  1. Service 는 Pod 에 접근하기 위한 "고정된 가상 IP 를 제공"하며 svc 로 줄여서 표현한다.
  2. Service 는 고유한 이름과 IP 를 가진다.
  3. (중요) k8s 내부의 서버는 Service 의 IP이름을 통해 실제 컨테이너로 요청을 보낼 수 있다.
    그래서 Pod 가 다른 Pod 로 요청을 보낼 때는 무조건 Service 가 있어야 한다.

참고:
서비스는 지속적으로 POD 의 IP 를 모니터링하기 때문에 신규로 POD 가 생성되더라도,
그에 맞게 내부적으로 설정이 변경되고 자신의 IP 는 계속해서 동일하게 유지한다.

참고2:
서비스는 Pod 의 레이블(label)을 기준으로 타깃을 잡는다.


yaml

apiVersion: v1
kind: Service
metadata:
  name: toast-svc
spec:
  selector:
    app: toast-app # 타겟팅할 Pod 의 레이블
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP # (기본값). 클러스터 내부에서만 접근 가능한 가상 IP
  # 외부에서 접근하려면 Ingress 추가로 필요!
  # 외부 → Ingress Controller → ClusterIP Service → Pods

port / targetPort 의 차이점:

  • port: Service 가 요청을 받는 포트번호
  • targetPort: Service 가 받은 트래픽을 forward 할 Pod(=컨테이너) 의 포트번호
  ┌─────────────────┐
  │   다른 Pod     │
  │  (예: 프론트엔드)│
  └────────┬────────┘
           │
           │ http://toast-service:80 요청
           │ # toast-service 는 Service 의 이름이다. 이름으로 통신도 가능하다!
           ▼
  ┌────────────────────┐
  │  toast-svc       │ ← ClusterIP: 10.96.100.50 (가상 IP)(Service)       │
  └─────────┬──────────┘
            │
            │ 로드밸런싱
            │
      ┌─────┴─────┬──────────┐
      ▼           ▼          ▼
  ┌──────┐   ┌──────┐   ┌──────┐
  │ Pod1 │   │ Pod2│   │ Pod3 │  ← app: toast-app
  │:8080 │   │:8080│   │:8080 │
  └──────┘   └──────┘   └──────┘

명령어로도 생성이 가능하다.

kubectl expose deploy 디플로이먼트명 type=ClusterIP --port=진입포트번호 --target-port=컨테이너포트번호 --name=서비스명

명령어 활용

kubectl get svc -n toast -o wide # service 조회
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
toast-svc     ClusterIP   10.96.135.168   <none>        80/TCP   5m    app=toast-app

kubectl describe svc 이름 -n toast # 서비스 상세조회
Name:                     toast-svc
Namespace:                toast
Labels:                   <none>
Annotations:              <none>
Selector:                 app=toast-app
Type:                     ClusterIP
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.96.135.168
IPs:                      10.96.135.168
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
Endpoints:                10.244.1.4:8080,10.244.3.3:8080,10.244.2.4:8080
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>

## Service 가 Pod 의 정보를 수집할 때 endpoint 를 통해서 IP 정보를 관리한다.
## endpoint 도 하나의 리소스이기 때문에 조회가 된다.
kubectl get endpoints -n toast
NAME          ENDPOINTS                                   AGE
backend-svc   10.244.1.4:8080,10.244.2.4:8080,10.244.3.3:8080   6m9s


kubectl describe endpoints -n toast # ==> 여기서도 각 POD 의 아이피 확인 가능
Name:         backend-svc
Namespace:    dev
Labels:       <none>
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2025-12-25T08:52:17Z
Subsets:
  Addresses:          10.244.1.4,10.244.2.4,10.244.3.3
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    <unset>  80    TCP

Events:  <none>

## Pod 를 삭제하고, endpoints 정보를 다시 조회하면,
## rs 에 의해서 다시 생성된 Pod 의 신규 IP 가 endpoints 에 다시 적용된다.

# 신규 서비스 생성, deploy 기반으로 생성
# kubectl expose deploy some-deploy --type=ClusterIP \
# --port:8081 --target-port=80 \
# --name=some-svc -n toast

Service & DNS

DNS 서버와의 관계

k8s 클러스터에서 dns 를 관리하는 파드가 따로 있고 그게 coredns 인데,
확인을 하려면 아래처럼 조회할 수 있다.

ToastBread → kubectl get po -n kube-system
NAME                                             READY   STATUS    RESTARTS       AGE
coredns-7db6d8ff4d-64zpq                         1/1     Running   23 (11m ago)   15d
coredns-7db6d8ff4d-vchls                         1/1     Running   23 (11m ago)   15d
# ... 생략 ...
  • 여기서 corednsk8s 에서 DNS 서비스를 제공하는 파드이다.
  • Core DNSDeployment 형태로 실행되고 있기 때문에
    kubectl get deploy 로 확인 가능하다.
ToastBread → kubectl get deploy -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
coredns          2/2     2            2           15d
# ... 생략 ...
  • 이 core dns 는 k8s 에 존재하는 pod 들의 DNS 서버 역할로 활용되기 때문에
    공통 엔드포인트로서도 존재한다. 아래처럼 조회할 수 있다.
ToastBread → kubectl get svc -n kube-system -o wide
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
kube-dns         ClusterIP   10.96.0.10    <none>        53/UDP,53/TCP,9153/TCP   15d   k8s-app=kube-dns
# ... 생략 ...

여기서 보이는 10.96.0.10 이 바로 모든 pod 들이 갖는 nameserverIP 다.
이를 한번 확인해보자.

# Pod 내부로 접근
kubectl exec -it toast-deploy-5ccd56fb5d-k69kc -- sh

# 
/ # cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10 ## ==> 아까 본 nameserver ip 와 동일하다!
options ndots:5
/ #

이런 coredns 와 관련해서 POD 의 nameserver 등록이 자동으로 된 덕분에
pod 안에서 nslookup {service명} 을 입력하면 서비스의 아이피값이 가져올 수 있고,
다른 namespace 에 있는 경우에는 nslookup {service명}.{namespace명} 을 붙여서 요청을 날리수도 있다.

참고: 다른 네임스페이스에 요청 보내기

  1. 같은 네임스페이스에 있는 경우
curl 서비스_이름
  1. 다른 네임스페이스에 Service 에 요청 보내기
curl 서비스_이름.네임스페이스_이름




ConfigMap

ConfigMap 은 컨테이너 실행 시에 필요한 다양한 환경변수를 관리하는 리소스다.
그런데 환경변수란 게 뭘까?

환경변수

  • 프로그램 코드가 아닌 프로그램이 실행되는 OS 에 저장하는 변수를 의미한다.
  • 데이터베이스 접속 정보처럼 실행 환경마다 달라지거나,
    보안상 민감한 값은 환경변수에 저장한다.

이런 환경변수를 그런데 왜 굳이 리소스로 거창하게 따로 관리할까?
이건 클라우드 네이티브 환경을 구성하는 주요 요건 중 하나인 설정 외부화 때문이다.


설정 외부화

  • 애플리케이션은 개발, 스테이징, 운영 환경으로 주로 구성된다.

  • 각 환경별로 다르게 적용되는 값을 설정(Configuration)이라고 부른다.

  • 설정값들을 소스코드에 저장하면 여러 문제가 발생한다.

    • 보안 상 보안 문제 발생 가능!
    • 주로 OS 의 환경변수 세팅 후, 그걸 애플리케이션에서 읽는 형태로 사용
    • 이런 이유로 소스코드와 분리된 외부에 설정값을 둔다.
  • 설정 외부화(Configuration Externalization)은 클라우드 네이티브 애플리케이션의 필수 설계 원칙 중 하나이다.

  • 환경 변수나 설정 파일을 통해 외부에서 설정을 주입하는 게 핵심이다.


yaml

apiVersion: v1
kind: Pod
metadata:
  name: busybox
spec:
  containers:
    - name: busybox
      image: busybox
      env: # --> 파드의 POD_ENV 환경변수에 env_test 값 주입
        - name: POD_ENV
          value: "env_test"      

위처럼 각각의 POD 별로 이렇게 환경변수를 세팅하면,
여러 POD 에 해야될 때는 상당히 불편해진다.

그래서 파드의 환경변수를 env 의 key-value 형식으로 관리하기 보다는
ConfigMapSecret 을 참조하는 형태로 설정을 하는 경우가 대다수다.



ConfigMap

  • ConfigMap 은 키-값으로 구성된 설정 데이터를 저장하는 리소스이며, cm 으로 줄여 표현한다.
  • Pod 에서 ConfigMap 을 여러 형태로 참조할 수 있다.
  • 여러 개의 Pod 가 한 개의 ConfigMap 을 참조할 수 있다.

Secret

  • Secret 은 ConfigMap과 유사하지만 비밀번호, API키, 인증서와 같은 민감한 정보를 관리한다.
  • 데이터를 Base64로 인코딩하여 저장된다.
  • 실제 서버에서는 원본 문자열을 불러온다.
  • 누구나 디코딩할 수 있기 때문에 보안적인 목적은 아니다.



Yaml 구조

ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  db_host: "my-app"
  log_level: "DEBUG"
  max_connetion: "100"

Secret

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
data:
  db_username: dXNlcgo=
  db_password: cGFzc3dvcmQ=
  # --> 저장할 데이터 (Base64 인코딩 되어 있음)

# 일일이 저장할 때마다 변환해서 넣는 건 힘들기 때문에 일반적으로는 아래처럼 함.

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
stringData:
  db_username: "user"
  db_password: "password"

# 이러면 알아서 Base64 로 인코딩해서 넣는다.

Pod 에 주입하기

apiVersion: v1
kind: Pod
metadata:
  name: toast-pod
spec:
  containers:
  - name: nginx-toast
    image: nginx:alpine-slim
    envFrom:
    - configMapRef:
      name: (컨피그맵명)
    - secretRef:
      name: (시크릿명)
# 이러면 env 필드에 key-value 로 넣던 방식과 동일한 효과를 갖는다.

참고: 명령어로 생성하기

kubectl create configmap 컨피그맵명 --from-literal=키1=값1 --from-literal=키2=갑2
kubectl create secret generic 시크릿명 --from-literal=키1=값1 --from-literal=키2=갑2
# generic 은 시크릿의 다양한 종류 중 하나임!



명령어 활용

ToastBread → kubectl create cm toast-config -n toast \
	--from-literal=REDIS_HOST=redis \
    --from-literal=REDIS_PORT=6379
# configmap/hitchecker-config created

ToastBread → kubectl get cm -n toast
NAME                DATA   AGE
toast-config   3      13s
kube-root-ca.crt    1      5m29s


ToastBread → kubectl describe cm toast-config -n toast
# 아래는 출력:
Name:         toast-config
Namespace:    toast
Labels:       <none>
Annotations:  <none>

Data
====
REDIS_HOST:
----
redis

REDIS_PORT:
----
6379


BinaryData
====

Events:  <none>
# ---


ToastBread → kubectl get cm hitchecker-config -o yaml -n dev
apiVersion: v1
data:
  REDIS_HOST: redis
  REDIS_PORT: "6379"
kind: ConfigMap
metadata:
  creationTimestamp: "2025-12-31T11:33:29Z"
  name: toast-config
  namespace: toast
  resourceVersion: "590730"
  uid: fcd8711d-0f0c-4d7d-86f2-382489f5fa9f

Secret 은 왜 사용하나?!

  • ConfigMap 과 Secret 은 사용자 관점에서 단순히 Base64 인코딩을 했냐
    안했냐의 차이만 있을 뿐 큰 차이를 못 느낀다.

  • 하지만 쿠버네티스 시스템의 리소스 관리, 보안, 권한 분리 등을 위해서 분리되어 설계되었다.


ConfigMap, Secret 이 적용 시점

  1. Pod 실행 시점에 환경변수(ConfigMap, Secret)을 읽어서 적용
  2. 이후에 ConfigMap, Secret 을 수정한다고 이미 실행 중인 Pod 에 적용되지 않는다.
  3. 변경된 것을 적용하고 싶다면 Pod 를 모두 재시작해야 한다.




Ingress

사용자와 쿠버네티스에서 실행중인 애플리케이션에 접속을 도와주는 게 Ingress 이다.

쿠버네티스의 Service 는 L4 기반(IP 와 Port 기준) 의 트래픽 라우팅하고,
반면에 Ingress 는 L7(요청의 URL 기준) 을 사용하여 트래픽을 라우팅을 한다.

Service 는 내부 Pod 들 끼리 통신할 때만 쓰고,
외부 요청은 Ingress 에게 맡기는 게 일반적이다.

Ingress 는 Service 로 네트워크 트랙픽을 전달하는 것을 목적으로 만들어졌다.
요청의 도메인과 경로에 따라 어떤 서비스로 연결할지를 지정한다.

Ingress 는 외부에서 app 으로 들어오는 요청의 entrypoint 역할도 수행.


참고: 노드의 로드밸런서

여러개의 노드로 실행되는 클러스터이다 보니,
쿠버네티스는 여러개의 Nodre 에 공통으로 접근할 수 있는 로드밸런서가 필요하다.

NodeL4 로드 밸런서 로 연결하며,
외부 사용자는 로드 밸런서를 통해 쿠버네티스 클러스에 접속한다.


사용자 요청의 흐름

사용자 접속 -> Node 의 로드밸런서 서버 -> Nginx Ingress Controller -> Service -> Pod 순이다.
결과적으로 사요자는 Node 의 로드 밸런서 서버 IP 만 알기 되기 때문에 사용자 입장에서 편하다.

yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: toast-ingress
  namespace: toast
spec:
  ingressClassName: nginx
  rules:
    - host: toast-manager.com # 사용자가 접속할 도메인, 현재 도메인이 없다면 생략 가능.
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: toast-frontend
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: toast-user
                port:
                  number: 80

명령어 활용

kubectl get ingress -n toast
NAME           CLASS   HOSTS   ADDRESS   PORTS   AGE
toast-ingress  nginx   *                 80      12s
ToastBread → kubectl describe ingress -n toast
Name:             toast-ingress
Labels:           <none>
Namespace:        toast
Address:
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /            toast-frontend:80 (10.244.1.2:80)
              /users       toast-user:80 (10.244.1.3:5000)
Annotations:  <none>
Events:
  Type    Reason  Age   From                      Message
  ----    ------  ----  ----                      -------
  Normal  Sync    31s   nginx-ingress-controller  Scheduled for sync





컨트롤 플레인

쿠버네티스의 컨트롤 루프는
관찰 -> 비교 -> 조치를 통해서 원하는 상태를 실제 상태로 바꾼다.
그런데 이 컨트롤 루프는 정확히 어디서 실행되는 걸까?


컨트롤 플레인 Pod

쿠버네티스는 클러스터 전체를 제어/관리하는 소프트웨어이고,
이러한 역할은 컨트롤 플레인이라는 핵심 구성요소들이 담당한다.

"컨트롤 플레인의 구성요소들은 Pod 형태로 실행"되며,
우리가 생성하는 일반 Pod 가 아닌, 쿠버네티스 설치시 실행되는 시스템 Pod 이다.


Control Plane Node , Work Node

이때 컨트롤 플레인의 Pod 들도 결국은 Pod 이기 때문에 Node 에 실행되어야 한다.
다만 이 Pod 들은 특별하게 Control Plane Node 에서 실행된다.
일반적으로 사용자들이 생성한 Pod 들은 Worker Node 에 생성된다.

즉 Node 의 종류가 2가지로 나뉜다는 점을 알아야 한다.

컨트롤 플레인 파드가 실행되는 노드를 Control Plane Node (컨트롤 플레인 노드)라고 한다.
사용자가 생성한 파드가 실행되는 노드를 Worker Node(워커 노드)라고 한다.


명령어 활용

ToastBread → kubectl get node
NAME                     STATUS   ROLES           AGE   VERSION
control-plane   Ready    control-plane   26d   v1.30.0
worker          Ready    <none>          26d   v1.30.0
worker2         Ready    <none>          26d   v1.30.0
worker3         Ready    <none>          26d   v1.30.0


# kubectl describe node 노드명 # 상세정보
# kubectl top node # 자원 사용량 조회

kubelet

kubelet 은 각 Node(Control Plane/Worker) 에 설치되는 소프트웨어.
kubelet 은 컨트롤 플레인의 지시에 따라 컨테이너 런타임에 컨테이너 관리 작업을 요청한다.
컨트롤 플레인이 요청하는 대로 컨테이너를 실행하거나 상태정보를 조회할 수 있다.




컨트롤 플레인

  • 클러스터의 중심 두뇌로, 전체 상태를 관리하고 제어한다.

  • 컨트롤 플레인 은 다음과 같이 구성

    • API 서버(요청 수용, kubectl 의 명령어를 받는 API 서버)
    • 스케줄러(새로운 파드를 적절한 노드에 배치),
    • 컨트롤 매니저(클러스터 상태를 원하는 대로 유지)
  • etcd 라는 클러스터 상태를 저장하는 DB 가 존재한다.

  • "컨트롤 플레인 파드"와 "etcd 파드"는 모두 Control Plane Node 에서 실행된다.

  • 컨트롤 플레인 구성요소들은 kube-system namesapce 에서 pod 로 실행된다.

kubectl get po -n kube-system -o wide

ToastBread → kubectl get po -n kube-system -o wide
NAME                                   READY   STATUS    RESTARTS        AGE   IP           NODE            NOMINATED NODE   READINESS GATES
etcd-control-plane                     1/1     Running   1 (121m ago)    13h   172.22.0.3   control-plane   <none>           <none>
kube-apiserver-control-plane           1/1     Running   1 (121m ago)    13h   172.22.0.3   control-plane   <none>           <none>
kube-controller-manager-control-plane  1/1     Running   28 (121m ago)   21d   172.22.0.3   control-plane   <none>           <none>
kube-scheduler-control-plane           1/1     Running   28 (121m ago)   21d   172.22.0.3   control-plane   <none>           <none>
# 더 많은 데 생략함.

API 서버(kube-apiserver)

  • 클러스터 내 모든 컴포넌트가 반드시 거쳐가는 통신 관문이다.
  • 클러스터에서 발생하는 모든 요청은 API 서버를 통해 처리되거나, 적절한 컴포넌트에 전달.
  • kubectl 명령을 실행할 때도 API 서버를 통해 클러스터에 전달되며, 사용자의 요청을 처리한다.

etcd

  • 클러스터의 상태 정보를 젖아하는 키-값 DB
  • API 서버는 주기적으로 각 노드에 설치된 kubelet 을 통해 상태를 수집하고,
    그걸 etcd 에 저장한다.
  • 사용자가 kubectl 로 생성한 리소스 구성 정보 또한 etcd 에 저장된다.

스케줄러

  • 새로 생성된 Pod 를 실행할 적절한 노드를 결정하는 역할
  • Pod 와 가장 적합한 노드 선택하고, 그 결과를 API 서버를 통해 etcd 에 기록
  • etcd 에 저장된 정보는 컨트롤러가 파드를 실제로 실행할 때 사용

컨트롤러 매니저

  • 컨트롤러 매니저는 클러스터의 상태를 지속적으로 감시한다.
  • 사용자가 요청한 상태와 실제 상태가 다를 경우 자동으로 조정한다.
  • 예를 들어 스케줄러가 지정한 Node 에 Pod 가 없으면 컨트롤러 매니저가
    새로운 Pod 생성을 요청한다.
  • 실제로는 Pod 생성을 직접하지 않고 API 서버에 요청하고,
    API 서버가 노드의 kubelet 에 다시 전달해서 컨테이너 생성하게 된다.



워커 노드와 스케줄링

Work Node 는 사용자가 생성한 Pod 가 실행되는 Node
스케줄러는 새로 생성된 Pod 를 실행할 가장 적절한 Node 를 선택
사용자가 Pod 를 생성 요청하면 스케줄러가 전체 Node 중 조건에 맞는 1개를 선택

Node 스케줄링을 제어하는 4개의 방법

  • nodeName : 직접 Node 지정
  • nodeSelector : 레이블이 일치하는 Node 선택
  • nodeAffinity : 복잡한 조건식을 사용해 Node 선택
  • Taint & Toleration : 특정 조건을 만족하는 Pod 만 배치되도록 제한

직접 배치 방식

스케줄러를 거치지 않고, 해당 Node 에 즉시 배치된다.
테스트용도로 주로 사용한다고 한다.

apiVersion: v1
kind: Pod
metadata:
  name: fixed-node-pod
spec:
  nodeName: node4 # 이렇게 직접 지정가능
  containers:
  - name:app
    image: busybox:1.35

레이블이 일치하는 Node 에 배치

apiVersion: v1
kind: Pod
metadata:
  name: fixed-node-pod
spec:
  nodeSelector: # !
    disktype: ssd # !
  containers:
  - name:app
    image: busybox:1.35

nodeAffinity 방식

표현식 기반으로 Node 선택
nodeSelecotr 보다 유연하다, 다만 복잡하다!



테인트와 톨러레이션

Control Plane Node 의 분리

Control Plane Node 는 컨트롤 플레인 파드를 실행하므로,
사용자가 생성한 Pod 와 물리적으로 분리되어야 한다.

특정 Node 에 Pod 를 올리지 못하도록 제한하는 것을 Taint(테인트)라고 한다.
기본적으로 Control Plane Node 는 아래와 같은 Taint 가 설정되어 있다.

# Taint: 스케줄링 금지 조건
key: node-role.kubernetes.io/control-plane
effect: NoSchedule

Taint 와 Toleration

  • Taint 는 특정 Node 에 Pod 가 스케줄링 되지 않도록 제한하는 설정
  • Node 에 설정된다.

그러면 어떤 파드를 설정할 수 있을까?
그건 Pod 에 Toleration(참을 수 있는) 설정이 있는 것들이다.


Taint Yaml 구조

  • Taint 는 key + value + effect 의 조합이다.
  • key, effect 는 필수이며, value 는 생략 가능하다.
apiVersion: v1
kind: Node
metadata:
  name: cpu-node
spec:
  taints:
    - key: resource
      value: highcpu
      effect: NoSchedule
  • effect
    • NoSchedule: 새로운 pod 중 toleration 이 없으면 해당 Node 에 스케줄되지 않음
    • NoExecute: 기존에 이미 Node 실행 중인 Pod 라도 toleration 없으면 퇴출(evict) 됨

Toleration Yaml 구조

  • Toleration 는 key + value + effect 의 조합으로 Taint 를 지정(선택)한다.
  • operator 의 판단 방식에 따라 Taint 통과의 여부가 결정된다.
apiVersion: v1
kind: Pod
metadata:
  name: tolerate-highcpu
spec:
  tolerations:
    - key: resource
      value: highcpu
      effect: NoSchedule
      operator: Equal
  containers:
    - name: busybox
      image: busybox
  • operator
    • Equal: key, value 가 모두 동일
    • Exists: key 만 일치하면 통과, value 는 무시됨 (더 자주 사용된다고 함)

참고:

kubectl taint node 노드명 <key>=<value>:<effect> # Node 에 Taint 설정
kubectl taint node 노드명 <key>:<effect> # Node 에 설정된 Taint 제거

참고로 control plane node 의 경우 아래와 같은 Taint 가 있다.

ToastBread → kubectl describe node control-plane
Name:               control-plane
Roles:              control-plane
# ... 생략 ...
Taints:             node-role.kubernetes.io/control-plane:NoSchedule





워크로드 리소스

워크로드?

  • 워크로드는 쿠버네티스에서 컨테이너를 실행하고 관리하기 위한 리소스를 의미
  • rs, deploy 는 pod 를 실행하고 관리하는 대표적인 워크로드 리소스
  • 쿠버네티스는 이외에도 다양한 목적에 특화된 워크로드 리소스를 제공한다.
  • 똑같이 파드를 실행하지만, 다른 방식으로 실행하게 된다.

Job

배치

Job 은 이런 일회성 작업을 실행하기 위한 워크로드 리소스이다.
작업 실행을 위해 Pod 를 일시적으로 생성하며, 작업 완료 시 자동으로 종료된다.
잡이 실행하는 Pod 에는 CMD 에 배치 프로그램을 실행하도록 지정해야 한다.

YAML

apiVersion: batch/v1
kind: Job
metadata:
  name: toast-job
spec:
  template:
    metadata:
      labels:
        app: my-batch
    spec:
      containers:
      - name: my-batch
        image: my-batch:1.0
        command: ["java","-jar", "batch.jar"] # CMD 지정 !!!
      restartPolicy: Never

명령어 활용

ToastBread → kubectl get job # 아래와 같은 3가지 상태가 존재한다.
NAME          STATUS     COMPLETIONS   DURATION   AGE
job-fail      Failed     0/1           19s        19s
job-running   Running    0/1           19s        19s
job-success   Complete   1/1           5s         19s
# Job 의 상태는 결국 Pod 의 상태에 달렸다.

Job 의 Pod 관리 및 상태

Job 은 생성한 Pod 가 실패하면, Job 이 성공할 때까지 새 Pod 를 계속 생성하여 실행한다.
설정한 횟수 이상 실패하면, Job 은 더 이상 Pod 를 생성하지 않으며, Job 은 Failed 상태로 전환된다.
Pod 가 정상적으로 종료되면, Job 은 Succeeded 상태로 전환된다.


Job 실행 옵션

  • Job 은 실행 방식과 동작 조건을 다양한 옵션으로 설정할 수 있다.

  • Pod 의 실행 횟수, 병렬 처리, 실패 시 재시도 횟수, 제한 시간등을 제어할 수 있다.

  • 옵션키:

    • completions : Job 완료에 필요한 성공 Pod 수 (기본값: 1) --> 2로 설정하면, 2 번 성공할 때까지 Pod 재생성
    • parallelism : 동시에 실행할 최대 Pod 수 (기본값: 1)
    • backoffLimit : Pod 실패 시 재시도 허용 횟수 (기본값: 6) --> 실패 하면 횟수채울 때까지 계속 재생성
    • activeDeadlineSeconds : Job 이 실행될 수 있는 최대 시간 (기본값 없음)
    • ttlSecondsAfterFinished : Job 완료 후 삭제까지 대기 시간 (기본값 없음)
apiVersion: batch/v1
kind: Job
metadata:
  name: my-job
spec:
  completions: 3 # 파드가 3번 성공해야 잡 성공
  parallelism: 2 # 동시에 최대 2개의 파드가 실행됨
  backoffLimit: 4 # 파드가 실패하면 4번까지는 다시 실행, 5번째에서는 잡 실패로 간주
  activeDeadlineSeconds: 120 # 잡이 120초 안에 끝나지 않으면 실패
  ttlSecondsAfterFinished: 60 # 잡이 끝나면 60초 후 자동 삭제/ 파드는 삭제되지 않고 남아 있음

ex:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-completions
spec:
  completions: 3
  parallelism: 1
  template:
    spec:
      containers:
      - name: c
        image: busybox:1.35
        command: ["sh", "-c", "echo '1회 실행'; sleep 5"]
      restartPolicy: Never
      
---
 
apiVersion: batch/v1
kind: Job
metadata:
  name: job-timeout
spec:
  activeDeadlineSeconds: 10 # 10 초가 지나면 실패로 간주!
  ttlSecondsAfterFinished: 40 # Job 끝나고 40 초 지난 후 Job 삭제
  template:
    spec:
      containers:
      - name: timeout
        image: busybox:1.35
        command: ["sh", "-c", "echo '30초 후 완료'; sleep 30"]
      restartPolicy: Never

CronJob

  • Job 을 주기적으로 실행(=생성)하는 워크로드 리소스
  • 스케줄링 기반의 배치 작업에 적절
apiVersion: batch/v1
kind: CronJob
metadata:
  name: one-minute-cronjob
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: echo-container
            image: busybox:1.35
            args:
            - /bin/sh
            - -c
            - |
              sleep 10
              echo "executed successfully at $(date)"
          restartPolicy: Never

크론표현식

총 5개의 필드 - 분,시,일,월,요일을 나타낸다.
아래는 예시:

  • * * * * * : 모든 경우의 수, 모든 요일, 매월, 매시, 매분
  • 5 20 * * * : 매일 밤 8시 5분 실행
  • 0 23 * * 0,6 : 토요일, 일요일 23:00분 실행
  • */5 * * * * : 매 5분마다 실행
  • 0 9-17/2 * * * : 9~17시 사이에 2시간 간격으로 실행 (9, 11, 13, 15, 17 시)
  • 0 0 1-15 * 1-5 : 매월 1~15일 중 월~금요일 자정에 실행

ToastBread → kubectl get cronjob,job,pod
NAME                               SCHEDULE    TIMEZONE   SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob.batch/one-minute-cronjob   * * * * *   <none>     False     0        34s             2m43s

NAME                                    STATUS     COMPLETIONS   DURATION   AGE
job.batch/one-minute-cronjob-29462578   Complete   1/1           13s        2m34s
job.batch/one-minute-cronjob-29462579   Complete   1/1           13s        88s
job.batch/one-minute-cronjob-29462580   Complete   1/1           14s        28s

NAME                                    READY   STATUS      RESTARTS   AGE
pod/one-minute-cronjob-29462578-rdf7n   0/1     Completed   0          2m34s
pod/one-minute-cronjob-29462579-gjbrv   0/1     Completed   0          88s
pod/one-minute-cronjob-29462580-wfgcj   0/1     Completed   0          28s

DaemonSet

  • ds 로 약칭 사용 가능
  • 모든 노드에 동일한 Pod 를 하나씩 실행하기 위한 리소스이다.
  • 주로 Node 단위의 데이터 수집이나 처리에 사용된다.
  • 예: 로그 수집 에이전트, 모니터링 에이전트

yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-daemonset
spec:
  selector:
    matchLables:
      app: sample-daemon
      
  template: # DaemonSet 이 관리하는 Pod 정의
    metadata:
      labels:
        app: sample-daemon
    spec:
      containers:
      - name: busybox-daemon
        image: busybox:1.35

replicaSet 과 달리 숫자를 지정하지 않는다.
어짜피 모든 Node 에 실행될 거니까!

profile
백엔드 개발자로 일하고 있는 식빵(🍞)입니다.

0개의 댓글