글을 시작하며

이번 글에서는 Highly Available Kubernetes Cluster를 구현해보는 과정을 담아보려고 합니다. 

 

위의 그림은 구현해볼 쿠버네티스의 구성도입니다. 

Highly Available Kubernetes Cluster의 구성 Components은 다음과 같습니다.

  • Master Node : k8s-master1, k8s-master2, k8s-master3
  • Worker Node : k8s-worker1, k8s-worker2
  • Load Balancer : nginx proxy
  • CNI : Weave Net

쿠버네티스 배포환경은 다음과 같습니다.

제 구현환경은 다음과 같습니다. 

  • Virtual Machine Ubuntu 22.04 LTS
  • kubernetes version : 1.28
  • Weaven NET version : 2.81
  • Server Sepc : 2 CPU, 2 GB Ram
  • linux swap Off
  • Docker version : 24.0.5
  • container runtime : containerD

Prerequisite

  • Node들에 kubeadm, kubectl, kubelet 이 모두 설치되어있어야한다.
  • Docker가 설치되어있어야한다.
  • 설치되어있는 Server의 방화벽 구성이 올바르게 설정되어있어야한다.

How it Works

Master Node (k8s-master-1, k8s-master-2, k8s-master3) Components 살펴보기

  • kube-APIServer 
    • Master Node가 Scale-Out 시에도 사용할 수 있도록 확장가능한 아키텍처를 가지고 있습니다.(Mastet Node가 여러대로 늘어나도 처리가능하도록)
    • kube-apiserver는 마스터 노드의 Control-Plane의 FrontEnd 역할을 합니다. (즉, 관리자의 명령을 받는 곳)
    • 인터페이스를 제공함으로써 외부와Request/Response로써  함께 통신할 수 있는 REST API를 제공합니다.
    • kube-apiserver는 Worker Node와 Master Node 간의 통신이 설정되도록 합니다.
  • etcd
    • Cluster 저장소입니다. Kubernetes 클러스터의 모든 구성 요소에 대한 정보가 etcd에 저장됩니다. 예를 들어, master node, worker node, service, namespace, Pod 및 기타 Kubernetes 개체에 대한 설정 및 상태 정보가 여기에 저장됩니다.
    • Node 정보를 저장합니다. etcd는 Kubernetes 클러스터의 모든 노드에 대한 정보를 저장합니다. 각 노드의 상태, 가용성, 노드의 IP 주소 및 호스트 이름과 같은 정보가 이곳에 저장됩니다.
    • 장애복구 가능한 분산 키-값 저장소로 작동됩니다.
    • 위의 그림과 같이 Stacked etcd cluster를 공유함으로써 Master Node와 현재 Worker Node들의 상태들을 모두 함께 공유합니다. 
    • 이러한 정보들을 모두 모아서 이후에 Scheduler에 전달하여 Scheduler는 현재 어떤 Worker Node에 작업을 할당하는것이 가장 좋을지에 대한 작업을 처리하여 APIServer에 다시 전달하여 해당 작업을 실행시킵니다.
    • Quorum체크를 통해 과반수 이상의 마스터가 살아있을때만 동작합니다.  즉, 마스터 노드가 3개로 구성되어있다면, 반드시 2개의 마스터노드는 작동되어야만 합니다. 이러한 과정에서 Raft Algorithm 을 사용하는데, 자세한 설명은 옆의 링크를 확인하시면 좋을 것 같습니다. https://tech.kakao.com/2021/12/20/kubernetes-etcd/  
 

Kubernetes 운영을 위한 etcd 기본 동작 원리의 이해

안녕하세요, 클라우드플랫폼팀 ted입니다. Container Cloud 관련 업무를 하고 계신 분이라면 모두 etcd[etsy d]를 한 번쯤은 들어보셨을 거라 생각합니다. 왜냐하면, 컨테이너 생태계에서 사실상 표준이

