AOC55

Cloud, Devops, Backend, Kubernetes, Openstack, ...

Cloud/kubernetes (k8s)

k8s :: kata container (v3) 설치 해보기 with k8s - #2

aoc55.soft@gmail.com 2025. 8. 20. 00:18

 

#2 :: kubernetes 와 kata 연동하기


이전 편에서 kata runtime과 containerd 를 설치해서 직접 kata 기반의 Container를 만들어 보았고, 이제 kubernetes 레벨에서 kata 기반의 Pod를 만들어본다.

이전편 >> https://aoc55.tistory.com/72

2-0 :: 목표 및 실습 환경

목표

  • 앞에서까지, containerd 를 통해서 kata를 기반 Container 직접 생성했다면,
  • 이제는 한단계 더 나아가 Container Orchestrator 인 kubernetes 를 통해서 kata 기반의 Pod 생성하기 목표.

구조

  • kubernetes의 Control Plane을 통해서 => Pod 생성 요청
  • 이후 스케줄러의 Pod가 생성될 Worker Node가 선정되면, 이후 해당 Worker Node에서 아래와 같이 흐른다.

  

이를 위해 대략 다음과 같이 진행한다.

  1. kubespray 통해 Control Plane으로만 구성된 k8s Cluster 를 우선 생성한다.
  2. 그리고 이전 과정에서 kata-runtime 을 설치한 Ubuntu Host를 k8s의 Worker Node로 직접 join 한다.
  3. 이후 kubernetes 통해서, 해당 Worker Node 위에서 kata 기반의 Pod가 정상 생성 되는지 확인한다.

2-1 :: kubespray 통한 k8s Cluster 생성

신규 kubernetes Cluster 구성을 위해서 kubespray를 활용한다. (물론 꼭 kubespary 뿐만 아니라, kubeadm 통한 직접 설치 방식 등도 가능하다!)

kubespary 준비

먼저 git 으로 kubespary 코드를 clone.
이후 안정적인 설치를 위해 kubespary의 release 버전으로 설치를 위해 checkout 을 수행.

git clone https://github.com/kubernetes-sigs/kubespray.git kubespary
cd kubespary
git checkout v2.27.1

inventory 파일 작성

k8s Cluster 설치를 위한 ansible 기반의 inventory 파일을 작성.

# 미리 정의된 샘플 인벤토리를 복사
cp -r inventory/sample/ inventory/kata-cluster
# vim kubespary/inventory/kata-cluster/inventory.ini 

[kube_control_plane]
k8s-control1    ansible_host=172.16.30.11
k8s-control2    ansible_host=172.16.30.12
k8s-control3    ansible_host=172.16.30.13

[etcd:children]
kube_control_plane

[kube_node]
# kata-worker1     ansible_host=172.16.30.31
  • 단, worker node(kata-worker1)의 경우 아래에서 kubeadm 통해서 수동으로 설치 및 join 할 예정이기에 해당 kubespary inventory 내에서는 주석처리한다.

k8s cluster 주요 변수 설정

kubespary/inventory/kata-cluster/...

ex. Cluster 구성 시, kubespary 통해서 CNI는 설치하지 않을 예정이라 "비활성화" 설정.

# vim kubespary/inventory/kata-cluster/group_vars/k8s_cluster/k8s-cluster.yml

# ...
kube_network_plugin: none
# ...
  • 아래에 별도로 따로 CNI 설치 할 예정.

k8s cluster 구성을 위한 playbook 수행

(ansible) playbook 수행을 위해 가상환경(venv)를 만들고 필요 패키지를 설치한다.

cd kubespary/

# venv 생성
python3 -m venv .venv
source .venv/bin/activate

# 사전 의존 패키지 설치
pip3 install -r requirements.txt

이후 Cluster 구성을 위한 "cluster" Playbook 수행

# cluster playbook 수행
ansible-playbook -i inventory/kata-cluster/inventory.ini --become cluster.yml 

생성한 k8s cluster의 kube-config 추출

playbook 이 성공적으로 끝났다면 Cluster 구성이 완료된 것이다. (CNI 설치 제외)

직전에 Cluster 구성을 위한 Playbook을 control node "내"에서가 아닌, 별도의 deploy node에서 수행함.
따라서 deploy node에서 Cluster에 접근 (ex. kubectl...) 하기 위해, control node 1번 내 kubeconfig 를 추출한다.
(만약 playbook을 control node '내'에서 직접 수행 하였을 경우에는 불필요)

rsync -e "ssh" \
      --rsync-path="sudo rsync" \
      -avz root@172.16.30.11:/root/.kube/config "${HOME}/.kube/config"
