2024. 1. 26. 01:41ㆍWEB/Infra
쿠버네티스란?
쿠버네티스는 컨테이너화된 어플리케이션의 배포, 스케일링 및 관리를 자동화하는 오케스트레이션 시스템으로, 사용자가 리소스와 어플리케이션의 원하는 상태를 Manifest라는 파일에 선언하면 쿠버네티스 시스템이 해당 상태를 실현하는 방식으로 동작합니다.
쿠버네티스는 클러스터 환경을 구성해 스케줄링, 복구, 스케일링, 로드 밸런싱 등의 작업을 수행해, 여러 서버에서 어플리케이션을 실행하며 발생하는 복잡성을 줄여주는 역할을 합니다.
클러스터의 구성 요소
배포에 사용되는 서버의 Cpu, 메모리, 네트워크, 스토리지와 같은 인프라 리소스는 Node라는 논리적 요소가 되며, Pod을 실행하고 관리하는 워커 노드와 클러스터를 관리하는 마스터 노드로 나뉩니다. 이러한 노드의 집합은 클러스터라는 요소로 묶여 마스터 노드의 컨트롤 플레인을 통해 관리됩니다.
어플리케이션을 배포하기 위한 최소 단위인 Pod은 실행에 필요한 1개 이상의 컨테이너 집합으로, 생성 시점에 컨트롤 플레인의 kube-scheduler를 통해 적합한 워커 노드를 할당받게 됩니다.
멀티 프로세스/스레드 시스템에서 각 프로세스의 개별 프로세스와 유사하게, 각 파드는 독립적인 실행 환경을 가집니다.
프로세스의 실행에 필요한 메모리, Cpu와 같은 자원을 운영체제로부터 제공받는 것처럼, 컨트롤 플레인은 파드의 스케쥴링, 클러스터 리소스의 관리, 클러스터 상태 모니터링 등을 수행합니다.
리소스와 오브젝트
객체 지향의 관점에서 클래스와 객체를 비교하는 것처럼, 쿠버네티스에도 이와 유사하게 리소스와 오브젝트라는 개념이 있습니다.
클래스가 객체의 생성에 사용되는 속성과 메소드가 정의된 틀이고, 클래스를 통해 구현된 데이터와 기능이 결합된 것을 객체라고 하는 것처럼(정확히는 객체 != 인스턴스) 쿠버네티스의 오브젝트는 쿠버네티스 리소스라는 틀을 통해 생성됩니다.
⭐️ 학습 과정에서 리소스와 오브젝트를 혼용하는 게시물이 많아서 헷갈렸습니다.. 두 개념의 차이를 알면 도움이 될 것 같아요
api-resource에 해당하는 bindings, endpoints 등은 오브젝트 생성에 필요한 템플릿 역할을 합니다.
manifest의 Kind를 통해 Pod, Service, Deployment, StatefulSet 등 오브젝트의 뼈대가 될 리소스를 정하고, 오브젝트를 식별하기 위한 metadata와 오브젝트의 상태인 spec을 작성하면 kubectl apply를 이용해 이를 클러스터에 등록할 수 있습니다.
쿠버네티스의 핵심 커맨드인 kubectl apply의 프로세스는 다음과 같습니다.
- apiVersion, kind, metadata, spec 등의 정보를 포함한 매니페스트 파일을 kube-apiserver에 전송합니다.
- kube-apiserver에서는 매니페스트 파일을 받아 검증하고, etcd에 저장하거나 업데이트합니다.
- 새로운 오브젝트 생성 시
- kube-apiserver에서 etcd에 오브젝트 정보 등록
- kube-scheduler에서 새로운 파드 실행에 적합한 노드를 할당
- 할당된 노드의 kubelet에서 파드를 실행
- 기존 오브젝트 업데이트 시
- kube-apiserver에서 etcd에 저장된 오브젝트의 상태 수정
- 변경 사항에 따라 kube-controller-manager 또는 다른 컨트롤러들이 추가적인 동작 수행(롤아웃 배포 등)
- 새로운 오브젝트 생성 시
- 상태 보고
- kubelet에서 실행 중인 파드의 상태를 지속적으로 api-server에 보고
- kube-controller-manager에서 파드의 상태 변화에 따라 필요한 동작을 수행
- 지속적인 관리
위처럼 클러스터 내부의 오브젝트는 manifest 파일을 통해 코드 형식으로 관리되는데, 이는 IaC(Infrastructure as Code) 방법론으로 인프라 환경을 git과 같은 VCS를 통해 소프트웨어 개발과 유사하게 관리할 수 있습니다.
Minikube
개발, 테스트 또는 학습 환경에서 여러 노드를 구성하기는 쉽지 않기 때문에 로컬 환경에서 단일 노드 기반의 클러스터를 실행할 수 있도록 Minikube가 사용됩니다. 클러스터 제어를 위한 마스터 노드와 워커 노드를 가진 로컬 기반의 가상 클러스터라고 보시면 될 것 같습니다.
쿠버네티스 클러스터와 구축에 드는 비용과 어려움을 줄이고, 쿠버네티스의 다양한 기능을 사용할 수 있도록 minikube 관리 커맨드 등을 제공합니다.
Docker Desktop에서도 유사하게 로컬에서 사용할 수 있는 가상 k8s 클러스터를 지원하고 있습니다.
Kubectl
kubectl은 클러스터의 apiserver로 요청을 보내 클러스터와 상호작용하기 위한 툴로, 여러 클러스터와 사용자를 "context"를 사용해 편리하게 제어할 수 있습니다.
context에 대한 정보는 ~/.kube/config에 담겨있으며, 클러스터의 정보와 클러스터와 상호작용하기 위한 사용자의 정보, 인증 방법 등이 포함됩니다. minikube이나 kubeadm을 통해 쉽게 초기 구성을 할 수 있습니다.
쿠버네티스의 config을 통해 컨텍스트의 정보들을 가져온 모습입니다.
테스트를 위해 minikube 컨텍스트를 이용해 보겠습니다.
Namespace
쿠버네티스는 리소스간의 이름 충돌을 방지하고, 권한 제어, 실행 환경의 분리를 위해 네임스페이스를 통해 여러 리소스를 논리적 단위로 격리해 효율적이고 안전한 운영을 돕습니다.
테스트를 위한 네임스페이스를 생성하고, 두 개의 Pod와 서비스를 통해 동작 방식을 알아보도록 하겠습니다.
네임스페이스가 생성되었으니, apache와 nginx 두 개의 파드를 생성해 보겠습니다.
CLI 명령어를 이용해 nginx 파드를 test 네임스페이스에 생성해 줍니다.
다음은 리소스를 선언적으로 관리하기 위한 manifest를 이용해 생성해 봅니다.
pod 매니페스트를 생성하기 위한 api 버전(v1)과 kind(Pod)을 통해 간단한 manifest를 작성해 줍니다.
- v1 버전의 api를 사용하며,
- test 네임스페이스에 속하는
- apache라는 이름의
- Pod입니다.
- 이 파드는 apache:latest 이미지를 사용해
- apache라는 이름의 컨테이너를 생성하며
- 80 포트를 노출합니다.
test 네임스페이스의 파드를 보면 문제가 있음을 알 수 있는데요.
아파치 웹서버의 이미지가 apache가 아니라 httpd라 생긴 오류였습니다ㅎ;
이제 이 파드들에 클러스터 외부에서 접근할 수 있도록 설정해 줍니다.
Service
쿠버네티스는 파드의 네트워킹을 위해 서비스라는 추상화 리소스를 사용합니다.
직접 파드에 접근할 필요 없이 서비스를 통해 접근이 가능하게 해 주며, 서비스는 파드의 metadata를 통해 동일한 레이블을 가진 파드들에게 요청을 분배합니다.
- test 네임스페이스에서
- webserver라는 이름을 가진
- v1 버전의 api를 사용하는
- Service는
- NodePort 타입으로
- 클러스터에서 12345 포트를 리스닝하며
- test: webserver라는 레이블을 가진 파드를 찾아
- 트래픽을 80번 포트로 포워딩합니다.
NodePort의 경우 port, targetPort 외에도 3만번대의 노드 포트가 생성됩니다.
특정 포트를 명시할 수 있으나, 충돌이 발생할 수 있어 자동 생성하도록 비워두었습니다.
해당 리소스가 클러스터에 적용이 되면 임의의 노드 포트가 생성되며, 해당 포트의 트래픽이 클러스터의 port를 거쳐 컨테이너의 targetPort로 포워딩되게 됩니다.
먼저 1번을 보면 각 파드에 클러스터 내부에서 사용되는 IP가 생성되어 있고, 2번을 보면 서비스에 31523이라는 nodePort가 생성된 것을 볼 수 있습니다.
노드 IP:31523으로 들어온 트래픽은 서비스인 10.98.23.32:12345로 포워딩됩니다.
이제 다시 3번을 보면 Selector로 test=webserver가 있습니다.
생성되는 파드마다 새로운 IP 주소를 가지게 되는데, 이를 동적으로 관리하기 위해 Label과 Selector를 사용합니다.
Label은 리소스에 붙는 키:값 식별자로, 쿠버네티스에서는 이를 통해 리소스를 식별, 분류, 선택합니다.
즉 서비스의 selector는 레이블에 test : webserver가 존재하는 파드를 자동으로 수집하는 서비스 디스커버리를 수행합니다.
4번 ENDPOINTS를 보면 apache와 nginx의 클러스터 내부 주소인 10.244.0.71:80과 10.244.0.72:80이 등록되어 있는데, 10.98.23.32:12345(서비스)로 포워딩된 트래픽은 10.244.0.71:80(nginx) 또는 10.244.0.72:80(apache)로 다시 전달됩니다.
트래픽의 전달은 라운드 로빈 알고리즘을 통해 이루어지기 때문에 요청마다 다른 파드가 연결됩니다.
이를 확인하기 위해 직접 해당 서비스를 요청해 보겠습니다.
가상 환경 위에서 실행되는 minikube 노드에 node port를 할당했지만, 호스트 PC에서 접근하기 위해서는 추가적인 연결이 필요합니다.
minikube service [서비스 명] -n [서비스 네임스페이스]라는 명령어를 실행하면, minikube는 해당 서비스의 node port에 접근할 수 있는 URL을 만들어줍니다.
접속해 봅시다.
해당 url로 접속해 보면 nginx로 연결되는 것을 볼 수 있습니다.
동일한 주소로 다시 접속해보면 이번엔 아파치로 연결이 된 것을 볼 수 있습니다.
쿠버네티스의 기초적인 컨셉을 알아보고, minikube 환경에서 2개의 파드와 서비스로 서비스 디스커버리를 테스트해 보았습니다.
label과 selector는 다양한 리소스를 동적으로 다루기 위해 사용되는 컨셉으로, 서비스 외에도 레플리케이션 컨트롤러 등에서 다양하게 사용되므로 개념 이해가 중요한 부분입니다.