tech.kakao.com

  • CoreDNS
    • Kubernetes CLuster 내에서 DNS(Domain Name System) 서버의 역할을 하여,  서비스 검색과 Domain Name 해석을 처리하는데 사용합니다.
    • DNS Routing, coreDNS를 활용하여 애플리케이션은 서비스간 통신이 가능합니다.
    • kubelet
      • kube-APISever와 통신하여 노드의 상태를 확인, 등록, Worker Node에 작업할당 등등이 가능합니다.
  • Container Engine, Container Runtime
    • Container를 배포하고 관리하기 위하여 사용됩니다. Kubernetes 1.28 버전에서는 Container Runtime으로써 ContainerD를 사용하고 있습니다. 
    • Container Runtime은 파드에서 실행중인 컨테이너를 관리하며 이미지를 가져와 배포하고 컨테이너를 시작/중지합니다.kube-proxy
      • Node의 네트워크 역할을 수행합니다.
      • 각 Pod가 고유한 IP주소를 할당받도록 보장하며, 여러 컨테이너를 단일 파드에 패키지하는 경우 파드 내의 모든 컨테이너가 동일한 IP를 공유하도록 관리합니다.
      • 서비스의 모든 파드에 대한 로드밸런싱도 수행합니다.

Worker Node (k8s-worker1, k8s-worker2, k8s-worker3) : Master Node의 지시에 따라 작업을 수행하는 Node

  • kubelet
    • 각 worker node에서 실행되는 Agent Service 로써, worker가 Master와 통신하도록 합니다.
    • Kubernets Cluster에 Worker Node를 등록하고, Master kube-APIServer에서 작업할당을 하도록 도와줍니다.
  • Container Engine, Container Runtime
    • Container를 배포하고 관리하기 위하여 사용됩니다. Kubernetes 1.28 버전에서는 Container Runtime으로써 ContainerD를 사용하고 있습니다. 
    • Container Runtime은 파드에서 실행중인 컨테이너를 관리하며 이미지를 가져와 배포하고 컨테이너를 시작/중지합니다.
  • kube-proxy
    • Node의 네트워크 역할을 수행합니다.
    • 각 Pod가 고유한 IP주소를 할당받도록 보장하며, 여러 컨테이너를 Pod에 패키지하는 경우 파드 내의 모든 컨테이너가 동일한 IP를 공유하도록 관리합니다.
    • 서비스의 모든 Pod에 대한 로드밸런싱도 수행합니다.

Starting

1. 현재 시스템의 호스트파일을 수정합니다. 

IP주소와 호스트 이름간의 매핑정보를 제공하여 kubernetes cluster에서 사용할 네트워크 정보를 저장합니다.

이를 통해 DNS로 다른 Node를 호출할 수 있습니다.

# cat /etc/hostname
k8s-master1.seminarhub.com

# cat /etc/hosts
127.0.0.1	localhost
10.0.0.101 k8s-master1.seminarhub.com k8s-master1
10.0.0.102 k8s-master2.seminarhub.com k8s-master2
10.0.0.103 k8s-master3.seminarhub.com k8s-master3
10.0.0.111 k8s-worker1.seminarhub.com k8s-worker1
10.0.0.112 k8s-worker2.seminarhub.com k8s-worker2
10.0.0.254 k8s-lb.seminarhub.com k8s-lb

master node 3대와 worker node 2대 load balancer 1대 모두에게 같은 설정을 해줍니다.

 

잘연결되었는지 확인하기 위해 ping 명령어를 통해 확인해봅니다.

$ ping -c 3 k8s-master1
$ ping -c 3 k8s-master2
$ ping -c 3 k8s-master3
$ ping -c 3 k8s-worker1
$ ping -c 3 k8s-worker2
$ ping -c 3 k8s-master2
$ ping -c 3 k8s-lb

2. k8s-lb (k8s-loadbalancer) 을 먼저 구성합니다. k8s-lb는 Master들의 단일진입점이 될 것 입니다.

오직 k8s-Load Balancer를 통해서만 Master에 작업을 분할시킨다는 의미입니다.

클라이언트에서 '6443' 포트로 들어오는 연결을 백엔드 서버 group인 'stream_backend' ( k8s-master1, 2, 3 을 grouping )로 Proxy(대리 연결) 하고 'least_conn' 방식(가장 연결이 적은 Master로) 으로 Load Balancing 합니다.

자세한 설명은 주석에 담아보았습니다.

$ vi /etc/nginx/nginx.conf