sed -i 's@server.*@server: https://172.16.30.11:6443@g' "${HOME}/.kube/config"

이후 deploy node 에서 kubectl get nodes 를 통해 정상적으로 k8s Cluster와 통신이 되는지 확인.

kubectl get node
# ---
NAME           STATUS     ROLES           AGE   VERSION
k8s-control1   NotReady   control-plane   19m   v1.31.9
k8s-control2   NotReady   control-plane   18m   v1.31.9
k8s-control3   NotReady   control-plane   18m   v1.31.9
  • CNI를 설치하기 이전임으로, STATUS는 NotReady 상태

2-2 :: CNI (kube-ovn) 설치

만든 kubernetes Cluster 의 CNI를 구성하기 위해, kube-ovn 을 설치.
(CNI로kube-ovn을 사용하는 이유는 해당 주제와는 무관한 다른 모종의 이유로 선정한 것으로, 아마도 다른 CNI를 사용해도 무관할 듯하다.)

kube-ovn 설치 스크립트 다운로드

kube-ovn 의 경우 helm을 통해 정식으로 설치할 수 있으나, 이번 실습에서 빠른 & 간단 설치를 위해 제공되는 "스크립트"로 한번에 설치함.

wget https://raw.githubusercontent.com/kubeovn/kube-ovn/refs/tags/v1.14.5/dist/images/install.sh 
  • kube-ovn 1.14.5 설치 스크립트 다운로드

(필요 시) script 내 주요부분 수정

# vim install.sh 

# ...
POD_CIDR="10.16.0.0/16" # Do NOT overlap with NODE/SVC/JOIN CIDR
POD_GATEWAY="10.16.0.1"
SVC_CIDR="10.96.0.0/12" # Do NOT overlap with NODE/POD/JOIN CIDR
JOIN_CIDR="100.64.0.0/16" # Do NOT overlap with NODE/POD/SVC CIDR
# ...
  • ex. Pod, Cluster IP 등의 대역을 확인 및 설정가능.
  • 만약 별도의 이유가 없으면, 초기값 그대로 두고 진행.

kube-ovn 설치 및 확인

위에서 다운로드 받은 설치 스크립트로 kube-ovn 설치.

 bash install.sh 

CNI 설치가 정상적으로 끝났는지 확인하자.

kubectl get nodes
# ---
NAME           STATUS   ROLES           AGE   VERSION
k8s-control1   Ready    control-plane   21m   v1.31.9
k8s-control2   Ready    control-plane   21m   v1.31.9
k8s-control3   Ready    control-plane   21m   v1.31.9
  • 이제 각 Node의 Status가 Ready 상태가 됨.

여기까지 수행함으로서 본격적으로 kata Container를 실행하기 위한, 사전 k8s cluster 구성완료.

2-3 :: kata container 기반의 k8s Worker Node로 수동 구성

이전 과정에서 진행한 kata runtime이 설치된 Ubuntu Host를 =>  k8s cluster에 "worker node"로 추가.

Node 사전설정

Worker Node로 Join 작업을 진행하기 전에, 필요한 OS 설정 등을 진행한다.

물론 추가적인 커널 파라미터 세팅 등이 반드시 이루어져하나, 이번 실습 목적 자체가 kata Pod가 생성이 가능한지만 보는 것이기에 "최대한 간단하게" 수행.

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables=1
net.ipv4.ip_forward = 1
EOF

sudo sysctl --system # 즉시 적용
  • 패킷 포워딩 활성화
sudo swapoff -a && sudo sed -i '/swap/s/^/#/' /etc/fstab
  • swap off 해제
sudo apt-get update
sudo apt-get install -y ipvsadm
cat <<EOF | sudo tee /etc/modules-load.d/ipvs.conf
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
overlay
EOF
sudo modprobe br_netfilter
sudo modprobe ip_vs
sudo modprobe ip_vs_rr
sudo modprobe ip_vs_wrr
sudo modprobe ip_vs_sh
sudo modprobe nf_conntrack
sudo modprobe overlay
  • kube-proxy의 backend로 ipvs 사용

kubelet, kubeadm, kubectl 설치

해당 Node의 경우에는, 별도로 kubespary를 쓰지 않고 kubeadm 방식으로 join을 직접 진행한다.

apt update
apt install -y apt-transport-https ca-certificates curl gpg

# k8s 패키지 keyring 저장
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# k8s 패키지 저장소 등록
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# 설치 진행
apt update
apt install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

이후 kubelet 을 활성화 해준다.

