kind
Kubernetes in Docker(Kind)는 로컬 개발 환경에서 Kubernetes 클러스터를 쉽게 실행할 수 있게 해주는 도구입니다.
Docker 컨테이너를 사용하여 전체 VM보다 적은 리소스 사용하며, 실제 Kubernetes와 유사하게 사용할 수 있습니다.
또 여러 Kubernetes 버전 테스트 가능합니다.
단, LB와 영구 볼륨 사용에 제약이 있기도 합니다.
아래와 같은 목적으로 주로 사용됩니다.
- 로컬 개발 환경에서 Kubernetes 애플리케이션 테스트
- CI/CD 파이프라인에서 Kubernetes 배포 테스트
- Kubernetes 관련 도구나 오퍼레이터 개발 및 테스트
퍼블릭 클라우드의 managed k8s 상품을 사용하기에 비용 부담이 있고,
로컬에서 가상 환경을 통해 설치하는 것이 익숙하지 않다면 k8s 공부와 테스트에 좋은 선택이 될 수 있을 것 같습니다.
Kind 설치
※ 작성자의 PC 환경은 M1 Mac pro로 mac 환경을 기준으로 작성하였습니다.
사전 설치 : Docker Desktop을 설치합니다.
MAC m 시리즈에서 Docker Desktop을 대체하여 유용하게 사용할 수 있는 OrbStack가 있습니다.
https://mokpolar.tistory.com/61
## kind 설치 ##
$ brew install kind
$ kind --version
## kubectl 설치 ##
$ brew install kubernetes-cli
$ kubectl version --client=true
## 이후 실습에 필요한 tool 설치 ##
$ brew install helm
$ brew install --cask wireshark
$ brew install krew
$ brew install kube-ps1
$ brew install kubectx
$ brew install kubecolor
## docker 프로세스 확인
$ docker ps
## kind를 이용해 cluster 생성
$ kind create clusters
$ kind get nodes
$ kubectl cluster-info
## docker에서 cluster 컨테이너 running 확인
$ docker ps
docker ps로 확인해 보면 컨테이너로 node가 기동되어 있는 것을 확인할 수 있습니다.
nginx pod 하나를 배포해보면 별 특이 사항 없이 잘 배포되는 것을 확인할 수 있습니다.
$ k run nginx --image=nginx:alpine
control plan에는 일반 Pod가 배포되지 않도록 설정되어 있지만, 아래서 확인할 수 있듯 taint가 설정되어 있지 않으므로
control plan에 pod를 배포할 수 있습니다.
Name: kind-control-plane
Roles: control-plane
Labels: beta.kubernetes.io/arch=arm64
beta.kubernetes.io/os=linux
kubernetes.io/arch=arm64
kubernetes.io/hostname=kind-control-plane
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Fri, 06 Sep 2024 21:21:52 +0900
Taints: <none>
Unschedulable: false
Kind 동작 원리
- kind는 docker 컨테이너를 사용하여 k8s를 시뮬레이션합니다.
- 각 node는 결국 하나의 docker 컨테이너라고 보아야 합니다.
- kind create cluster 명령어가 실행되면, 노드 이미지를 바탕으로 k8s 컨테이너가 생성됩니다.
- 당연히 컨테이너가 설치되는 동안 내부에서는 k9s 컴포넌트도 설치되고 실행됩니다.
- kind는 docker의 네트워크를 사용하여 노드 간 통신을 수행합니다.
- 기본으로 사용되는 CNI는 kindnet이라는 이름의 경량화된 네트워크 인터페이스를 사용합니다.
kind가 배포되면 docker network에 kind라는 이름으로 배포됩니다.
배포된 network에 할다된 대역으로 내부 ip가 배포됩니다.
Worker node 배포
cat << EOT > kind-2node.yaml
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOT
$ kind create cluster --config kind-2node.yaml --name myk8s
Joining worker node를 통해 control plan에 조인된 것을 확인할 수 있습니다.
local-path 라는 StorageClass 가 설치되고, local-path 는 노드의 로컬 저장소를 활용합니다.
로컬 호스트의 path 를 지정할 필요 없이 local-path provisioner 이 볼륨을 관리합니다.
생성된 Control-plan과 worker node에서 여러 정보들을 확인할 수 있습니다.
- control-plan
## Static Pod manifest
$ docker exec -it myk8s-control-plane grep staticPodPath /var/lib/kubelet/config.yaml
$ docker exec -it myk8s-control-plane tree /etc/kubernetes/manifests/
/etc/kubernetes/manifests/
|-- etcd.yaml
|-- kube-apiserver.yaml
|-- kube-controller-manager.yaml
`-- kube-scheduler.yaml
- worker node
worker node에서 동작하고 있는 container도 조회할 수 있습니다.
## worker node iptables 정책 확인
$ iptables -t filter -S
$ iptables -t nat -S
$ iptables -t mangle -S
- pod 생성 테스트
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
$ k create -f 2pod.yaml
$ k get pod -o wide
이전에 control-plan만 생성했을 때와 달리 taint가 설정되어 있고, taint 정책에 따라 worker node에 pod가 배포되는 것을 확인할 수 있습니다.
컨트롤플레인 컨테이너 정보 확인 : 아래 “Node” Container 은 ‘myk8s-control-plane’ 컨테이너 (그림에 빨간색) 입니다
해당 “Node” 컨테이너 내부에 쿠버네티스 관련 파드(컨테이너)가 기동되는 구조 → Docker in Docker (DinD)
Control plan 내부 뒤적뒤적 해보겠습니다.
$ docker exec -it myk8s-control-plane bash
$ arch
kind의 경우 크로스 플랫폼 이미지를 제공해서 host의 cpu 아키텍처에 따라 그에 맞는 버전으로 자동 설치합니다.
ex)
arch
aarch64 # mac m1~m3
혹은
x86_64 # intel/호환 cpu
네트워크 정보도 확인할 수 있습니다.
프로세스 리스트도 확인할 수 있고, 컨테이너 런타임의 동작 정보도 확인해 볼 수 있습니다.
docker in docker 구조이기 때문에 호스트이기 때문에 control-plan 내부의 컨테이너는 조회할 수 없습니다.
- Multi node Cluster 생성
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 31000
hostPort: 31000
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
protocol: tcp # Optional, defaults to tcp
- containerPort: 31001
hostPort: 31001
worker node 내부에 외부에서 접근해야하는 포트들이 있을 경우 extraPortMappings를 사용하면 외부에서 접근할 수 있도록
port forward가 설정됩니다.
$ kind create cluster --config kind-2node.yaml --name myk8s
- kube-ops-view 설치
## helm chart 추가 및 설치
$ helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
$ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=31000 --set env.TZ="Asia/Seoul" --namespace kube-system
## 설치 확인
$ kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
웹 페이지로 접속해보겠습니다.
$ echo -e "KUBE-OPS-VIEW URL = http://localhost:31000/#scale=2"
KUBE-OPS-VIEW URL = http://localhost:31000/#scale=2
파드 & PAUSE 컨테이너
💡 파드는 1개 이상의 컨테이너로 구성된 컨테이너의 집합이며,
PAUSE 컨테이너가 Network / IPC / UTS 네임스페이스를 생성하고 유지 / 공유합니다.
파드를 이야기 하기 전에 CRI 등장 배경에 대해 간략히 나열하겠습니다. [Old_docs]
1. 초기 Kubernetes는 Docker에 의존도가 굉장히 높았음
2. 여러 컨테이너 런타임 (runc)가 출시 (rkt, containerd, cri-o)
3. 다른 runc를 도입하려면 컨테이너 관리 기능을 가지고 있던 kubelet의 코드를 수정하고 재컴파일 해야했음
4. 이로 인해 확장성에 대한 문제 뿐만 아니라 유지 보수 측면에서도 꽤나 크리티컬한 문제를 갖고 있었음
5. 이 문제를 해결하고자, 표준화 인터페이스의 필요성이 있었고, 그 니즈에 따라 CRI 개발을 진행하게 됨
6. CRI는 프로토콜 버퍼와 gRPC API, 라이브러리로 구성되어 있는 플로그인 형태의 인터페이스
7. 새로운 runc로 교체해야 하는 경우 Kubelet을 재컴파일할 필요가 없어짐으로 이전 문제들이 해소됨
8. 이 플러그인으로 인해 Kubernetes 1.20부터 Docker 지원이 deprecated 되었음
[POD]
pod는 1개 이상의 컨테이너를 가질 수 있으나, pod 삭제 시 내부의 모든 컨테이너가 삭제됩니다.
아래 그림에서는 App container가 2개로 표현되었으나, Sidecar 패턴을 위한 컨테이너일 수도 있습니다.
그림에서 Pause 컨테이너는 일반적으로 describe와 같은 명령어를 통해는 존재를 확인할 수 없으며,
worker node 내부에서 crictl 명령어를 통해 직접 확인이 가능합니다.
Pause 컨테이너는 모든 파드가 생성될 때 함께 생성됩니다.
그림에는 network namespace만 공유하는 그림이지만, IPC, UTS namespace도 공유합니다.
[예제 1]
Step 1) 실습 환경 구성 (kind multi-node cluster)
위에서 수행했던 것과 동일하게 추가 프로그램과 kube-ops-view까지 설치해줍니다.
# two node (one workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
extraPortMappings:
- containerPort: 31000
hostPort: 31000
listenAddress: "0.0.0.0" # Optional, defaults to "0.0.0.0"
protocol: tcp # Optional, defaults to tcp
- containerPort: 31001
hostPort: 31001
Step 2) 파드 배포 및 격리 확인
## worker node shell 진입
$ docker exec -it myk8s-worker bash
실행 서비스 확인
$ systemctl list-unit-files | grep 'enabled enabled'
# 실행 중인 전체 프로세스 트리
$ pstree -anl
# pid 1번과 pause 비교
$ lsns -p 1
$ lsns -p {pause container pid}
해당 파드에 pause 컨테이너는 호스트NS와 다른 5개의 NS를 가지며, mnt/pid 는 pasue 자신만 사용, net/uts/ipc는 app 컨테이너를 위해서 먼저 생성해둡니다.
또, app 컨테이너(metrics-server)는 호스트NS와 다른 6개의 NS를 가지며, mnt/pid/cgroup 는 자신만 사용, net/uts/ipc는 pause 컨테이너가 생성한 것을 공유 사용합니다.
[예제 2]
Step 1)
Container가 2개있는 pod를 생성 합니다.
Step 2) 컨테이너 내부 조회
두 컨테이너의 ip를 확인해보면 동일한 것을 확인할 수 있습니다.
ip가 같은 이유는 network namespace를 공유해서 사용하기 때문에 동일한 ip가 할당되는 것입니다.
또 netshoot 컨테이너에서 포트와 프로세스를 조회하면 80 port는 Listen되어 있지만,
80을 사용하는 프로세스는 확인되지 않습니다.
실제로 80포트는 nginx container에서 사용하고 있고,
netshoot에서 curl로 80포트에 접근 시 nginx welcome 페이지에 접속되는 것을 알 수 있습니다.
이러한 동작이 가능한 이유는 위에 첨부한 그림과 같이 network namespace를 공유해 사용하고 있기 때문입니다.
Step 3) 네임스페이스 격리 확인
# worker 노드 진입
$ docker exec -it myk8s-worker bash
# 워커 노드에서 컨테이너 프로세스 정보 확인
$ ps -ef | grep 'nginx -g' | grep -v grep
root 1213 1137 0 14:34 ? 00:00:00 nginx: master process nginx -g daemon off;
$ ps -ef | grep 'curl' | grep -v grep
root 1342 1137 0 14:34 ? 00:00:00 /bin/bash -c while true; do sleep 5; curl localhost; done
# 각각 프로세스를 변수에 지정
$ NGINXPID=$(ps -ef | grep 'nginx -g' | grep -v grep | awk '{print $2}')
$ echo $NGINXPID
$ NETSHPID=$(ps -ef | grep 'curl' | grep -v grep | awk '{print $2}')
$ echo $NETSHPID
생성한 단일 파드 내의 각각의 컨테이너의 네임스페이스 정보 확인
time, user는 host와 공유하고, mnt, uts, pid는 컨테이너 별로 격리합니다.
ipc, uts, net 네임스페이스는 컨테이너 . 간공유하는 것을 확인할 수 있습니다.
'Cloud > Kubernetes' 카테고리의 다른 글
[KANS] Calico 네트워크 모드 (1) | 2024.09.15 |
---|---|
[KANS] Calico CNI 기본 통신 (0) | 2024.09.14 |
[KANS] Flannel CNI (2) | 2024.09.08 |
CKAD 시험 후기 (0) | 2024.07.17 |
CKA 시험 후기 (0) | 2024.07.17 |