들어가기 앞서
✔️ 컨테이너 오케스트레이션(Container Orchestration)이란 ?
- 컨테이너 오케스트레이션이란 컨테이너를 쉽고 빠르게 배포/확장하고 관리를 자동화해주는 도구이다.
- 여러개의 서버에 컨테이너를 배포하고 운영하면서 서비스 간 연결을 쉽게 해주는 것이다. (서비스 디스커버리같은 기능을 이용)
- 서버마다 다른 이름을 짓고 개별적으로 관리하는 것이 아니라 Server 1, 2, 3, ...을 하나로 묶어 적당한 서버를 자동으로 선택해 어플리케이션을 배포하는 것이다.
- 부하가 생기면 컨테이너를 늘리고 일부 서버에 장애가 생기면 정상 동작 중인 서버에 다시 띄워 장애를 방지한다.
- 흔히 잘 알려진 오케스트레이션 툴로는 도커 스웜(Docker Swam), 쿠버네티스(Kubernetes), 아파치 메소스(Apache Mesos) 등이 있다.
✔️ 오케스트레이션 툴의 기능
컨테이너 오케스트레이션 툴의 기능에는 컨테이너 배포 뿐만이 아니라 서비스를 관리하고 유지보수 하기위한 많은 기능을 포함한다.
- 노드 클러스터링
- 컨테이너 로드 밸런싱
- 컨테이너의 배포와 복제 자동화
- 컨테이너 장애 복구 기능(정상 작동 체크 및 문제시 재가동)
- 컨테이너 오토스케일링
- 컨테이너 스케줄링(컨테이너를 적절한 서버에 배포하는 것)
- 로깅 및 모니터링
✔️ 쿠버네티스 (Kubernetes)란?
쿠버네티스란 컨테이너화된 어플리케이션의 배포, 확장 및 관리를 자동화하는 오픈 소스 플랫폼이다.
우리가 단일 서버에서 도커를 단순히 업로드하고 배포하는 것으로만 사용한다면 오케스트레이션이라 불리는 쿠버네티스를 사용할 이유가 없다.
반면 두개 이상의 서버에서 도커 데몬을 사용하게 된다면 혹은 10대 이상의 서버에서 도커를 사용하게 된다면 어떤 시스템에 컨테이너를 생성하는 것이 맞을까를 생각해야 한다.
당연히 idle 상태인 서버를 선택해 해당 서버에서 컨테이너를 생성하여 운용해야 한다.
그것을 일일이 각 서버에 접근해 유휴 자원을 확인하는 것은 매우 비효율적이다. 그래서 등장한 것이 k8s이다.
✔️ 쿠버네티스 기능
- 자동 재시작 기능 - 컨테이너들을 모니터링, 쿠버네티스는 한 기능을 담당하는 컨테이너를 n개 보유하고 있어서 그 중 하나가 다운되면 빠르게 다른 하나를 가동시킴
- 컨테이너 스케일 조정 - 유저가 많거나 적음에 따라 쿠버네티스가 자동적으로 컨테이너 수를 조절
- 웹 사이트 다운 위험 방지 - 컨테이너 코드의 버그 수정, 버전 업데이트를 해야하는 경우 쿠버네티스가 컨테이너의 신규 버전을 차례로 업데이트 해준다.
- 서비스 디스커버리와 로드 밸런싱 - DNS 이름을 사용하거나 자체 IP 주소를 사용하여 컨테이너를 노출
- 스토리지 오케스트레이션 - 로컬 저장소, 공용 클라우드 공급자 등과 같이 원하는 저장소 시스템을 자동으로 탑재
- 자동화된 롤아웃과 롤백 - 원하는 상태를 서술하고 현재 상태를 원하는 상태로 설정한 속도에 따라 변경 가능
- 자동화된 빈 패킹 - 각 컨테이너가 필요로 하는 CPU와 메모리(RAM)를 제공
- 자동화된 복구(self-healing) - 실패한 컨테이너를 다시 시작하고, 컨테이너를 교체
- 시크릿과 구성 관리 - 암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리
✔️ 쿠버네티스 기본 개념/용어
쿠버네티스에서 가장 중요한 것은 Desired State - 원하는 상태라는 개념이다.
구체적으로 얼마나 많은 웹서버가 떠 있으면 좋은지, 몇번 포트로 서비스하기를 원하는지 등을 말한다.
Current State를 모니터링하면서 관리자가 설정한 Desired State를 유지하기위해 내부적으로 작업을 하는 로직으로 구성되어 있다.
관리자가 서버를 배포할 때 "nginx 컨테이너 실행, 80번 포트 오픈" 이라고 하면 현재 상태를 원하는 상태로 바꾸기 위한 명령이고 "80번 포트 오픈한 nginx 컨테이너 1개 유지"는 원하는 상태를 선언한 것이다.
즉 핵심은 상태이며 k8s를 사용하기 위해서는 어떤 상태가 있고 어떻게 상태를 선언해야 하는지가 중요하다.
Control Loop
원하는 상태를 만들기 위해 사용하는 메커니즘이 Control Loop (제어 루프)이다.
1. Observe : Objcet들이 원하는 상태가 무엇인지 확인
2. Check Differencs : Object들의 현재 상태가 어떤지 체크하고 원하는 상태와 비교해 어떤 차이가 있는지 확인
3. Take Action : 현재 상태를 원하는 상태로 만들어준다.
1, 2, 3 과정을 반복하며 지속적으로 원하는 상태를 유지하게 된다.
Kubernetes Object
쿠버네티스는 상태를 관리하기 위한 대상을 오브젝트로 정의한다. Basic Object와 Controller로 이루어져있다.
기본적으로 수십 가지 오브젝트를 제공하며 새로운 오브젝트를 추가하는 것이 쉬워 확장성이 좋다.
Basic Object (기본 오브젝트)
- 컨테이너화가 되어 배포되는 어플리케이션의 워크로드를 기술하는 오브젝트
- 종류 : Pod, Service, Volume, Namespace
Controller (컨트롤러)
- 기본 오브젝트는 애플리케이션을 설정하고 배포하는 것이 가능한데, 이를 좀 더 편리하게 관리하기 위해서 컨트롤러라는 개념 사용
- 종류: Replication Controller, ReplicaSet, Deployment, DaemonSet, Job, StatefulSet 등
Object Spec - YAML
오브젝트의 명세는 YAML 파일로 정의하고 여기에 오브젝트의 종류와 원하는 상태를 입력한다.
이러한 명세는 생성, 조회, 삭제로 관리할 수 있기 때문에 REST API로 쉽게 노출할 수 있다.
접근 권한 설정도 같은 개념을 적용해 누가 어떤 오브젝트에 어떤 요청을 할 수 있는지 정의할 수 있다.
Basic Object
📌 Pod
쿠버네티스에서 배포할 수 있는 가장 작은 단위로 한 개 이상의 컨테이너와 스토리지, 네트워크 속성을 가진다.
Pod에 속한 컨테이너는 스토리지와 네트워크(IP, Port)를 공유하며 서로 localhost로 접근할 수 있다.
ex) A:8080, B:7001 Port로 배포시 A에서 B를 localhost:7001로 호출 가능
1개의 컨테이너라도 반드시 Pod로 감싸서 관리한다.
Pod 내 배포된 컨테이는 디스크 Volume를 공유 가능하다. (다른 컨테이너의 파일을 읽어올 수 있다.)
하나의 Pod는 하나의 노드에만 배치될 수 있으며, Pod 내 컨테이너가 각각의 다른 노드에 배치될 수 없다.
📌 Service
네트워크와 관련된 오브젝트로 Pod를 외부 네트워크와 연결해주고 여러개의 Pod를 바라보는 내부 로드 밸런서를 생성할 때 사용한다. 내부 DNS에 서비스 이름을 도메인으로 등록하기 때문에 서비스 디스커버리 역할도 한다.
📌 Volume
저장소와 관련된 오브젝트이다. 호스트 디렉토리를 그대로 사용할 수도 있고 EBS(Elastic Block Storage)같은 스토리지를 동적으로 생성하여 사용할 수도 있다.
컨테이너의 restart와 상관없이 파일을 영속적으로 저장해야하는 경우 사용한다. (ex. DB)
Pod를 기동할 때 컨테이너에 마운트해서 사용한다.
PersistentVolume : 쿠버네티스에 지정한 물리 디스크
PersistentVolumeClaim : PersistentVolume과 Pod를 연결할 수 있게 해주는 개념
📌 Namespace
쿠버네티스 클러스터 내의 논리적인 분리단위
네임스페이스 별로 자원들을 나누어 관리할 수 있으며 접근 권한, 리소스 할당량 등을 설정할 수 있다.
Controller (컨트롤러)
📌 ReplicaSet
Pod를 여러개(한개 이상) 복제하여 관리하는 오브젝트이다.
Pod를 생성하고 개수를 유지하려면 반드시 ReplicaSet을 사용해야 한다. ReplicaSet은 복제할 개수, 개수를 체크할 라벨 선택자, 생성할 Pod의 설정값(템플릿) 등을 가지고 있다.
직접적으로 ReplicaSet을 사용하기 보다는 Deployment 등 다른 오브젝트에 의해 사용되는 경우가 많다.
...
spec:
replicas: 3 # replicas: 관리될 Pod의 수
selector: # selector: Pod들을 묶는 기준 (label)
app:nginx
template: # template: Pod를 추가로 띄울 때, Pod정보 정의
...
containers:
- name: nginx
image: nginx
ports:
- containerPort:80
📌Deployment
ReplicaSet보다 상위에 있는 개념으로 ReplicaSet 배포의 기본 단위가 되는 리소스
(실제 운영에서는 ReplicaSet을 바로 사용하는 것 보다, 좀 더 추상화된 Deployment를 사용)
Pod 배포를 위해 ReplicaSet을 생성하고 관리하는 역할을 하며, 특히 롤백을 위한 기존 버전 RC 관리등 여러 기능을 포괄적으로 포함하고 있다.
✔️ 쿠버네티스 배포 방식
쿠버네티스는 애플리케이션을 배포하기 위해 원하는 상태(desired state)를 다양한 오브젝트(object)에 라벨Label을 붙여 정의(yaml)하고 API 서버에 전달하는 방식을 사용한다.
“컨테이너를 2개 배포하고 80 포트로 오픈해줘”라는 간단한 작업을 위해 다음과 같은 구체적인 명령을 전달해야 한다.
✔️ 쿠버네티스 구조
쿠버네티스는 중앙(Master)에 API 서버와 상태 저장소를 두고 각 서버(Node)의 에이전트(Kubelet)과 통신하는 단순한 구조이다.
마스터 - 노드 구조
쿠버네티스는 전체 클러스터를 관리하는 마스터와 컨테이너가 배포되는 노드로 구성되어 있다.
모든 명령은 마스터의 API 서버를 호출하고 노드는 마스터와 통신하면서 필요한 작업을 수행한다.
특정 노드의 컨테이너에 명령하거나 로그를 조회할 때도 노드에 직접 명령하는 게 아니라 마스터에 명령을 내리고 마스터가 노드에 접속하여 대신 결과를 응답한다.
Master
마스터 서버는 다양한 모듈의 확장성을 고려해 기능별로 쪼개져 있는 것이 특징이다.
관리자만 접속할 수 있도록 보안 설정이 필요하고 마스터 서버가 죽으면 클러스터를 관리할 수 없으므로 보통 3대를 구성해 안정성을 높인다.
AWS EKS 같은 경우 마스터를 AWS에서 자체 관리해 안정성을 높였고 (마스터에 접속 불가) 개발 환경이나 소규모 환경에서는 마스터와 노드를 분리하지 않고 같은 서버에 구성하기도 한다.
Master 구성 요소
Master 구성 요소 자세히 알아보기
API 서버 kube-apiserver
API 서버는 모든 요청을 처리하는 마스터의 핵심 모듈
kubectl의 요청뿐 아니라 내부 모듈의 요청도 처리하며 권한을 체크하여 요청을 거부할 수 있다.
실제로 하는 일은 원하는 상태를 key-value 저장소에 저장하고 저장된 상태를 조회하는 매우 단순한 작업이다.
Pod을 노드에 할당하고 상태를 체크하는 일은 다른 모듈로 분리되어 있다.
노드에서 실행 중인 컨테이너의 로그를 보여주고 명령을 보내는 등 디버거 역할도 수행한다.
분산 데이터 저장소 etcd
RAFT 알고리즘을 이용한 key-value 저장소입니다. 여러 개로 분산하여 복제할 수 있기 때문에 안정성이 높고 속도도 빠른 편입니다. 단순히 값을 저장하고 읽는 기능뿐 아니라 watch 기능이 있어 어떤 상태가 변경되면 바로 체크하여 로직을 실행할 수 있습니다.
클러스터의 모든 설정, 상태 데이터는 여기 저장되고 나머지 모듈은 stateless하게 동작하기 때문에 etcd만 잘 백업해두면 언제든지 클러스터를 복구할 수 있습니다. etcd는 오직 API 서버와 통신하고 다른 모듈은 API 서버를 거쳐 etcd 데이터에 접근합니다. k3s 같은 초경량 쿠버네티스 배포판에서는 etcd대신 sqlite를 사용하기도 합니다.
스케줄러, 컨트롤러
API 서버는 요청을 받으면 etcd 저장소와 통신할 뿐 실제로 상태를 바꾸는 건 스케줄러와 컨트롤러 입니다. 현재 상태를 모니터링하다가 원하는 상태와 다르면 각자 맡은 작업을 수행하고 상태를 갱신합니다.
스케줄러 kube-scheduler
스케줄러는 할당되지 않은 Pod을 여러 가지 조건(필요한 자원, 라벨)에 따라 적절한 노드 서버에 할당해주는 모듈입니다.
큐브 컨트롤러 kube-controller-manager
큐브 컨트롤러는 다양한 역할을 하는 아주 바쁜 모듈입니다. 쿠버네티스에 있는 거의 모든 오브젝트의 상태를 관리합니다. 오브젝트별로 철저하게 분업화되어 Deployment는 ReplicaSet을 생성하고 ReplicaSet은 Pod을 생성하고 Pod은 스케줄러가 관리하는 식입니다.
클라우드 컨트롤러 cloud-controller-manager
클라우드 컨트롤러는 AWS, GCE, Azure 등 클라우드에 특화된 모듈입니다. 노드를 추가/삭제하고 로드 밸런서를 연결하거나 볼륨을 붙일 수 있습니다. 각 클라우드 업체에서 인터페이스에 맞춰 구현하면 되기 때문에 확장성이 좋고 많은 곳에서 자체 모듈을 만들어 제공하고 있습니다.
Node
노드 서버는 마스터 서버와 통신하면서 필요한 Pod를 생성하고 네트워크와 볼륨을 설정한다.
실제 컨테이너들이 생성되는 곳으로 수백, 수천대로 확장할 수 있다. 각각의 서버에 라벨을 붙여 사용목적(GPU 특화, SSD 서버 등)을 정의할 수 있다.
Node 구성 요소
node 구성 요소 자세히 알아보기
큐블릿 kubelet
노드에 할당된 Pod의 생명주기를 관리합니다. Pod을 생성하고 Pod 안의 컨테이너에 이상이 없는지 확인하면서 주기적으로 마스터에 상태를 전달합니다. API 서버의 요청을 받아 컨테이너의 로그를 전달하거나 특정 명령을 대신 수행하기도 합니다.
프록시 kube-proxy
큐블릿이 Pod을 관리한다면 프록시는 Pod으로 연결되는 네트워크를 관리합니다. TCP, UDP, SCTP 스트림을 포워딩하고 여러 개의 Pod을 라운드로빈 형태로 묶어 서비스를 제공할 수 있습니다. 초기에는 kube-proxy 자체가 프록시 서버로 동작하면서 실제 요청을 프록시 서버가 받고 각 Pod에 전달해 주었는데 시간이 지나면서 iptables를 설정하는 방식으로 변경되었습니다. iptables에 등록된 규칙이 많아지면 느려지는 문제 때문에 최근 IPVS를 지원하기 시작했습니다.
추상화
컨테이너는 도커고 도커가 컨테이너라고 생각해도 무리가 없는 상황이지만 쿠버네티스는 CRI(Container runtime interface)를 구현한 다양한 컨테이너 런타임을 지원합니다. containerd(사실상 도커..), rkt, CRI-O 등이 있습니다.
CRI 외에 CNI(네트워크), CSI(스토리지)를 지원하여 인터페이스만 구현한다면 쉽게 확장하여 사용할 수 있습니다.
Kubectl
API 서버는 json 또는 protobuf 형식을 이용한 http 통신을 지원한다. 이 방식을 그대로 쓰면 불편하므로 보통 kubectl이라는 명령행 도구를 사용한다.
🔗참고
https://www.byfuls.com/programming/read?id=73
https://dalsacoo-log.tistory.com/entry/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-Kubernetes
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] Service Discovery (0) | 2022.03.17 |
---|---|
[Kubernetes] Object - Service (0) | 2022.03.17 |
[Kubernetes] Object 개념 (0) | 2022.03.17 |
[Kubernetes] Workload Resources (0) | 2022.03.16 |
[Kubernetes] Pod란 ? (0) | 2022.03.16 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!