[K8S Deploy] kind k8s

진웅·2026년 1월 10일

k8s deploy

목록 보기
3/20

[Kind] macOS 로컬 k8s 설치 가이드

  • 로컬 맥북(Mac) 환경에서 kind(Kubernetes IN Docker)를 이용해 멀티 노드 클러스터를 띄우고, 실제 네트워크와 구성 소개.

1. 사전 준비 (Pre-flight Check)

Kind는 도커 컨테이너를 노드처럼 쓰기 때문에 도커 데몬이 살아있는지 먼저 확인해야 한다.

# 도커 데몬 상태 및 실행 중인 컨테이너 확인
docker info
docker ps

2. 클러스터 생성 (Multi-node 구성)

설정 파일(Config)을 넣어서 Control Plane 1개 + Worker 1개로 구성한다.
특히 extraPortMappings 설정을 넣어줘야 나중에 NodePort 서비스 띄웠을 때 로컬(localhost)에서 접속 가능하다.

# kind-config.yaml 내용을 인라인으로 바로 적용해서 클러스터 생성
kind create cluster --name myk8s --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
  - containerPort: 30001
    hostPort: 30001
- role: worker
EOF

3. 설치 결과 1차 확인

클러스터가 떴으니 노드 리스트와 이미지를 확인해 본다.

# Kind가 다운로드 받은 노드 이미지 확인
docker images

# kind 명령어로 노드 목록 확인 (myk8s-control-plane, myk8s-worker)
kind get nodes --name myk8s

# 현재 컨텍스트 및 네임스페이스 확인 (kubectx/kubens 설치 시)
kubens default

4. 네트워크 심층 분석 (Network Deep Dive)

"로컬에서 어떻게 k8s에 붙는 걸까?"
Kind는 전용 도커 브리지 네트워크를 만들어서 그 안에서 노드(컨테이너)들을 묶는다.

# 도커 네트워크 리스트 확인 ('kind' 라는 네트워크가 생겼을 것임)
docker network ls

riverjin@gangjin-ung-ui-Macmini k8sDeploy % docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
09c6a26e9d6d   bridge    bridge    local
0cb0081feebe   host      host      local
468c485492a0   kind      bridge    local
1f0321e31b81   none      null      local

# kind 네트워크 상세 정보 확인 (서브넷 대역 확인용)
# -> docker desktop 기본값은 172.18.0.0/16, OrbStack 사용 시 192.168.97.0/24 등으로 다를 수 있음
docker inspect kind | jq



