Cka 정리6
cka 정리6
234: Design a Kubernetes Cluster
k8s 클러스터 설계에 대해 다룬다. 설계하기 전 다음과 같은 고민이 필요하다
- 목적
- 교육
- 개발 & 테스트
- PROD 애플리케이션 호스트 환경
- 클라우드 혹은 온프레미스
- 워크로드의 양
- 교육 목적으로 cluster를 배포하고 싶다면 minikube, GCP ,AWS 등을 사용하거나 단일 노드 클러스터 Development & Testing
- 개발 및 테스트 목적이면 단일 마스터가 있는 다중 워커 노드 클러스터가 좋다
- kubeadm 혹은 GCP의 google container, AWS , Azure 등 사용 Hosting Production Applications
- 프로덕션급 애플리케이션 호스팅이면 고가용성(HA) 다중 마스터 노드 클러스터를 사용하는 게 좋다.
- 여러 클라우드 솔루션을 보면 다음 예시와 같다. 클러스터에 최대 5000개의 노드를 포함할 수 있고 노드당 최대 100개의 파드를 가질 수 있다. 이렇듯 클러스터 크기에 따라 노드의 리소스 요구 사항이 다르다.
Node
- 마스터 노드도 노드이기에 workload를 호스트할 수 있다. 하지만 모범적인 사례로는 전용 마스터 노드를 사용하는 것이 좋다.
235: Choosing Kubernetes Infrastructure
k8s 클러스터 배포의 다양한 옵션과 형태에 대하여 minikube는 단일 노드 클러스터를 쉽게 배포한다. kubeadm은 하나의 노드 또는 다중 노드 클러스터를 빨리 배포하는 데 좋다
236: Configure High Availability
K8S의 고 가용성에 대해 알아보자 클러스터의 마스터 노드를 잃어버리면 어떻게 될까?
워커 노드들이 동작하고 컨테이너들이 살아있는 한 애플리케이션은 작동한다. 유저는 계속 앱에 접근할 수 있다. 하지만 컨테이너나 파드가 고장나면 어떨까? pod가 replicaset으로부터 만들어졌다면 마스터 노드의 replication controller가 워커 노드에 새 파드를 로드하라고 지시해야한다. 하지만 지금의 마스터는 할 수 없는 상태이다. 스케쥴링 컴포넌트, kube-apiserver 모두 안된다. 그래서 프로덕션 환경에서는 고가용성 구성에 다중 마스터 노드를 고려해야 하는 것이다.
HA 구성은 클러스터 내 모든 컴포넌트에 걸쳐 중복을 갖는 것이다. 마스터 노드, 워커 노드, 컨트롤 플레인 컴포넌트, 애플리케이션 모두 다 마스터 노드는 controlplane 컴포넌트를 호스팅한다. (API Server, ETCD, Scheduler, Controller Manager) 만약 추가 마스터 노드를 설치하면 어떻게 작동할까? 같은 일을 두번 할까? 일을 분담할까?
그래서 API서버의 경우 서버간 트래픽을 분할하는 마스터 노드 앞에 로드밸런서를 갖는 것도 좋다.
다만 스케쥴러와 컨트롤러는 병렬로 실행되면 안되고 active와 standby mode로 실행되어야 한다. active가 되는건 투표 (leader-elect) 옵션을 통해 수행된다. 지정된 lease(임대) 기간을 갖고 수행하고 갱신 하고 다시 양보하고 한다.
237: ETCD in HA
ETCD도 분산해서 여러 노드에 각각의 ETCD를 심어놓을 수 있다. 이제 AWS의 db HA랑 비슷해진다. write하는 master node가 있고 나머지는 follower node가 된다. write 명령은 어느 노드로 들어오든 write master node에게 전달되고 쓰여진다. 마스터노드는 쓰고 팔로워 노드들에게 복사본을 전달한다. 리더 선출은 어떻게 할까?
Leader Election - RAFT
raft 알고리즘은 무작위로 타이머 맞춰 신호를 보낸다. 타이머 순서대로 투표하고 리더를 선출하는 것 리더는 주기적으로 공지를 보내 자신이 리더임을 알린다. 알림이 안온다면 리더가 다운됐거나 네트워크가 끊긴 것이고 재선 프로세스가 시작된다.
쓰기는 다른 인스턴스로 복제됐을 때 완료로 간주한다. 만일 팔로워 노드를 잃게되어 일부 노드로 복제가 안됐을 때 쓰기를 완료해야할까? 실패일까? 이 때 클러스터 내 대부분의 노드에 쓰기가 완료되면 완료로 간주한다. 대부분은 Quorum이라는 것으로 결정한다. 쿼럼은 클러스터가 제대로 기능하고 성공적으로 쓰기위해 반드시 필요한 최소의 노드 수이다.
Quorum = N/2 + 1 쿼럼은 노드 개수를 2로 나눈 뒤 1을 더한 수이다.
fault tolerance는 감내할 수 있는 손실 노드 개수이다. 그래서 노드가 최소 3개는 돼야 ETCD 분산의 의미가 있는 것이다. 홀수가 좋은 것이 짝수일때와 Fault Tolerance 개수가 같으면서 결정에 필요한 쿼럼 수는 적다.
238: Introduction to Deployment with Kubeadm
kubeadm
- k8s 클러스터는 kube-apiserver, etcd, controller 등 다양한 컴포넌트로 구성된다
- 컴포넌트간 통신을 위한 보안과 인증서 등 여러 요구사항도 보았다.
- 이런 다양한 컴포넌트를 각 노드에 개별적으로 모두 설치하고 configuration file 수정하고 컴포넌트가 서로를 가리키는지 확인하고 인증서가 잘 작동하는지 확인하는건 엄청 귀찮은 일이다
- kubeadm 툴은 이런 모든 작업을 해준다
설치하는 법
1.30.0-1.1 버젼을 까는 것이여도 curl로는 1.30 라인을 받아온다
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL \https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg –dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg |
echo ‘deb signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /’ | sudo tee /etc/apt/sources.list.d/kubernetes.list |
sudo apt-get update
+To see the new version labels
sudo apt-cache madison kubeadm
sudo apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl
실습##
kubelet과 kubeadm을 설치하는 것은 k get nodes를 가능하게 하지 않는다 master node(control plane node) 를 활성화 시켜라
“initialize master node” 로 docs에 검색하면 잘 나옴
- $ kubeadm init –apiserver-advertise-address 192.20.88.6 –apiserver-cert-extra-sans controlplane –pod-network-cidr 10.244.0.0/16
다른 노드를 join 시켜라
- $ ssh node01
- master node에서 kubeadm init 했을 때 마지막에 나온 node join cli 라인 복사
- $ kubeadm join 192.20.88.6:6443 –token t7a4b5.58jedyukf0uzopr2 –discovery-token-ca-cert-hash sha256:db8bb140823ede88d2ce33259b1b221cd2075b1e81a8fced26a371290be53999
네트워크 플러그인을 설치하기 위해 Flannel을 쓸것이다. 호스트간 소통을 위해 eth0 인터페이스 쓴다
- flannel yml 다운
- $ curl -LO https://raw.githubusercontent.com/flannel-io/flannel/v0.20.2/Documentation/kube-flannel.yml
- kube-flannel.yml 파일 오픈
- 다음 파라미터에 eth0 인터페이스 추가
- args:
- –ip-masq
- –kube-subnet-mgr
- –iface=eth0
- $ k apply -f kube-flannel.yml
- $ k get nodes
- 모두 ready 상태로 바뀐다
248: Application Failure
애플리케이션에 오류가 발생했다
Check Accessibility
시작전에 애플리케이션의 구성에 대해 그림을 그리거나 글을 써보는 것이 좋다. 문제의 근본적 원인을 찾을때까지는 그림의 모든 오브젝트와 연결고리를 확인해야 한다.
유저가 애플리케이션에 접근하는데 이슈가 있다고 가정해보자. 그렇다면 프론트엔드부터 시작한다. 웹 애플리케이션의 경우 curl을 사용해 웹 서버가 노트 포트의 IP에 접근할 수 있는지 체크한다.
- $ curl http://web-server-ip:node-port
Check Service Status
다음은 서비스를 체크한다. 웹 파드의 endpoint를 찾아야 한다
- $ kubectl describe service web-service (or k get services)
서비스에서 구성한 selector(name=webapp-mysql)과 웹 서버 pod의 label이 일치하는지 확인한다
파드가 running 상태인지 확인한다
- $ k get pods
- 상세 이벤트를 확인한다
- $ k describe pods web-app
- 애플리케이션 로그를 확인한다
- $ kubectl logs web -f –previous 마찬가지 과정을 db 서비스에 확인해본다
- pod 상태, 이벤트, 로그
251: Control Plane Failure
controlplane 장애를 해결하는 다양한 방법을 알아보자
우선 클러스터의 노드들과 파드들의 상태를 확인한다
- $ k get nodes
- $ k get pods
클러스터가 kubeadm을 통해 설치됐거나 controlplane이 pod로 배포된 경우 확인해보자
- $ kubectl get pods -n kube-system
혹은 controlplane 컴포넌트들이 서비스로 배포된 경우 각각의 상태가 정상인지 확인해봐야한다.
이후 controlplane 컴포넌트의 로그를 확인해보자. kubeadm의 경우 controlplane 컴포넌트를 호스팅하는 파드의 로그를 보려면 apiserver 로그를 확인하면 된다
- $ kubectl logs kube-apiserver-master -n kube-system
컴포넌트들이 pods로 잘 배포돼있는데 워커 노드가 Not Ready로 안될때는 연결소통하는 창구인 kubelet을 의심해라
- $ ssh node01
- $ service kubelet status
그러나 컴포넌트들이 서비스로 배포된 경우 journalctl을 활용해 apiserver service의 로그를 확인해야한다
- $ sudo journalctl -u kube-apiserver
- 혹은 워커 노드가 문제일 경우
- $ journalctl -u kubelet
- $ journalctl -u kubelet -f (f 옵션을 줘서 follow로 실시간 추적 하면 실패로그를 더 잘 확인할 수 있다)
- kubelet 설정 파일은 /var/lib/kubelet/config.yaml에 있다!! (/etc/kubernetes/kubelet.conf가 아님)
+kube-system의 기본 컴포넌트들은 /etc/kubernetes/manifest 예하의 기본 정의 yaml 파일에서 수정해야한다. kubectl edit을 통해서 수정하는건 먹지 않는다. 기본적으로 k8s가 manifest 정보를 보고 있음
257: Network Troubleshooting
k8s는 CNI 플러그인을 사용하여 네트워크를 설정하고 kubelet은 플러그인을 실행한다.
CNI
- cni-bin-dir: kubelet은 시작 시 이 디렉터리에서 플러그인을 검색한다
- network-plugin: cni-bin-dir에서 사용할 네트워크 플러그인. 플러그인 디렉토리에서 프로브된 플러그인이 보고한 이름과 일치해야 한다
플러그인 예시
- weavenet, flannel, calico 가 있다. 공식 git에서 직접 다운로드
- $ k apply -f cni.yaml
svc의 endpoint가 안잡히면 네트워크를 의심해봐라 그러나 시험에서 cni 설치를 요구하진 않는다
+cni-bin-dir에 여러개의 CNI 구성 파일이 있는 경우 kubelet은 사전순 제일 먼저 오는 configuration을 이용한다.
weave 또한 pod로 kube-system에 존재하는 것이다
- /etc/cni/net.d/ 예하를 봤을 때 뭐가 있는지 보아라
DNS IN K8s
k8s는 CoreDNS를 이용한다.
Memory and Pods
대규모 쿠버네티스 클러스터에서, 코어DNS의 메모리 사용량은 주로 클러스터의 파드 및 서비스 수에 의해 영향을 받는다. 다른 요인으로는 filled DNS 응답 캐시의 크기와 CoreDNS 인스턴스당 쿼리 수신 속도(QPS)가 있다
coreDNS를 위한 k8s 리소스
- serviceaccount
- clusterrole & clusterrolebinding
- deployment
- configmap
- service coreDNS와 kubeDNS 모두 확인한다
+53번 포트는 coredns를 위함이다
CoreDNS### 와 관련된 다른 트러블슈팅###
- pending인 상태의 CoreDNS 파드를 발견하면 먼저 네트워크 플러그인이 설치되어 있는지 확인합니다. 2. 코어DNS 파드가 CrashLoopBackOff 또는 오류 상태입니다. 이전 버전의 Docker로 SELinux를 실행하는 노드가 있는 경우 coredns 파드가 시작되지 않는 시나리오가 발생할 수 있습니다. 이 문제를 해결하려면 다음 옵션 중 하나를 시도해 볼 수 있습니다:
a)최신 버전의 Docker로 업그레이드합니다. b)SELinux를 비활성화합니다. c)허용 권한 확장을 true로 설정하도록 coredns 배포를 수정합니다:
3.CoreDNS 서버와 kubeDNS가 정상적으로 작동한다면 kube-dns에 유효한 endpoint가 있는지 확인한다
- $ kubectl -n kube-system get ep kube-dns
서비스에 대한 엔드포인트가 없는 경우, 서비스를 describe해서 올바른 셀렉터와 포트를 사용하는지 확인합니다. 엉뚱한 파드를 가르키고 있을 수 있음
Kube-Proxy
kube-proxy는 클러스터의 각 노드에서 실행되는 네트워크 프록시이며, 노드에서 네트워크 규칙을 유지 관리한다. 이러한 네트워크 규칙은 클러스터 내부 또는 외부의 네트워크 세션에서 파드로의 네트워크 통신을 허용한다.
kubeadm으로 구성된 클러스터에서는 데몬셋으로 kube-proxy를 찾을 수 있습니다.
- $ k get daemonset
kubeproxy는 각 서비스와 관련된 서비스 및 엔드포인트를 감시합니다(watching). 클라이언트가 가상 IP를 사용하여 서비스에 연결하려고 할 때, 실제 파드로 트래픽을 전송하는 것은 kubeproxy가 담당합니다
- $ kubectl describe ds kube-proxy -n kube-system
kubeproxy 관련 트러블 슈팅
- kube-proxy pod 확인
- kube-proxy log 확인
- kube-proxy를 위한 config file과 configmap 이 제대로 정의됐는지 확인
- kube-config 확인
Practice test - Advanced kubectl commands
- Get the list of nodes in JSON format and store it in a file at /opt/outputs/nodes.json.
- $ k get nodes -o json > /opt/outputs/nodes.json
- Use JSON PATH query to fetch node names and store them in /opt/outputs/node_names.txt.
- $ kubectl get nodes -o=jsonpath=’{.items[*].metadata.name}’ > /opt/outputs/node_names.txt
- A kube-config file is present at /root/my-kube-config. Get the user names from it and store it in a file /opt/outputs/users.txt. Use the command kubectl config view –kubeconfig=/root/my-kube-config to view the custom kube-config.
- $ kubectl config view –kubeconfig=my-kube-config -o jsonpath=”{.users[*].name}” > /opt/outputs/users.txt
- jsonpath 쿼리로 첫 depth에 있는 모든 유저들 그리고 이름을 가져온다
- A set of Persistent Volumes are available. Sort them based on their capacity and store the result in the file /opt/outputs/storage-capacity-sorted.txt.
- $ kubectl get pv –sort-by=.spec.capacity.storage > /opt/outputs/storage-capacity-sorted.txt
Lightning Lab
- 클러스터 업데이트 Upgrade the current version of kubernetes from 1.29.0 to 1.30.0 exactly using the kubeadm utility. Make sure that the upgrade is carried out one node at a time starting with the controlplane node. To minimize downtime, the deployment gold-nginx should be rescheduled on an alternate node before upgrading each node.
Upgrade controlplane node first and drain node node01 before upgrading it. Pods for gold-nginx should run on the controlplane node subsequently.
이 문제는 일반적인 controlplane (마스터 노드)와 worker node를 업데이트하는 경우가 아니다. 마스터 노드가 워커노드처럼 서비스를 운용해야하는 경우이다. 그렇기에 준비된 kubelet과 kubectl 또한 업그레이드해 주어야 한다. 그렇지 않으면 k get nodes에서 controlplane의 버젼이 업그레이드되어 잡히지 않는다
- 노드의 선장 kubelet이 업데이트되지 않았으므로 controlplane에서 k get nodes의 결과는 계속 이전 버젼을 가르키게 된다.
공식문서를 보고 그대로 따라하다보니 이런 일이 생겼다. 왜냐면 공식문서에서는 클러스터 업데이트에 대해 트래픽을 마스터 노드가 나눠갖는 상황을 가정하지 않고 있기 때문
Mock Exam2
deployment를 배포하고 도커 이미지 tag를 업데이트하라
- k create deploy로 배포
- $ k create deployment nginx-deploy –image nginx:1.16 –replicas 1
- k set 으로 이미지 변경
- $ kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
pod을 하나 배포하고 clusterIP service를 만들어 내부적으로 배포하라 이후 busybox:1.28 이미지를 이용해 dns lookup을 하고 record를 /root/CKA/nginx.svc와 /root/CKA/nginx.pod에 저장하라
- $ kubectl run nginx-resolver –image=nginx
- $ kubectl expose pod nginx-resolver –name=nginx-resolver-service –port=80 –target-port=80 –type=ClusterIP
테스트
$ kubectl run test-nslookup –image=busybox:1.28 –rm -it – nslookup nginx-resolver-service > /root/nginx.svc
IP 복사 후
$ kubectl get pod nginx-resolver -o wide $ kubectl run test-nslookup –image=busybox:1.28 –rm -it – nslookup 10-32-0-5.default.pod > /root/nginx.pod
# 클러스터 내의 모든 서비스(DNS 서버 자신도 포함하여)에는 DNS 네임이 할당된다. 기본적으로 클라이언트 파드의 DNS 검색 리스트는 파드 자체의 네임스페이스와 클러스터의 기본 도메인을 포함한다.
+ 참조
https://itformeeting.tistory.com/2