Kubernetes??

k8s-logo
본 포스트는 쿠버네티스의 기본 개념, 설치, 클러스터 구성 등 꽤 많은 내용을 다루고 있으니 오른쪽의 목차 tocbot을 참고하자.

들어가기 전에

서버 스터디를 시작하며 NHN Toast Cloud 플랫폼을 통해 도커를 접해보았다. 컨테이너를 쓰는 이유가 점점 납득이 갈 때쯤 쿠버네티스가 그렇게 핫하다는 말을 듣고 구글링해보다가 도커와 같이 공부하면 좋겠다는 생각에 무턱대고 도서관에 가서 책을 빌리고 공부를 시작했다. 매력적인 서비스임은 분명하다. 왜 매력적인 서비스인지 알아보려 한다.

컨테이너가 멋진 이유

컨테이너, 레이어의 기본 개념은 도커 관련 포스트를 참조하자.
컨테이너의 인기는 몇년 전부터 불같다. 도커, 컨테이너 관련 내용이 없는 IT 컨퍼런스는 찾기 힘들어지고 있다. 컨테이너 그 자체는 기술이 아니며, 수년 전부터 사용되고 있었다. 도커가 인기있는 이유는 유저에게 제공되는 도구와 사용의 편리함에 있다.

현대의 개발 관행은 지속적 통합, 지속적 배포에 있다. 소프트웨어의 품질을 극대화하기 위함이다. 조직은 코드를 작성, 배포하는 지속적인 과정을 통해 품질 관리, 테스트를 도입해 수행한다. 그 결과 더욱 빨리 업데이트되고 버그가 수정되어 전체적인 품질이 향상되는 것이다. 그러나 테스트와 배포가 일치하는 개발 환경을 만드는 건 어렵다.

도커를 사용하면 이 과정이 너무 편리해진다. 개발자의 PC에서 배포된 컨테이너는 사내 staging 서버에 쉽게 배포할 수 있다. 그 다음 클라우드에서 실행중인 배포 서버로 쉽게 전송할 수 있다. 이는 도커가 부모 레이어가 명시된 빌드 파일을 사용해서 컨테이너를 생성하기 때문이다. 이 방식은 OS, 패키지, 어플리케이션 버전의 일치를 보장하는 장점이 있다.

오케스트레이션

쿠버네티스는 다른 컨테이너 오케스트레이션 도구보다 늦게 등장했다. 컨테이너 오케스트레이션이란 여러 개의 서버에 컨테이너를 배포, 운영하면서 서비스 간 연결을 쉽게 해주는 것이다. 서버마다 각각 이름을 부여해서 한개씩 접속하여 관리하는 것이 아닌, 서버 몇개를 하나로 묶어 적당한 서버를 자동으로 선택해 애플리케이션을 배포하고, 부하가 생기면 컨테이너를 늘리는 등의 기능을 제공한다. 오케스트레이션 툴들은 많았지만, 구글의 노하우와 강력한 확장성이 보장된 쿠버네티스의 등장으로 사실상 de facto가 되었다.

마스터-노드 Structure

k11
쿠버네티스는 전체 클러스터를 관리하는 마스터와 컨테이너가 배포되는 노드로 구성되어 있다. 모든 명령은 마스터의 API 서버를 호출하고, 노드는 마스터와 통신하면서 필요한 작업을 수행한다. 특정 노드에 명령을 내려도 노드에 직접 명령이 전해지는게 아니라 마스터에 명령을 내리고 마스터가 노드에 접속하여 대신 결과를 응답한다.

쿠버네티스를 구성하는 것들

클러스터는 쿠버네티스에서 관리하는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 기계의 집합이다. 클러스터는 최소 1개의 마스터 노드와 최소 1개의 워커 노드를 가진다.

워커 노드는 애플리케이션의 구성요소인 파드(Pod)를 호스트한다. 마스터 노드워커 노드클러스터 내 파드를 관리한다. 다수의 마스터 노드는 failover(장애극복)과 고가용성의 클러스터에서 사용한다.

클러스터를 구성하기 전에 몇가지 컴포넌트의 개념을 알아보자.

마스터 컴포넌트

kube-apiserver

API 서버는 쿠버네티스의 API를 노출하는 쿠버네티스 컨트롤 플레인 컴포넌트이다. API 서버의 주요 구현은 kube-apiserver이다. 즉, 더 많은 인스턴스를 배포해서 확장할 수 있다. 여러 kube-apiserver 인스턴스를 실행하고, 인스턴스간의 트래픽을 균형있게 조절할 수 있다.

etcd

모든 클러스터 데이터를 담는 쿠버네티스 뒷단의 저장소로 사용되는 일관성, 고가용성 키-값(Key-Value) 저장소이다.

kube-scheduler

노드가 배정되지 않은 새로 생성된 파드를 감지하고 그 파드가 구동될 노드를 선택하는 마스터 상의 컴포넌트이다. 스케줄링 결정을 위해 고려되는 요소는 리소스에 대한 개별 및 총체적 요구 사항, 하드웨어/소프트웨어/정책적 제약 등의 모든 사항이 포함되어 있다.

kube-controller-manager

컨트롤러를 구동하는 마스터 상의 컴포넌트이다. 논리적으로 각 컨트롤러는 개별 프로세스이지만, 복잡성을 갖추기 위해 모두 단일 바이너리로 컴파일되고 단일 프로세스 내에서 실행된다. 컨트롤러에는 노드 컨트롤러, 레플리케이션 컨트롤러, 엔드포인트 컨트롤러, 서비스 어카운트 & 토큰 컨트롤러가 있다.

