TestForge Blog
← 전체 포스트

Kubernetes 개발·운영 실전 1편 — 로컬 개발 환경 구성 (Kind + Skaffold)

Kind로 로컬 Kubernetes 클러스터를 구성하고 Skaffold와 Tilt로 개발 루프를 단축하는 방법. 프로덕션과 동일한 환경에서 개발하는 실전 가이드.

TestForge Team ·

왜 로컬 Kubernetes 환경이 필요한가

docker run으로 충분했던 시대는 지나갔습니다. 서비스가 Deployment, Service, ConfigMap, Ingress로 구성되는 순간, 로컬에서도 동일한 구조로 개발해야 합니다. 환경 차이로 발생하는 “로컬에선 됐는데 클러스터에서 안 됨” 문제를 원천 차단하는 것이 목표입니다.


1. Kind로 로컬 클러스터 구성

Kind(Kubernetes IN Docker)는 Docker 컨테이너를 노드로 사용하는 경량 클러스터입니다. CI 환경에서도 동일하게 사용할 수 있어 dev/CI 일관성이 높습니다.

설치

# macOS
brew install kind

# Linux
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.23.0/kind-linux-amd64
chmod +x ./kind && mv ./kind /usr/local/bin/kind

멀티 노드 클러스터 설정

# kind-cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
      - containerPort: 443
        hostPort: 443
  - role: worker
  - role: worker
kind create cluster --config kind-cluster.yaml --name local
kubectl cluster-info --context kind-local

Ingress 컨트롤러 설치

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

2. Skaffold로 개발 루프 자동화

Skaffold는 코드 변경 감지 → 이미지 빌드 → 클러스터 배포를 자동화합니다. skaffold dev 명령 하나로 파일 저장 시마다 반영됩니다.

설치

# macOS
brew install skaffold

# Linux
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
chmod +x skaffold && mv skaffold /usr/local/bin

skaffold.yaml 구성

apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: my-app

build:
  artifacts:
    - image: my-app
      docker:
        dockerfile: Dockerfile
  local:
    push: false  # 로컬 클러스터는 push 불필요

deploy:
  kubectl:
    manifests:
      - k8s/*.yaml

portForward:
  - resourceType: service
    resourceName: my-app
    port: 8080
    localPort: 8080

개발 모드 실행

# 파일 변경 감지 + 자동 배포
skaffold dev

# 한 번만 빌드/배포
skaffold run

# 배포된 리소스 정리
skaffold delete

3. Tilt — 더 세밀한 제어가 필요할 때

Tilt는 Skaffold보다 설정이 유연하고 웹 UI 대시보드를 제공합니다. 마이크로서비스가 여러 개인 경우 서비스별 상태를 한눈에 볼 수 있습니다.

Tiltfile 기본 구성

# Tiltfile
docker_build('my-app', '.',
  live_update=[
    sync('./src', '/app/src'),          # 소스 파일 실시간 동기화
    run('cd /app && npm install',        # 패키지 변경 시만 실행
        trigger=['./package.json']),
  ]
)

k8s_yaml(['k8s/deployment.yaml', 'k8s/service.yaml'])

k8s_resource('my-app',
  port_forwards=8080,
  labels=['frontend']
)
tilt up    # 웹 UI: http://localhost:10350
tilt down  # 정리

4. 로컬 이미지 레지스트리 구성

Kind는 기본적으로 외부 레지스트리를 사용하는데, 로컬 레지스트리를 연결하면 이미지 push/pull 속도가 빨라집니다.

#!/bin/bash
# local-registry.sh

# 로컬 레지스트리 컨테이너 시작
docker run -d --restart=always -p 5001:5000 --name registry registry:2

# Kind 클러스터와 네트워크 연결
docker network connect kind registry

# Kind에 레지스트리 설정 등록
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: local-registry-hosting
  namespace: kube-public
data:
  localRegistryHosting.v1: |
    host: "localhost:5001"
    help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

이제 localhost:5001/my-app:latest로 이미지를 push하면 Kind 클러스터에서 바로 사용 가능합니다.


5. 실전 디렉터리 구조

my-project/
├── src/                    # 애플리케이션 소스
├── Dockerfile
├── skaffold.yaml
├── kind-cluster.yaml
└── k8s/
    ├── namespace.yaml
    ├── deployment.yaml
    ├── service.yaml
    ├── ingress.yaml
    └── configmap.yaml

로컬 개발에서도 k8s/ 디렉터리를 프로덕션과 동일한 구조로 유지하면, 환경별 차이를 최소화할 수 있습니다.


6. 자주 쓰는 디버깅 명령

# Pod 로그 실시간 확인
kubectl logs -f deployment/my-app

# Pod 내부 접속
kubectl exec -it deployment/my-app -- /bin/sh

# 이벤트 확인 (에러 원인 파악)
kubectl get events --sort-by='.lastTimestamp'

# 포트 포워딩 (서비스 직접 접근)
kubectl port-forward svc/my-app 8080:8080

# 리소스 상태 실시간 감시
watch kubectl get pods,svc,ingress

정리

도구특징추천 상황
Kind경량, CI 친화적단일 서비스, CI 파이프라인
Skaffold설정 간단, 빠른 시작초기 프로젝트, 소규모 팀
Tilt웹 UI, 세밀한 제어마이크로서비스, 복잡한 의존성

다음 편에서는 Namespace와 RBAC 설계를 다룹니다. 팀과 환경을 어떻게 분리하고 최소 권한을 부여하는지 알아봅니다.