쿠버네티스 클러스터 구축하기 - 2 / Kubeadm, Containerd, Calico 세팅

 

 

쿠버네티스 클러스터 구축을 위한 가상머신 세팅 - Vagrant & VMware Workstation 사용

언젠간 해봐야지 하고 미뤄뒀던 로컬 쿠버네티스 클러스터 구축을 시도한 과정을 공유하고자 한다. 이번 포스팅에서는 쿠버네티스 클러스터 구축을 위한 가상머신 세팅 과정을 담고 있다. 다음

alive-wong.tistory.com

이전 글에 이어서 Vagrant로 프로비저닝된 Ubuntu 20.04 가상 머신들을 통해서 쿠버네티스 클러스터를 구축하는 과정을 공유한다.

기존 Vagrantfile 또한 활용하여 가상머신에서 할 일을 최소하하여 클러스터를 구축하는 것이 목적이다. 


# 쿠버네티스 클러스터 구축 방법

우선 쿠버네티스 클러스터를 구축하기 위해 필요한 요소들과 방법들을 간략하게 정리한다.

쿠버네티스 클러스터 구성 요소

쿠버네티스 클러스터 구성 요

 
쿠버네티스는 컨테이너 오케스트레이션 자동화 도구로써 각 클러스터를 관리하는 마스터 노드(컨트롤 플레인)와 컨테이너화된 애플리케이션을 실행하는 워커 노드(데이터 플레인로 구성된다.
 
따라서, 컨트롤 플레인에 필요한 컴포넌트와 워커 노드에 필요한 컴포넌트가 다르다.


컨트롤 플레인 컴포넌트 - Worker Node

kube-apiserver: 쿠버네티스 API를 노출하는 컴포넌트이다. 실제 통신을 담당하는 서버이다. 이는 수평적으로 확장할 수 있게 설계되어 추가적인 인스턴스를 배포하여 확장이 가능하다.

etcd(엣씨디): 모든 클러스터 데이터를 담은 저장소로 사용되는 일관성 & 고가용성을 보장하는 Key Value 구조의 데이터베이스이다. etcd를 백업하고 있으면 클러스터를 복수할 수 있다.

kube-scheduler: 사용자가 요청한 컨테이너 애플리케이션을 어느 노드로 배치할 지 선택하는 컴포넌트이다.

kube-controller-manager: 컨트롤러들의 프로세스를 실행하는 컴포넌트이다. 노드, 잡, 엔드포인트슬라이스, 서비스어카운트 컨트롤러를 포함한다.


데이터 플레인 컴포넌트 - Worker Node

kubelet: 파드에서 컨테이너가 확실하게 동작하도록 관리하는 컴포넌트이다.

kube-proxy: 네트워크 프록시로, 쿠버네티스 서비스 개념의 구현체이다. 워커 노드의 통신을 담당하는 컴퓨넌트이다. 

컨테이너 런타임: 컨테이너의 실행을 담당하는 소프트웨어이다.


애드온 - Addon

DNS: 쿠버네티스 서비스를 위해 DNS 레코드를 제공해주는 DNS 서버이다. 이를 구성하면 쿠버네티스에 의해 구동되는 컨테이너는 DNS Search에서 해당 DNS 서버를 자동으로 포함한다.

컨테이너 네트워크: 워커 노드들에 동작되는 컨테이너들 사이의 통신을 가능하게 하는 컴포넌트이다. 노드들 사이에 오버레이 네트워크를 구성하기 위해 필요하다.


클러스터 구축 방법

쿠버네티스는 마스터 노드와 워커 노드로 구성되어야 하므로 앞서 살펴본 컴포넌드들을 역할에 맞게 구성해야한다.
 
각 컴포넌트들을 직접 구성하여 클러스터를 구축하는 Hardway 방식을 사용할 수도 있고, 다른 도구를 사용하여 쿠버네티스 클러스터를 구축할 수도 있다.

Kubespray, KOps, ClusterAPI 등의 별도 도구를 사용하는 방법도 존재하고, 공식적으로 지원하는 방법인 kubeadm을 통해서 클러스터를 생성할 수 있다..
 
이번 클러스터 구축에서는 kubeadm을 통해 간단하게 구축할 계획이다.
 
나머지 상세 요소들은 아래를 따른다.

  • version: 1.28
  • CRI: containerd
  • CNI: Flannel Calico (외부 노출을 위해 L3 인터페이스 사용)

원래 Flannel로 컨테이너 오버레이 네트워크를 구성했는데, 외부 노출하는 방식이 어려워서 L3 방식을 지원하는 Calico를 사용하여 클러스터를 구성하였다.


# 클러스터 구축하기

Vagrantfile에서 스크립트를 정의한 후 프로비저닝 과정에서 동작시켜 가상의 관리자의 개입을 최소화하도록 구성한다.
 

사전 작업 with Vagrantfile

Vagrant를 사용하여 사전 작업을 스크립트에 담아 실행한다.

echo 'root:test1234' | sudo chpasswd # root 계정 passwd 지정
sudo echo "192.168.1.100 master" >> /etc/hosts # master ip 호스트네임 매핑
sudo echo "192.168.1.101 worker1" >> /etc/hosts # worker1 ip 호스트네임 매핑
sudo echo "192.168.1.102 worker2" >> /etc/hosts # worker2 ip 호스트네임 매핑
sudo sysctl net.ipv4.ip_forward=1 # iptables 및 IP 포워딩 활성화
sudo modprobe br_netfilter # 브릿지 커널 모듈 로드
sudo swapoff -a # Swap 메모리 비활성화

 

# Containerd 설치
sudo apt-get update # 패키지 목록 업데이트
sudo apt-get install ca-certificates curl gnupg -y # 필요 패키지 설치 
sudo install -m 0755 -d /etc/apt/keyrings # GPG 공개 키를 저장하기 위한 keyrings 디렉토리 생성 및 권한 부
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # Docker 공개 키 다운로드 및 .gpg 파일로 변환
sudo chmod a+r /etc/apt/keyrings/docker.gpg # 읽기 권한 부여
sudo echo \ # Docker 저장소를 패키지 목록에 등록
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update # 패키지 목록 업데이트
sudo apt-get install containerd.io # containerd 설치
sudo echo "" > /etc/containerd/config.toml # 설정 파일 삭제
sudo systemctl restart containerd # 재실행

 
여기에서 `/etc/containerd/config.toml` 파일을 삭제하는 이유는 기본적으로 containerd 설정이 CRI를 사용하지 않도록 되어 있기 때문이다.

# kubectl, kubeadm, kubelet 설치
sudo apt-get install -y apt-transport-https
sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \ # gpg 키 디코딩 후 저장
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list # 쿠버네티스 저장소 추가
sudo apt-get update # 패키지 목록 갱신
sudo apt-get install -y kubelet kubeadm kubectl # kubelet, kubeadm, kubectl 최신 버전 다운로드
sudo apt-mark hold kubelet kubeadm kubectl # 자동 업그레이드 차단

 
마스터 노드에도 필요한 요소들을 동작시켜야하므로 kubelet 설치가 필요하다.
 
위 스크립트를 통해서 사전 준비를 수행할 수 있다.

 

# 마스터 노드용 스크립트

sudo kubeadm init --apiserver-advertise-address 192.168.1.100 2>&1 | tee /root/kubeadm_init_output.txt # 쿠버네티스 클러스터 초기화 - API 서버 주소 지정
sudo mkdir -p $HOME/.kube # kubernetes 설정 파일을 위한 디렉토리 생성
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config # 인증서 복사
sudo chown $(id -u):$(id -g) $HOME/.kube/config # 권한 부여

 
kubeadm을 통해서 클러스터 생성을 시작한다. 이를 별도의 파일로 전달하고, 추후에 활용한다.
 
위 스크립트를 Vagrantfile에 선언하여 프로비저닝 과정에서 수행한 후 아래의 명령어만 사용하면 쿠버네티스 클러스터 구축이 완료된다.

ssh root@worker1 "$(tail -n 2 kubeadm_init_output.txt)" # Worker Node 1 Cluster Join
ssh root@worker2 "$(tail -n 2 kubeadm_init_output.txt)" # Worker Node 2 Cluster Join
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml # CNI Calico 배포

# 클러스터 확인

 

kubeadm을 통해서 구축된 클러스터이다. 3개의 노드가 확인된다. 다만 STATUS가 NotReady 상태인 이유는 CNI를 구성하지 않았기 때문이다.
 
따라서 CNI로 사용할 Calico를 배포해주면 아래와 같이 상태가 정상적으로 찍힌다.

 
노드 상태를 자세히 확인해보면, 구성한 모든 내용이 정상적으로 잡힌다.
 

 
Calico를 통해 컨테이너의 네트워크를 구성했으므로, 해당 컴포넌트를 확인할 수 있고, 모든 Core Components가 정상적임을 알수 있다.
 
이제 간단한 애플리케이션을 배포하여 클러스터가 정상적으로 동작하는지 확인해보자.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: test
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
        - name: test
          image: pengbai/docker-supermario:latest
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: test-service
spec:
  selector:
    app: test
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

 
정상적으로 배포되었음을 확인할 수 있다.

 
NodePort로 노출시켜 이를 확인해보면 정상적으로 배포한 애플리케이션에 접근이 가능하다.
 
쿠버네티스 클러스터를 정상적으로 구축했다!


# 결론

아래는 이번 실습에서 구축한 클러스터를 시각화한 자료이다.

 
OS: Ubuntu 20.04.6 LTS
Kernel: 5.4.0-163-generic
K8s Version: 1.28.2
CRI: Containerd 1.6.25
CNI: Calico 3.26.1
 
Calico 이전 Flannel을 구성하다가, 안됐던 오류는 컨테이너 포트를 잘못 봐서 밀어버렸는데, 이 부분도 Vagrantfile이 남아있으니 다음에는 Flannel로 구성하여 시도해봐야겠다.
 
쿠버네티스의 각 컴포넌트에 대한 이해도를 더 올리기 위해서 kubeadm 없이 쿠버네티스 클러스터를 구축하는 방법과 나름의 Script를 작성해보는 것을 도전할 계획이다.
 
추가로, 네트워크에 대한 공부를 진행해야겠다. 배울건 참 많은 듯 하다.
 
이번 클러스터 구축에 사용한 Vagrantfile은 아래이다.

더보기
$pre_install = <<-SCRIPT
  echo ">>>> pre-install <<<<<<"
  echo 'root:test1234' | sudo chpasswd
  sudo echo "192.168.1.100 master" >> /etc/hosts
  sudo echo "192.168.1.101 worker1" >> /etc/hosts
  sudo echo "192.168.1.102 worker2" >> /etc/hosts
  sudo sysctl net.ipv4.ip_forward=1
  sudo modprobe br_netfilter
  sudo swapoff -a
  
  echo ">>>> Install Containerd <<<<<<"
  sudo apt-get update
  sudo apt-get install ca-certificates curl gnupg -y
  sudo install -m 0755 -d /etc/apt/keyrings
  sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  sudo chmod a+r /etc/apt/keyrings/docker.gpg
  sudo echo \
    "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
    $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  sudo apt-get update
  sudo apt-get install containerd.io
  sudo echo "" > /etc/containerd/config.toml
  sudo systemctl restart containerd

  echo ">>>> Install K8s Component <<<<<<"
  sudo apt-get install -y apt-transport-https
  sudo curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
  echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
  sudo apt-get update
  sudo apt-get install -y kubelet kubeadm kubectl
  sudo apt-mark hold kubelet kubeadm kubectl
SCRIPT

$mater_config = <<-SCRIPT
  echo ">>>> Master Node Config <<<<<<"
  sudo ssh-keyscan worker1 >> ~/.ssh/known_hosts
  sudo ssh-keyscan worker2 >> ~/.ssh/known_hosts
  sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address 192.168.1.100 2>&1 | tee /root/kubeadm_init_output.txt
  sudo mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config
  export KUBECONFIG=/etc/kubernetes/admin.conf
SCRIPT


Vagrant.configure("2") do |config|
  # Master 노드 설정
  config.vm.define "master" do |master|
    master.vm.box = "generic/ubuntu2004"
    master.vm.network "private_network", ip: "192.168.1.100"
    master.vm.provider "vmware_desktop" do |v|
      v.vmx['displayname'] = "Master"
      v.gui = true 
      v.memory = 6144 # 6GB
      v.cpus = 3
    end
    master.vm.hostname = "master"
    master.vm.provision "shell", inline: $pre_install
    master.vm.provision "shell", inline: $mater_config
  end

  # Worker 노드 설정
  (1..2).each do |i|
    config.vm.define "worker#{i}" do |worker|
      worker.vm.box = "generic/ubuntu2004"
      worker.vm.network "private_network", ip: "192.168.1.10#{i}"
      worker.vm.provider "vmware_desktop" do |v|
        v.vmx['displayname'] = "Worker#{i}"
        v.gui = true 
        v.memory = 4096
        v.cpus = 2
      end
      worker.vm.hostname = "worker#{i}"
      worker.vm.provision "shell", inline: $pre_install
    end
  end
end

트러블 슈팅 및 참고 자료

GPG error: https://packages.cloud.google.com/apt kubernetes-xenial InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY B53DC80D13EDEF05
 

Cannot install kubectl on Ubuntu - GPG Error

Hi I'm trying to install kubectl following the native package install instructions on the official site, but I get the following error when I try to update apt package list before installing kubect...

serverfault.com

 

CRI v1 runtime API is not implemented for endpoint \"unix:///var/run/containerd/containerd.sock\": rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"

 

 

validate service connection: CRI v1 runtime API is not implemented for endpoint · containerd/containerd · Discussion #8033

Description [mhyuser@10-234-42-14 ~]$ sudo kubeadm init [init] Using Kubernetes version: v1.26.1 [preflight] Running pre-flight checks [WARNING Hostname]: hostname "10-234-42-14" could not be reach...

github.com

/proc/sys/net/bridge/bridge-nf-call-iptables does not exist

 

 

kubeadm 시 bridge-nf-call-iptables does not exist

kubeadm init 시 아래와 같이 /proc/sys/net/bridge/bridge-nf-call-iptables does not exist 라는 에러 메시지가 나오는 경우가 있다. 이럴 경우 sudo modprobe br_netfilter 명령 후에 kubeadm init 명령을 실행 시켜 준다.

shonm.tistory.com

container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized

> CNI 구성으로 해결

Error registering network: failed to acquire lease: node "worker1" pod cidr not assigned

Error registering network: failed to acquire lease: node "worker2" pod cidr not assigned

> Flannel 사용 시 Pod CIDR 지정 필요. `kubeadm init --pod-network-cidr=10.244.0.0/16`으로 해결
 

728x90
반응형