이전 글에서는 가상화에 대한 내용을 글로 적어봤는데, 오랫동안 귀찮기도 하고, 취업 준비하느라(핑계임) 글을 못썼습니다. 원래 차례대로 가상화 - 컨테이너 - 컨테이너 오케스트레이션 - 그 외 이 순으로 쓰려고 했는데, 그냥 이제는 생각나는 대로 글을 써보려 합니다. 이전 포스트는 모두 개인적으로 Notion에다가 먼저 작성하고 외적으로 보여주는 글인 벨로그에는 약간이나마 좀 정리해서 올렸었습니다. 근데 뭐.. 보는 사람만 보니 그냥 써도 될거 같아서 그냥 쓰겠습니다.
이번에 포스트할 내용은 쿠버네티스 고가용성 클러스터를 만드는 과정을 작성할 것입니다. 이 전에 교육을 받을 당시 고가용성 쿠버네티스 인프라 구축을 주제로 프로젝트를 진행하거나 몇가지 리뷰를 좀 하였었는데, 그 때 나온 내용이 Stacked Etcd Clustering과 External etcd Clustering 이 두가지 내용이었습니다. 당시에는 단일 PC에다가 쿠버네티스를 설치하였기 때문에, 리소스 가용량이 많지 않아서 새로 별도의 Etcd 노드를 두는 것은 불가능 하여, Stacked Etcd Clustering을 선택했었습니다.
해당 Topology 형태로 클러스터를 구성하게 되면, 각 Control Plane에 주요 컴포넌트(kube-apiserver, Controller-manager, Scheduler, Etcd)들이 존재하게 되며, 각 Control Plane에 존재하는 Etcd들은 클러스터링 되어 전체 클러스터 내 리소스 정보들을 공유하여, 저장하게 됩니다. 또한, Worker 노드와 Control Plane 노드들은 중간에 존재하는 Load Balancer를 이용하여, 상호 API 통신을 하여, 정보를 주고받게 됩니다.
교육받을 당시 해당 Topology를 이용하여, 프로젝트를 진행 했었지만, 한 가지 문제점이 있었습니다. Load Balancer가 장애났을 경우인데요. 이 경우에는 각 Worker 노드 및 Control Plane 노드들이 API 통신을 할 수 없게됩니다. 그래서 당시에는 별도의 Load Balancer를 두고 클러스터링 할 시에 kubeadm init시 apiserver-cert-extra-sans로 별도로 생성한 Load Balancer IP를 추가하였습니다. 그리고는, 인증서 내 SANs구문에 두 개의 LB IP를 넣고 Worker 노드 그룹을 A, B로 나누어서 각 LB를 이용하여, 클러스터링 하도록 구성했었습니다.
저는 당시에도 이 문제점을 어떻게 해결할까 고민하였습니다. 하지만 결과를 만들어어야되는 상황이라 시간적 여유가 없었고, 교육이 끝나고 나중에서야 해답을 찾을 수 있었습니다.
당시 LoadBalancer는 HAProxy를 이용하여, 구성했었습니다. 하지만, 아무리 찾아봐도 HA구성에 대한 내용을 찾을 수 없었는데 제가 못찾은 거였습니다...
keepalived는 인프라에 L4 로드밸런싱을 제공해주는 소프트웨어 패키지로, IPVS(Linux Virtual Server) 커널 모듈을 기반으로 합니다. 이는 또한 VRRP 프로토콜을 이용하여, 고 가용성의 시스템 환경을 유지하게 해줍니다.
VRRP(Virtual Router Redundancy Protocol)
주로 Failover를 목적으로 사용되며, 각 장비에 우선순위(Priority)를 부여하고, 우선순위가 높은 장비에게 VIP(Virtual IP)를 부여함으로써, Master 또는 Slave를 결정하게 된다.
게이트웨이 이중화 프로토콜 중 HSRP(Host Stanby Redundancy Protocol)과 비슷하나, 몇 가지 차이점으로 HSRP는 주로 VLAN에 설정을 하고, VRRP는 벤더마다 VLAN이 달라서 주로 물리 인터페이스에 설정한다.
이를 글로 표현하면 어려우니 대충 그림으로 그려보면, 다음과 같다.
위와 같이 각 Worker 노드와 Control Plane들은 Keepalived로 구성한 VIP(Virtual IP)를 이용하여, API통신을 하게 되며, 최초 구성시 LoadBalancer A를 통하게 된다.(Priority 구성이 높다면) 이후에 만약 LoadBalancer A가 장애가 발생할 경우, 부여되었던 VIP는 LoadBalancer B가 가져가게 되며, 클러스터링 설정상에는 변경사항이 없으나, 네트워크 통신상으로 LoadBalancer B를 통하게 된다.
그럼 여기서 의문점으로, 어떻게 LoadBalancer B는 LoadBalancer A가 장애난 것을 인지하고 자신을 Master로 승격시킬까라는 의문점이 생긴다.
위 그림에서 기존에 Master였던 LoadBalancer A노드에서 VRRP에 예약된 멀티캐스트 주소인 224.0.0.18로 주기적으로 Advertisement 패킷을 송신하는 것을 확인할 수 있다. 그리고는 Master가 장애났을 경우 Priority 0의 패킷을 송신하고, 이를 Backup 상태인 LoadBalancer B가 수신받아, 자신을 Master로 승격시키게 된다. 이후에는 Master가 된 LoadBalancer B가 동일하게 멀티캐스트 주소로 Advertisement 패킷을 송신하게 된다.
Hostname | CPU | RAM | OS | Subnet Address | Prefix |
---|---|---|---|---|---|
Master1 | 4 vCore | 4 GB | Ubuntu 20.04.6 LTS | 211.183.3.100 | 24 |
Master2 | 4 vCore | 4 GB | Ubuntu 20.04.6 LTS | 211.183.3.101 | 24 |
Master3 | 4 vCore | 4 GB | Ubuntu 20.04.6 LTS | 211.183.3.102 | 24 |
Worker | 2 vCore | 2 GB | Ubuntu 20.04.6 LTS | 211.183.3.110 | 24 |
LoadBalancer A | 1 vCore | 1 GB | CentOS 7 | 211.183.3.251 | 24 |
LoadBalancer B | 1 vCore | 1 GB | CentOS 7 | 211.183.3.252 | 24 |
LB VIP | - | - | - | 211.183.3.250 | 24 |
네트워크 설정
# 네트워크 설정파일 변경
echo "TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=no
NAME=ens32
DEVICE=ens32
ONBOOT=yes
IPADDR=211.183.3.251
PREFIX=24
GATEWAY=211.183.3.2" > /etc/sysconfig/network-scripts/ifcfg-ens32
# 네트워크 데몬 재시작
systemctl restart network
HAProxy 설치 및 설정
# epel-release 설치
yum -y epel-release
# HAProxy 설치
yum -y install haproxy
# HAProxy 설정 변경
vi /etc/haproxy/haproxy.cfg
---------------------------------------------------------------------------
--- 위 내용 생략 ---
frontend apiserver
bind *:6443
mode tcp
option tcplog
default_backend apiserver
backend apiserver
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
server master1 211.183.3.100:6443 check
server master2 211.183.3.101:6443 check
server master3 211.183.3.102:6443 check
---------------------------------------------------------------------------
# haproxy 데몬 시작 및 시스템 실행시 자동실행 설정
systemctl enable haproxy
systemctl start haproxy
Keepalived 설치 및 설정
# IPVS 사용을 위한 커널 파라미터 변경
echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
# keepalived 설치
yum -y install keepalived
# keepalived 설정 변경
vi /etc/keepalived/keepalived.conf
---------------------------------------------------------------------------
global_defs {
router_id VR_1
}
vrrp_instance VI_1 {
state MASTER
interface ens32
virtual_router_id 51
priority 200
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
211.183.3.250
}
}
---------------------------------------------------------------------------
# keepalived 데몬 시작 및 시스템 실행시 자동실행 설정
systemctl enable keepalived
systemctl start keepalived
네트워크 설정
# 네트워크 설정파일 변경
echo "TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=no
NAME=ens32
DEVICE=ens32
ONBOOT=yes
IPADDR=211.183.3.252
PREFIX=24
GATEWAY=211.183.3.2" > /etc/sysconfig/network-scripts/ifcfg-ens32
# 네트워크 데몬 재시작
systemctl restart network
HAProxy 설치 및 설정
# epel-release 설치
yum -y epel-release
# HAProxy 설치
yum -y install haproxy
# HAProxy 설정 변경
vi /etc/haproxy/haproxy.cfg
---------------------------------------------------------------------------
--- 위 내용 생략 ---
frontend apiserver
bind *:6443
mode tcp
option tcplog
default_backend apiserver
backend apiserver
option httpchk GET /healthz
http-check expect status 200
mode tcp
option ssl-hello-chk
balance roundrobin
server master1 211.183.3.100:6443 check
server master2 211.183.3.101:6443 check
server master3 211.183.3.102:6443 check
---------------------------------------------------------------------------
# haproxy 데몬 시작 및 시스템 실행시 자동실행 설정
systemctl enable haproxy
systemctl start haproxy
Keepalived 설치 및 설정
# IPVS 사용을 위한 커널 파라미터 변경
echo "net.ipv4.ip_nonlocal_bind=1" >> /etc/sysctl.conf
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
# keepalived 설치
yum -y install keepalived
# keepalived 설정 변경
vi /etc/keepalived/keepalived.conf
---------------------------------------------------------------------------
global_defs {
router_id VR_2
}
vrrp_instance VI_2 {
state BACKUP
interface ens32
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
211.183.3.250
}
}
---------------------------------------------------------------------------
# keepalived 데몬 시작 및 시스템 실행시 자동실행 설정
systemctl enable keepalived
systemctl start keepalived
네트워크 설정
# Netplan 파일 수정
vi /etc/netplan/01-network-manager-all.yaml
---------------------------------------------------------------------------
network:
version: 2
renderer: networkd
ethernets:
ens32:
dhcp4: no
addresses:
- 211.183.3.100/24 # Master 1 기준이며, 2와 3은 각각 끝자리 101, 102로 할당
gateway4: 211.183.3.2
nameservers:
addresses:
- 8.8.8.8
- 8.8.4.4
---------------------------------------------------------------------------
# Netplan 적용
sudo netplan apply
쿠버네티스 설치
해당 내용은 별도로 포스트 하겠읍니다 ^^7
kubeadm을 이용한 Stacked Etcd Clustering
# 클러스터 초기화 (Master 1에서만 실행)
sudo kubeadm init --control-plane-endpoint 211.183.3.250:6443 --upload-certs
# Master 2,3 클러스터 join(토큰이나 키 값은 각자 다를 수 있음)
kubeadm join 211.183.3.250:6443 --token vb4sk5.0y88uxfwto02pgid \
--discovery-token-ca-cert-hash sha256:f42ab9980703887d697fdfd3bbc4821e0df1abd7beefcad7ee7f4c9c24d4578 \
--control-plane --certificate-key acd48963c28053bd7db3cca24d39de3fcbb6c8787928d1570bee696bae5161fa
네트워크 설정
# Netplan 파일 수정
vi /etc/netplan/01-network-manager-all.yaml
---------------------------------------------------------------------------
network:
version: 2
renderer: networkd
ethernets:
ens32:
dhcp4: no
addresses:
- 211.183.3.110/24 # Master 1 기준이며, 2와 3은 각각 끝자리 101, 102로 할당
gateway4: 211.183.3.2
nameservers:
addresses:
- 8.8.8.8
- 8.8.4.4
---------------------------------------------------------------------------
# Netplan 적용
sudo netplan apply
쿠버네티스 설치
위와 동일합니다.
kubeadm을 이용한 클러스터링
# 클러스터에 Worker로써 Join하기
kubeadm join 211.183.3.250:6443 --token vb4sk5.0y88uxfwto02pgid \
> --discovery-token-ca-cert-hash sha256:f42ab9980703887d697fdfd3bbc4821e0
3개의 Control plane 노드와 1개의 Worker노드가 존재하며, 각 Control Plane에는 주요 컴포넌트들이 모두 존재합니다.
먼저 아래 그림에서 LoadBalancer A의 ens32 인터페이스에 VIP가 설정된 내역을 확인할 수 있습니다.
이제 LoadBalancer A가 장애가 발생했다는 것을 가정하여, VM 자체를 종료시킨 후 클러스터링이 잘 되어있는지 확인해보겠습니다.
Loadbalancer B에서 데몬상태와 인터페이스를 확인한 결과, 정상적으로 VIP를 가져왔고, 인터페이스에 할당된 것을 확인할 수 있습니다.
또한, kubectl을 이용하여, API요청을 하였을 경우에도 정상적으로 통신이 되는 것을 확인할 수 있습니다.
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/ha-topology/
https://www.keepalived.org/
https://developnote-blog.tistory.com/148
https://beer1.tistory.com/6
https://limvo.tistory.com/13