EKS – Kubernetes ReplicaSet

Kubernetes에서 ReplicaSet과 Deployment는 Pod의 복제본을 생성하고 안정적으로 유지 관리하는 핵심 자원이다

ReplicaSet의 역할

  • Pod 복제: 개발자가 명시한 수만큼 동일한 Pod 복제본을 생성한다. 이는 수동으로 여러 개의 Yaml 파일을 만들 필요 없이 효율적인 Pod 배포를 가능하게 한다
  • Pod 유지 관리: ReplicaSet의 가장 중요한 기능은 지정된 수의 Pod가 항상 실행되도록 보장하는 것이다. 만약 Pod 중 하나가 어떤 이유로(예: 노드 오류, 애플리케이션 충돌)로 인해 종료되면, ReplicaSet은 자동으로 새로운 Pod를 생성하여 지정된 개수를 유지한다
  • 선언적 자원: ReplicaSet은 “Pod를 2개 실행하고 그 Pod의 내용은 nginx 이미지로 80번 포트를 통해 실행할 것이다”라고 선언하는 선언적 자원이다. ReplicaSet 자체는 물리적인 자원이 아니라, 이러한 선언을 바탕으로 Pod들을 관리한다

ReplicaSet Yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-replicaset
  namespace: hyeok
spec:
  replicas: 2 # (1) Pod 복제본 개수
  selector:
    matchLabels:
      app: my-nginx # (2) ReplicaSet이 관리할 Pod를 선택하는 기준
  template: # (3) 새로운 Pod를 생성할 때 사용할 템플릿
    metadata:
      labels:
        app: my-nginx # (4) 새로 생성될 Pod에 부여될 라벨
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
  • spec.replicas: 이 ReplicaSet이 유지할 Pod 복제본의 목표 개수를 정의한다. 여기서는 2개로 설정되어 있다
  • spec.selector.matchLabels: ReplicaSet이 어떤 Pod들을 자신의 관리 대상으로 삼을지 결정하는 중요한 부분이다. 여기에 정의된 라벨(예: app: my-nginx)를 가진 Pod들만 이 ReplicaSet에 의해 관리된다
  • spec.template: 새로운 Pod를 생성할 때 사용되는 ‘청사진’이다. 이 안에 Pod의 전체 정의(컨테이너, 이미지, 포트, 환경 변수 등)가 들어간다
  • spec.template.metadata.labels: template에 따라 새로 생성되는 Pod에 자동으로 부여될 라벨이다. 이 라벨은 spec.selector.matchLabels와 반드시 일치해야 한다. 만약 일치하지 않으면 ReplicaSet은 자신이 생성한 Pod를 인식하지 못하고 계속 새로운 Pod를 생성하는 무한 루프에 빠질 수 있다
    • 이 라벨은 ReplicaSet의 관리 대상 선택뿐만 아니라, Service의 Pod들을 찾아 트래픽을 라우팅하는 데도 사용된다

실습을 통한 확인

nginx_replicaset.yml (ReplicaSet과 Service 정의)
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-replicaset
  namespace: hyeok
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: hyeok
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80
  selector: # Service가 트래픽을 라우팅할 Pod를 선택하는 기준
    app: my-nginx
자원 배포
kubectl apply -f nginx_replicaset.yml
Pod, Service, ReplicaSet 상태 확인
kubectl get pods -n hyeok
kubectl get svc -n hyeok
kubectl get replicaset -n hyeok
Pod 삭제 시 자동 복구 확인
# kubectl delete pod <pod-name> -n hyeok
kubectl delete pod nginx-replicaset-9kzmz -n hyeok
  • 즉시 kubectl get pods -n hyeok을 다시 실행하면, 삭제된 Pod가 ReplicaSet에 의해 새로운 Pod로 교체되어 다시 2개의 Pod가 유지되는 것을 볼 수 있다(새로운 Pod의 AGE가 다르다)

Service를 통한 로그 밸런싱 확인 (로그 이용)

  • 두 개의 터미널에서 각각 Pod의 로그를 모니터링한다 (Pod 이름은 kubectl get pods로 확인)
# 터미널 1 kubectl logs -f <nginx-pod-name-1> -n hyeok
kubectl logs -f nginx-replicaset-c8g67 -n hyeok

# 터미널 2 kubectl logs -f <nginx-pod-name-2> -n hyeok
kubectl logs -f nginx-replicaset-rt2lm -n hyeok
  • 세 번째 터미널에서 Service의 ClusterIP를 통해 요청을 보낸다(이때 Pod 내부에서 curl을 실행하여 Service IP로 요청하는 방식이 적합하다. 외부에서 직접 Service ClusterIP로 요청하기는 어렵다)
# 임의의 Pod에 접속
kubectl exec -it <any-nginx-pod-name> -n hyeok -- /bin/sh

# Pod 내부에서 Service의 ClusterIP로 요청 (ClusterIP는 'kubectl get svc'로 확인)
# curl <nginx-service-cluster-ip>

curl http://nginx-service

exit # Pod 접속 종료
service 터미널
pod1 터미널
pod2 터미널

curl 요청을 반복적으로 실행하면서 터미널1과 터미널2의 로그를 확인하면, 요청이 두 Pod에 분산되어 찍히는 것을 볼 수 있다 (Service의 기본 로그 밸런싱 알고리즘은 라운드 로빈이지만, 캐싱 등의 이유로 완벽하게 5:5로 분산되지 않을 수도 있다)

출처 – eks를 활용한 spring 운영서버 배포(feat. devops의 모든것)