쿠버네티스(Kubernetes) 등장 배경
소프트웨어 배포 방식의 변화
- 전통적 배포 방식
- 한 대의 물리서버에 여러 애플리케이션이 동작
- 각 애플리케이션 리소스 제약이 있고 서로의 성능 저하를 유발
- 물리 서버의 수를 증설할 수 있지만 운영/비용 문제 발생
- 가상화 기반 배포 방식
- 단일 물리서버에 여러 가상머신을 생성하고 각 가상머신에 애플리케이션 탑재
- 가상머신에 할당된 리소스 제한 가능, 가상머신이 독립적으로 운영되어 애플리케이션 간 간섭 제거
- 하지만 애플리케이션을 실행하기 위해 가상머신마다 운영체제를 설치하는 오버헤드 발생
- 컨테이너 기반 배포 방식
- 운영체제 위에 컨테이너 플랫폼을 올리고 그 위에 컨테이너 애플리케이션 동작
- 독립적인 파일시스템/CPU/메모리 등의 리소스 제약으로 상호 간섭 없이 독립적으로 운영
- 애플리케이션 추가 시 애플리케이션 자체 용량만 필요하므로 빠른 확장/축소 가능
도커 그 이후…
- 코드 작성 → 빌드(도커 이미지 생성) → ship(이미지를 도커허브 같은 저장소에 올림) → run
- 도커 이미지로 만들기만 하면, 저장하고 사용하는 방식은 모두 동일
- 모든 것을 컨테이너로 만들기 시작 → 컨테이너가 수십, 수백 개로 늘어나면… 이걸 다 어떻게 관리할까?
- 도커 서버 여러 대에 각각 ssh 접속하여 docker run 실행?
- 모든 컨테이너 롤아웃/롤백하려면?
- 각 컨테이너에 접근하기 위한 네트워크 설정?
- 컨테이너가 갑자기 죽거나 부하를 많이 받아 응답 속도가 느려지면?
컨테이너 오케스트레이션
- 복잡한 컨테이너 환경을 효과적으로 관리하기 위한 도구(서버 관리자가 하는 일을 대신 수행)
- 노드를 하나하나 관리하는 것이 아니라, 마스터 서버에 명령어를 던지면 알아서 각 노드에 실행
- 원하는 개수의 애플리케이션을 자동으로 실행
- 각 서버의 상태를 체크하여 적합한 서버에 컨테이너를 배포하거나 새로운 서버 실행
- 자동 배포 버전관리 (Rollout/Rollback)
- 노드 내부에 접근하기 위한 IP 주소 등록 및 조회
대표적인 도구: 쿠버네티스
- 컨테이너화된 애플리케이션을 자동으로 배포, 스케일링 및 관리해주는 오픈소스 시스템
- 컨테이너 오케스트레이션의 “De facto” (사실상의 표준)
- Kubernetes는 그리스어로 ‘조타수’, ‘파일럿’ 의미,
K8s
로 표기하기도 한다.
- 구글에서 2015년 7월 출시, Cloud Native Computing Foundation(CNCF)에 기부, 오픈소스화
- 장점
- 대규모 확장성: 수십억 개 이상의 컨테이너 관리할 수 있도록 설계
- 무한한 유연성: 사용자의 복잡하고 다양한 요구사항을 반영하여 애플리케이션을 끊김없이 쉽게 제공
- 어디에서나 실행: 온 프레미스, 프라이빗, 퍼블릭, 또는 하이브리드 클라우드 어디에서든지 실행 가능
- EKS(Elastic Kubernetes Service)
- ACS(Azure Container Service)
- GKE(Google Kubernetes Engine)
- 등등…
쿠버네티스(Kubernetes) 구조
- 쿠버네티스 클러스터
- 쿠버네티스 배포 시 생성된다.
- 컨테이너화된 애플리케이션을 실행하는
노드
라고 불리는 워커 머신의 집합이다.
- 모든 클러스터는 최소 한 개의 워커 노드를 갖는다.
- 컨트롤 플레인
- 클러스터에 대한 전체적인 상태를 점검한다.
- 정의된 상태가 아닐 경우 정의된 상태가 되도록 클러스터를 관리한다.
Master (컨트롤 플레인)
(1) etcd (엣시디)
- 쿠버네티스 클러스터와 관련된 모든 상태와 데이터를 저장하는 저장공간
- 분산 시스템으로 구성하여 안정성 높임 (고가용성)
- 가볍고 빠르면서 정확하게 설계 (일관성)
key(directory)-value
형태로 데이터 저장
- 백업 필수
(2) API Server
- 마스터와 노드 간 통신을 담당, 상태를 바꾸거나 조회하는 역할
- etcd와 통신하는 유일한 모듈
- REST API 형태로 제공 (
kubectl
)
- 권한을 체크해 적절한 권한이 없으면 요청을 차단
- 관리자 요청 뿐 아니라 다양한 내부 모듈과 통신
(3) Scheduler
- 컨테이너를 담고 있는 Pod가 생성될 때 이를 실행할 노드 선택
어떤 노드에 어떤 컨테이너를 실행할지
- 노드의 현재 상태와 Pod의 요구사항 등을 확인하여 배치
(4) Controller
- 클러스터가 요구되는 상태가 되도록 API 서버와 통신
- 끊임없이 상태를 체크하고 원하는 상태를 유지
- 복잡성을 낮추기 위해 하나의 프로세스로 실행
- 논리적으로 다양한 컨트롤러 존재
- 노드 컨트롤러: 노드가 다운되었을 때 통지/대응
- 레플리케이션 컨트롤러: 클러스터에 생성되어야 할 레플리케이션 수에 맞게 Pod를 유지
- 엔드포인트 컨트롤러: 서비스와 파드 연결
Node
(1) kubelet
- 클러스터의 각 워커 노드에서 실행하며, Pod를 실행/중지하고 상태를 체크
- 쿠버네티스에 의해 생성되지 않은 컨테이너는 관리하지 않음
(2) kube-proxy
- 각 워커 노드에서 실행되는 네트워크 및 로드 밸런싱 프록시 (내/외부 통신)
- Pod 내에서 실행 중인 컨테이너를 외부로 노출시켜 외부에서 컨테이너에 접근하게 함
- iptables 또는 IPVS를 사용하여 설정 관리
(3) 컨테이너 런타임
- 컨테이너 실행을 담당하는 소프트웨어
- docker, Containerd, CRI-O 등의 컨테이너 런타임 지원
오브젝트
- 쿠버네티스는 클러스터의 상태를 나타내기 위해 오브젝트를 이용한다.
- 오브젝트를 생성하면 쿠버네티스 시스템은 그 오브젝트 생성을 보장하기 위해 지속적으로 작동할 것이다.
- 따라서 쿠버네티스 시스템에서 영속성을 가지며, 일종의
의도를 담은 레코드
이다.
(1) Pod
- 가장 작은 배포 단위로, 한 개 이상의 컨테이너로 구성된다.
- 쿠버네티스는 파드 단위로 노드에 할당한다.
즉, 스케줄링의 기본 단위
- 각 파드마다 IP 주소가 할당된다.
(2) ReplicaSet
- 신규
Pod
를 생성하거나 기존 Pod를 제거하여 원하는 수(Replicas)를 유지한다.
(3) Deployment
- 애플리케이션을 배포하기 위한 설정이다.
- 쿠버네티스가 애플리케이션의 인스턴스를 어떻게 생성하고 업데이트해야 하는지 지시한다.
- 내부적으로
ReplicaSet
을 이용한다.
(4) Service
- 동적으로 변하는 Pod에 고정적으로 접근할 때 사용하는 방법이나 정책을 정의한 것이다.
- 서비스를 사용하면 Pod가 클러스터 내부 어디에 있든 고정 주소를 이용해 접근할 수 있다.
- 클러스터 외부에서 클러스터 안의 Pod에 접근할 수도 있다.
- 서비스 타입
- ClusterIP: 클러스터 내부 IP에 대해 서비스 노출, 외부에서 접근 불가
- NodePort:
<NodeIP>:<NodePort>
로 클러스터 외부로부터 서비스 접근 가능, CluterIP의 상위 집합
- LoadBalancer
(5) Ingress
- IP 포트가 아닌 도메인 또는 경로별로 라우팅하여 내부 ClusterIP 접근 가능
```s
[일반적인 구성]
- Deployment를 생성 (ReplicaSet, Pod 순차적으로 생성)
- 여기에 Service(Cluster IP) 붙임
- 여기에 Ingress 붙임 (NodePort, LoadBalancer 자동으로 따라 붙음)
[오브젝트 기술하기]
- 쿠버네티스 오브젝트 생성 시, 오브젝트에 대한 기본정보와 함께 의도한 상태를 기술한 spec을 제시함
- 오브젝트 spec을 yaml 파일로 작성하고, 이를 통해 쿠버네티스 API를 이용함
[예시]
apiVersion: apps/v1
kind: Deployment # Pod, Service, Ingress, ...
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
```
API 호출 방식
- 원하는 상태(desired state)를
- 다양한 오브젝트(object)로 정의(spec)하고
- API 서버에 yaml 형식으로 전달한다.
Minikube
# minikube 설치
brew install minikube
# minikube 버전 확인
minikube version
# Docker Desktop을 실행한 후 (docker 드라이버 사용)
# 가상머신을 띄우고 쿠버네티스 클러스터 생성
minikube start
# 상태 확인
minikube status
# 쿠버네티스 대시보드 실행
minikube dashboard
# kubectl - 쿠버네티스 CLI. 쿠버네티스 API를 통해 클러스터와 상호작용
# kubectl 버전 확인 (clientVersion: kubectl 버전, serverVersion: 쿠버네티스 버전)
kubectl version
kubectl version --output=json
# 클러스터 정보 확인
kubectl cluster-info
# 클러스터 내 노드 확인
# 상태가 Ready라면, 애플리케이션 배포 가능한 상태를 의미
kubectl get nodes
##### 앱 배포하기 #####
# 디플로이먼트 생성 - 디플로이먼트 이름, 앱 이미지 위치 포함
# 앱 인스턴스가 실행할 수 있는 노드를 찾아서 스케줄링
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
# 디플로이먼트 확인
# NAME - 클러스터 내 디플로이먼트 이름
# READY - 현재 replica 수 / 원하는(desired) replica 수
# UP-TO-DATE - desired 상태를 달성하기 위해 업데이트한 replica 수
# AVAILABLE - 사용 가능한 replica 수
# AGE - 애플리케이션 실행 시간
kubectl get deployments
# 프록시 생성 - 클러스터 접근 가능하도록 포워딩 (파드는 독립된 내부망 사용)
# (터미널 새 탭에서 실행)
kubectl proxy
# 호스트에서 쿠버네티스 클러스터에 접근 가능, API 확인 및 실행
curl http://localhost:8001
curl http://localhost:8001/version
##### 앱 조사하기 #####
# kubectl get - 자원 나열
# kubectl describe - 자원에 대한 상세 정보 확인
# kubectl logs - 파드 내 컨테이너 로그 출력
# kubectl exec - 파드 내 컨테이너에 명령어 실행
# 파드 확인
kubectl get pods
# 파드 상세 정보 확인 (e.g. 컨테이너, 이미지)
kubectl describe pods
# 파드 이름 저장 및 출력
export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
echo Name of the Pod: $POD_NAME
# 파드 내 컨테이너 로그 출력 (컨테이너가 1개이므로 컨테이너명 생략)
kubectl logs $POD_NAME
# 파드 내 컨테이너 환경변수 목록 출력
kubectl exec $POD_NAME -- env
# 컨테이너 bash 실행
kubectl exec -ti $POD_NAME -- bash
# 컨테이너 bash - 코드 확인
cat server.js
# 컨테이너 bash - 애플리케이션 실행 확인
curl localhost:8080
# 컨테이너 bash 종료
exit
##### 앱 스케일링하기 #####
# 디플로이먼트 확인
kubectl get deployments
# 디플로이먼트가 생성한 ReplicaSet 확인
# NAME - ReplicaSet 이름 ([디플로이먼트이름]-[랜덤문자열])
# DESIRED - 애플리케이션의 원하는 replica 수
# CURRENT - 현재 실행 중인 replica 수
kubectl get rs
# replica를 4개로 스케일링
kubectl scale deployments/kubernetes-bootcamp --replicas=4
# 디플로이먼트 확인 -> replica 4개로 변경됨
kubectl get deployments
# 파드 정보 조회 - 각 파드마다 ip 주소 할당
kubectl get pods -o wide
# 디플로이먼트 상세 정보 - Event에 로그 추가됨
kubectl describe deployments/kubernetes-bootcamp
# replica 2개로 스케일 다운
kubectl scale deployments/kubernetes-bootcamp --replicas=2
# 디플로이먼트 확인 -> replica 2개로 변경됨
kubectl get deployments
# 파드 정보 조회 - 2개의 파드가 종료됨
kubectl get pods -o wide
##### 앱 업데이트하기 #####
# 디플로이먼트 확인
kubectl get deployments
# 파드 확인
kubectl get pods
# 파드 상세 정보에서 현재 이미지 버전 확인 (Image 필드)
kubectl describe pods
# set image 명령어로 이미지 업데이트 (디플로이먼트 이름, 이미지 버전 전달)
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
# 파드 확인
kubectl get pods
# rollout 상태 확인
kubectl rollout status deployments/kubernetes-bootcamp
# 파드 상세 정보에서 현재 이미지 버전 확인 -> v2로 업데이트됨
kubectl describe pods
# v10 태그 이미지로 업데이트해보기
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
# 파드 확인 - ErrImagePull 또는 ImagePullBackOff 상태 발생
kubectl get pods
# 파드 상세 정보에서 에러 확인 (Events) - v10 버전이 존재하지 않음
kubectl describe pods
# rollout 되돌리기
kubectl rollout undo deployments/kubernetes-bootcamp
# 파드 확인
kubectl get pods
# minikube 클러스터 정지
minikube stop
# minikube 클러스터 삭제
minikube delete