stream { // TCP 레벨에서의 프록시 설정을 의미, HTTP가 아닌 TCP 연결에 대한 Proxy 역할을 합니다.
  upstream stream_backend { //upstream 서버로 분배한뒤, stream_backend 서버 그룹으로 Proxy.
  	least_conn;   //연결이 가장 적은 서버로 분배한다는 설정
    server 10.0.0.101:6443; //k8s-master1
    server 10.0.0.102:6443; //k8s-master2
    server 10.0.0.103:6443; //k8s-master3
  }
  
  server {  // 6443 Port로 들어오는 모든 연결을 이 Server Block으로 Listening 하는중
    listen    6443;  //6443 port로 client connection 이 들어오면 proxy_pass, stream_backend로 전달하겠다. 그중에서 master1, master2, master3 구성파일을 만들었습니다.
    proxy_pass	stream_backend; //Client 연결을 'stream_backend'로 연결 전달
    proxy_timeout 180s; //Proxy 연결 타임아웃 180초(3분)으로 설정. 3분동안 연결되지 않으면 연결종료
    proxy_connect_timeout 1s; //백엔드 서버와의 연결이 1초 이내에 끝내야 연결이 성공됩니다.
  }
}

이제 해당 Load Balancer를 실행시킵니다.

$ docker run -p 6443:6443 -v /etc/nginx/nginx.cnf:/etc/nginx/nginx.conf:ro --name proxy -d nginx --restart=always
  • restart=always: 종료되었을 때 자동으로 다시 시작하도록 설정합니다. 
  • p 6443:6443: Host의 Port와 Container의 Port를 매핑합니다. Host의 6443 포트와 Container의 6443 포트를 연결하여 Host에서 Container 내부의 Nginx 서버에 접근할 수 있게 합니다.
  • -v /etc/nginx/nginx.cnf:/etc/nginx/nginx.conf:ro: Host의 nginx.conf 파일을을 Container 내부로 볼륨마운트하여, 해당 파일을 사용합니다. Host의 /etc/nginx/nginx.cnf 파일을 Container 내부의 /etc/nginx/nginx.conf 경로에 읽기 전용(ro: read-only)으로 마운트합니다. 이렇게 함으로써 컨테이너에서 host에 존재하는 /etc/nginx/nginx.conf 파일을 사용할 수 있습니다.
  • --name proxy: Container의 이름으로 "proxy"를 할당합니다.
  • -d: Container를 백그라운드 모드로 실행합니다.
  • nginx: 실행할 Docker 이미지의 이름입니다. Nginx 웹 서버 이미지를 사용하여 컨테이너를 load balancer로 사용합니다.

잘 실행되는지 확인하기 위해 아래의 명령어로 확인합니다.

$ curl k8s-lb:6443

아직 nginx.conf에 명시한대로 stream_backend에 해당하는 server들을 구성하지 않았으므로 

curl: (56) Recv failure: Connection reset by peer 이와 같은 메세지가 뜨는데 정상입니다.

 

3. k8s-master1 에서 kubeadm init으로 Kubernetes Clustering을 위한 시작점을 잡아줍니다.

$ kubeadm init --control-plane-endpoint "k8s-lb.seminarhub.com:6443" --upload-certs

 

위의 명령어를 실행하면 많은 로그들이 나오는데 아래의 로그들이 필요합니다.

 

 

첫번째 로그를 확인해보면, 아래의 명령어를 root에서 실행하면 control-plane에 join할 수 있다고 합니다. 즉 해당 Master Node들을 Kubernets Cluster에 포함시킵니다.

아래의 명령어를 k8s-master2, k8s-master3 에서 명령어를 각각 실행합니다.

You can now join any number of the control-plane node running the following command on each as root:
 
  kubeadm join k8s-lb.seminarhub.com:6443 --token [token 값] \
	--discovery-token-ca-cert-hash sha256:[token-ca-cert 값] \
	--control-plane --certificate-key [certificate-key 값]

 

두번째는, 아래의 명령어를 root에서 실행하면 worker nodes로써 join 할 수 있습니다.

kubernetes cluster에 worker node로써 join 합니다.

Then you can join any number of worker nodes by running the following on each as root:
 
kubeadm join k8s-lb.seminarhub.com:6443 --token [token 값] \
	--discovery-token-ca-cert-hash sha256:[token-ca-cert-hash 값]

 

