들어가기 앞서, 이 글은 도커(Docker) 및 컨테이너 배포에 대한 기본적인 이해를 전제로 작성되었습니다. 도커와 관련된 자세한 설명은 여기에 모두 정리해 두었으니, 참고해 주시면 좋겠습니다.
✅ 쿠버네티스 (Kubernetes, k8s)
쿠버네티스는 컨테이너화된 애플리케이션을 배포하고 관리하기 위한 오픈 소스 플랫폼이다. 컨테이너 오케스트레이션 도구로서, 애플리케이션의 확장, 배포, 운영을 자동화한다.
오케스트레이션: 여러 개의 컨테이너 또는 서버를 효율적으로 관리하고 작업을 의미한다. 주요 역할은 애플리케이션이 여러 컨테이너로 구성되어 있을 때, 각각의 컨테이너를 배포, 스케일링, 업데이트, 복구하는 것을 자동화한다.
▶ 쿠버네티스의 등장 배경
도커의 등장으로 컨테이너 기반 배포 방식이 보편화되었고, 많은 서비스들이 도커라이징되어, 도커 이미지로 관리되기 시작했다. 시간이 지남에 따라 관리해야 할 이미지와 컨테이너, 서버의 수가 증가하게 되었고, 이를 효과적으로 관리할 필요성이 대두되었다. 이를 위해 다양한 컨테이너 오케스트레이션 도구들이 등장했으며, Docker Swarm, AWS의 ECS, HashiCorp의 Nomad, Mesos의 Marathon 등이 그 예이다. 그러나 Google에서 만든 쿠버네티스가 현재 사실상 표준으로 자리 잡게 되었다. 이를 통해 컨테이너 기반 인프라에서 쉽게 애플리케이션을 쉽게 관리하고, 자동으로 확장 및 복구가 가능해졌다.
도커라이징(Dockerizing): 애플리케이션과 그 실행 환경을 도커 컨테이너에 담아 실행할 수 있도록 만드는 과정을 의미한다. 이 과정에서는 애플리케이션의 코드, 의존성, 설정 파일 등을 포함한 도커 이미지를 생성하여, 해당 애플리케이션을 어느 환경에서나 일관되게 실행할 수 있게 한다.
✅ 쿠버네티스의 기능
서비스 디스커버리와 로드 밸런싱: 쿠버네티스는 DNS 이름을 사용하거나 자체 IP 주소를 사용하여 컨테이너를 노출할 수 있다. 컨테이너에 대한 트래픽이 많으면, 쿠버네티스는 네트워크 트래픽을 로드밸런싱하고 배포하여 배포가 안정적으로 이루어질 수 있다.
스토리지 오케스트레이션: 쿠버네티스를 사용하면 로컬 저장소, 공용 클라우드 공급자 등과 같이 원하는 저장소 시스템을 자동으로 탑재할 수 있다.
자동화된 롤아웃과 롤백: 쿠버네티스를 사용하여 배포된 컨테이너의 원하는 상태를 서술할 수 있으며 현재 상태를 원하는 상태로 설정한 속도에 따라 변경할 수 있다. 예를 들어 쿠버네티스를 자동화해서 배포용 새 컨테이너를 만들고, 기존 컨테이너를 제거하고, 모든 리소스를 새로운 컨테이너에 적용할 수 있다.
자동화된 빈 패킹(bin packing): 컨테이너화된 작업을 실행하는데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공한다. 각 컨테이너가 필요로 하는 CPU와 메모리(RAM)를 기반으로, 쿠버네티스는 해당 컨테이너들을 클러스터 내의 노드에 가장 효율적으로 배치하여 리소스를 최대한 활용할 수 있도록 해준다.
자동화된 복구(self-healing): 쿠버네티스는 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며, '사용자 정의 상태 검사'에 응답하지 않는 컨테이너를 죽이고, 서비스 준비가 끝날 때까지 이러한 과정을 클라이언트에 보여주지 않는다.
시크릿과 구성 관리: 쿠버네티스를 사용하면 암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리할 수 있다. 컨테이너 이미지를 재구성하지 않고 스택 구성에 시크릿을 노출하지 않고도 시크릿 및 애플리케이션 구성을 배포 및 업데이트할 수 있다.
롤아웃(Rollout): 새로운 버전의 애플리케이션을 배포하는 과정이다. 업데이트나 새로운 기능 추가가 있을 때, 현재 실행 중인 애플리케이션을 새로운 버전으로 교체하는 작업을 말한다. 롤백(Rollback): 이전 버전으로 되돌리는 과정이다. 새로운 버전 배포 후 문제가 발생하거나 예상하지 못한 버그가 있을 때 안전한 이전 버전으로 복구하는 작업을 의미한다. 빈 패킹(Bin Packing): 문제는 최적화 문제 중 하나로, 주어진 크기의 항목들을 최소한의 빈(박스 또는 용기)에 담는 방법을 찾는 문제이다.
✅ 쿠버네티스 클러스터
쿠버네티스 클러스터는 쿠버네티스가 애플리케이션을 실행하고 관리하기 위한 단위이다. 하나 이상의 마스터 노드와 여러 개의 워커 노드로 구성되며, 마스터 노드가 클러스터를 제어하고 워커 노드가 애플리케이션 컨테이너를 실행한다. 각 노드는 컨테이너 런타임(예: Docker)을 통해 컨테이너를 실행하고, 쿠버네티스는 이를 관리한다.
▶ 구성 요소: 마스터 - 노드 구조
🔽 마스터 노드
API 서버: 클러스터와의 모든 상호작용을 처리한다.
모든 요청은 API 서버를 통해 처리된다.
kubectl과 같은 Client 도구로 API 서버에 접근이 가능하다.
마스터 노드의 다른 구성 요소와 워커 노드 사이의 통신을 중재한다.
스케줄러: Pod를 적절한 노드에 할당한다.
새로운 Pod를 생성할 때, 클러스터 내의 어느 워커 노드에 할당할지 결정한다.
클러스터의 리소스 사용량(메모리, CPU 등)을 고려하여 가장 적합한 노드를 선택한다.
이러한 스케줄링을 통해 클러스터의 리소스를 최적으로 활용하게 도와준다.
컨트롤러 매니저: 클러스터의 상태를 모니터링하고 유지한다.
다양한 컨트롤러를 모아 관리하는 역할을 한다.
클러스터의 Desired State를 유지하기 위해 Pod, 서비스, 복제된 인스턴스 등을 모니터링하고 적절한 조치를 취한다.
etcd: 클러스터의 상태 정보를 저장한다.
분산 키-값 저장소로, 쿠버네티스의 모든 클러스터 상태 정보를 저장한다.
클러스터 내의 모든 구성 요소들은 etcd를 통해 정보를 공유하며, 클러스터의 Desired State와 Current State를 관리한다.
🔽 워커 노드
kubelet: Pod의 실행 및 상태를 관리한다.
각 워커 노드에서 실행되며, API 서버로부터 전달된 명령에 따라 Pod를 생성하고 관리한다.
Pod의 실행 상태를 지속적으로 확인하고, 문제가 발생했을 경우 이를 API 서버에 보고한다.
컨테이너 런타임을 통해 컨테이너를 생성하고, 각 컨테이너의 리소스 상태를 모니터링한다.
컨테이너 런타임: 컨테이너를 실제로 실행하는 엔진이다. (ex: Docker, containerd)
쿠블릿이 Pod를 생성하라고 지시하면 컨테이너 런타임이 컨테이너를 생성한다.
kube-proxy: 네트워크 통신을 관리한다.
각 워커 노드에서 실행되며, 네트워크 규칙을 유지하고 클러스터의 서비스와 통신을 관리한다.
외부에서 들어오는 요청을 올바른 Pod로 전달하고, 클러스터 내부의 네트워크 트래픽을 라우팅한다.
이 역할을 통해 클러스터 내 여러 Pod들이 서로 통신할 수 있도록 지원한다.
Desired State: 쿠버네티스에서 시스템이 달성해야 하는 이상적인 상태를 의미한다. 사용자가 쿠버네티스에 의해 관리되는 애플리케이션의 상태를 정의한 것으로, Pod의 개수, 애플리케이션 버전, 서비스 접근 방식 등과 같은 정보를 포함한다. 사용자는 manifest 파일을 통해 이 Desired State를 쿠버네티스에 정의한다. Current State: 현재 시스템에서 실제로 실행 중인 상태를 의미한다.
쿠버네티스는 항상 Current State를 Desired State와 일치시키려 한다. 만약 차이가 발생하면, 컨트롤러가 이를 감지하고 적절한 조치를 취해 Current State를 Desired State로 맞춘다. 이를 통해 자동화된 복구와 확장이 이루어진다.
✅ 쿠버네티스 오브젝트(= 리소스)
쿠버네티스는 여러 가지 오브젝트를 통해 애플리케이션의 상태와 설정을 정의하고 관리한다. 대표적으로 Pod, Deployment, service 등이 있다.
▶구성 요소
Pod: 컨테이너의 집합으로, 쿠버네티스에서 배포되고 관리되는 가장 작은 단위이다.
Deployment: Pod의 배포, 업데이트, 스케일링을 관리하는 컨트롤러이다.
Service: Pod에 대한 네트워크 접근을 제공하고, 로드 밸런싱을 지원하여 여러 Pod 간의 트래픽을 균등하게 분배한다.
ReplicaSet: 지정된 수의 Pod를 항상 유지하는 오브젝트이다. Deployment에 의해 관리되며, Pod의 개수를 자동으로 조정한다.
StatefulSet: 상태를 가진 애플리케이션(Pod)을 관리하는 오브젝트로, 순서 있는 배포와 고유한 네트워크 아이덴티티를 제공한다.
DaemonSet: 각 노드에서 하나의 Pod를 실행하는 오브젝트로, 모든 노드에서 실행되어야 하는 작업(예: 로그 수집, 모니터링 등)에 사용된다.
Job & CronJob:
Job: 특정 작업을 한 번 실행하고 완료하면 종료되는 오브젝트이다.
CronJob: 일정한 주기로 Job을 실행하는 오브젝트로, 스케줄링 작업에 사용된다.
PersistentVolume (PV): 클러스터 내에서 사용되는 지속적인 스토리지를 정의하는 자원이다.
PersistentVolumeClaim (PVC): Pod가 특정 스토리지를 요청하는 선언적 오브젝트이다.
ConfigMap: 애플리케이션의 환경 설정과 같은 비밀이 아닌 데이터를 저장하는 오브젝트이다.
Secret: 비밀번호, 인증 정보 등 민감한 데이터를 안전하게 저장하기 위한 오브젝트이다.
Namespace: 클러스터 내 리소스를 논리적으로 분리하여 여러 사용자나 팀이 자원을 공유하고 독립적으로 사용할 수 있게 하는 오브젝트이다.
Ingress: 외부 HTTP/HTTPS 요청을 클러스터 내부의 서비스로 라우팅하는 오브젝트로, 외부에서 서비스에 접근할 수 있는 경로를 제공한다.
HorizontalPodAutoscaler (HPA): CPU, 메모리 사용량 등을 기준으로 Pod의 개수를 자동으로 늘리거나 줄이는 오브젝트이다.
NetworkPolicy: Pod 간의 네트워크 트래픽을 제어하는 오브젝트로, 네트워크 접근을 제한하거나 허용하는 역할을 한다.
Role & RoleBinding / ClusterRole & ClusterRoleBinding:
Role & RoleBinding: 특정 네임스페이스 내의 자원 접근을 제어하기 위한 권한을 설정한다.
ClusterRole & ClusterRoleBinding: 클러스터 전체에 대해 권한을 설정한다.
ServiceAccount: Pod가 쿠버네티스 API에 접근할 수 있는 권한을 부여하는 계정이다.
쿠버네티스는 다양한 배포 방식을 지원한다. 예를 들어, - 여러 대의 애플리케이션을 띄우고 싶을 경우에는 Deployment를 사용한다. - 로그 수집이나 모니터링 등 모든 서버에 설치가 필요한 경우에는 DaemonSet을 사용한다. - 배치성 작업은 Job이나 CronJob을 사용한다.
▶ 쿠버네티스 오브젝트 Spec 기술: Manifest
Manifest는 쿠버네티스 오브젝트를 생성하기 위한 메타 정보를 작성한 설정 파일이다.
🔽 특징
쿠버네티스에서 애플리케이션을 실행하기 위해 필요한 오브젝트(Pod, Deployment, Service 등)의 속성을 정의하는 데 사용된다.
YAML 또는 JSON 형식으로 작성되며, Desired State를 정의한다.
각 오브젝트의 이름, 레플리카 수, 컨테이너 이미지, 포트, 환경 변수 등의 정보를 담고 있으며, 이를 통해 쿠버네티스는 클러스터 내의 리소스를 자동으로 생성하고 관리한다.
🔽 yaml 파일
apiVersion: <API_VERSION> # API 버전
kind: <OBJECT_KIND> # 오브젝트 유형
metadata:
name: <OBJECT_NAME> # 오브젝트의 이름, 필수 항목
labels: #라벨 설정, 선택 항목
key: value
spec:
initContainers: # 초기화 전용 컨테이너 명세
- name: <INIT_CONTAINER_NAME>
image: <INIT_CONTAINER_IMAGE>
command: [ "<COMMAND>" ]
args: [ "<ARGUMENTS>" ]
nodeSelector: # Pod가 배포될 노드 지정
<NODE_LABEL_KEY>: <NODE_LABEL_VALUE>
volumes: # Pod 내에서 공유할 수 있는 볼륨 정의
- name: <VOLUME_NAME>
<VOLUME_TYPE>: <VOLUME_SPEC>
containers: # 컨테이너 명세 (여러 개의 컨테이너 정의 가능)
- name: <CONTAINER_NAME> # 컨테이너 이름
image: <CONTAINER_IMAGE> # 컨테이너 이미지
livenessProbe: # 컨테이너 정상 동작 여부 검사
httpGet:
path: <HEALTH_CHECK_PATH>
port: <PORT_NUMBER>
readinessProbe: # 컨테이너 준비 상태 검사
httpGet:
path: <READINESS_CHECK_PATH>
port: <PORT_NUMBER>
ports: # 외부 요청을 위한 포트 목록
- containerPort: <PORT_NUMBER> # 컨테이너에서 노출할 포트
resources: # CPU와 메모리 제한 설정
limits:
cpu: <CPU_LIMIT>
memory: <MEMORY_LIMIT>
requests:
cpu: <CPU_REQUEST>
memory: <MEMORY_REQUEST>
volumeMounts: # 볼륨 마운트 설정
- name: <VOLUME_NAME>
mountPath: <MOUNT_PATH>
command: [ "<COMMAND>" ] # 컨테이너 시작 시 실행할 명령어
args: [ "<ARGUMENTS>" ] # comma
🔽 예시
apiVersion: v1 # 쿠버네티스 API 버전
kind: Pod # 생성할 오브젝트의 종류 (Pod)
metadata:
name: example-pod # 오브젝트 이름
labels:
app: example # 레이블 지정
spec: # 오브젝트 설정
containers: # Pod 내에서 실행될 컨테이너 목록
- name: nginx-container # 컨테이너 이름
image: nginx:1.21.6 # 사용할 도커 이미지
ports:
- containerPort: 80 # 컨테이너 내에서 사용할 포트
env: # 컨테이너 환경 변수 설정
- name: EXAMPLE_ENV # 환경 변수 이름
value: "This is an example." # 환경 변수 값
apiVersion: apps/v1 # 쿠버네티스의 API 버전
kind: Deployment # 생성할 오브젝트의 종류 (Deployment)
metadata:
name: example-deployment # 오브젝트 이름
labels:
app: example # 레이블 지정
spec:
replicas: 3 # 생성할 Pod의 복제본 수
selector:
matchLabels:
app: example # 관리할 Pod의 레이블
template:
metadata:
labels:
app: example # Pod에 붙일 레이블
spec:
containers:
- name: nginx-container # 컨테이너 이름
image: nginx:1.21.6 # 사용할 도커 이미지
ports:
- containerPort: 80 # 컨테이너의 포트
env:
- name: EXAMPLE_ENV # 환경 변수 이름
value: "This is an example." # 환경 변수 값
✅ 쿠버네티스 관리 도구: Kustomize, Helm
쿠버네티스 관리 도구인 Kustomize와 Helm은 쿠버네티스 리소스를 더 쉽게 배포하고 관리할 수 있도록 돕는 도구들이다.
Kustomize: 쿠버네티스 리소스를 템플릿 없이 정의할 수 있도록 하는 구성 관리 도구
Helm: 차트라는 패키지 형식을 사용하여 애플리케이션을 정의하고 설치하는 관리 도구
▶ Kustomize
Kustomize는 쿠버네티스 manifest를 쉽게 구성하고 관리하기 위한 도구이다. 기존의 YAML 파일을 직접 수정하지 않고도 여러 환경에서 사용될 수 있는 manifest를 구성할 수 있도록 돕는다. Kustomize는 쿠버네티스에 기본 내장되어 있으며, 선언형 방식으로 리소스를 관리한다.
🔽 Kustomize의 특징
패치 적용: 기본 YAML 파일을 변경하지 않고 특정 필드만 수정하는 형태로 패치를 적용할 수 있다. 이를 통해 개발, 테스트, 프로덕션 등 여러 환경에서 필요한 설정을 재사용하면서도 차이점만 관리할 수 있다.
중복 코드 제거: Kustomize는 여러 쿠버네티스 리소스 간의 중복된 설정을 제거하여 유지 보수를 쉽게 한다.
오버레이 사용: 오버레이라는 기능을 사용해 공통 베이스 설정에서 환경별(예: staging, production) 차이점을 덮어쓰는 방식으로 리소스를 구성할 수 있다.
🔽 Kustomize의 구조
1. base: kustomization + resources
base 디렉토리에는 Yaml 리소스(오브젝트) 파일(deployment, service, configmap 등)이 포함되어 있으며, 이 디렉토리에서 kustomization.yaml 파일을 생성하여 참조할 리소스와 적용할 모든 사용자 정의 내용을 선언해야 한다.
2. overlayes: kustomization + patches + 기타 resources
overlays 디렉토리에는 base를 참조하고 수정하는 내용을 패치(patch)형태로 정의한 kustomization.yaml 파일과, 패치에 적용할 실제 내용의 파일들이 포함되어 있다. overlays 하위에는 development, staging, production 등의 디렉터리를 생성하여 환경별로 관리할 수 있다.