이너루프가 느려지는 이유

쿠버네티스 위에서 서비스를 개발할 때, 코드 한 줄을 고치고 실제 클러스터에서 확인하기까지의 반복 주기를 이너루프(inner loop)라고 부른다. 문제는 이 주기가 docker build → docker push → kubectl set image → 롤아웃 대기 → 로그 확인이라는 다섯 단계를 매번 수동으로 거친다는 점이다. 각 단계 사이의 컨텍스트 전환과 이미지 태그 관리, 매니페스트 수정이 누적되면 한 번의 변경 확인에 수 분이 걸린다. 하루 수십 번 반복하면 개발자 집중력과 시간이 그대로 증발한다.

Skaffold는 이 다섯 단계를 파일 변경 감지로 자동 트리거하고, 이미지 태그를 자동 주입하며, 로그와 포트포워딩까지 하나의 프로세스로 묶어 준다. 로컬에서 go run을 실행하는 감각에 가깝게 만드는 것이 목표다.

기본 설정: skaffold.yaml

Skaffold의 동작은 skaffold.yaml 한 파일로 선언한다. 빌드(build)와 배포(deploy)를 분리해 정의하며, 이미지 이름은 매니페스트의 이름과 일치시켜야 태그가 자동으로 주입된다.

apiVersion: skaffold/v4beta11
kind: Config
metadata:
  name: order-api
build:
  artifacts:
    - image: registry.local/order-api
      context: .
      docker:
        dockerfile: Dockerfile
  local:
    push: false          # 로컬 클러스터(kind, minikube)면 push 생략
deploy:
  kubectl:
    manifests:
      - k8s/*.yaml

local.push: false는 kind나 minikube처럼 노드가 로컬 데몬의 이미지를 직접 참조하는 환경에서 레지스트리 왕복을 없애는 핵심 옵션이다. 원격 클러스터에서는 true로 두고 태그 정책을 함께 지정한다.

dev 모드와 파일 동기화

skaffold dev는 소스 변경을 감지해 자동으로 다시 빌드·배포하고 로그를 스트리밍한다. 여기에 sync를 더하면, 이미지 재빌드 없이 변경된 파일만 실행 중인 컨테이너로 복사한다. 인터프리터 언어나 정적 파일에서 특히 효과가 크다.

build:
  artifacts:
    - image: registry.local/web
      sync:
        manual:
          - src: "src/**/*.py"
            dest: /app
          - src: "static/**/*"
            dest: /app/static
skaffold dev --port-forward --tail
# 파일 저장 → 컨테이너로 즉시 동기화, 재빌드 없이 반영

단, sync는 프로세스가 파일 변경을 스스로 감지해 리로드할 수 있을 때만 의미가 있다. FastAPI의 --reload, Flask 디버그 모드처럼 파일 감시 리로더가 컨테이너 안에서 돌고 있어야 한다.

프로파일로 환경 분리

로컬과 스테이징은 빌드 방식도 배포 대상도 다르다. 프로파일을 쓰면 하나의 파일에서 환경별 차이만 오버라이드할 수 있다.

profiles:
  - name: staging
    build:
      local:
        push: true
      tagPolicy:
        gitCommit: {}
    deploy:
      kubectl:
        manifests:
          - k8s/overlays/staging/*.yaml

skaffold run -p staging으로 호출한다. gitCommit 태그 정책은 커밋 해시를 이미지 태그로 사용해, 어떤 코드가 배포됐는지 추적 가능하게 만든다.

빌드 방식 비교

Skaffold는 Dockerfile 외에 여러 빌더를 지원한다. 팀 상황에 맞게 선택하면 이너루프 속도가 더 개선된다.

빌더장점주의점
Docker가장 단순, 캐시 익숙함레이어 캐시 관리 직접 필요
BuildpacksDockerfile 불필요, 언어별 최적화이미지 크기·투명성 낮음
Kaniko데몬 없이 클러스터 내 빌드로컬 캐시 활용 제한
Jib(Java)JVM 계층 캐시로 초고속JVM 프로젝트 한정

CI로 이어 붙이기

같은 skaffold.yaml을 CI에서도 재사용할 수 있다. skaffold build로 이미지를 만들고 태그를 파일로 출력한 뒤, 배포 단계에서 그 결과를 그대로 넘긴다. 개발과 CI가 동일한 빌드 정의를 공유하므로 "로컬에선 되는데 CI에선 안 되는" 격차가 줄어든다.

skaffold build -p staging --file-output=tags.json
skaffold deploy -p staging --build-artifacts=tags.json

실무 주의점

몇 가지 함정을 미리 알아 두면 도입이 매끄럽다. 첫째, sync 대상 경로가 컨테이너의 실제 작업 디렉터리와 다르면 조용히 반영되지 않는다. 배포 전 WORKDIR와 dest를 반드시 대조하라. 둘째, skaffold dev는 Ctrl+C로 종료할 때 배포한 리소스를 자동으로 정리하므로, 남겨 두려면 --no-prune=false 동작을 이해하고 skaffold run을 쓴다. 셋째, 파일 감시는 변경이 잦은 대형 모노레포에서 CPU를 크게 잡아먹으니 sync와 빌드 컨텍스트 범위를 좁게 유지한다. 마지막으로 태그 정책은 로컬에선 기본값으로 충분하지만, 원격 배포에서는 gitCommit이나 inputDigest를 명시해 추적성과 캐시 적중률을 확보해야 한다.