본문 바로가기
스터디 이야기/Kubernetes Advanced Networking Study

[KANS] Docker In Docker - Kind

by lakescript 2024. 9. 5.
더보기

이 스터디는 CloudNet@에서 진행하는 KANS 스터디를 참여하면서 공부하는 내용을 기록하는 블로그 포스팅입니다.

CloudNet@에서 제공해주는 자료들을 바탕으로 작성되었습니다.

 

Kind

 

 

 

kind(Kubernetes in Docker)는 Docker Conatainer "Node"를 사용하여 Local 환경에 Kubernetes Cluster를 실행하는 도구입니다. 이때, kubeadm을 사용하여 Cluster Node를 구성합니다. 또한, Kubernetes를 테스트 해야 할 때 사용하기에 적절하며, 특히 multi-node를 지원하기 때문에 HA등을 테스트할 수 있습니다.

Host의 Docker안에 Node Container역할을 하는 Docker를 또 띄어서 구성합니다. 하지만 Host에서 docker ps 명령어를 실행했을 때 Node Container 역할을 하는 Docker가 보이지 않습니다. 

 

 

Kind 설치

공식문서에 따르면 Kind 사용하는 Docker Engine 리소스에는 최소 vCPU 4, Memory 8GB 할당을 권고합니다.

 

Docker Desktop 설치

공식문서에서 설치를 진행합니다.

 

 

kind 설치

brew install kind

간단하게 brew를 통해 kind를 설치합니다.

 

kubectl 설치

brew install kubernetes-cli

 

helm 설치

brew install helm

 

Wireshark 설치

brew install --cask wireshark

캡처된 패킷 확인을 확인하기 위해 wireshark도 설치합니다.

 

Kind 실행

kind를 통해 cluster 생성

kind create cluster

kind create 명령어를 통해 cluster를 생성합니다. 이때 뒤에 --name을 입력하지 않으면 기본값(kind-kind)으로 생성됩니다.

 

cluster 생성 확인

kind get clusters

 

 

cluster 정보가 조회되지 않을 때 !

export KUBECONFIG=~/.kube/config-kind

cluster의 정보가 조회가 되지 않다면 위의 명령어로 kubeconfig 파일의 경로를 수정해주세요.

 

cat ~/.kube/config-kind

config-kind 파일의  내용을 살펴보면 cluster의 config 값들이 입력되어 있습니다. 

 

 

node 확인

kind get nodes

 

kubectl get nodes -o wide

 

cluster 정보 확인

kubectl cluster-info

 

pod 확인

kubectl get pod -A

 

docker ps를 통해 container 확인

docker ps

docker가 설치된 host에서 docker ps 명령어를 실행하면 cluster에서 control-plane 역할을 하는 컨테이너(노드) 1대가 실행되고 있는 것을 확인할 수 있습니다.

Pod 배포

kubectl run nginx --image=nginx:alpine

현재 control-plane node 밖에 없는 상태에서 pod를 배포하게 되면 어떻게 될까요? 

control-plane에 배포되게 됩니다. 

 

기본적으로 control plane에는 pod를 띄울 수 없습니다. 하지만 왜 kind에서는 control-plane에 배포가 되었을까요?

 

kubectl describe node ${controle-plane-node} | grep Taints

기본적으로 K8s에서 contol-plane node의 명세를 살펴보면 taints가 설정되어있습니다. 

Taints:             node-role.kubernetes.io/master:NoSchedule

하지만 kind의 경우는 taints가 설정되어있지 않아 pod가 control-plane에 배포가 가능합니다.

 

Kind 삭제

kind cluster 삭제

간단하게 kind를 통해 cluster를 배포한 후 설정을 살펴보았습니다. 다음 실습을 위해 해당 cluster는 삭제합니다. 

kind delete cluster

이 명령어 역시 뒤에 --name 옵션을 붙일 수 있는데, 없기 때문에 기본값인 kind-kind가 할당됩니다. 

 

config-kind 확인

 

아까와 다르게 안에 설정되어있던 값들이 삭제되어있는 것을 확인하실 수 있습니다.

 

 

 