세번째 로그는, 각 node들의 $HOME/.kube/config에 접속정보와 ca-certificates key 와 같은 보안정보들을 저장시켜서 kubernetes cluster에서 해당 cluster의 정보를 가져올 수 있습니다.

해당 권한을 얻음으로써 kubectl 로 현재 Cluster 의 정보를 가져올 수 있습니다.

즉, $ kubectl get nodes 와 같은 명령어를 실행할 수 있습니다.

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

4. CNI(Container Network Interface)로 Weave Net을 설치해줍니다.

이떄 CNI를 k8s-master1 에만 설치해주면 kubernetes cluster 전체에서 사용할 수 있습니다.

설치 URL : https://www.weave.works/docs/net/latest/kubernetes/kube-addon/

kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s-1.11.yaml

 

전반적인 설치가 모두 종료되었습니다.

5. 잘 작동하는지 확인하기 위한 방법입니다.

다음의 명령어를 통해서 현재 kubernetes Cluster가 올바르게 연결되었는지 State 상태를 확인할 수 있습니다. 모두 Ready 상태인지 확인합니다. 모두 Ready 상태라면 올바르게 연결된 것 입니다.

$ kubectl get nodes //현재 nodes가 총 5개가 존재하고, 모두 ready 상태인지 확인합니다.

 

Kubernets Cluster에서 Pod를 실행시킨다고 가정했을때의 흐름

1. 우리는 Master Node를 다중화시켰으므로 Load Balancer를 활용하여 Master Node에 올바르게 배분되는지 확인할 것 입니다.

2. K8s-worker1 에서 helloPod를 하나 실행시킵니다.

$ kubectl run helloPod --image=nginx

3. 이제 명령이 k8s-lb:6443 으로 호출되고, 우리의 nginx Proxy는 이 호출을 stream_backend에 존재하여 현재 작동하고 있는 master-Node1, 2, 3 중 least_conn 방식으로 Load Balancing 됩니다. 

4. 명령을 받은 k8s-master는 rest-api를 통해 명령을 받고, scheduler는 etcd( k8s-worker1과 k8s-worker2의 작업상태를 저장)에 정보를 요청하여 가져옵니다. 이를 기반으로 Scheduler가 가장 적합한 worker node를 선택하여 해당 작업을 실행하도록 한다.

 

글을 마무리하며

이로써 고가용성(HA)의 Kubernetes Cluster를 구성해보았습니다.

 

 

도움

kubernetes 공식사이트의 Creating Highly Availbe Cluster with kubeadm

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/

 

Creating Highly Available Clusters with kubeadm

This page explains two different approaches to setting up a highly available Kubernetes cluster using kubeadm: With stacked control plane nodes. This approach requires less infrastructure. The etcd members and control plane nodes are co-located. With an ex

kubernetes.io

각 컴포넌트들에 대한 설명 및 구조도 이해

https://www.linuxtechi.com/setup-highly-available-kubernetes-cluster-kubeadm/

 

How to Setup Kubernetes(k8s) Cluster in HA with Kubeadm

In this tutorial we will learn how to install and setup Kubernetes (k8s) cluster in HA (High Availability) on-premises with kubeadm on centos servers.

www.linuxtechi.com

 

https://www.unixarena.com/2019/05/how-kubernetes-works-core-components-and-architecture.html/

 

How Kubernetes works ? - Core Components and Architecture - UnixArena

This artcile will walk you thorough about the Kubernetes Master and Workers node components and shows the overall architecture of K8s

www.unixarena.com

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/

 

Creating Highly Available Clusters with kubeadm

This page explains two different approaches to setting up a highly available Kubernetes cluster using kubeadm: With stacked control plane nodes. This approach requires less infrastructure. The etcd members and control plane nodes are co-located. With an ex

kubernetes.io

 

 

https://tech.cloudmt.co.kr/2022/06/27/k8s-highly-available-clusters/

 

고가용성 쿠버네티스를 구축해 봅시다!

쿠버네티스를 AKS(Azure), EKS(Amazon), GKE(Google)와 같은 관리형 서비스로 구성하는 것이 아닌 물리서버 위에 Hyper-v 라는 가상화 환경에서 고가용성 형태로 구성하는 형태로 구축하

tech.cloudmt.co.kr

 

+ Recent posts