Master Node 와 ETCD 를 HA(High Availability) 구성하기


이전 포스팅에서 구성한 HA에서 etcd 까지 분리한 구조입니다.

아시다시피 etcd 는 Kubernetes Cluster 의 Database 역할을 하는 서버입니다. Cluster 의 각종 서버정보와 상태를 Key/Value 형태로 저장합니다.


이전 포스팅의 HA 구성은 Master Node 가 3개이며, etcd 는 그 중 한곳에만 존재합니다.

apiserver 로 몰리는 Traffic 을 분산할 수 있는 구조입니다만, FailOver 에 대해선 취약할 수 밖에 없습니다.

왜냐면 etcd 가 돌고있는 서버가 shutdown 되어버린다면 나머지 두개의Master Node 는 제 역할을 할 수 없기 때문이죠.

ETCD 자체는 Traffic 이 많이 몰리거나 Access 가 자주 일어나진 않겠지만, 하나가 죽어버리면 모든 시스템이 죽는다는 단점이 존재합니다.


이런 문제를 해결하기 위해서 Master Node 뿐 아니라, etcd 까지 HA 구성을 해야 한다고 생각합니다.

이번 포스팅에서는 ApiServer 트래픽 분산을 위한 Master Node HA 구성과 FailOver 를 위한 ETCD HA 를 통해 안정적인 Cluster 를 만들어 보도록 하겠습니다.


모든 서버에는 Docker 와 Kubernetes 가 미리 설치되어 있어야 합니다.


이전 Kubernetes 설치 포스팅을 참고하시기 바랍니다.

http://crystalcube.co.kr/202?category=834418


스크립트는

DockerWithKubernetes_Common.txt





환경 구성



기억하셔야 할것은 모든 작업은 아래 명령을 통해서 Root Shell 로 실행합니다.


$ sudo -Es



환경구성에 대한 정리도 하고, 추후에 설정을 편하게 하기 위해서 먼저 환경변수를 세팅하도록 하겠습니다.

아래 환경변수를 Master Node 와 ETCD Host 총 6곳에 추가시켜 줍니다.


export KUBECONFIG=/etc/kubernetes/admin.conf

export LOAD_BALANCER_DNS=master.crystalcube.com

export LOAD_BALANCER_PORT=6443

export VIP_IP=10.113.228.57

export CP1_HOSTNAME=master001-ncl

export CP2_HOSTNAME=master002-ncl

export CP3_HOSTNAME=master003-ncl

export CP1_IP=10.106.221.90

export CP2_IP=10.105.187.194

export CP3_IP=10.106.154.223

export ETCD1_HOSTNAME=etcd001-ncl

export ETCD1_HOSTNAME=etcd002-ncl

export ETCD1_HOSTNAME=etcd003-ncl

export ETCD1_IP=10.105.186.195

export ETCD2_IP=10.105.187.193

export ETCD3_IP=10.106.218.127


LOAD_BALANCER_DNS 는 도메인 네임이 아닌 IP 주소를 써도 되기는 하지만, 유지보수 측면에서는 도메인을 쓰시길 권장합니다.

VIP_IP 는 LOAD_BALANCER 의 VIP 입니다.

CP#_HOSTNAME, CP#_IP 는 각 마스터 서버의 hostname 과 ip 주소입니다.

ETCD#_HOSTNAME, ETCD#_IP 는 각 etcd 서버의 hostname 과 ip 주소입니다.







로드밸런서 설정



각 Master Node 를 향하도록 Load Balancer 를 설정해야 합니다.

Load Balancer 의 6443 포트가 CP1_IP, CP2_IP, CP3_IP 의 6443 으로 향하게 설정합니다.

당연히 DNS 는 VIP_IP 를 향해야 하고요.





ETCD Cluster 구성하기




이 부분은 ETCD1_IP, ETCD2_IP, ETCD3_IP 모두에서 해 주어야 합니다.

아래처럼 kubelet 의 설정을 변경합니다.


# cat << EOF > /etc/systemd/system/kubelet.service.d/20-etcd-service-manager.conf

[Service]

ExecStart=

ExecStart=/usr/bin/kubelet --address=127.0.0.1 --pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true

Restart=always

EOF


# systemctl daemon-reload

# systemctl restart kubelet



여기서부터는 ETCD1_IP 한곳에서만 해 줍니다.
그리고 kubeadm 설정 파일을 만듧니다.

$ mkdir -p /tmp/${ETCD1_IP}/ /tmp/${ETCD2_IP}/ /tmp/${ETCD3_IP}/


$ ETCDHOSTS=(${ETCD1_IP} ${ETCD2_IP} ${ETCD3_IP})

$ NAMES=("infra0" "infra1" "infra2")


$ for i in "${!ETCDHOSTS[@]}"; do

HOST=${ETCDHOSTS[$i]}

NAME=${NAMES[$i]}

cat << EOF > /tmp/${HOST}/kubeadmcfg.yaml

apiVersion: "kubeadm.k8s.io/v1alpha2"

kind: MasterConfiguration

etcd:

    local:

        serverCertSANs:

        - "${HOST}"

        peerCertSANs:

        - "${HOST}"

        extraArgs:

            initial-cluster: infra0=https://${ETCDHOSTS[0]}:2380,infra1=https://${ETCDHOSTS[1]}:2380,infra2=https://${ETCDHOSTS[2]}:2380

            initial-cluster-state: new

            name: ${NAME}

            listen-peer-urls: https://${HOST}:2380

            listen-client-urls: https://${HOST}:2379

            advertise-client-urls: https://${HOST}:2379

            initial-advertise-peer-urls: https://${HOST}:2380

