지난 시간에 도커에 대해 알아보고 몇 가지 실습을 진행했어요. 이번 시간에는 컨테이너 오케스트레이션 도구인 쿠버네티스(Kubernetes, k8s)에 대해 알아볼게요.
쿠버네티스 클러스터는 크게 마스터 노드(컨트롤 플레인)와 워커 노드로 나뉘어요.
마스터 노드 (컨트롤 플레인)
워커 노드
쿠버네티스는 절차적 구조가 아닌 선언적 구조를 가지고 있어요. 사용자가 원하는 최종 상태를 선언하면, 쿠버네티스가 현재 상태와 비교하여 지속적으로 그 상태를 유지하려고 노력해요.
포드가 생성되는 과정은 다음과 같아요.
1. 포드 생성 요청
2. 포드 생성 및 API 서버에 상태 전달
3. 스케줄러가 적절한 워커 노드에 포드 실행 요청
4. 워커 노드의 kubelet이 CRI에 컨테이너 실행을 요청해 포드가 사용 가능한 상태가 됨
ClusterIP: 클러스터 내부에서만 접근 가능한 기본 타입이에요.NodePort: 워커 노드의 특정 포트를 열어 외부 요청을 내부로 전달해요.LoadBalancer: 클라우드 제공자의 로드밸런서를 이용해 부하를 분산해요.kubectl get <타입> 명령어로 현재 상태를 확인할 수 있어요. 타입에는 pods, nodes, deployment, svc(service) 등이 있어요. -o wide 옵션을 추가하면 IP와 노드 위치 등 더 자세한 정보를 볼 수 있어요. 상세 정보는 kubectl describe <타입> <이름>으로 확인하고, 삭제는 kubectl delete <타입> <이름>을 사용해요.
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 <이름> 명령어를 사용해 이전 버전으로 안전하게 롤백할 수 있어요.
Metrics Server를 설치한 뒤, CPU 사용률이 50%를 넘을 때 포드 개수를 1개에서 최대 10개까지 늘리도록 HPA를 설정했어요.
kubectl autoscale deploy php-apache --cpu-percent=50 --min=1 --max=10
테스트용 컨테이너를 띄워 강제로 트래픽 부하를 주면, kubectl get hpa --watch 명령어를 통해 CPU 사용률이 올라감에 따라 포드 개수가 자동으로 증가하고, 부하가 줄어들면 다시 포드 개수가 감소하는 것을 확인할 수 있어요.