Docker In Docker 원리

https://kccnceu2024.sched.com/event/1YhhY

 

kind는 kubeadm으로 cluster를 생성한 후 workder node역할을 하는 container를 join시키는 것이 기본 아키텍처입니다. 실제로는 위에 그림에서 보이시는 것 처럼 master-node(control-plane) 1대, worker-node 2대가 docker로 띄어져 있습니다. 맨 아래의 Docker가 host에 설치된 docker daemon으로 보시면 됩니다.

Docker Daemon(dockerd)은 Docker의 핵심 백그라운드 프로세스으로, 컨테이너를 관리하고 동작시키는 역할을 담당합니다. 특히, Container의 생성, 실행, 중지 및 삭제 등과 같은 Docker 엔진의 주요 기능을 수행하는 중심적인 구성 요소입니다.

 

cluster 배포 전 docker 프로세스 확인

docker ps

 

kind를 통해 cluster를 배포하기 전 docker ps를 통해 docker process를 확인해보면, 현재는 아무것도 보이지 않습니다.

Docker network 확인

docker network ls

docker network 명령어를 통해 docker network를 확인해보겠습니다.

kind는 별도 Docker Network를 생성 후 사용하는 것을 확인하실 수 있습니다.

docker inspect kind | jq

 

(기본값 172.18.0.0/16)

 

node를 할당하는 cluster yaml 파일 생성

cat << EOT > kind-2node.yaml 
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOT

control-plane과 worker node 역할을 하는 node를 각각 할당한 cluster를 생성하는 yaml파일을 작성합니다.

 

kind를 이용하여 cluster 생성

kind create cluster --config kind-2node.yaml --name myk8s

이번엔 myk8s라는 이름을 넣어서 cluster를 생성해보겠습니다.

위에서 yaml을 통해 workder node를 넣어주었기 때문에 Joining worker nodes라는 문구가 보입니다.

 

cluster 확인

kubectl cluster-info

cluster 정보를 보았을 때 60054 port로 control plane이 설정된 것을 확인할 수 있습니다. 근데 저 port가 누구를 가리키는지 한번 확인해보겠습니다.

 

node 확인

kind get nodes --name myk8s

일단 control-plane과 worker node가 잘 띄어져 있습니다.

 

Docker process들의 port-forwarding확인

docker ps

docker ps 명령어를 통해 docker로 띄어진 container process들의 목록을 확인해보겠습니다. 이때, PORTS쪽을 보시면 60054라는 host port가 control-plane역할을 하는 conatiner의 6443 port로 바인딩된 것을 확인하실 수 있습니다.

 

그럼 저 6443 port는 무엇일까요?

docker exec -it myk8s-control-plane ss -tnlp | grep 6443

exec 명령어를 통해 myk8s-control-plane Docker 컨테이너 내부에서 6443 port에 대한 네트워크 상태를 확인해보겠습니다.

control-plane의 kube-apiserver가 바인딩되어있는 것을 확인할 수 있습니다.

 

 

node의 상세 정보 확인

kubectl get nodes -o wide

-o wide 옵션을 붙여 node의 상세 정보를 확인해보도록 하겠습니다.

IP 목록을 확인하실 수 있고, Container-Runtime은 containerd를 사용하는 것을 확인하실 수 있습니다.

 

Pod의 상세 정보 확인

kubectl get po -o wide -A

 

이번엔 위와 마찬가지로 -o wide 옵션을 주어 pod의 상세 정보를 확인해보겠습니다.

CNI는 kindnet 사용하는 것을 확인하실 수 있습니다.

실습에 필요한 tool 설치

docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'
docker exec -it myk8s-worker sh -c 'apt update && apt install tree jq psmisc lsof wget bridge-utils tcpdump htop git nano -y'

 

 

Kind Cluster로 배포한 환경에서 K8s 환경 조사

static pod manifest 위치 찾기

보통 k8s에서 kube-apiserver, kube-contoller-manager, kube-scheduelr, etcd는 static pod 형태로 띄어집니다. 그렇기 때문에 Docker로 띄운 contol-plane에도 정상적으로 생성되어있는지 확인해보겠습니다.

