쿠버네티스 기본 개념: Namespace와 선언적 관리

성윤·2026년 2월 15일

[☸️Kubernetes]

목록 보기
4/13
post-thumbnail

들어가며 👋

지난 포스팅에서 kubeadm으로 쿠버네티스 클러스터를 구축했습니다. 이제 실제로 컨테이너(파드)를 띄워봐야겠죠.

하지만 실습용으로 파드 몇 개 띄우는 것과 실제 회사에서 여러 사람이 함께 운영하는 것은 완전히 다른 이야기입니다.

실무에서는 이런 문제들이 생깁니다:


문제 1. 환경 충돌

개발팀이 my-app이라는 이름으로 파드를 띄웠는데, QA팀도 같은 이름으로 띄우려니까 "이미 존재합니다" 에러가 뜹니다. 개발 DB와 운영 DB가 같은 클러스터에 있으면? 상상만 해도 끔찍합니다.

문제 2. 설정 공유와 협업

팀원 A가 터미널에서 명령어로 파드를 띄웠습니다. 다음 날 팀원 B가 "어? 이 파드 누가 만들었지? 설정이 뭐였지?"라고 물어봅니다. 명령어로만 실행했기 때문에 기록이 없습니다.

문제 3. 배포 타이밍

배포 스크립트에서 파드를 삭제하고 즉시 새로운 파드를 생성했습니다. 그런데 "이미 존재합니다" 에러가 발생합니다. 삭제 완료 응답을 받았는데 왜 이런 일이?

이번 포스팅에서는 쿠버네티스가 이 세 가지 문제를 어떻게 해결하는지 알아보겠습니다. 🚀


1. 환경 충돌 해결: Namespace로 논리적 공간 분리 📦

문제 상황

같은 클러스터를 여러 팀이 공유할 때, 리소스 이름이 겹치면 충돌이 발생합니다.

# 개발팀이 실행
kubectl run my-app --image=nginx

# QA팀이 실행 (같은 클러스터)
kubectl run my-app --image=nginx
# ❌ Error: pod "my-app" already exists


해결책: Namespace

Namespace는 하나의 클러스터 안에 논리적인 경계를 만들어 리소스를 격리합니다.

물리적으로 서버를 나누는 게 아니라, 같은 서버 안에 투명한 벽을 세워서 공간을 분리하는 개념입니다.

# 개발 네임스페이스 생성
kubectl create namespace dev

# QA 네임스페이스 생성
kubectl create namespace qa

# 이제 같은 이름이어도 괜찮음
kubectl run my-app --image=nginx -n dev
kubectl run my-app --image=nginx -n qa

# 확인
kubectl get pods -n dev   # dev의 my-app
kubectl get pods -n qa    # qa의 my-app (별개의 파드)


기본 제공 시스템 네임스페이스

클러스터를 처음 만들면 쿠버네티스가 자기 자신을 관리하기 위해 미리 만들어둔 네임스페이스들이 있습니다:

  • kube-system: API Server, Scheduler 등 쿠버네티스 핵심 구성 요소가 실행되는 공간
  • kube-public: 모든 사용자가 읽을 수 있는 공개 리소스 저장 공간
  • kube-node-lease: 각 노드의 상태(살아있는지) 정보를 저장하는 공간
  • default: 네임스페이스를 지정하지 않으면 기본적으로 사용되는 공간

💡 네임스페이스를 지정하지 않으면 자동으로 'default' 네임스페이스에 등록됩니다.

# 시스템 네임스페이스 확인
kubectl get namespaces

💡 리눅스 Namespace와의 관계

리눅스의 Namespace(프로세스 격리)와 동일한 개념입니다. 충돌 방지와 격리 환경 제공이라는 목적이 같습니다.


2. 클러스터와 소통하기: kubectl의 원리 ⚙️

Namespace로 공간을 분리했으니, 이제 각 공간에 명령을 내려볼 차례입니다.

kubectl이 클러스터와 통신하는 방법

kubectl마스터 노드의 API Server와 통신해서 명령을 전달합니다.

이때 필요한 정보:

  1. 어디로 보낼까? (클러스터 서버 주소)
  2. 나는 누구인가? (인증 정보)

이 정보들은 ~/.kube/config 파일에 YAML 형식으로 저장됩니다.

# config 파일 확인
cat ~/.kube/config


여러 클러스터 관리: Context

실무에서는 개발 클러스터, 스테이징 클러스터, 운영 클러스터 등 여러 개를 동시에 관리합니다.

  • 개발(Dev) 클러스터: 개발자들이 자유롭게 코드를 배포하고 테스트하는 환경입니다.

  • 스테이징(Staging) 클러스터: 운영 환경과 동일한 조건에서 최종 검증을 하는 환경입니다.

  • 운영(Prod) 클러스터: 실제 고객이 사용하는 환경으로, 보안과 안정성이 최우선입니다.


매번 서버 주소와 인증 정보를 바꿀 수는 없겠죠?

Context는 "클러스터 + 인증정보 + 기본 네임스페이스"를 하나의 세트로 묶은 것입니다.