EOF

done




이제 인증을 위한 키를 생성합니다.

kubeadm alpha phase certs etcd-ca



파일이 정상적으로 만들어졌는지 아래 두 파일을 확인합니다.

/etc/kubernetes/pki/etcd/ca.crt
/etc/kubernetes/pki/etcd/ca.key




이제 이 두 파일을 나머지 두 ETCD host 를 위한 폴더로 복사합니다.


kubeadm alpha phase certs etcd-server --config=/tmp/${ETCD3_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-peer --config=/tmp/${ETCD3_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-healthcheck-client --config=/tmp/${ETCD3_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs apiserver-etcd-client --config=/tmp/${ETCD3_IP}/kubeadmcfg.yaml

cp -R /etc/kubernetes/pki /tmp/${ETCD3_IP}/


# cleanup non-reusable certificates

find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete


kubeadm alpha phase certs etcd-server --config=/tmp/${ETCD2_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-peer --config=/tmp/${ETCD2_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-healthcheck-client --config=/tmp/${ETCD2_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs apiserver-etcd-client --config=/tmp/${ETCD2_IP}/kubeadmcfg.yaml

cp -R /etc/kubernetes/pki /tmp/${ETCD2_IP}/


# cleanup non-reusable certificates

find /etc/kubernetes/pki -not -name ca.crt -not -name ca.key -type f -delete


kubeadm alpha phase certs etcd-server --config=/tmp/${ETCD1_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-peer --config=/tmp/${ETCD1_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs etcd-healthcheck-client --config=/tmp/${ETCD1_IP}/kubeadmcfg.yaml

kubeadm alpha phase certs apiserver-etcd-client --config=/tmp/${ETCD1_IP}/kubeadmcfg.yaml

# No need to move the certs because they are for ETCD1_IP


# clean up certs that should not be copied off this host

find /tmp/${ETCD3_IP} -name ca.key -type f -delete

find /tmp/${ETCD2_IP} -name ca.key -type f -delete



준비된 인증서를 복사하고 kubeadm 설정을 시작해 봅시다.
먼저 ETCD2 설정입니다.

$ USER=ubuntu

$ HOST=${ETCD2_IP}

$ scp -r /tmp/${HOST}/* ${USER}@${HOST}:

$ ssh ${USER}@${HOST}

USER@HOST $ sudo -Es

root@HOST # chown -R root:root pki

root@HOST # mv pki /etc/kubernetes/


USER 는 여러분들의 사용자 id 를 맞게 넣으시면 됩니다.



ETCD3 에도 똑같이 해 줍니다.


$ USER=ubuntu

$ HOST=${ETCD3_IP}

$ scp -r /tmp/${HOST}/* ${USER}@${HOST}:

$ ssh ${USER}@${HOST}

USER@HOST $ sudo -Es

root@HOST # chown -R root:root pki

root@HOST # mv pki /etc/kubernetes/




이 작업이 모두 끝나고나면, 호스트들의 파일은 다음처럼 되어 있어야 합니다.


$ETCD1_IP 의 구성

/tmp/${ETCD1_IP}

└── kubeadmcfg.yaml


/etc/kubernetes/pki

├── apiserver-etcd-client.crt

├── apiserver-etcd-client.key

└── etcd

    ├── ca.crt

    ├── ca.key

    ├── healthcheck-client.crt

    ├── healthcheck-client.key

    ├── peer.crt

    ├── peer.key

    ├── server.crt

    └── server.key




$ETCD2_IP 의 구성


$HOME

└── kubeadmcfg.yaml


/etc/kubernetes/pki

├── apiserver-etcd-client.crt

├── apiserver-etcd-client.key

└── etcd

    ├── ca.crt

    ├── healthcheck-client.crt

    ├── healthcheck-client.key

    ├── peer.crt

    ├── peer.key

    ├── server.crt

    └── server.key



$ETCD3_IP 의 구성


$HOME

└── kubeadmcfg.yaml


/etc/kubernetes/pki

├── apiserver-etcd-client.crt

├── apiserver-etcd-client.key

└── etcd

    ├── ca.crt

    ├── healthcheck-client.crt

    ├── healthcheck-client.key

    ├── peer.crt

    ├── peer.key

    ├── server.crt

    └── server.key




이제 pod 의 manifests 파일을 만들 차례입니다.

각 호스트에서 아래처럼 실행해 줍니다.


$ETCD1_IP 에서


# kubeadm alpha phase etcd local --config=/tmp/${ETCD1_IP}/kubeadmcfg.yaml



$ETCD2_IP 에서


# kubeadm alpha phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml


$ETCD3_IP 에서


# kubeadm alpha phase etcd local --config=/home/ubuntu/kubeadmcfg.yaml




ETCD 설정이 끝이 났습니다.

제대로 동작하는지 확인합니다.


$ docker run --rm -it \

--net host \

-v /etc/kubernetes:/etc/kubernetes quay.io/coreos/etcd:v3.2.18 etcdctl \

--cert-file /etc/kubernetes/pki/etcd/peer.crt \

--key-file /etc/kubernetes/pki/etcd/peer.key \

--ca-file /etc/kubernetes/pki/etcd/ca.crt \

--endpoints https://${ETCD1_IP}:2379 cluster-health


member 913b8723bf024477 is healthy: got healthy result from https://10.105.187.193:2379

member 9c84133e05f15352 is healthy: got healthy result from https://10.105.186.195:2379

member ab419205341210ba is healthy: got healthy result from https://10.106.218.127:2379

cluster is healthy


초록색 부분처럼 출력이 나오면 제대로 설치된 것입니다.