[
  {
    "Name": "kind",
    "Id": "468c485492a0cb548c5d14218b609d97d20ec668dd70a3040651a6989741d8c7",
    "Created": "2025-09-07T12:40:56.569091094Z",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv4": true,
    "EnableIPv6": true,
    "IPAM": {
      "Driver": "default",
      "Options": {},
      "Config": [
        {
          "Subnet": "172.18.0.0/16",
          "Gateway": "172.18.0.1"
        },
        {
          "Subnet": "fc00:f853:ccd:e793::/64",
          "Gateway": "fc00:f853:ccd:e793::1"
        }
      ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {
      "a5d274543bba8a024b0902c9cc34fb860bb3304648dd113dafafbb942827c0ac": {
        "Name": "myk8s-control-plane",
        "EndpointID": "d28e2ba27ce7d8240cd5d2a06f2b8c650131c4deea60c3ad33c6aada06cb981a",
        "MacAddress": "52:67:17:11:19:a9",
        "IPv4Address": "172.18.0.3/16",
        "IPv6Address": "fc00:f853:ccd:e793::3/64"
      },
      "db37299466b8149864a6be3e555d3eadb9030309f590e9ae4505f98851936083": {
        "Name": "myk8s-worker",
        "EndpointID": "4a0770fc4b783374e6fec315e9c0f0f74da0a820920b57d9d82138ef979ae62d",
        "MacAddress": "32:7b:d9:65:1f:78",
        "IPv4Address": "172.18.0.2/16",
        "IPv6Address": "fc00:f853:ccd:e793::2/64"
      }
    },
    "Options": {
      "com.docker.network.bridge.enable_ip_masquerade": "true",
      "com.docker.network.driver.mtu": "65535",
      "com.docker.network.enable_ipv4": "true"
    },
    "Labels": {}
  }
]

API 서버 접속 원리

kubectl이 어떻게 도커 컨테이너 안에 있는 API 서버랑 통신하는지 확인.
도커가 호스트의 포트를 컨테이너의 API 서버 포트(6443)로 포워딩해주고 있다.

# 클러스터 정보 및 API 서버 주소 확인 (https://127.0.0.1:xxxxx 형태)
kubectl cluster-info

Kubernetes control plane is running at https://127.0.0.1:49674
CoreDNS is running at https://127.0.0.1:49674/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy


# 도커 포트 매핑 확인 (PORTS 컬럼 확인)
riverjin@gangjin-ung-ui-Macmini k8sDeploy % docker ps 
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                                                             NAMES
db37299466b8   kindest/node:v1.32.8   "/usr/local/bin/entr…"   4 minutes ago   Up 4 minutes                                                                     myk8s-worker
a5d274543bba   kindest/node:v1.32.8   "/usr/local/bin/entr…"   4 minutes ago   Up 4 minutes   0.0.0.0:30000-30001->30000-30001/tcp, 127.0.0.1:49674->6443/tcp   myk8s-control-plane

5. 노드 및 파드 상세 스펙 확인

실제 쿠버네티스 내부 컴포넌트들이 뭘 쓰고 있는지 확인.

# 노드 정보 상세 확인
# -> OS-Image, Kernel, 그리고 **Container Runtime(CRI)**이 containerd 인지 확인
riverjin@gangjin-ung-ui-Macmini k8sDeploy % kubectl get node -o wide

NAME                  STATUS   ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION     CONTAINER-RUNTIME
myk8s-control-plane   Ready    control-plane   5m2s    v1.32.8   172.18.0.3    <none>        Debian GNU/Linux 12 (bookworm)   6.10.14-linuxkit   containerd://2.1.3
myk8s-worker          Ready    <none>          4m48s   v1.32.8   172.18.0.2    <none>        Debian GNU/Linux 12 (bookworm)   6.10.14-linuxkit   containerd://2.1.3
# 파드 정보 확인 (모든 네임스페이스)
# -> **CNI(네트워크 플러그인)**가 kindnet으로 동작 중인지 확인
riverjin@gangjin-ung-ui-Macmini k8sDeploy % kubectl get pod -A -o wide

NAMESPACE            NAME                                          READY   STATUS    RESTARTS   AGE     IP           NODE                  NOMINATED NODE   READINESS GATES
kube-system          coredns-668d6bf9bc-45vwj                      1/1     Running   0          5m23s   10.244.0.3   myk8s-control-plane   <none>           <none>
kube-system          coredns-668d6bf9bc-kdzvm                      1/1     Running   0          5m23s   10.244.0.2   myk8s-control-plane   <none>           <none>
kube-system          etcd-myk8s-control-plane                      1/1     Running   0          5m31s   172.18.0.3   myk8s-control-plane   <none>           <none>
kube-system          kindnet-mll82                                 1/1     Running   0          5m23s   172.18.0.3   myk8s-control-plane   <none>           <none>
kube-system          kindnet-rd7g2                                 1/1     Running   0          5m19s   172.18.0.2   myk8s-worker          <none>           <none>
kube-system          kube-apiserver-myk8s-control-plane            1/1     Running   0          5m31s   172.18.0.3   myk8s-control-plane   <none>           <none>
kube-system          kube-controller-manager-myk8s-control-plane   1/1     Running   0          5m32s   172.18.0.3   myk8s-control-plane   <none>           <none>
kube-system          kube-proxy-gr796                              1/1     Running   0          5m19s   172.18.0.2   myk8s-worker          <none>           <none>
kube-system          kube-proxy-w9l6d                              1/1     Running   0          5m23s   172.18.0.3   myk8s-control-plane   <none>           <none>
kube-system          kube-scheduler-myk8s-control-plane            1/1     Running   0          5m31s   172.18.0.3   myk8s-control-plane   <none>           <none>
local-path-storage   local-path-provisioner-7dc846544d-sc2nc       1/1     Running   0          5m23s   10.244.0.4   myk8s-control-plane   <none>           <none>

6. 네임스페이스와 컨테이너 내부

k8s의 네임스페이스와 리눅스(Docker)의 네임스페이스는 개념이 다르다.
실제로 노드 역할을 하는 것은 도커 컨테이너다.

# k8s 논리적 네임스페이스 확인
kubectl get namespaces


NAME                 STATUS   AGE
default              Active   5m57s
kube-node-lease      Active   5m57s
kube-public          Active   5m57s
kube-system          Active   5m57s
local-path-storage   Active   5m53s

# 실제 물리적(?) 노드 역할을 하는 도커 컨테이너 확인
# 이름이 myk8s-control-plane, myk8s-worker 로 되어 있음
docker ps
docker images

# 컨트롤 플레인 컨테이너 내부로 들어가서 포트 리슨 상태 확인 (ss 명령)
docker exec -it myk8s-control-plane ss -tnlp

7. 설정 파일 및 디버깅

kubectl 명령어가 느리거나 이상할 때 디버깅하는 법.

# API 호출 과정을 상세하게 출력 (-v6 ~ -v9)
# -> 인증 정보 로드 과정, API 요청 URL 등이 다 보임
kubectl get pod -v6

# kubeconfig 파일 까보기 (인증서, 클러스터 주소, 유저 정보)
cat ~/.kube/config
# 또는 환경변수 확인
cat $KUBECONFIG

8. 내 맥북에서 컨테이너까지 네트워크 패킷 흐름

[Kind] 네트워크 패킷 여행기: 내 맥북에서 컨테이너까지

방금 ss -tnlp로 확인한 건 "컨테이너 내부 상황"이었다.
이제 "내 맥북(Host)에서 쏜 명령어가 어떻게 저 깊은 곳에 있는 6443 포트까지 닿는지" 그 연결 고리를 파헤쳐 본다.

이걸 이해해야 나중에 "왜 로컬에선 되는데 배포하면 안 되지?" 같은 네트워크 문제를 풀 수 있다.


9. 전체 흐름도 (Architecture Flow)

kubectl 명령 한 번 칠 때 일어나는 일이다.
생각보다 과정이 많다.


10. 단계별 상세 분석

Step 1. 내비게이션 확인 (~/.kube/config)

kubectl은 무작정 통신하는 게 아니다. 먼저 설정 파일을 본다.

# cat ~/.kube/config 예시
clusters:
- cluster:
    server: https://127.0.0.1:51234  # <--- 여기를 주목!
  name: kind-myk8s
  • 포인트: server 주소가 kind-control-plane 같은 도메인이 아니라 127.0.0.1(내 컴퓨터)로 되어 있다.
  • 포트: 6443이 아니라 51234 같은 임의의 5자리 포트가 적혀 있다. (Kind가 클러스터 만들 때 랜덤으로 배정함)

Step 2. 문지기 (Docker Proxy)

내 맥북의 51234 포트는 누가 듣고 있을까? 바로 도커(Docker Desktop or OrbStack)다.

  • 도커는 내 맥북의 51234 포트를 리스닝(LISTEN)하고 있다가, 여기로 패킷이 들어오면 낚아챈다.
  • 역할: "아, 이건 myk8s-control-plane 컨테이너의 6443으로 갈 녀석이구나" 하고 토스해준다.
# 맥북 터미널에서 확인해보면
docker ps
# 출력 예시:
# 0.0.0.0:51234->6443/tcp
# (내 맥북 51234로 오면 -> 컨테이너 6443으로 보내라)

Step 3. 다리 건너기 (Bridge Network)

도커는 패킷을 들고 가상 다리(Bridge Network)를 건넌다.
아까 docker network ls로 봤던 kind 네트워크다.

  • 이 다리를 건너는 순간 패킷의 목적지는 127.0.0.1에서 172.18.0.x(컨테이너 내부 IP)로 바뀐다. (DNAT)

Step 4. 목적지 도착 (Container Internal)

드디어 패킷이 myk8s-control-plane 컨테이너에 도착했다.
아까 ss -tnlp로 확인했던 그 프로세스가 맞이한다.

  • 수신: kube-apiserver 프로세스
  • 포트: *:6443 (누구든 환영)

11. 요약 (Conclusion)

  1. 전달 과정 비유 나는 내 컴퓨터(127.0.0.1)에 말을 걸었지만, 사실은 도커가 중간에서 전화 내용을 받아서 컨테이너(172.18.x.x)로 전달해주고 있었다.
  2. 핵심 기술: 이것이 바로 포트 포워딩(Port Forwarding)이다.
  3. 트러블슈팅: 만약 kubectl이 안 된다면?
  • 도커가 죽었거나 (docker ps 확인)
  • 포트 매핑이 꼬였거나 (~/.kube/config의 포트와 docker ps의 포트가 다른지 확인)
  • 컨테이너 내부 API 서버가 죽었는지 확인 해본다.
profile
bytebliss

0개의 댓글