systemctl enable kubelet.service
systemctl start kubelet.service

runc 추가 설치

앞서, 작업 대상 host에서 Containerd의 runtime 으로 kata 만 설치 및 기본 Runtime 으로 설정함.

하지만 현재 k8s Cluster에 구성된 CNI인 kube-ovn 의 경우, daemonset 기반으로 CNI 구성을 위한 Pod를 생성한다.

이때, 해당 Pod 역시 kata Runtime 기반으로 실행할 경우 hostpath 관련 오류 발생하면서 기동되지 않음.
물론 이와 관련해서 자세히 보면 해결할 방법이 있을 수 있으나, 금번 실습 목적에 맞게 우선 아래와 같이 runc를 추가로 설치.
(겸사겸사 한 worker node에서 2개의 runtime 이 모두 존재할 수 있는지도 확인!)

그리고 설치 이후에는 이를 Containerd 내에서 runc를 기본 Runtime으로 다시 바꿔주자.

위 사항이 반영된 그림으로 보면 아래와 같다.

 

 

runc 설치

wget https://github.com/opencontainers/runc/releases/download/v1.3.0/runc.amd64
install -m 755 runc.amd64 /usr/local/sbin/runc

containerd 내 runc 설정

runc 설치 이후, worker node 내에서 runc, kata Runtime 방식 모두 지원가능 하도록 추가 설정을 진행.
(사실 runc 관련 설정은 기본적으로 containerd 설정에 반영되어 있으므로, default runtime만 runc로 다시 설정)

containerd 설정

