[Week15] 웹 개발 파이프라인 구축 (2)

Younha Lee·2026년 4월 20일

TIL

목록 보기
69/70

지난 시간에 도커에 대해 알아보고 몇 가지 실습을 진행했어요. 이번 시간에는 컨테이너 오케스트레이션 도구인 쿠버네티스(Kubernetes, k8s)에 대해 알아볼게요.

쿠버네티스 클러스터 구성 요소

쿠버네티스 클러스터는 크게 마스터 노드(컨트롤 플레인)와 워커 노드로 나뉘어요.

마스터 노드 (컨트롤 플레인)

  • API 서버, etcd: 클러스터 구성 요소 중 중심 역할을 담당하며 클러스터의 모든 상태 데이터를 저장해요.
  • 컨트롤러 매니저: 클러스터의 상태를 지속적으로 모니터링하고 제어해요.
  • 스케줄러: 새로 생성된 포드(Pod)를 어떤 워커 노드에 배치할지 결정해요.
  • kubectl: 클러스터와 통신하기 위한 CLI 도구예요. (필수 구성 요소는 아니에요.)

워커 노드

  • 컨테이너 런타임 (CRI): 포드를 구성하는 실제 컨테이너를 실행해요.
  • kubelet: API 서버로부터 포드 명세서를 받아 CRI에 전달하고, 컨테이너의 동작 상태를 모니터링해요.

주요 기능

  • 트래픽 로드 밸런싱: 복제본이 여러 개인 경우 트래픽 부하를 클러스터 내부에 적절히 분배해요.
  • 동적 수평 스케일링 (HPA): 부하량에 따라 인스턴스(포드) 수를 유동적으로 조절하여 자원을 효율적으로 활용해요.
  • 자동 복구: 포드와 노드를 지속적으로 모니터링하여 장애 발생 시 새 포드를 실행해 지정된 복제본 수를 유지해요.
  • 롤링 업데이트: 서비스 지연 시간을 최소화하며 새로운 버전을 순차적으로 업데이트해요.
  • 스토리지 오케스트레이션: AWS EBS, Google Persistent Disk 등 다양한 스토리지 시스템을 자동으로 마운트해요.
  • 서비스 디스커버리: 수명이 짧고 IP가 동적으로 변하는 포드들을 자체 DNS를 기반으로 쉽게 찾아 바인딩할 수 있게 해줘요.

쿠버네티스의 선언적 구조와 포드의 생명 주기

쿠버네티스는 절차적 구조가 아닌 선언적 구조를 가지고 있어요. 사용자가 원하는 최종 상태를 선언하면, 쿠버네티스가 현재 상태와 비교하여 지속적으로 그 상태를 유지하려고 노력해요.

포드가 생성되는 과정은 다음과 같아요.
1. 포드 생성 요청
2. 포드 생성 및 API 서버에 상태 전달
3. 스케줄러가 적절한 워커 노드에 포드 실행 요청
4. 워커 노드의 kubelet이 CRI에 컨테이너 실행을 요청해 포드가 사용 가능한 상태가 됨

쿠버네티스 주요 오브젝트

  • Pod: 한 개 이상의 컨테이너가 모여 단일 목적을 수행하는 최소 배포 단위예요. 독립적인 IP를 가지며 언제든지 삭제되고 재생성될 수 있어요.
  • Namespace: 클러스터 내에서 사용되는 리소스들을 논리적으로 구분하여 관리하는 그룹이에요.
  • Volume: 포드 내부 컨테이너들이 데이터를 영구적으로 저장하거나 공유할 수 있도록 제공되는 디렉터리예요.
  • Service: 동적으로 변하는 포드들에 안정적으로 접근할 수 있도록 네트워크를 노출하는 기능이에요.
    • ClusterIP: 클러스터 내부에서만 접근 가능한 기본 타입이에요.
    • NodePort: 워커 노드의 특정 포트를 열어 외부 요청을 내부로 전달해요.
    • LoadBalancer: 클라우드 제공자의 로드밸런서를 이용해 부하를 분산해요.
  • Ingress: 서비스의 일종은 아니지만, HTTP/HTTPS 트래픽을 여러 서비스로 라우팅하는 규칙 모음이에요.
  • Deployment: 레플리카셋(동일한 포드의 복제본 모음)과 포드의 배포 및 롤링 업데이트를 관리하는 상위 오브젝트예요.

쿠버네티스 실습

kubectl get <타입> 명령어로 현재 상태를 확인할 수 있어요. 타입에는 pods, nodes, deployment, svc(service) 등이 있어요. -o wide 옵션을 추가하면 IP와 노드 위치 등 더 자세한 정보를 볼 수 있어요. 상세 정보는 kubectl describe <타입> <이름>으로 확인하고, 삭제는 kubectl delete <타입> <이름>을 사용해요.

매니페스트(YAML)를 이용한 오브젝트 생성

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          ports:
            - containerPort: 80

명령어 방식 대신 위와 같은 YAML 파일을 작성한 뒤, kubectl apply -f <파일 이름>을 실행하면 설정한 상태 그대로 오브젝트가 생성돼요. apply는 리소스가 없으면 생성하고, 이미 있다면 변경된 내용을 덮어씌워 적용해 줘요.

장애 복구와 포트 업데이트

실행 중인 포드 내부에 kubectl exec -it <포드 이름> -- /bin/bash 명령어로 접속한 뒤 프로세스를 강제로 종료(kill -9)해 보았어요. 일시적인 에러가 발생하지만, 쿠버네티스가 상태를 감지하고 자동으로 포드를 재시작하여 정상 동작을 복구하는 것을 확인할 수 있었어요.

버전 업데이트 시에는 kubectl set image deployment <이름> <컨테이너명>=<새 이미지> 명령어를 사용해요. 업데이트 후 kubectl rollout history deploy <이름>으로 히스토리를 확인할 수 있어요.
만약 잘못된 이미지로 업데이트를 시도하여 ImagePullBackOff 에러가 발생했다면, kubectl rollout undo deploy <이름> 명령어를 사용해 이전 버전으로 안전하게 롤백할 수 있어요.

HPA(동적 수평 스케일링) 실습

Metrics Server를 설치한 뒤, CPU 사용률이 50%를 넘을 때 포드 개수를 1개에서 최대 10개까지 늘리도록 HPA를 설정했어요.

kubectl autoscale deploy php-apache --cpu-percent=50 --min=1 --max=10

테스트용 컨테이너를 띄워 강제로 트래픽 부하를 주면, kubectl get hpa --watch 명령어를 통해 CPU 사용률이 올라감에 따라 포드 개수가 자동으로 증가하고, 부하가 줄어들면 다시 포드 개수가 감소하는 것을 확인할 수 있어요.

profile
할 땐 하고 놀 땐 노는 일일놀놀입니다.

0개의 댓글