쿠버네티스에서 안정적이고 관리하기 쉬운 클러스터를 위해 알아 두면 좋은 설정 모범 사례를 정리합니다. API 버전, 매니페스트 관리, 레이블 전략, Service 및 워크로드 구성 등에 대한 실용적인 팁을 제공합니다.
Kirti Goyal 작성 | 2025년 11월 25일 화요일
쿠버네티스에서 설정(configuration)은 사소해 보이다가도 어느 순간 핵심 문제가 되곤 합니다. 설정은 모든 쿠버네티스 워크로드의 심장과도 같습니다. 따옴표 하나 빠졌거나, 잘못된 API 버전을 썼거나, 들여쓰기가 한 칸 어긋난 YAML 한 줄이 전체 배포를 망가뜨릴 수 있습니다.
이 글은 실전에서 검증된 설정 모범 사례를 한데 모았습니다. 쿠버네티스 환경을 더 깔끔하고 일관되며 관리하기 쉽게 만들어 주는 작은 습관들입니다. 이제 막 시작했든, 이미 매일 앱을 배포하고 있든, 이런 사소해 보이는 것들이 클러스터를 안정적으로 유지해 주고, 나중의 나 자신을 편하게 해 줍니다.
이 글은 여러 쿠버네티스 커뮤니티 구성원의 기여로 발전해 온 원래의 Configuration Best Practices 페이지에서 영감을 받았습니다.
쿠버네티스는 빠르게 발전합니다. 오래된 API는 결국 사용 중단(deprecated)되고, 어느 시점에는 더 이상 동작하지 않게 됩니다. 리소스를 정의할 때는 항상 최신의 안정 API 버전을 사용하고 있는지 확인해야 합니다. 아래 명령으로 확인할 수 있습니다.
bashkubectl api-resources
이 간단한 단계만으로도 미래의 호환성 문제를 예방할 수 있습니다.
로컬 데스크톱에서 매니페스트 파일을 곧바로 kubectl apply 하지 마세요. 항상 Git 같은 버전 관리 시스템에 넣어 두어야 합니다. 버전 관리는 일종의 안전망입니다. 문제가 생기면, 바로 이전 커밋으로 롤백하거나, 변경 사항을 비교하거나, 당황하지 않고 클러스터 구성을 다시 만들 수 있습니다.
설정 파일은 JSON 대신 YAML로 작성하세요. 둘 다 기술적으로는 동작하지만, 사람이 읽고 쓰기에는 YAML이 훨씬 편합니다. 더 읽기 쉽고, 군더더기가 적고, 커뮤니티에서도 널리 쓰입니다.
다만 YAML에는 boolean 값과 관련된 은근한 함정이 있습니다. true 또는 false만 사용하세요. yes, no, on, off 같은 값은 어떤 YAML 버전에서는 boolean으로 취급되고, 다른 버전에서는 다르게 동작할 수 있습니다. 안전하게 가려면, boolean처럼 보이는 값은 모두 따옴표로 감싸세요(예: "yes").
쿠버네티스가 이미 기본값으로 처리하는 항목까지 굳이 매니페스트에 다 적지 마세요. 최소한의 매니페스트는 디버깅하기도 쉽고, 코드 리뷰도 깔끔하며, 나중에 변경하다가 실수로 무언가를 망가뜨릴 가능성도 줄여 줍니다.
같은 애플리케이션에 속한 Deployment, Service, ConfigMap 등이 있다면, 가능하면 한 매니페스트 파일 안에 묶어 두세요.
이렇게 하면 변경 사항을 한 덩어리로 추적하기 쉽고, 한 번에 적용하기도 좋습니다. 이런 방식의 대표적인 예로 Guestbook all-in-one.yaml 파일을 참고할 수 있습니다.
또한 전체 디렉터리를 한 번에 적용할 수도 있습니다.
bashkubectl apply -f configs/
이 명령 한 번이면 해당 폴더 안의 리소스가 모두 배포됩니다.
매니페스트 파일은 기계만 보는 것이 아니라, 사람도 함께 보는 문서입니다. annotation을 활용해 “왜 이 리소스가 존재하는지”, “무엇을 하는지”를 적어 두세요. 짧은 한 줄 설명이 나중 디버깅 때 몇 시간을 아껴 줄 수 있고, 협업에도 큰 도움이 됩니다.
가장 유용한 annotation 중 하나는 kubernetes.io/description입니다. 주석처럼 쓸 수 있지만, 이 값은 API 오브젝트에도 함께 저장되므로, 배포된 이후에도 누구나 해당 설명을 확인할 수 있습니다.
쿠버네티스를 처음 사용할 때 자주 하는 실수 중 하나는 바로 Pod를 직접 만드는 것입니다. Pod 자체도 동작은 하지만, 문제가 생겼을 때 자동으로 다시 스케줄링되지 않습니다.
컨트롤러(예: Deployment, StatefulSet)가 관리하지 않는 Pod를 흔히 나체(Naked) Pod라고 부릅니다. 나체 Pod는 테스트 용도로는 괜찮지만, 실제 환경에서는 위험합니다.
이유는 단순합니다. Pod가 올라가 있는 노드가 죽으면, 그 Pod도 함께 사라지고, 쿠버네티스가 자동으로 다시 띄워 주지 않기 때문입니다.
Deployment는 내부적으로 ReplicaSet을 만들어 원하는 수의 Pod가 항상 존재하도록 관리하고, Pod 교체 전략(예: RollingUpdate)도 함께 정의합니다. 단순히 Pod를 직접 만드는 것보다 거의 항상 더 좋은 선택입니다.
새 버전을 롤아웃할 수도 있고, 문제가 생기면 바로 롤백할 수도 있습니다.
Job은 한 번 실행해서 끝나야 하는 작업(예: DB 마이그레이션, 배치 처리 작업)에 적합합니다. Pod가 실패하면 재시도해 주고, 작업이 완료되면 성공 여부를 알려 줍니다.
Service는 클러스터 안(그리고 경우에 따라서는 클러스터 밖)에서 워크로드들이 서로 통신할 수 있게 해 주는 리소스입니다. Service 없이도 Pod는 존재할 수 있지만, 서로 연결되지는 못합니다. 그런 상황이 벌어지지 않도록 해 봅시다.
쿠버네티스는 Pod를 시작할 때, 이미 존재하는 Service들에 대한 환경 변수를 자동으로 주입합니다. 따라서 어떤 Pod가 특정 Service에 의존한다면, 해당 Pod의 backend 워크로드(Deployment 또는 StatefulSet)보다 먼저 그 Service를 생성하고, 그 Service에 접근해야 하는 다른 워크로드들보다도 먼저 만드는 것이 좋습니다.
예를 들어, foo라는 이름의 Service가 있다면, 모든 컨테이너는 초기 환경 변수에 다음 두 변수를 받게 됩니다.
FOO_SERVICE_HOST=<Service가 동작하는 호스트>
FOO_SERVICE_PORT=<Service가 동작하는 포트>
DNS 기반 서비스 디스커버리를 사용하면 이런 문제가 덜하지만, 그래도 Service를 먼저 만드는 습관을 들여 두는 것이 좋습니다.
클러스터에 DNS 애드온이 설치되어 있다면(대부분의 클러스터가 그렇습니다), 모든 Service는 자동으로 DNS 레코드를 갖게 됩니다. 즉, IP 대신 이름으로 접근할 수 있습니다.
bashcurl http://my-service.default.svc.cluster.local
쿠버네티스 네트워킹이 마치 마법처럼 느껴지는 기능 중 하나입니다.
hostPort와 hostNetwork는 꼭 필요할 때만 사용하기매니페스트에서 가끔 이런 옵션을 볼 수 있습니다.
yamlhostPort: 8080 hostNetwork: true
하지만 문제는, 이런 옵션은 Pod를 특정 노드에 강하게 묶어 버려서 스케줄링과 스케일링을 어렵게 만든다는 점입니다. <hostIP, hostPort, protocol> 조합은 클러스터 전체에서 유일해야 합니다. hostIP와 protocol을 명시적으로 지정하지 않으면, 쿠버네티스는 기본값으로 hostIP=0.0.0.0, protocol=TCP를 사용합니다.
디버깅을 하거나 네트워크 플러그인 같은 특수한 구성 요소를 만들고 있는 것이 아니라면, 이런 설정은 피하는 것이 좋습니다.
단순히 로컬에서 테스트용으로 접근만 필요하다면, kubectl port-forward를 사용해 보세요.
bashkubectl port-forward deployment/web 8080:80
더 자세한 내용은 포트 포워딩을 사용해 클러스터 안의 애플리케이션에 접근하기를 참고하세요.
만약 정말로 외부에서 접근해야 한다면, type: NodePort Service를 사용하는 것이 좋습니다. 보다 안전하고, 쿠버네티스에 자연스럽게 녹아드는 방식입니다.
가끔은 쿠버네티스의 로드 밸런싱 기능을 쓰고 싶지 않을 때가 있습니다. 각각의 Pod에 직접 통신하고 싶은 경우입니다. 이럴 때 사용하는 것이 Headless Service입니다.
clusterIP: None으로 설정하면 Headless Service가 됩니다. 이렇게 하면 단일 IP 대신, DNS 조회 결과로 모든 Pod IP 목록을 받게 되므로, 애플리케이션이 자체적으로 연결 관리를 할 수 있을 때 유용합니다.
레이블(label)은 Pod 같은 오브젝트에 붙는 key/value 쌍입니다. 레이블은 리소스를 조직화하고, 조회하고, 그룹화하는 데 도움을 줍니다. 레이블 자체로 뭔가 동작을 하지는 않지만, Service에서 Deployment까지 쿠버네티스의 거의 모든 요소가 함께 잘 동작하도록 만드는 핵심 메커니즘입니다.
좋은 레이블은 몇 달이 지나서 봐도 “무엇이 무엇인지” 이해하는 데 도움이 됩니다. 애플리케이션이나 Deployment의 의미 있는 속성을 나타내는 레이블을 정의하고 사용하세요. 예를 들면 다음과 같습니다.
yamllabels: app.kubernetes.io/name: myapp app.kubernetes.io/component: web tier: frontend phase: test
app.kubernetes.io/name : 애플리케이션 이름(무엇인지)tier : 계층(프론트엔드/백엔드 등)phase : 단계(테스트/운영 등)이렇게 붙여 둔 레이블은 강력한 selector를 만드는 데 활용할 수 있습니다. 예를 들어:
bashkubectl get pods -l tier=frontend
이 명령은 어떤 Deployment에서 생성되었는지와 상관없이, 클러스터 전체에서 tier=frontend 레이블이 붙은 모든 Pod 목록을 보여 줍니다. 개별 Pod 이름을 하나씩 나열하는 대신, “무엇을 원한다”는 조건만 기술하는 셈입니다. 이런 접근 방식의 예는 guestbook 애플리케이션에서 확인할 수 있습니다.
쿠버네티스에서는 권장하는 공통 레이블 집합을 정의해 두고 있습니다. 여러 워크로드나 프로젝트 전반에 걸쳐 이름을 표준화하는 방법입니다. 이 규약을 따르면 매니페스트가 더 일관되고 깔끔해질 뿐 아니라, Headlamp, 대시보드, 그리고 서드파티 모니터링 시스템 같은 도구들이 자동으로 무엇이 무엇인지 이해할 수 있습니다.
ReplicaSet이나 Deployment 같은 컨트롤러는 레이블을 기반으로 Pod를 관리합니다. 이 특성을 이용해, 레이블을 제거함으로써 일시적으로 Pod를 컨트롤러에서 “분리(detach)”할 수 있습니다.
예:
bashkubectl label pod mypod app-
여기서 app-은 app이라는 레이블 key를 제거하라는 의미입니다. 이 레이블이 사라지면 컨트롤러는 더 이상 그 Pod를 관리하지 않습니다. 마치 해당 Pod를 격리해서 살펴보는, 디버깅용 “격리 모드” 같은 효과입니다. 레이블을 상호작용적으로 추가/삭제하려면 kubectl label을 사용하세요.
그 이후에는 로그를 확인하거나, kubectl exec으로 안에 들어가서 조사할 수 있고, 다 끝나면 수동으로 Pod를 삭제하면 됩니다. 쿠버네티스를 사용하는 엔지니어라면 꼭 알아 두면 좋은, 과소평가된 팁입니다.
여러 매니페스트 파일과 클러스터를 다룰 때, 이런 작은 팁들이 작업을 훨씬 수월하게 만들어 줍니다.
파일을 하나씩 적용하는 대신, 디렉터리 전체를 적용할 수 있습니다.
bash# server-side apply를 함께 사용하는 것도 좋은 습관입니다 kubectl apply -f configs/ --server-side
이 명령은 해당 폴더 안의 .yaml, .yml, .json 파일을 찾아 한 번에 모두 적용합니다. 더 빠르고 깔끔하며, 애플리케이션 단위로 리소스를 묶어 관리하기 좋습니다.
리소스 이름을 하나씩 타이핑할 필요는 없습니다. 대신 셀렉터를 사용해 한 번에 전체 그룹에 대해 작업할 수 있습니다.
bashkubectl get pods -l app=myapp kubectl delete pod -l phase=test
특히 CI/CD 파이프라인에서 동적으로 테스트 리소스를 정리(clean up)해야 할 때 유용합니다.
간단한 실험을 할 때, 항상 매니페스트 파일을 써야 하는 것은 아닙니다. CLI만으로도 Deployment를 바로 띄울 수 있습니다.
bashkubectl create deployment webapp --image=nginx
그다음 Service로 노출합니다.
bashkubectl expose deployment webapp --port=80
전체 매니페스트를 작성하기 전에 그냥 가볍게 테스트해 보고 싶을 때 유용합니다. 예시는 Service를 사용해 클러스터 안의 애플리케이션에 접근하기 문서에서도 확인할 수 있습니다.
설정이 깔끔해지면, 클러스터 관리자의 마음도 한결 편안해집니다. 설정을 단순하고 최소한으로 유지하고, 모든 것을 버전 관리하며, 일관된 레이블을 사용하고, 나체 Pod에 의존하지 않는 습관만 들여도, 나중에 디버깅에 쏟을 시간을 엄청나게 줄일 수 있습니다.
무엇보다 좋은 점은, 잘 정리된 설정은 시간이 지나도 여전히 읽기 쉽다는 것입니다. 몇 달이 지난 뒤에도, 팀의 누구든 매니페스트를 한번 훑어보기만 하면 “무슨 일이 일어나고 있는지” 바로 이해할 수 있습니다.