노드 컴포넌트

kubelet

클러스터의 각 노드에서 실행되는 에이전트이다. Kubelet은 파드에서 컨테이너가 확실하게 동작하도록 관리한다. 다양한 메커니즘을 통해 제공된 파드 스펙(PodSpec)의 집합을 받아서 해당 파드 스펙에 따라 건강하게 동작하는 것을 확실히 한다. Kubelet은 쿠버네티스를 통해 생성되지 않는 컨테이너는 관리하지 않는다.

kube-proxy

클러스터의 각 노드에서 실행되는 네트워크 프록시로, 쿠버네티스 서비스 개념의 구현부이다. kube-proxy는 노드의 네트워크 규칙을 유지, 관리한다. 이 네트워크 규칙이 내부 네트워크 세션에서 바깥으로 네트워크 통신을 할 수 있도록 해준다.

쿠버네티스 설치하기

이제 쿠버네티스를 설치하고 클러스터를 구성해보자. 필자의 환경은 Ubuntu 18.04이다. os에 따라 설치법이 다를 수 있으나 쿠버네티스 설치 후의 kubectl 명령은 동일하니 centOS 등의 운영체제를 사용한다면 구글링을 통해 충분히 해결할 수 있을 것이다.

docker 설치

컨테이너 기반의 툴이기 때문에 도커 설치가 필요하다.

1
sudo wget -qO- https://get.docker.com/ | sh

이 명령어는 리눅스 배포판을 알아서 인식해서 도커를 설치한다. wget 명령어가 사용되지 않는다면 sudo apt-get install wget 명령을 사용해서 wget 패키지를 설치한 후 진행하자.

Port 설정

아래 표의 포트들은 쿠버네티스가 사용하는 포트임으로 비워두자. 클라우드를 사용한다면 포트 보안 정책의 수정이 필요하다. 필자는 NHN Toast Cloud을 사용중이므로 보안 정책을 Master, Worker 포트에 맞게 각각 설정해놓았다.

k21

쿠버네티스 설치

클러스터 구성을 위해 필요한 kubeadm, kubelet, kubectl을 설치한다.

1
2
3
4
5
6
7
8
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

쿠버네티스 구동 시 swap을 사용할 수 없다. 따라서 swap을 꺼준다.

1
swapoff -a

클러스터 구성하기

클러스터 구성 - Master

1
kubeadm init --pod-network-cidr=10.244.0.0/16

네트워크 옵션은 pod network 구성을 위한 옵션이다. 어떤 구성을 할지에 따라 옵션이 달라지는데 공식 홈페이지를 확인하자. 이번에는 Flannel을 사용할 것이다.

다시 init하고 싶다면 kubeadm reset 을 통해 리셋할 수 있다.

성공적으로 init이 되었다면 출력 결과의 마지막 줄에 kubeadm join ~ 부분을 어딘가에 잘 복사해놓자. 워커 노드를 마스터 노드에 연결하기 위한 명령이고, 24시간동안 유효하다.

그 윗줄을 잘 보면 CONFIG 파일을 특정 경로에 복사해두라는 말과 세줄의 명령어를 출력하는데 이는 앞으로 kubectl을 통해 명령을 내릴 때 어느 클러스터에 명령을 내릴 지 등이 설정이 저장된 파일이다. 세 줄의 명령을 실행한다.

1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

이제 pod network 설정이다.

1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml

Master 노드의 구성은 완료되었다. 진행 사항이 궁금하다면 kubectl get pods --all-namespaces 명령어를 입력하면 생성중인 컨테이너들을 볼 수 있다.

클러스터 구성 - Worker

워커 노드에서도 위에서의 docker, kubeadm, kubelet, kubectl을 설치한다. 위에 서술한 포트 정책 변경도 잊지 말자. 나는 2개의 워커 노드를 구성했다. (1 마스터노드 - 2 워커노드) 복수의 워커노드를 사용하더라도 똑같이 docker, kubeadm, kubelet, kubectl을 설치하면 된다.

이제 워커노드에서 masterinit하고 나서 잘 복사해뒀던 명령어 (kubeadm join ~ 부분)를 입력한다.

1
2
kubeadm join <master-ip>:<master-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
#예시 코드이므로 마스터에서 복사해두었던 코드 사용하기!

token의 유효기간은 24시간이고 혹시 위 명령어를 잃어버렸거나 유효기간이 지난 것 같으면 kubeadm token create --print-join-command 명령어를 master 노드에서 입력하면 된다.

마스터 노드에서 get 명령을 입력하여 join이 잘 되었는지 확인해보자.

1
2
kubectl get no
#kubectl get nodes와 같다

마치며

쿠버네티스의 기본적인 개념에서 클러스터 구성 방법까지 알아보았다.
쿠버네티스 생태계는 현재도 빠르게 변하고 발전하고 있다. 사용법이 바뀌고 계속해서 새로운 기능들이 추가되고 있지만 기본적인 구성과 아키텍쳐는 거의 동일하다. 기본적인 동작 원리를 이해한다면 새로운 버전이 나와도 쉽게 이해하고 확장하여 사용할 수 있다. 도커와 쿠버네티스의 조합은 devOps 개발에서 거의 필수가 되어가는 만큼 경험해보면 좋은 플랫폼인 것은 확실하다.