쿠버네티스 시작하기
- 6.1 파드(Pod)
- 6.2 레플리카셋(ReplicaSet)
- 6.3 디플로이먼트(Deployment)
- 6.4 서비스(Service)
쿠버네티스의 핵심 오브젝트 네 가지 — 파드, 레플리카셋, 디플로이먼트, 서비스. 이 네 가지를 알면 쿠버네티스의 절반은 이해한 거야.
파드는 쿠버네티스에서 컨테이너를 배포하는 최소 단위야. 도커에서는 컨테이너 하나가 단위였지만, 쿠버네티스에서는 파드가 단위지. 파드 안에는 하나 이상의 컨테이너가 들어갈 수 있는데, 같은 파드 안의 컨테이너들은 네트워크 네임스페이스를 공유하기 때문에 localhost로 서로 통신할 수 있고, 볼륨도 공유 가능해. 대부분의 경우 파드에 컨테이너 하나만 넣지만, 사이드카 패턴(로그 수집기, 프록시 등)처럼 밀접하게 결합된 컨테이너를 같은 파드에 넣기도 하지.
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
ports:
- containerPort: 80
kubectl apply -f pod.yaml
kubectl get pods
kubectl describe pod my-pod
kubectl delete pod my-pod
중요한 건 — **파드는 일시적(ephemeral)**이라는 거야. 파드가 죽으면 그냥 죽는 거지. 자동으로 다시 생성되지 않아. 그래서 파드를 직접 만들어서 쓰는 경우는 거의 없고, 레플리카셋이나 디플로이먼트를 통해 관리해. 파드에는 라벨을 붙일 수 있는데, key: value 쌍으로 쿠버네티스의 거의 모든 리소스 선택이 라벨 기반이야. 서비스가 특정 파드를 찾을 때, 레플리카셋이 관리할 파드를 식별할 때 모두 라벨 셀렉터를 사용하거든.
파드가 죽으면 자동으로 다시 만들어주는 게 레플리카셋이야. "이 파드를 항상 N개 유지해라"고 선언하면, 레플리카셋 컨트롤러가 파드 수를 감시하다가 부족하면 만들고 넘치면 지워:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: my-rs
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:latest
selector는 어떤 라벨을 가진 파드를 관리할지 지정하고, template은 파드를 만들 때 사용할 템플릿이야. 이 둘의 라벨이 일치해야 해. replicas: 3인데 현재 파드가 2개면 1개를 추가로 생성하고, 4개면 1개를 삭제하고, 파드가 죽으면 새 파드를 생성해서 3개를 유지하는 식이지. 하지만 실무에서 레플리카셋을 직접 만드는 일은 거의 없어. 왜냐하면 디플로이먼트가 레플리카셋을 자동으로 관리해주기 때문이야.
디플로이먼트는 쿠버네티스에서 애플리케이션을 배포하는 사실상의 표준 단위야. 레플리카셋을 한 단계 더 추상화한 것으로, 레플리카셋의 기능에 롤링 업데이트와 롤백 기능을 추가하지:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deploy
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: nginx:1.24
레플리카셋과 YAML이 거의 같은데, kind만 Deployment로 바뀐 거야. 디플로이먼트를 생성하면 내부적으로 레플리카셋이 자동으로 만들어져. 이미지를 nginx:1.25로 바꾸고 다시 apply하면, 디플로이먼트가 새 레플리카셋을 만들어서 파드를 하나씩 교체해. 기존 레플리카셋의 파드를 줄이면서 새 레플리카셋의 파드를 늘리는 방식이라 다운타임이 없지:
kubectl set image deployment/my-deploy my-container=nginx:1.25
kubectl rollout status deployment/my-deploy
롤백도 간단해:
kubectl rollout undo deployment/my-deploy # 직전 버전으로 롤백
kubectl rollout history deployment/my-deploy # 리비전 히스토리
kubectl rollout undo deployment/my-deploy --to-revision=2 # 특정 리비전으로 롤백
디플로이먼트는 이전 레플리카셋을 삭제하지 않고 보관하기 때문에 롤백이 가능해. revisionHistoryLimit으로 보관할 히스토리 수를 설정할 수 있지. 정리하면 — 파드 < 레플리카셋 < 디플로이먼트 순서로 추상화 레벨이 올라가고, 대부분의 경우 디플로이먼트만 사용하면 돼.
이제 네트워크 쪽을 보자면, 파드는 생성될 때마다 IP가 바뀌잖아. 파드가 죽고 다시 만들어지면 새 IP를 받으니까, 파드의 IP를 직접 사용하면 안 돼. 서비스는 파드에 고정된 엔드포인트(IP + DNS)를 제공하는 오브젝트야. 라벨 셀렉터로 대상 파드를 선택하고, 트래픽을 해당 파드들에 로드 밸런싱하지:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 80
type: ClusterIP
서비스 타입에 따라 접근 범위가 달라져. ClusterIP(기본값)는 클러스터 내부에서만 접근 가능한 가상 IP를 할당해. 다른 파드에서 my-service:80으로 접근 가능하지만 외부에서는 접근 불가하고, 내부 서비스 간 통신에 사용돼. NodePort는 각 노드의 특정 포트(30000~32767)를 열어서 외부에서 접근 가능하게 하는 거야. 노드IP:NodePort로 접근하면 서비스를 통해 파드로 전달되지. ClusterIP 기능을 포함하고:
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
LoadBalancer는 클라우드 환경에서 외부 로드 밸런서를 자동으로 생성해. AWS의 ELB, GCP의 Cloud Load Balancing 등이 자동 프로비저닝되고, NodePort와 ClusterIP 기능을 모두 포함해. 실제로 외부 트래픽을 받는 프로덕션 서비스에서 가장 많이 사용하지:
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
정리하면 — ClusterIP 포함 NodePort 포함 LoadBalancer 순서로 기능이 포함 관계에 있어. ClusterIP는 내부용, NodePort는 테스트/개발용, LoadBalancer는 프로덕션용으로 생각하면 돼.
정리
6장 읽고 기억할 거 네 가지:
- 파드는 컨테이너 배포의 최소 단위지만, 직접 만들어 쓰지 않는다. 파드는 일시적이라 죽으면 그냥 끝.
- 레플리카셋은 파드 수를 유지하고, 디플로이먼트는 레플리카셋을 관리한다. 실무에서는 디플로이먼트만 쓰면 됨.
- 디플로이먼트가 롤링 업데이트와 롤백을 제공한다. 이미지를 바꾸면 자동으로 무중단 배포가 이루어진다.
- 서비스는 파드에 고정 엔드포인트를 제공한다. ClusterIP(내부), NodePort(노드 포트), LoadBalancer(외부 LB) 세 가지 타입.