Cloud/NCP

[NCP] 네이버 클라우드에 k8s HA(고가용성) 클러스터 구축하기

nayoungs 2022. 10. 6. 19:00
728x90

 

📌Index

  • 프로젝트 목표
  • VPC 및 Subnet 생성하기
  • Init Script 작성하기
  • Server 생성하기
  • Server 세팅하기
  • Kubernetes 초기화 및 노드 조인
  • CNI(Container Network Interface) 설치
  • 마무리



✔️ 프로젝트 목표

NCP(네이버 클라우드)에서 고가용성(HA) 쿠버네티스 토플로지 : stacked etcd를 구성한다.

stacked etcd(중첩된 토플로지)는 etcd에서 제공하는 분산 데이터 스토리지 클러스터를, 컨트롤 플레인 구성 요소를 실행하는 kubeadm으로 관리되는 노드에 의해서 형성된 클러스터 상단에 중첩하는 토플로지이다.

 

고가용성 쿠버네티스 토플로지에 대한 더 자세한 설명은 다음에서 확인할 수 있다.

 

[Kubernetes] k8s HA(고가용성) 클러스터 구축하기 : stacked etcd

📌Index Kubernetes의 HA Vagrant로 VM 생성하기 로드밸런서 구성하기 호스트 파일 수정 및 Swap off Docker 및 Kubernetes 설치하기 shell script로 간편화하기 Kubernetes 초기화 및 노드 조인 CNI(Container Ne..

nayoungs.tistory.com

NCP 서비스 설명
VPC 격리된 가상 네트워크 구성
Server lb node, master node, worker node 구성
노드 개수 OS
로드 밸런서 노드 1개 ubuntu-20.04
마스터 노드 3개 ubuntu-20.04
워커 노드 3개 ubuntu-20.04

 

✔️ VPC 및 Subnet 생성하기

가장 먼저 VPC와 서브넷을 다음과 같이 생성한다.

항목 CIDR
VPC 172.16.0.0/16
Public Subnet 172.16.0.0/20

생성 과정 및 방법은 다음에서 확인할 수 있다.

 

[NCP] VPC와 서브넷 생성하기

📌Index VPC 생성하기 서브넷 생성하기 ✔️ VPC 생성하기 NCP 콘솔에 접속해서 VPC를 생성한다. 다음과 같이 VPC 이름과 IP 주소 범위를 작성한다. 생성 후 시간이 조금 지나면 운영중 상태가 되는 것

nayoungs.tistory.com



✔️ Init Script 작성하기

Swapoff, docker 설치 및 kubernetes 설치를 7개의 Server에서 모두 진행하는 것이 상당히 번거롭기 때문에, NCP의 Init Script를 작성해서 Server 생성 시 사용한다.

init script는 [Server] - [Init Script] - [Script 생성]을 통해 등록할 수 있다.

 

🔧Trouble Shooting

더보기

초기에 다음과 같이 init sript를 작성했으나, 접속하여 확인했을 때 docker만 설치되어있을 뿐 kubectl, kubelet, kubeadm은 설치되어있지 않았다.

#!/bin/bash

#------Swap Disable-----#
echo "Swap off"
sudo swapoff -a
echo 0 > /proc/sys/vm/swappiness
sed -e '/swap/ s/^#*/#/' -i /etc/fstab

#------Install Docker-----#
echo "Install docker"
sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker

cat << EOF | sudo tee –a /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo systemctl daemon-reload
sudo systemctl restart docker

#------Install k8s-----#
echo "Install kubernetes"
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

따라서 로그 파일을 확인해보았다.

ncp의 init script의 로그는 /var/log/ncloud-init.log에 저장된다.

 

🔎 참고

서버의 상태가 운영중으로 표시되더라도 스크립트 설치가 계속 진행 중일 수도 있다. 설치 완료 여부를 확인하려면 진행 상태 로그를 확인한다. 관련 사항은 ncloud-docs에서 확인할 수 있다.

  • Linux: /var/log/ncloud-init.log
  • Windows: C:\Program Files(X86)\NBP\ncloud-init\logs

 

cat /var/log/ncloud-init.log 명령으로 로그를 확인해보니, 주요 원인은 다음과 같았다.

curl: (7) Failed to connect to packages.cloud.google.com port 443: Connection timed out

kubernetes 설치 과정 중 gpg 키를 curl 명령어로 받을 때 발생하는 에러였다.

구글링해보니 방화벽 혹은 포트 문제일 것이라고 하지만, 방화벽도 해제되어있고 포트도 문제 없이 열려있었다. Server에 접속해서 동일한 명령어를 실행할 때는 에러 없이 잘 실행되는데, init script로 실행되면 에러가 발생하는 것이 의아하다.

결국 curl을 wget명령어로 대체함으로써 해결할 수 있었다. curl에 대한 문제는 더 생각해봐야 할 것 같다.

최종적으로 완성된 init script는 다음과 같다.

 

#!/bin/bash

#------Swap Disable-----#
echo "Swap off" 
swapoff -a 
echo 0 > /proc/sys/vm/swappiness 
sed -e '/swap/ s/^#*/#/' -i /etc/fstab 

#------Install Docker-----#
echo "Install docker"
sudo apt update 
sudo apt install -y docker.io 
sudo systemctl start docker 
sudo systemctl enable docker 

cat << EOF | sudo tee -a /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

sudo mkdir -p /etc/systemd/system/docker.service.d 
sudo systemctl daemon-reload 
sudo systemctl restart docker 

#------Install k8s-----#
echo "Install kubernetes"
sudo apt-get update 
sudo apt-get install -y apt-transport-https ca-certificates curl 

echo "Gpg Key......." 
wget https://packages.cloud.google.com/apt/doc/apt-key.gpg 
mv apt-key.gpg /usr/share/keyrings/kubernetes-archive-keyring.gpg

echo "Repository......." 
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list  

echo "Update....." 
sudo apt-get update 
sudo apt-get install -y kubelet kubeadm kubectl 
sudo apt-mark hold kubelet kubeadm kubectl 

이제 이 script를 Server 생성 시 사용하면, docker 및 kubernetes 설치가 완료된 상태에서 시작할 수 있다.



✔️ ACG 생성하기

ACG란 네이버 클라우드의 IP 주소/포트 기반 필터링 기능으로, AWS의 보안 그룹과 같다고 생각하면 된다.

쿠버네티스 공식 문서를 보면, 허용해줘야 하는 포트 번호 및 프로토콜을 확인할 수 있다.

 

컨트롤 플레인(마스터 노드)

프로토콜 방향 포트 범위 용도 사용 주체
TCP 인바운드 6443 쿠버네티스 API 서버 전부
TCP 인바운드 2379-2380 etcd 서버 클라이언트 API kube-apiserver, etcd
TCP 인바운드 10250 Kubelet API Self, 컨트롤 플레인
TCP 인바운드 10259 kube-scheduler Self
TCP 인바운드 10257 kube-controller-manager Self

 

워커 노드

프로토콜 방향 포트 범위 용도 사용 주체
TCP 인바운드 10250 Kubelet API Self, 컨트롤 플레인
TCP 인바운드 30000-32767 NodePort 서비스 전부

위를 참조하여 ACG를 생성하자.

 

master node의 ACG ny-acg-k8s-master

 

worker node의 ACG ny-acg-k8s-worker

아웃바운드는 둘 다 모든 포트(1-65535)를 열어주었다. 



✔️ Server 생성하기

로드 밸런서 노드

가장 먼저 로드밸런서 노드로 사용할 서버를 만들자. 본 프로젝트에서는 Standard 타입의 ubuntu-20.04 이미지를 사용하였다.

 

 

VPC와 서브넷을 선택해준 후, 네트워크 인터페이스도 추가해준다.

이때 [새로운 공인 IP 할당] 옵션을 선택하면 자동으로 공인 IP가 할당되어 나중에 따로 공인 IP를 부여해주지 않아도 된다. 그리고 앞서 작성한 init script를 선택해준다.

 

 

서버의 인증키는 기존의 키가 있다면 선택하고, 없다면 새로 생성하여 다운 받는다.

ACG는 앞서 생성한 ny-acg-k8s-master를 사용한다.

 

마스터 노드

마스터 노드의 기본 설정은 로드밸런서 노드와 동일하다. 개수만 3개로 하며, 서버를 한번에 2개 이상 생성할 때는 공인IP 자동할당이 불가능하여, 따로 부여해줘야한다. 마스터 노드의 설정은 다음과 같다.

 

 

워커 노드

워커 노드 또한 로드밸런서 노드와 기본 설정이 동일하고, 3개를 생성하며, ACG는 앞서 생성한 ny-acg-k8s-worker를 선택한다.

 

 

시간이 지나 모두 서버 생성이 완료되면, 마스터 노드와 워커 노드에 모두 공인 IP를 부여해준다.

 



 

✔️ Server 세팅하기

로드밸런서 구성하기

로드밸런서 노드의 공인IP를 통해 SSH 접속하자.

ssh root@[로드밸런서 노드의 공인 IP]

접속 비밀 번호는 [서버 관리 및 설정 변경] - [관리자 비밀번호 확인]을 클릭하여, 앞서 서버의 인증키로 설정한 키를 사용하면 확인할 수 있다. 이 과정을 매번 반복하는 것이 귀찮다면 다음 명령어를 통해 직접 비밀번호를 설정할 수 있다.

passwd

 

고가용성(HA)을 위해 필요한 것이 로드밸런서이다. 로드 밸런서 뒤에 있는 apiserver 중 한개의 apiserver에 장애가 발생해도, 나머지 apiserver로 정상적인 서비스를 하도록 로드를 분배한다.

로드 밸런서는 HAproxy라는 application을 설치한다.

sudo apt update && sudo apt install haproxy -y

다음으로 HAproxy 설정 파일을 다음과 같이 입력한다.

cat << EOF | sudo tee -a /etc/haproxy/haproxy.cfg
frontend kubernetes-master-lb
bind 0.0.0.0:6443
option tcplog
mode tcp
default_backend kubernetes-master-nodes
backend kubernetes-master-nodes
mode tcp
balance roundrobin
option tcp-check
option tcplog
server ny-k8s-master001 [마스터 노드 1의 private ip]:6443 check
server ny-k8s-master002 [마스터 노드 2의 private ip]:6443 check
server ny-k8s-master003 [마스터 노드 3의 private ip]:6443 check
EOF

다음으로 변경 사항이 적용될 수 있도록 HAproxy 시스템을 재시작한다.

sudo systemctl restart haproxy
sudo systemctl enable haproxy

마지막으로 SELinux을 permissive mod(disable)로 세팅한다.

sudo apt install selinux-utils
setenforce 0

 

공통 구성

모든 노드에서 hosts 파일을 설정해줘야한다. 안해도 큰 문제는 없지만 ip 주소를 일일히 입력하는 대신 도메인 네임을 사용하는 것이 더 편리하다.

sudo vi /etc/hosts

hosts 파일에 아래 내용을 추가한다.

[로드밸런서 노드의 private ip] ny-k8s-lb
[마스터 노드 1의 private ip] ny-k8s-master001
[마스터 노드 2의 private ip] ny-k8s-master002
[마스터 노드 3의 private ip] ny-k8s-master003
[워커 노드 1의 private ip] ny-k8s-worker001
[워커 노드 2의 private ip] ny-k8s-worker002
[워커 노드 3의 private ip] ny-k8s-worker003



✔️ Kubernetes 초기화 및 노드 조인

Kubernetes 초기화

컨트롤 플레인 노드 중 하나(ny-k8s-master001)에서 kubeadm init 명령을 통해 kubernetes 초기화 작업을 진행한다.

sudo kubeadm init --control-plane-endpoint ny-k8s-lb:6443 --pod-network-cidr 172.16.0.0/16 --apiserver-advertise-address=0.0.0.0  --apiserver-cert-extra-sans=ny-k8s-master001,ny-k8s-master002,ny-k8s-master003 --upload-certs
  • --control-plane-endpoint : 로드밸런서 서버와 6443 포트를 입력
  • --pod-network-cidr : 쿠버네티스에서 사용할 컨테이너의 네트워크 대역을 지정
  • --apiserver-advertise-address : 쿠버네티스가 생성한 TLS 인증서에 적용할 IP 또는 도메인을 명시 => 현재 마스터 노드의 ip 주소 입력
  • --upload-certs : 노드 join에 필요한 cert key값을 받기 위해 필요
  • --apiserver-cert-extra-sans : API 서버 제공 인증서에 사용할 선택적 추가 SAN(주체 대체 이름), 마스터 노드의 ip를 세팅

 

성공하면 다음과 같은 결과가 출력된다.

  • 작업하는 환경마다 token, hash, key 값은 다르다.
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join ny-k8s-lb:6443 --token 2swoy9.kimg4x50uhe57ony \
        --discovery-token-ca-cert-hash sha256:98e5f153b72117c12cd86ad8eebc70e7a9cc9419ca5d36ae9d4516b21d5683a1 \
        --control-plane --certificate-key bf2423da961b7d8b70bf97db73fc3cb36fe5eebb188c282b971d7f9857a9dd0d

Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join ny-k8s-lb:6443 --token 2swoy9.kimg4x50uhe57ony \
        --discovery-token-ca-cert-hash sha256:98e5f153b72117c12cd86ad8eebc70e7a9cc9419ca5d36ae9d4516b21d5683a1

 

kubectl 명령어 사용을 위해서는 인증 파일을 생성해야한다.

kubectl은 항상 $HOME/.kube를 참조한다. root가 아닌 노멀 사용자는 반드시 인증이 필요하다.

이 파일은 쿠버네티스에 인증하기 위한 파일로, 절대 노출되면 안된다.

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

 

노드 조인

다른 마스터 노드에서 아래와 같은 명령을 실행하여 ny-k8s-master001으로 조인한다. (앞서 컨트롤 플레인의 initialization 시 출력되는 값을 참조한다) 이때, 루트로 실행해야하기 때문에 sudo를 붙이거나,

sudo -i 명령으로 루트 사용자로 전환한다.

sudo kubeadm join ny-k8s-lb:6443 --token 2swoy9.kimg4x50uhe57ony \
        --discovery-token-ca-cert-hash sha256:98e5f153b72117c12cd86ad8eebc70e7a9cc9419ca5d36ae9d4516b21d5683a1 \
        --control-plane --certificate-key bf2423da961b7d8b70bf97db73fc3cb36fe5eebb188c282b971d7f9857a9dd0d

워커 노드들에서는 컨트롤 플레인 노드로 조인하기 위해 다음 명령을 실행한다.

sudo kubeadm join ny-k8s-lb:6443 --token 2swoy9.kimg4x50uhe57ony \
        --discovery-token-ca-cert-hash sha256:98e5f153b72117c12cd86ad8eebc70e7a9cc9419ca5d36ae9d4516b21d5683a1

모든 노드에서 조인이 성공하면 결과는 다음과 같다.

$ kubectl get nodes
NAME               STATUS     ROLES           AGE     VERSION
ny-k8s-master001   NotReady   control-plane   12m     v1.25.2
ny-k8s-master002   NotReady   control-plane   9m53s   v1.25.2
ny-k8s-master003   NotReady   control-plane   8m17s   v1.25.2
ny-k8s-worker001   NotReady   <none>          7m47s   v1.25.2
ny-k8s-worker002   NotReady   <none>          6m33s   v1.25.2
ny-k8s-worker003   NotReady   <none>          5m34s   v1.25.2

아직 상태가 NotReady인 것을 확인할 수 있다.

kubeadm init 명령 시 add-on을 완성하지 않았었기 때문에(CNI(container network interface) 설정), 구성을 마무리 해줘야한다. Cluster Networking | Kubernetes



✔️ CNI(Container Network Interface) 설치

여러가지 CNI 플러그인이 있지만 여기서는 Calico를 사용한다.

curl 명령어로 yaml 파일을 다운 받는다.

curl https://docs.projectcalico.org/manifests/calico-typha.yaml -o calico.yaml

calico.yaml 파일을 다음과 같이 수정한다. 주석 #을 해제하고, kubeadm init 명령 시 설정했던 pod의 cidr와 동일하게 맞춰줘야한다.

vi calico.yaml
- name: CALICO_IPV4POOL_CIDR
  value: "172.16.0.0/16"

다음으로 calico를 설치한다.

kubectl apply -f calico.yaml

시간이 조금 지나면 모두 Ready 상태가 되는 것을 확인할 수 있다.

$ kubectl get nodes
NAME               STATUS   ROLES           AGE   VERSION
ny-k8s-master001   Ready    control-plane   17m   v1.25.2
ny-k8s-master002   Ready    control-plane   14m   v1.25.2
ny-k8s-master003   Ready    control-plane   13m   v1.25.2
ny-k8s-worker001   Ready    <none>          12m   v1.25.2
ny-k8s-worker002   Ready    <none>          11m   v1.25.2
ny-k8s-worker003   Ready    <none>          10m   v1.25.2

이때, pod들도 모두 Running상태가 되어야한다.

$ kubectl get pod -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-58dbc876ff-868n6   0/1     Running   0          64s
kube-system   calico-node-5kwf2                          0/1     Running   0          64s
kube-system   calico-node-d5z46                          0/1     Running   0          64s
kube-system   calico-node-jc2f9                          0/1     Running   0          64s
kube-system   calico-node-jzc24                          0/1     Running   0          64s
kube-system   calico-node-zdn9z                          0/1     Running   0          64s
kube-system   calico-node-zv79m                          0/1     Running   0          64s
kube-system   calico-typha-644446b795-b95tt              1/1     Running   0          64s
kube-system   coredns-565d847f94-h5lm4                   0/1     Running   0          17m
kube-system   coredns-565d847f94-vgpr9                   0/1     Running   0          17m
kube-system   etcd-ny-k8s-master001                      1/1     Running   2          18m
kube-system   etcd-ny-k8s-master002                      1/1     Running   0          15m
kube-system   etcd-ny-k8s-master003                      1/1     Running   0          13m
kube-system   kube-apiserver-ny-k8s-master001            1/1     Running   2          18m
kube-system   kube-apiserver-ny-k8s-master002            1/1     Running   0          15m
...

watch 명령어로 실시간으로 확인해볼 수 있고, 시간이 조금 지나면 모두 Running 상태가 되는 것을 확인할 수 있다.

watch kubectl get pods -A



✔️ 마무리

지금까지 네이버 클라우드에서 고가용성 쿠버네티스 중첩된 토플로지를 구성해보았다. 이전에 쿠버네티스 클러스터를 구축해본 적은 있으나, 여러개의 마스터 노드를 두고, 로드 밸런서 노드를 활용하는 것은 처음이었다. init script 작성 과정 및 노드 조인 과정에서 여러가지 에러를 겪었지만, 그 과정에서 쿠버네티스에 대한 이해도를 더 높일 수 있었던 것 같다. 다음에는 간단한 애플리케이션을 사용하여 컨트롤러를 생성한 뒤, 모니터링 서비스 prometheus, grafana를 구축하여 부하 테스트까지 진행해볼 에정이다.

 

네이버 클라우드는 본 프로젝트를 통해 처음 접하게 되었다. 아직 VPC, Server 밖에 사용해보지 못했지만, 다음 기회에 NKS도 사용해 볼 수 있으면 좋을 것 같다. 사용하면서 크게 불편함은 느낄 수 없었고, 서버 생성 시 매번 입력/복붙 해야하는 user data를 사용하는 AWS와 달리, init script를 따로 생성해 둘 수 있어서 편리했다. 단, 타 퍼블릭 클라우드 AWS, Azure 등에 비해 서버 부팅 시간이 조금 느린 것이 조금 아쉬웠던 것 같다. 전체적으로는 만족하면서 사용하였다.

 

 

네이버클라우드 큐레이션 뉴스 (10월 2주) - 클라우드 / IT / 테크 트렌드 요약

비즈니스에 꼭 필요한 클라우드 네이버 클라우드 플랫폼 ncloud.com 입니다. 흥미로운 클라우드, IT, 테...

blog.naver.com

 

 

 

 

 

728x90