이번에 데브코스 파이널 프로젝트에 k8s를 도입하게 되어 도커 -> 쿠버네티스로의 인프라 마이그레이션이 필요해졌다.
이어지는 내용은 내가 사용하던 도커 컨테이너에 대한 복습과 이번에 사용하게 될 쿠버네티스의 파드가 어떻게 다른지에 대해 학습한 내용이다.
Docker 이 정도는 알고 넘어가자
개발을 하다 보면 "내 컴퓨터에서는 되는데 서버에서는 안 된다"는 상황을 한 번쯤 겪게 된다. 이 문제를 해결하기 위해 등장한 것이 Docker다.
Docker는 애플리케이션과 그 실행 환경을 컨테이너라는 단위로 묶어서 어디서든 동일하게 실행할 수 있도록 해주는 도구다.
- Docker 이미지 : 컨테이너를 만들기 위한 설계도. 어떤 OS, 어떤 라이브러리, 어떤 설정으로 실행할지에 대한 정보를 담고 있다. 이 이미지를 다른 컴퓨터에 가져가도 동일한 환경을 만들 수 있기 때문에 이식성이 보장된다.
- Docker 컨테이너 : Docker 이미지를 기반으로 실제로 실행 중인 인스턴스다. EC2든 로컬이든 이미지만 있으면 동일한 컨테이너를 띄울 수 있다.
컨테이너가 1~2개일 때는 Docker만으로도 충분히 관리할 수 있다. 그런데 MSA처럼 서비스가 수십 개의 컨테이너로 구성되면 다음과 같은 문제가 생긴다.
- API Gateway 컨테이너가 죽었다 → 누가 다시 살려주나?
- 트래픽이 몰린다 → 컨테이너를 몇 개 더 띄워야 하나?
- 컨테이너를 어느 서버에 띄울지 → 누가 결정하나?
이걸 사람이 직접 하면 한계가 있다.
그래서 쿠버네티스(K8s)라는 오케스트레이션 툴을 사용하면 이걸 자동으로 해준다.
자동 복구(Self-healing) : 파드가 죽으면 자동으로 감지하고 재시작한다. 사람이 모니터링하다가 수동으로 재시작할 필요가 없다.
스케줄링 : 여러 서버(노드) 중 현재 자원이 여유로운 곳에 파드를 자동으로 배치한다.
스케일링 : 트래픽에 따라 파드 수를 자동으로 늘리고 줄인다.
쿠버네티스의 최소 배포 단위는 파드(Pod) 다.
Docker가 컨테이너 단위로 관리한다면, 쿠버네티스는 파드 단위로 관리한다.
대부분의 경우 파드 1개 = 컨테이너 1개로 운영하는 것이 국룰이긴 하다.
참고로 파드 안에 컨테이너를 여러 개 넣는 경우도 있는데, 이를 사이드카 패턴이라고 한다.
같은 파드 안의 컨테이너끼리는 네트워크와 볼륨을 공유하기 때문에 localhost로 통신할 수 있다. 단, 이는 "두 컨테이너가 항상 같은 서버에서 함께 실행돼야 한다"는 강결합 관계일 때만 사용한다.
스케일링을 파드 내부에서 컨테이너를 늘리는 것으로 오해할 수 있다. 하지만 스케일링은 파드 자체를 복제하는 것이다.
트래픽 적을 때 트래픽 많아질 때
Deployment Deployment
└── Pod A └── Pod A
└── Pod B ← 자동 추가
└── Pod C ← 자동 추가
DB를 예로 들면, Master와 Replica는 역할이 다르기 때문에 각각 별도의 파드로 띄운다. 같은 파드로 묶으면 해당 서버가 죽을 때 둘 다 죽기 때문에 Replica의 의미가 없어진다.
// DB를 하나의 파드로 묶는게 아닌 서로 다른 파드로 관리 해야 한다.
Pod A : Master DB
Pod B : Replica DB
Pod C : Replica DB
HPA(Horizontal Pod Autoscaler) 는 메트릭 기준으로 파드 수를 자동으로 조절해주는 쿠버네티스 리소스다.
minReplicas: 2 # 평소 최소 2개 유지
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
averageUtilization: 70 # CPU 70% 넘으면 파드 추가
파드가 여러 개로 복제되면 HTTP 요청 분산은 K8s Service가 담당한다. 기본 분산 방식은 라운드 로빈이다.
클라이언트
↓
K8s Service (로드밸런서 역할)
↓
Pod A / Pod B / Pod C
개발자는 파드 IP를 직접 알 필요 없이 Service 이름으로만 호출하면 된다.
"http://product-service/api/products" // Service 이름으로 호출
k3s는 경량화된 쿠버네티스다. 기능을 제거한 것이 아니라, 무겁고 잘 쓰지 않는 것들을 걷어낸 버전이다.
이번에 우리 팀은 프로젝트에서 서버 리소스 이슈로 인해 k3s를 적용하였다.
경량화가 되었다고 해도 HPA, Service, 자동 복구 등 핵심 기능은 그대로 지원한다.