docker exec -it myk8s-control-plane grep staticPodPath /var/lib/kubelet/config.yaml

exec 명령어를 통해 control-plane container 내부에 접속하여 config.yaml 파일에서 staticPodPath부분을 필터링해보겠습니다. (보통 staitc pod는 /etc/kubernetes/manifests/ 경로 하위에 생성되어 있습니다.)

static pod 정보 확인

docker exec -it myk8s-control-plane tree /etc/kubernetes/manifests/

 

정상적으로 /etc/kubernetes/manifests 경로에 생성되어있는 것을 확인하실 수 있습니다.

 

worker-node에는 없어요!

 

kubelet 확인

이번엔 worker-node에만 배포되어서 pod를 관리하는 kubelet에 대해 확인해보겠습니다.

docker exec -it myk8s-worker bash

exec 명령어를 통해 worker-node의 bash로 접근합니다.

systemctl status kubelet

kubelet 상태 확인를 위해 systemctl 명령어로 확인해보겠습니다.

정상적으로 active(running) 상태인 것을 확인하실 수 있습니다.

 

컨테이너 확인

crictl ps

crictl 명령어를 통해 worker-node 내부의 컨테니어의 목록을 확인해보겠습니다.

kindnet과 kube-proxy가 확인됩니다.

 

원래 container를 위해 사용했던 docker의 docekr ps도 한번 해보겠습니다.

docker ps

왜 docker ps는 안될까요? Docker는 k8s에서 지원하는 여러 컨테이너 런타임 중 하나입니다. 최근 K8s는 기본 container run time으로 Docker 대신 CRI-O나 containerd와 같은 ContainerRuntimeInterface(CRI) 호환 런타임을 더 많이 사용합니다.

 

 그렇기 때문에 공식문서를 참고해보면 docker를 사용하려면 설치를 해야 사용이 가능합니다.

 

tcp listen 포트 정보 확인

 

Pod 생성 및 확인

Pod 생성

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: netpod
spec:
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx-pod
    image: nginx:alpine
  terminationGracePeriodSeconds: 0
EOF

 

배포된 pod 확인

kubectl get po -o wide

 

이번엔 worker node에 배포된 것을 확인할 수 있습니다.

 

control plane의 Taints 확인

kubectl describe node myk8s-control-plane | grep Taints

worker node에 배포되었기 때문에 control plane에 taint가 설정되었는지 확인해보겠습니다.

NoScheule이라는 Taints가 설정되어있기 때문에 이제 Control plane에는 Pod가 배포되지 않습니다.

worker node는 Taints가 설정되어있지 않아 모든 pod 배포가 worker node에서 이루어집니다.

 

 

Control Plane Container 정보 확인

Docker 컨테이너 확인

docker inspect myk8s-control-plane | jq

inspect 명령어를 통해 myk8s-control-plane의 상세 정보를 확인해보겠습니다. 

 

다양한 정보들이 보여지지만 여기서 주의깊게 보셔야 하는 것은 Entrypoint에 있는 /sbin/init입니다. 

/sbin/init
리눅스 시스템에서 init 프로세스를 나타내며, 운영 체제 부팅 과정에서 실행되는 첫 번째 프로세스입니다. 이는 시스템에서 가장 기본적이고 중요한 프로세스로, 모든 다른 프로세스들의 부모 역할을 합니다. 간단히 말해, 시스템이 시작될 때 실행되는 첫 번째 프로세스이며, 시스템의 나머지 프로세스를 시작하고 관리하는 역할을 합니다.

 

 

Control Plane bash shell 접속

docker exec -it myk8s-control-plane bash

 

프로세스 확인

ps -ef

마치 하나의 리눅스처럼 프로세스가 생성되어 실행되고 있습니다.

 

 

컨테이터 런타임 정보 확인

systemctl status containerd

 

 

DinD 컨테이너 확인

crictl을 통해 Docker 안에서 Docker를 사용합니다.

crictl ps

 

728x90