# vim /etc/containerd/config.toml
[plugins]

    [plugins."io.containerd.grpc.v1.cri"]

        [plugins."io.containerd.grpc.v1.cri".containerd]
            # default_runtime_name = "kata"
            default_runtime_name = "runc"
             [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
                 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
                [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
       SystemdCgroup = true
  • default runtime을 다시 runc 로 바꾸어 주었다.
  • 그리고 runc 에서 SystemdCgroup 활성화.

Containerd 재기동

systemctl daemon-reload
systemctl restart containerd
  • 확인 systemctl status containerd

Worker Node Join

이제 해당 Host를, 구성한 k8s cluster 내에 worker node로 join 하자.

Control Node에서 Join을 위한 token 발행

# Control node 에서 수행
kubeadm token create --print-join-command

# 출력 예시
kubeadm join 127.0.0.1:6443 --token qls8g6.t83c55c95yptlkvh --discovery-token-ca-cert-hash sha256:a06d648473860b2962e99c79d065b306b97b15b0a4447129dd9609afd9012d4f
  • 출력에서 127.0.0.1 부분은 이후 수행 시 실제 Control Node의 IP로 변경해서 수행한다.

Worker Node Join 수행

# Worker Node로 추가할 Host에서 수행
# Control Node의 IP로 변경해서 사용
kubeadm join 172.16.30.11:6443 --token qls8g6.t83c55c95yptlkvh --discovery-token-ca-cert-hash sha256:a06d648473860b2962e99c79d065b306b97b15b0a4447129dd9609afd9012d4f 
  • 복사한 명령어를 Join 을 진행할 실제 Host에서 수행한다.

(만약) 중간에 인증서 위치가 안 맞아서 join 이 안되는 경우 '임시'로 아래와 심볼릭 링크를 설정해준다.

mkdir /etc/kubernetes/ssl/
ln -s /etc/kubernetes/pki/ca.crt /etc/kubernetes/ssl/ca.crt

Worker Node Join - 확인

정상적으로 Join 이 진행되었다면, 이후 CNI를 위한 Pod들이 자동으로 올라오면서 CNI 구성까지 진행된다.
이후 모든 요소들이 올라오면 아래와 같이 Node의 상태가 Ready 상태인지 확인한다.

kubectl get nodes

# -----
NAME           STATUS   ROLES           AGE   VERSION
k8s-control1   Ready    control-plane   34m   v1.31.9
k8s-control2   Ready    control-plane   34m   v1.31.9
k8s-control3   Ready    control-plane   34m   v1.31.9
kata-worker1   Ready    <none>          82s   v1.31.12. # ---> 신규 추가

2-4 :: kata 기반의 Pod 생성해보기

k8s Cluster에 Join 까지 완료하였으니, 이제 kubernetes를 통해 kata 기반의 Pod를 생성해보자.

kata 전용 Runtime Class 선언

kubenetetes 에서 Pod 생성 시, 사용할 runtime을 지정하기 위한 (kata) RuntimeClass 를 선언.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata
handler: kata
  • 이후 kubectl apply -f ... 로 선언한다.

kata 기반 Pod 생성하기

이제 정말 Pod를 생성하자. 단 생성 시에 아래와 같이 runtimeClassName 을 지정한다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-kata
spec:
  nodeName: kata-worker1  # 신규 추가한 Node
  runtimeClassName: kata  # kata 지정
  containers:
  - name: nginx
    image: nginx
  • 이후 kubectl apply -f ... 로 선언한다.

Pod 생성 확인

아래와 같이 kata container 기반의 Pod가 정상 생성 되었음을 확인.

kubectl get pods -o wide

# ---
NAME         READY   STATUS    RESTARTS   AGE    IP          NODE           NOMINATED NODE   READINESS GATES
nginx-kata   1/1     Running   0          3m9s   10.16.0.9   kata-worker1   <none>           <none>

이후 Worker Node(Host) 관점에서 Process 레벨로 확인하자.

ps aux
  • kata-worker1 Node에서 수행
root       65638  3.2  0.2  70752 24064 ?        Sl   23:52   0:00 /usr/local/bin/containerd-shim-kata-v2 -id 6e977248867557095fb99892294ac1c4580e06e635dc3baca6df97f085927677 -namespace k8s.io -address /run/containerd/containerd.sock -publish-binary /usr/local/bin/containerd
root       65651  0.0  0.0 2306624 4224 ?        Sl   23:52   0:00 /usr/libexec/virtiofsd --socket-path virtiofsd.sock --shared-dir /run/kata-containers/shared/sandboxes/6e977248867557095fb99892294ac1c4580e06e635dc3baca6df97f085927677/ro --cache auto --sandbox none --seccomp none --thread-pool-size=1 -o announce_submounts
root       65654 97.4  2.1 2941140 170188 ?      Sl   23:52   0:01 /usr/bin/qemu-system-x86_64 -name sandbox-6e977248867557095fb99892294ac1c4580e06e635dc3baca6df97f085927677 -kernel /usr/share/kata-containers/vmlinux.container -append reboot=k panic=1 systemd.unit=kata-containers.target systemd.mask=systemd-networkd.service root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro ro rootfstype=ext4 cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1 selinux=0 -
  • kata 기반으로 실행되었기에, contained-shim-kata-v2, viriofsd, qemu-.. 3개의 프로세스가 Host에서 실행된 것을 확인.

즉, kubernetes Level에서, kata 기반의 Pod 생성을 완료하였다!

(+) runc 기반 Pod 도 생성해보기

혹시 모르니, runc 기반으로도 Pod를 생성해본다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx-runc
spec:
  nodeName: kata-worker1  # 신규 추가한 Node
  # 별도 runtimeClass 미지정
  containers:
  - name: nginx
    image: nginx
  • default가 runc 기반임으로, 별도의 runtimeClass는 지정하지 않음.
kubectl get pods -o wide

# ---
NAME         READY   STATUS    RESTARTS   AGE    IP           NODE           NOMINATED NODE   READINESS GATES
nginx-kata   1/1     Running   0          3m3s   10.16.0.10   kata-worker1   <none>           <none>
nginx-runc   1/1     Running   0          30s    10.16.0.11   kata-worker1   <none>           <none>
  • 역시 정상 생성되었음을 확인할 수 있다.

이를 통해 하나의 worker node(containerd) 에서, runc와 kata runtime 이 각각 존재할 수 있음을 확인할 수 있다.

역시 실제 Host 에서 Process 관점에서 조회해본다.

ps aux
  • 역시 kata-worker1 Node에서 수행
root       71901  0.0  0.1 1238360 15332 ?       Sl   23:54   0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 7ac6791ddd34560db31db2c1c62c7428387b2bfdcfc78cadebb0363bcdc48b3b -address /run/containerd/containerd.sock
65535      71925  0.0  0.0    996   640 ?        Ss   23:54   0:00 /pause
root       72001  0.0  0.0  11472  7552 ?        Ss   23:54   0:00 nginx: master process nginx -g daemon off;
message+   72036  0.0  0.0  11936  3052 ?        S    23:54   0:00 nginx: worker process
message+   72037  0.0  0.0  11936  3052 ?        S    23:54   0:00 nginx: worker process
message+   72038  0.0  0.0  11936  3052 ?        S    23:54   0:00 nginx: worker process
message+   72039  0.0  0.0  11936  3052 ?        S    23:54   0:00 nginx: worker process
  • kata 와 달리, containerd-shim-runc-v2pause process 등을 확인할 수 있다!

 

끝!