Kubernetes Deep Dive - (2). Cluster Management
k8s High Availability (availability in Cluster)
k8s 자체가 high availability를 달성하기 위해 만들어진 SW.
- Application Availability와 Cluster Availability는 별도의 개념(aspect)이다.
Cluster의 Availability는 infra 레벨이므로, infra (that application is executing) Availability is important in production environment.
- k8s는 High Availability를 위해 multiple control plane 구조를 사용한다.
- 즉 multi-master, multi-worker Topology로 되어 있다.
- Multiple Control plane의 존재 = master node가 여러 개. 각각의 마스터 노드는 kube-api-server가 있고, worker 노드와 통신해야 한다.
- 따라서, 여러 개 마스터 노드가 트래픽을 받아서 worker node에 전달할 수 있도록 Load balancer가 필요하다. 어느 마스터 노드 하나가 죽으면 다른 노드로 트래픽을 변경해야 Availability가 유지되므로.
- = High-Availability production-like k8s Deployment.
- Load balancer는 Master - Worker 간 통신에도 쓰인다. 꼭 클라이언트 트래픽만 받아 처리하는 게 아님.
- etcd: key-value pair DB for k8s Cluster.
etcd Management를 위한 아키텍처는 여러 가지가 있지만, 대표적인 두 가지를 꼽아보면
- Stacked Etcd.
- 마스터 노드는 최소 2개라고 가정.
- 각각의 마스터 노드에 etcd DB가 존재하며, 각 control plane의 kube-api-server와 연결되어 있다.
- etcd끼리 통신하면서 sync를 맞추는 방식.
- popular approach.
- External Etcd.
- 1과 비슷하지만, etcd가 master node 내부에 component 형태로 존재하지는 않음. 즉, etcd를 관리하는 별도의 서버가 존재함
Management Tools.
- Kubeclt : 공식 cli, REST API로도 통신 가능함.
- kubadam : 클러스터 생성을 쉽게 해 주는 cli
- minikube : Dev용으로 단일 마스터노드 + 워커노드를 빠르게 생성할 수 있도록 해줌
- helm: prod, dev 등 여러 환경에 맞는 yaml 템플릿을 관리하고, 배포를 쉽게 할 수 있도록 도와주는 Package Management Tool.
- K8s 오브젝트 간 inter-dependency가 있을 때 complex chart / template 생성을 쉽게 할 수 있도록 도와준다.
- Kompose : docker compose와 유사함. docker compose파일을 k8s 오브젝트 형태로 사용할 수 있게 지원함.
- Kustomize : manage the configuration of K8s Cluster. helm과 비슷한 목적으로 만들어졌음.
Setup K8s Cluster
DigitalOcean으로 k8s 리소스를 받아온다. master 1개, worker 2개. master node의 ip주소를 받아서 ssh로 로그인하고, k8s master node로 작동하기 위한 dependency들을 설치한다. (ubuntu 21.04 서버 기준)
## 1. Upgrade apt packages
sudo apt-get update
## 2. Install Docker Engine
sudo apt-get install -y docker.io
## 3. Install Support packages - apt-transport-https, curl 두 개.
sudo apt-get install -y apt-transport-https curl
## 4. Retrieve the key for the Kubernetes repo and add it to your key manager
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
## 5. Add the kubernetes repo to your system
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
## 6. Install the three pieces you’ll need, kubeadm, kubelet, and kubectl
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
## apt-mark hold는 해당 패키지들의 버전을 앞으로 계속 유지한다는 의미.
sudo apt-mark hold kubelet kubeadm kubectl
## 7. Create the actual cluster
## 해당 클러스터에서 생성되는 모든 리소스는 192.168.0.0/16 내에서 만들어진다는 뜻.
# setup, initialize, start까지 한 번에 진행되므로 시간이 좀 걸림
kubeadm init --pod-network-cidr=192.168.0.0/16
## Note - Notedown the Command to join cluster
# 명령어를 실행하고 나면 "To start using your cluster, you need to run the following as as regular user:"
# 뒤에 몇 개의 명령어가 나온다. 그대로 복사해서 실행하면 됨.
# 이후의 명령어도 중요하다
# Then you can join any number of worker nodes by running the following on each as a root:
## kubeadm join ... 뭐시기 명령어.
## -> 이 명령어는 worker node를 생성할 때 사용해야 한다. worker node가 클러스터에 join하기 위해서 필요함.
## 8. Install the Calico network plugin. network plugin으로 여러 종류가 있지만 calico 선택해서 적용.
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
## 9. Untaint the master so that it will be available for scheduling workloads
kubectl taint nodes --all node-role.kubernetes.io/master-
## 10. Get Cluster Nodes
kubectl get nodes
Install & Configure Kubernertes Worker Node
## 1. Upgrade apt packages
sudo apt-get update
## 2. Install Docker Engine
sudo apt-get install -y docker.io
## 3. Install Support packages
sudo apt-get install -y apt-transport-https curl
## 4. Retrieve the key for the Kubernetes repo and add it to your key manager
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
## 5. Add the kubernetes repo to your system
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
## 6. Install the three pieces you’ll need, kubeadm, kubelet, and kubectl
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
## 7. Execute the Join command, which was copied from the master node.
## Command to Generate the Join Token in case you missed to Copy
kubeadm token create --print-join-command
## 생성된 토큰을 보고 싶으면 (master node에서 실행)
kubeadm token list
Maintenance Window : K8s Cluster
- Maintenance window : 유지보수를 위해 특정 노드를 k8s 클러스터에서 제외한 뒤, 작업이 끝난 후 다시 k8s 클러스터에 추가하는 기간
- Node Draining: 위의 maintenance window동안 시행되는 작업 (클러스터에서 노드 제외, 작업 후 노드 추가)
- 단, application에 downtime이 있어선 안 된다. node draining이 시행되고 있더라도 애플리케이션은 영향을 받아선 안 됨.
- Containers running on that node will be gracefully terminated -> re-scheduled to another available node.
Standard process to drain the k8s node - kubectl 사용.
해당 node와 tightly coupled 상태인 pods를 DaemonSet이라고 부르는데 (monitoring이나 Logging 기능 같은 것들), 얘네가 있는 node의 경우 ignoreDaemonSet 명령어를 추가로 붙여줘야 한다.
분리한 노드에서 필요한 작업을 완료한 뒤, 클러스터가 해당 노드를 다시 스케줄링할 수 있도록 (클러스터 안에 포함시킬 수 있도록) 만드는 명령어가 uncordon이다.
Master Node에 ssh로 접근한 다음
kubectl get pods -o wide
: 실행중인 모든 Pod 정보 + 해당 pod이 어느 Node에서 돌아가고 있는지
먼저 pods.yml 파일을 생성하고, kubectl apply -f pods.yml
로 클러스터에 배포한다.
다음으로 deployment.yml 파일을 생성하고, kubectl로 배포한다.
현재 pods의 개수는 아래와 같다.
여기서 kubectl drain k8s-worker-2
를 실행하면,
두 개의 오류가 뜬다.
- pods.yaml로 생성한 pod가 ReplicationController, ReplicaSet... 등과 같은 어느 Object와도 연결되어 있지 않다
- DaemonSet-managed Pod가 있어서 node를 drain할 수 없다
- 여기서 DeamonSet은 Deployment의 결과로 생성된 pod를 의미한다. Deployment로 생성된 pod에는 kube-system의 proxy, 네트워크를 위해 설치한 calico가 작동하고 있기 때문.
두 개의 오류를 모두 해결하려면 kubectl drain k8s-worker-2 --ignore-daemonsets --force
를 입력하면 된다.
해당 노드를 unscheduled하면서, 노드 안에 있던 두 개의 pod도 전부 evicted (쫒아내다).
k8s-worker-2 노드가 schedulingDisabled 상태인 걸 확인할 수 있고,
Deployment에서 정의한 replica 개수인 2개를 맞추기 위해 k8s-worker-1에 새 Pod가 생성된 것을 볼 수 있다.
get nodes에서 scheduleDisabled되어 있는 노드를 활성화하려면 kubectl uncordon k8s-worker-2
를 입력하면 된다. 단, k8s-worker-2에 등록되어 있던 pod가 이전 상태로 돌아오지는 않는다. (pod의 상태를 보장하지는 않는다)
Upgrading k8s Cluster
kubeadm을 활용하면 seamless한 upgrade가 가능하다.
## 1. Get the Running Node and Version
kubectl get nodes
## 2. Drain Master Node
kubectl drain <node-to-drain> --ignore-daemonsets
## 3. Upgrade kubeadm
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubeadm=1.21.1-00
## 4. Verify that the download works and has the expected version:
kubeadm version
## 5. Verify the upgrade plan - 업그레이드 가능한지 미리 체크.
sudo kubeadm upgrade plan v1.21.1-00
## 6. Apply the Upgrade
sudo kubeadm upgrade apply v1.21.1
## 7. Upgrade kubelet and kubectl packages
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubelet=1.21.1-00 kubectl=1.21.1-00
## 8. Restart the kubelet:
sudo systemctl daemon-reload
sudo systemctl restart kubelet
## 10. Get the Running Node and Version
kubectl get nodes
## 11. Uncordon the Node
kubectl uncordon <node-to-uncordon>
## 1. Drain Worker Node
kubectl drain <node-to-drain> --ignore-daemonsets --force
## 2. Upgrade kubeadm
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubeadm=1.21.1-00
## 3. Verify that the download works and has the expected version:
kubeadm version
## 4. For worker nodes this upgrades the local kubelet configuration
sudo kubeadm upgrade node
## 5. Upgrade kubelet and kubectl packages
sudo apt-get update
sudo apt-get install -y --allow-change-held-packages kubelet=1.21.1-00 kubectl=1.21.1-00
## 6. Restart the kubelet:
sudo systemctl daemon-reload
sudo systemctl restart kubelet
## 7. Get the Running Node and Version
kubectl get nodes
## 8. Uncordon the Node
kubectl uncordon <node-to-uncordon>