쿠버네티스 환경 구성하기
스터디에서는 각자 환경 (Window, Mac)에서 쿠버네티스 클러스터를 구성했다. 쿠버네티스 클러스터를 구현하기 위해 KIND를 활용했으나 (kind 내용은 다른 스터디원들이나 자료가 많으므로) 본인은 홈서버에 k8s 클러스터가 있어, 이를 활용하였다.
Proxmox 활용, 쿠버네티스 환경 구축
Proxmox란 ?
가상화 관리를 위한 소프트웨어 서버. 하이퍼바이저 운영체제
Proxmox에서 클러스터 구성하기
1. 하드웨어 구성
- 마더보드: B365M
- CPU: i9-9900 es qqbz
(인텔 i9-9900 모델이 만들어지기 전에 엔지니어링 샘플링(es) 용도로 풀린 물건을 중국 마켓을 통해 구입, 가격은 20만원대 중후반)
- 메모리: 삼성 DDR 4 16GB * 2
proxmox를 k8s 클러스터 목적으로 구매하기 보다는 홈 클라우드 환경을 구축하기 위해 구매. 현재는 집에서 운영 레벨의 k8s를 구축하여 kind나 미니큐브 같은 경량화 모델의 단점을 해소하고 운영 환경을 직접 구현해보기 위한 용도로 사용중
2. Proxmox OS 설치
- 1GB 이상의 저장 공간을 제공하는 장치를 준비합니다. (USB)
- https://www.proxmox.com/en/downloads/proxmox-virtual-environment/iso proxmox iso 이미지 파일을 준비합니다.
(2024.09 월 기준 최신 버전은 8버전 입니다.)
- 준비된 PC에 부팅이미지를 넣은 USB를 인식시키고 전원을 가동합니다.
- 설치과정 자체는 아주 간단하므로 문서로 대체하겠습니다. https://pve.proxmox.com/wiki/Installation
설치가 완료되면 아래와 같은 proxmox 콘솔 접속 ip를 안내합니다. 자 이제 이 PC에서 볼 일은 없습니다. 메인 PC에서 아래 주소로 접속해봅니다.
3. VM 생성
아까 위에서 보여준 페이지를 접속해보면 이런 콘솔 화면이 나타납니다.
우측 상단에 Create VM 버튼을 누르면 VM을 생성할 수 있습니다. 마치 AWS 콘솔에서 EC2를 생성하듯이 VM을 만들 수 있습니다.
쿠버네티스 control plane에 포함될 vm 3대, data plane에 포함될vm 3대를 구성할겁니다.
vm 한 대만 같이 생성해보겠습니다.
name을 설정합니다. 저는 여러 vm이 구성되어 있으니 이 vm이 포함될 pool 만 별도로 지정해주겠습니다.
resource pool은 vm 을 생성하기 전에 미리 만들어야 합니다. 여기서는 다루지 않겠습니다.
미리 받아둔 iso 이미지 중에 현재 vm에서 사용할 iso 이미지를 선택합니다. iso 이미지는 proxmox 콘솔에서 url로 다운로드 받거나 내가 갖고 있는 iso 이미지를 업로드하여 사용할 수 있습니다.
CPU 코어 수를 지정합니다. Advanced 기능을 활용하면 논리코어를 지정할 수 있습니다. (vCPU)
메모리를 지정할 수 있습니다. 여기서는 4 GiB 메모리를 지정하겠습니다.
이렇게 마지막에는 요약해서 보여줍니다. 확인 후 Finish 버튼을 눌러 vm 생성을 완료합니다.
이렇게 6대의 vm을 구성합니다.
4. k8s 클러스터 구축하기
우리는 k8s 클러스터를 구성하기 위해 kubespray를 사용할겁니다.
4-1 우리가 사용할 계정은 ubuntu 계정이고, 이 계정이 root 계정의 권한을 빌릴 수 있도록 설정해야합니다.
sudo su -
명령어를 통해 root 계정으로 로그인한 다음 /etc/sudoers 파일을 수정합니다.
파일 가장 아래에 다음과 같이 입력합니다.
ubuntu ALL=NOPASSWD: ALL
4-2 각 서버별 확인되는 ip 주소를 각 서버별 hosts 파일에 기입해야합니다.
/etc/hosts 파일에 다음과 같이 모든 서버의 ip 목록을 입력해줍니다.
4-3 각 서버끼리 액세스 할 수 있도록 ssh 접속을 열어줍니다.
각 서버에서 ssh 접속을 한 다음, ssh key를 생성합니다.
이렇게 ssh-key를 생성하면 /home/ubuntu/.ssh 경로에 id_rsa, id_rsa.pub 파일이 생성됩니다. 생성한 vm 6대에 모두 동일한 key 로 구성합니다.
4-4 kubespray를 활용하여 클러스터를 구성할 준비를합니다.
하나의 노드에 접속해서 kubespray 소스를 다운로드 받습니다.
git clone https://github.com/kubernetes-sigs/kubespray
kubespray는 ansible을 통해 쿠버네티스 클러스터를 구성합니다. ansible을 사용하기 위해 python3을 설치합니다.
sudo apt update -y
sudo apt install python3-pip -y
kubespray를 사용하기 위한 패키지를 설치합니다.
cd /home/ubuntu/kubespray
sudo pip3 install -r requirements.txt
4-5 kubespray 로 클러스터를 설치하기 위해 구성파일을 일부 수정합니다.
cd /home/ubuntu/kubespray
cat inventory/mycluster/hosts.yml
all:
hosts:
k8s-master-1:
ansible_host: k8s-master-1
k8s-master-2:
ansible_host: k8s-master-2
k8s-master-3:
ansible_host: k8s-master-3
k8s-worker-1:
ansible_host: k8s-worker-1
k8s-worker-2:
ansible_host: k8s-worker-2
k8s-worker-3:
ansible_host: k8s-worker-3
children:
kube_control_plane:
hosts:
k8s-master-1:
k8s-master-2:
k8s-master-3:
kube_node:
hosts:
k8s-worker-1:
k8s-worker-2:
k8s-worker-3:
etcd:
hosts:
k8s-master-1:
k8s-master-2:
k8s-master-3:
k8s_cluster:
children:
kube_control_plane:
kube_node:
calico_rr:
calico_rr:
hosts: {}
이후 원하는 값을 설정한 다음, 클러스터를 구성해보자
4-6 클러스터 설치
cd /home/ubuntu/kubespray
ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root -v cluster.yaml
20분 내에 쿠버네티스 클러스터 모두 구성된 것을 확인할 수 있다.
현재까지 구성된 클러스터는 다음과 같다.
5. 로컬에서 클러스터에 api 요청하기
클러스터를 생성하고나서는 클러스터에 포함된 노드에서만 kubectl을 사용할 수 있다. 그 이유는 kubectl 프로그램을 사용하기 위해서는 kubeconfig이 구성되어 있어야 하는데 아직까지 노드에서만 구성되어 있기 때문이다.
이 파일 내용을 복사해서 로컬환경에도 동일하게 구성해보자
쿠버네티스 도구 설치
kubectl
kubectl은 공식문서 가이드를 기반으로 작성하였다.
https://kubernetes.io/ko/docs/reference/kubectl/
brew install kubectl
kubectx & kubens
kubectl을 활용하여 context switching을 할 수 있지만 조금 번거롭다. 이를 간단히 하기 위해서 kubectx를 설치하도록 하자.
brew install kubectx
brew install kubens
kubecolor
kubectl을 활용하여 쿠버네티스 클러스터에 요청시에 색이 없어서 보기 불편한 점을 개선하기 위한 도구
brew install kubectx
# kubectl 결과 하이라이트 처리
echo "alias kubectl=kubecolor" >> ~/.zshrc
echo "compdef kubecolor=kubectl" >> ~/.zshrc
k9s
쿠버네티스 tui 도구
brew install k9s
k9s 명령으로 클러스터를 TUI로 제어할 수 있다.
익숙해지면 헤어나오지 못한다.
k9s에서 사용할 수 있는 단축키를 확인하는 방법은 '?' 키를 눌러보면 된다.
이 내용 외에도 다양한 k9s 사용법을 참고하기 좋은 블로그를 소개하겠다.
https://peterica.tistory.com/276
파드 & 포즈 컨테이너
CRI (Container Runtime Interface)
쿠버네티스에서 동작하는 애플리케이션은 1개 이상의 컨테이너를 포함하는 파드가 가장 기본 단위이다. 마치 물질을 이루는 가장 작은 단위인 분자(molecule)이고 분자를 쪼개면 원자(atom)가 나오는 것 처럼 보인다. 물론 현실에서 원자는 더 작은 단위로 쪼개지지만 우리가 사용하는 컨테이너는 여기서 가장 작은 단위이다. 컨테이너는 더이상 쪼개질 수 없지만 컨테이너가 실행되는 환경인 런타임은 여러 종류가 있다. 컨테이너 런타임은 도커, containerd, singularity, cri-o 등이 있고 비슷해보이지만 제각각 차이점이 있다.
쿠버네티스는 '컨테이너 오케스트레이션 툴' 이라고 불린다. 컨테이너를 구성, 조율, 관리 하는 도구이다. 그렇다면 하나의 컨테이너 런타임만 사용할 수 있는게 아니라 여러 컨테이너 런타임을 통해 클러스터를 구성, 조율, 관리할 수 잇어야 하지 않을까 ? (그래서 나온 것인지는 모르겠지만) 쿠버네티스가 여러 컨테이너 런타임 사이에 동작할 수 있도록 하기 위해 정의된 표준이 CRI 컨테이너 런타임 인터페이스 이다. 이러한 표준을 OCI (Open Container Initiative) 이다.
기존에 Docker 컨테이너 런타임이 kubelet 소스코드와 긴밀하게 통합되어 있었는데 이러한 상황은 유지관리 오버헤드가 많이 있어왔다. 쿠버네티스 1.5 버전부터 CRI가 도입되면서 점진적으로 OCI 표준을 따르는 컨테이너 런타임은 살아남게 되었고 1.24 버전부터는 쿠버네티스에서 도커 컨테이너 지원이 완전히 종료되었다.
kubelet은 gRPC 프레임워크를 사용하여 Unit 소켓을 통해 CRI Shim과 통신한다. 이때 protobug API가 이미지 서비스, 런타임 서비스를 활용한다.
파드가 생성될 때 kubelet은 RuntimeService.RunPodSandbox를 호출하여 환경을 만든다. 이때 ip 할당 등의 네트워킹 설정도 포함된다. PodSandbox가 활성화되면 개별 컨테이너를 독립적으로 제어할 수 있다. 또한 파드가 종료될 때도 컨테이너가 종료되고 제거된 다음 PodSandbox가 중지 제거된다. 마치 집을 지을때 주춧돌 같은 역할이라고 볼 수 있다.
Pod & Pause Container
파드는 컨테이너 애플리케이션의 가장 작은 단위이다. 파드에는 사실 1개 이상의 컨테이너가 존재한다. 2개일수도 있고 더 많은 컨테이너를 포함할수도 있다. 도커에서는 2개의 컨테이너가 존재하면 각각의 IP가 할당되는데 파드 내에서 2개의 컨테이너가 존재하는 경우는 어떨까 ??
정답은 파드 내에서 아무리 많은 컨테이너가 생성되더라도 모두 같은 IP를 공유한다. 그럼 그 IP는 누가 가지고 있을까 ? 2개의 컨테이너 중에 먼저 생성되는 컨테이너 ? 만약 그렇다면 파드 내에서 생성되는 컨테이너 순서가 항상 일정해야하는 문제점이 있다. 정답은 앞서 말한 PodSandbox(Pause Container)가 그 일을 대신한다.
조금 더 구체적으로 설명하자면, pause container가 network ns를 만들고, 다른 컨테이너들은 pause container의 ns를 공유한다.
정말 그런지 확인해보자
1. 증명할 파드의 위치를 확인한다.
kubectl get pods -o wide
deploy-websrv-56bc96f466-q6jm4 이 파드는 k8s-worker-1 노드에 위치해있다.
2. k8s-worker-1 노드에 접속한다.
3. crictl 명령어로 containerd container runtime으로 실행중인 컨테이너 정보를 확인한다.
4. 확인된 pid를 노드에서 lsns 명령어를 통해 확인한다.
application container namespaces
root@k8s-worker-1:/home/ubuntu# lsns -p 3366592
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 184 1 root /sbin/init
4026531837 user 183 1 root /sbin/init
4026532288 net 7 3366376 65535 /pause
4026532406 uts 7 3366376 65535 /pause
4026532407 ipc 7 3366376 65535 /pause
4026532409 mnt 6 3366592 root nginx: master process nginx -g daemon off;
4026532410 pid 6 3366592 root nginx: master process nginx -g daemon off;
pause container namespaces
root@k8s-worker-1:/home/ubuntu# lsns -p 3366376
NS TYPE NPROCS PID USER COMMAND
4026531835 cgroup 184 1 root /sbin/init
4026531837 user 183 1 root /sbin/init
4026532288 net 7 3366376 65535 /pause
4026532405 mnt 1 3366376 65535 /pause
4026532406 uts 7 3366376 65535 /pause
4026532407 ipc 7 3366376 65535 /pause
4026532408 pid 1 3366376 65535 /pause
pause container가 net,uts,ipc namespace를 생성하고 application container가 pause container의 namespace를 공유받아서 활용한다.
Flannel CNI
CNI
쿠버네티스의 네트워크 모델을 만족하는 CNI 플러그인이 존재한다. 대표적으로 Calico, Cilium, 등이 있다.
쿠네티스의 CNI를 만족하기 위해서는 4가지 요구사항과 4가지 문제를 해결해야한다.
요구사항
1. 파드간 통신시 NAT 없이 통신
2. 노드의 에이전트는 파드와 통신이 가능하다.
3. 호스트 네트워크를 사용하는 파드는 NAT 없이 파드와 통신이 가능하다.
4. 서비스 클러스터 IP 대역과 파드가 사용하는 IP 대역은 중복되지 않아야 한다.
문제
1. 파드 내 컨테이너는 루프백을 통한 통신이 가능해야한다.
2. 파드 간 통신을 할 수 있습니다.
3. 클러스터 내부에서 서비스를 통한 통신을 할 수 있습니다.
4. 클러스터 외부에서 서비스를 통한 통신을 할 수 있습니다.
모드(mode)
Flannel CNI는 3가지 모드를 지원합니다.
VXLAN
물리적인 네트워크 환경위에서 논리적인 가상의 네트워크 환경을 만들어준다. 터널링 기법을 사용하여 파드의 패킷을 encapsulation하여 노드를 빠져나간다. 목적지 노드에서 패킷을 decapsulation하여 목적지 파드에 전달하게 된다. encapsulation, decapsulation 하는 지점을 VTEP(Vxlan Tunnel End Point)라고 한다. flannel.1 네트워크 인터페이스가 이 역할을 한다. UDP 8472 포트를 사용한다.
UDP
UDP 네트워크 오버레이 기법을 지원한다. UDP 8285 포트를 활용한다.
host-gw
각 노드의 파드 네트워크 대역을 라우팅 테이블에 업데이트하여 직접 라우팅을 수행한다. 문제점은 모든 노드가 동일한 서브넷에 배포되어 있어야한다. -> 실제 운영환경에서는 활용되기 어려워 보인다.
Flannel CNI 구성하기
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
물론 기본 설정을 사용하지 않는 경우에는 다음과 같이 한다.
wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
sed -i 's/<원래 내용>/<바꿀 내용>/g' kube-flannel.yml
현재 사용가능한 CNI 확인하기
1. 컨트롤 플레인 서버에 접속
ssh ubuntu@192.168.1.38
2. 확인
ubuntu@k8s-master-1:~$ ls /opt/cni/bin
bandwidth bridge calico calico-ipam dhcp dummy firewall flannel host-device host-local install ipvlan loopback macvlan portmap ptp sbr static tap tuning vlan vrf
현재 사용중인 CNI 확인
ubuntu@k8s-master-1:~$ ls -al /etc/cni/net.d/
total 20
drwxr-xr-x 2 kube root 4096 Sep 7 15:46 .
drwxr-xr-x 3 kube root 4096 Nov 25 2023 ..
-rw-r--r-- 1 root root 844 Jan 14 2024 10-calico.conflist
-rw-r--r-- 1 root root 292 Sep 7 15:46 10-flannel.conflist
-rw------- 1 root root 2737 Sep 7 15:41 calico-kubeconfig
Flannel CNI는 각 노드에 flannel.1 이라는 네트워크 인터페이스를 사용하므로 노드에서 ip 명령어를 통해 네트워크 인터페이스를 확인할 수 있다.
스터디 자료 외에 추가로 도움이 되었던 자료
https://mvallim.github.io/kubernetes-under-the-hood/documentation/kube-flannel.html
코멘트:
네트워크는 어렵지만 배운 걸 바로바로 써먹을 수 있어서 아주 흥미로운 주제이다.네트워크 이슈는 아주 조그만 이슈도 제대로 해결하지 못하면 눈덩이처럼 크게 불려진 문제가 들이닥칠수도 있다. 그래서 지금 당장은 어렵고 험난하겠지만 실무에서 문제가 발생했을 때 지금 어려웠던 것들이 빛을 발하리라 생각한다.
나는 생선요리를 좋아한다. 처음 생선 요리를 먹을 땐 뼈를 발라내기가 어렵다. 한 번에 발라내는 것도 쉽지 않다. 하지만 한 두번 생선 살을 발라내다보면 어느새 귀신같이 생선 가시만 뚝딱하고 발라내고 있는 날 볼 수 있다. 이렇게 연마한 생선뼈 발라내기를 사랑하는 사람 앞에서 뚝딱하고 발라낸다면 충분히 상대방에게 멋지고 예쁨받을 수 있다고 본다. 네트워크도 지금 당장은 어렵겠지만 조금씩 쌓인 경험을 통해 동료가 어려워하는 상황을 간단히 해결함으로써 신뢰도 얻고, 동료의 시간을 아껴주고 싶다.
'스터디' 카테고리의 다른 글
[KANS 3기] 3주차 Calico CNI (2/3) (1) | 2024.09.21 |
---|---|
[KANS 3기] 3주차 실습환경 구성하기 (1/3) (1) | 2024.09.21 |
[KANS 3기] 내가 쓰는 도커 이미지는 어떻게 구성되어 있나요 ? (0) | 2024.08.31 |
[KANS 3기] 슈퍼컴퓨팅 워크로드를 위한 컨테이너 설정 (1) | 2024.08.31 |
시간 최소화 성과 최대화 법칙 (0) | 2023.12.21 |