# 현재 사용 중인 컨텍스트 확인
kubectl config current-context

# 사용 가능한 컨텍스트 목록
kubectl config get-contexts

# 컨텍스트 전환 (개발 → 운영)
kubectl config use-context production

이제 명령어 한 줄로 제어 대상을 바꿀 수 있습니다.

💡 실습 환경 참고

현재 제 환경에는 클러스터가 하나만 있어서 컨텍스트도 하나만 보입니다.
실무에서는 보통 dev-cluster, staging-cluster, prod-cluster 등 여러 개가 나열됩니다.


3. 설정 공유와 협업: 왜 apply를 써야 할까? 🛠️

이제 본격적으로 리소스를 생성해 봅시다. 쿠버네티스에는 두 가지 방식이 있습니다.

방식 1: 명령형 (create, run)

터미널에 명령어를 직접 입력해서 즉시 생성합니다.

# 파드 생성
kubectl run nginx --image=nginx

# Deployment 생성
kubectl create deployment my-deploy --image=nginx

장점: 빠르고 직관적입니다.

문제점:

  • ❌ 누가 언제 무슨 설정으로 만들었는지 기록이 없음
  • ❌ Git으로 버전 관리 불가능
  • ❌ 팀원들과 설정 공유 어려움
  • ❌ 같은 이름의 리소스가 이미 있으면 에러 발생

방식 2: 선언형 (apply)

"어떻게 만들어라"가 아니라 "이런 상태가 되게 해라"를 파일에 정의합니다.

# nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.21
# 파일로 생성
kubectl apply -f nginx-pod.yaml

장점:

  • ✅ 설정이 파일로 남아서 누구나 볼 수 있음
  • ✅ Git으로 버전 관리 가능 (언제 누가 무엇을 바꿨는지 추적)
  • ✅ 팀원들과 공유하기 쉬움
  • ✅ 같은 파일을 여러 번 apply 해도 괜찮음 (멱등성)

실무에서는 왜 무조건 apply를 쓸까?

1) CI/CD 자동화가 쉬워진다

create로 배포 스크립트를 짜려면 이렇게 해야 합니다:

# create 방식 (복잡함)
if kubectl get pod nginx 2>/dev/null; then
  kubectl delete pod nginx
  kubectl create -f nginx-pod.yaml
else
  kubectl create -f nginx-pod.yaml
fi

'해당 파드가 있다면 지우고 만들어라' 라는 조건문을 적어줘야 합니다.

apply는 이렇게 간단합니다:

# apply 방식 (간단함)
kubectl apply -f nginx-pod.yaml

이미 있으면 변경된 부분만 업데이트하고, 없으면 새로 만듭니다. 멱등성이 보장됩니다.

💡 apply의 똑똑한 점

apply는 무조건 지우고 새로 만드는 게 아닙니다!

  • 리소스가 없으면 → 생성
  • 리소스가 있고 변경사항 없으면 → 아무것도 안 함
  • 리소스가 있고 변경사항 있으면 → 변경된 부분만 업데이트

이것이 바로 멱등성(Idempotency)입니다.


2) 변경 이력을 추적할 수 있다

apply를 사용하면 쿠버네티스가 내부적으로 마지막으로 적용된 설정을 기록해둡니다.

# 리소스에 기록된 마지막 설정 확인
kubectl get pod nginx -o yaml | grep last-applied-configuration

다음에 다시 apply할 때, 이 기록과 새 YAML을 비교해서:

  • 무엇이 추가되었는지
  • 무엇이 삭제되었는지
  • 무엇이 변경되었는지

정확하게 계산합니다. create는 이런 기록이 없어서 업데이트 시 충돌이 발생할 수 있습니다.


3) Infrastructure as Code (IaC)

코드로 인프라를 관리하는 현대적인 방식입니다.

코드(YAML) → Git → CI/CD → 클러스터 자동 배포

이 흐름이 가능하려면 선언형 방식이 필수입니다.

주로 사용되는 CI/CD 툴에서 yaml 파일 형식을 많이 사용합니다.

💡 실무 팁

테스트나 임시 작업은 create를 써도 괜찮습니다. 하지만 운영 환경이나 팀 프로젝트에서는 무조건 YAML 파일 + apply를 사용해야 합니다.


4. 배포 타이밍 이해: 비동기 처리 방식 ⏳

이제 앞서 말한 세 번째 문제로 돌아가봅시다.

문제 재현

# 파드 삭제
kubectl delete pod nginx
# pod "nginx" deleted  (즉시 응답)

# 바로 다시 생성
kubectl apply -f nginx-pod.yaml
# ❌ Error: pod "nginx" already exists

분명 "deleted" 응답을 받았는데 왜 아직 존재한다고 할까요?


원인: 쿠버네티스는 비동기 시스템이다

명령어를 실행하면 이런 일이 벌어집니다:

1. kubectl이 API Server에 요청
2. API Server가 문법만 확인하고 즉시 "OK" 응답 ⚡
3. 백그라운드에서 실제 작업 진행
   API Server → etcd → Scheduler → Kubelet → 컨테이너 삭제

터미널에 "deleted" 응답이 떴을 때는 접수만 완료된 상태입니다.

실제 삭제는 백그라운드에서 진행 중입니다.


해결책: --wait 옵션

실제 작업이 완료될 때까지 기다리게 만듭니다.

# 삭제 완료까지 대기
kubectl delete pod nginx --wait=true

# 이제 바로 생성해도 괜찮음
kubectl apply -f nginx-pod.yaml
# ✅ Success

CI/CD에서 반드시 필요한 이유

자동화 스크립트에서는 이런 상황이 자주 발생합니다:

# 잘못된 스크립트
kubectl delete -f old-version.yaml
kubectl apply -f new-version.yaml  # ❌ 실패할 수 있음

# 올바른 스크립트
kubectl delete -f old-version.yaml --wait=true
kubectl apply -f new-version.yaml  # ✅ 안전함

💡 강제 즉시 삭제

긴급 상황에서 즉시 삭제해야 한다면:

kubectl delete pod nginx --grace-period=0 --force

5. 실무 주의사항: 직접 수정의 위험성 ⚠️

운영 중인 파드의 설정을 터미널에서 직접 바꿀 수도 있습니다.

# 이미지 버전 변경
kubectl set image pod nginx nginx=nginx:1.22

하지만 이건 매우 위험합니다!

무슨 문제가 생기나?

  1. 터미널에서 이미지를 1.22로 변경
  2. 로컬 YAML 파일은 여전히 1.21
  3. 다음 날 팀원이 YAML 파일로 apply
  4. 서버 상태가 1.21로 롤백됨! 🔥
# 현재 실제 상태 확인
kubectl get pod nginx -o yaml

# 로컬 파일과 비교
kubectl diff -f nginx-pod.yaml
# ⚠️ 차이가 있다면 위험 신호!

올바른 방법

# 1. YAML 파일 수정
vim nginx-pod.yaml
# image: nginx:1.22 로 변경

# 2. Git에 커밋
git add nginx-pod.yaml
git commit -m "Update nginx to 1.22"

# 3. apply로 반영
kubectl apply -f nginx-pod.yaml

이렇게 하면:

  • ✅ 변경 이력이 Git에 남음
  • ✅ 팀원들이 변경사항을 알 수 있음
  • ✅ 파일과 클러스터 상태가 일치함

💡 (고급) Server-Side Apply

여러 사람이나 자동화 도구가 동시에 같은 리소스를 수정할 때 충돌을 방지하는 기능입니다.
초보자는 일단 넘어가도 괜찮고, 나중에 필요할 때 찾아보아도 괜찮습니다.

사용법: kubectl apply --server-side -f app.yaml


6. YAML과 JSON: 사람과 기계 🤖

마지막으로 재미있는 사실 하나.

우리는 YAML로 파일을 작성하지만, kubectl apply를 실행하면 내부적으로 JSON으로 변환되어 API Server에 전달됩니다.

# 우리가 작성하는 YAML (사람 친화적)
apiVersion: v1
kind: Pod
metadata:
  name: nginx  # 주석 가능
spec:
  containers:
  - name: nginx
    image: nginx
// API Server가 받는 JSON (기계 친화적)
{
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {
    "name": "nginx"
  },
  "spec": {
    "containers": [
      {
        "name": "nginx",
        "image": "nginx"
      }
    ]
  }
}

YAML = 사람을 위한 포맷 (읽기 쉽고, 주석 가능)
JSON = 기계를 위한 포맷 (파싱 빠름, 프로그래밍 언어와 호환)


마치며 ✍️

오늘은 실무에서 겪는 세 가지 문제와 쿠버네티스의 해결 방법을 알아봤습니다:

  1. 환경 충돌 → Namespace로 논리적 공간 분리
  2. 설정 공유 → YAML + apply로 선언적 관리
  3. 배포 타이밍 → 비동기 처리 이해 및 --wait 옵션

핵심은 선언적 방식(apply) 입니다:

  • 파일로 관리 → Git으로 버전 관리
  • 멱등성 보장 → CI/CD 자동화 가능
  • 변경 이력 추적 → 안전한 운영

이것이 바로 Infrastructure as Code (코드로 인프라 관리)의 시작입니다.

다음 포스팅에서는:

  • 무중단으로 파드 재시작하기 (rollout restart)
  • Git과 클러스터 자동 동기화 (--prune)
  • 효율적인 다중 리소스 설계 방법

을 다뤄보겠습니다. 🚀


이 글에서 배운 핵심 명령어:

# Namespace
kubectl create namespace dev
kubectl get pods -n dev

# Context
kubectl config get-contexts
kubectl config use-context dev-cluster

# 선언적 관리
kubectl apply -f app.yaml
kubectl delete -f app.yaml --wait=true

# 상태 확인
kubectl diff -f app.yaml
kubectl get pod nginx -o yaml

0개의 댓글