6. Core Concepts - Section Introduction
- Kubernetes 클러스터 아키텍처의 핵심 개념 소개
- 주요 API 프리미티브: Pods, ReplicaSets, Deployments, Services
- CKAD 과정을 이미 수료했다면 일부 섹션은 건너뛰고 Practice Test만 진행해도 됨
7. Cluster Architecture
공식문서: Kubernetes Components
항구 비유: 화물선(Worker Node) = 컨테이너 운반, 관제선(Master Node) = 모니터링 및 관리
Master Node (Control Plane) 구성 요소
| 컴포넌트 | 역할 |
|---|---|
| ETCD | 클러스터 전체 상태/설정을 key-value로 저장 |
| Kube Scheduler | 새 컨테이너를 어느 Worker Node에 배치할지 결정 |
| Controllers | 노드 생명주기, 컨테이너 복제, 시스템 안정성 관리 |
| Kube API Server | 클러스터 통신/관리의 중앙 허브 |
Worker Node 구성 요소
| 컴포넌트 | 역할 |
|---|---|
| Kubelet | 노드의 “선장” - 컨테이너 생명주기 관리, 상태 보고 |
| Kube Proxy | 네트워킹 규칙 설정, 노드 간 컨테이너 통신 지원 |
| Container Runtime | Docker, Containerd, CRI-O 등 |
graph TB subgraph Master["Master Node (Control Plane)"] ETCD["ETCD"] SCH["Scheduler"] CTRL["Controllers"] API["API Server"] end subgraph W1["Worker 1"] K1["Kubelet"] KP1["Kube Proxy"] CR1["Container Runtime"] P1["Pod Pod"] end subgraph W2["Worker 2"] K2["Kubelet"] KP2["Kube Proxy"] CR2["Container Runtime"] P2["Pod Pod"] end subgraph W3["Worker 3"] K3["Kubelet"] KP3["Kube Proxy"] CR3["Container Runtime"] P3["Pod Pod"] end API --> K1 API --> K2 API --> K3
8. Docker vs ContainerD
공식문서: Container Runtimes
Container Runtime 진화 과정
- Docker가 처음 컨테이너 생태계를 지배
- Kubernetes가 CRI (Container Runtime Interface) 도입 → OCI 표준 준수 런타임 지원
- Docker는 CRI 이전에 만들어져서 호환 X → Docker Shim 으로 임시 해결
- ContainerD 가 CRI-compatible 런타임으로 독립 → Docker Shim 불필요
- Kubernetes v1.24: Docker 런타임 지원 제거 (Docker Shim 제거)
Docker로 빌드한 이미지는 OCI 호환이므로 ContainerD에서 정상 동작
CLI 도구 비교
| 도구 | 개발 주체 | 용도 | 비고 |
|---|---|---|---|
| ctr | ContainerD | 디버깅 전용 | 기능 제한적, 일상 사용 비추천 |
| nerdctl | ContainerD | 범용 컨테이너 관리 | Docker CLI와 거의 동일한 문법 |
| crictl | Kubernetes | 디버깅/검사 | 모든 CRI 런타임과 호환 |
# ctr 사용 예시
ctr images pull docker.io/library/redis:alpine
ctr run docker.io/library/redis:alpine redis
# nerdctl 사용 (docker 명령어와 동일)
nerdctl run --name redis redis:alpine
nerdctl run --name webserver -p 80:80 -d nginx
# crictl 사용 (Kubernetes 디버깅용)
crictl pull busybox
crictl images
crictl ps -a
crictl pods # Docker에는 없는 기능Runtime Endpoint 설정 (v1.24+)
crictl --runtime-endpoint <endpoint>
# 또는
export CONTAINER_RUNTIME_ENDPOINT=<endpoint>9. A Note on Docker Deprecation
- Kubernetes v1.24부터 Docker 런타임 지원 공식 제거
- Docker로 빌드한 이미지는 계속 사용 가능 (OCI 표준 준수)
- ContainerD가 Docker의 핵심 런타임이었으므로, 실질적으로 동일한 컨테이너 실행
- 기존 Docker 워크플로우(이미지 빌드, 푸시 등)는 변경 없음
10. ETCD For Beginners
- 분산 key-value 저장소 (신뢰할 수 있고 일관성 있는 데이터 저장)
- 쿼럼 메커니즘으로 데이터 일관성 보장
기본 동작
# ETCD 설치 및 실행
tar -xzvf etcd-v3.5.0-linux-amd64.tar.gz
./etcd
# 기본 포트: 2379
# key-value 저장/조회
etcdctl put key1 value1
etcdctl get key1
# 모든 키 조회
etcdctl get / --prefix --keys-onlyETCD 버전
| 버전 | API | 비고 |
|---|---|---|
| v2 | etcdctl (v2 API) | 이전 버전 |
| v3 | etcdctl (v3 API) | 현재 기본값 |
# API 버전 확인/설정
export ETCDCTL_API=3
etcdctl version11. ETCD in Kubernetes
- 클러스터의 모든 정보 저장: Nodes, Pods, Configs, Secrets, Accounts, Roles, Bindings 등
kubectl get명령의 모든 정보가 ETCD에서 조회됨- 클러스터에 대한 모든 변경사항이 ETCD에 반영되어야 완료로 간주
배포 방식에 따른 차이
수동 설치:
wget -q --https-only https://github.com/etcd-io/etcd/releases/download/...
# etcd 서비스 직접 구성
# --advertise-client-urls https://${INTERNAL_IP}:2379kubeadm 설치:
# etcd가 kube-system 네임스페이스에 pod으로 실행
kubectl get pods -n kube-system | grep etcd
# etcd 내부의 모든 키 확인
kubectl exec etcd-master -n kube-system -- etcdctl get / \
--prefix --keys-only \
--limit=10 \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--cert /etc/kubernetes/pki/etcd/server.crt \
--key /etc/kubernetes/pki/etcd/server.keyHA (고가용성) 환경
- 여러 Master Node에 ETCD가 분산 배포
--initial-cluster옵션으로 ETCD 인스턴스들의 주소 설정
12. ETCD - Commands (Optional)
# API v3 사용 설정
export ETCDCTL_API=3
# 필수 인증 옵션
etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
member list
# 스냅샷 저장 (백업)
etcdctl snapshot save /tmp/etcd-backup.db
# 스냅샷 상태 확인
etcdctl snapshot status /tmp/etcd-backup.db13. Kube-API Server
공식문서: kube-apiserver Reference
- Kubernetes의 중앙 관리 컴포넌트
- 모든 kubectl 명령은 API Server를 통해 처리됨
- 유일하게 ETCD와 직접 통신하는 컴포넌트
요청 처리 흐름
- 사용자/kubectl → API Server로 요청
- Authentication — 누구인지 확인
- Authorization — 권한 있는지 확인
- Admission Control — 요청 내용 검증/수정
- ETCD 업데이트 — 변경사항 저장
API Server ↔ Scheduler / Controller / Kubelet 은 항상 양방향 통신
Pod 생성 시 동작 순서
- API Server가 요청 인증/인가
- Pod 객체 생성 (아직 노드 미할당)
- ETCD 업데이트
- Scheduler가 적절한 노드 결정 → API Server에 알림
- API Server가 ETCD 업데이트
- 해당 노드의 Kubelet이 컨테이너 런타임에 이미지 배포 지시
- Kubelet이 상태를 API Server에 보고 → ETCD 업데이트
설정 확인
# kubeadm 환경
cat /etc/kubernetes/manifests/kube-apiserver.yaml
# 서비스 환경
cat /etc/systemd/system/kube-apiserver.service
# 프로세스 확인
ps -aux | grep kube-apiserver14. Kube Controller Manager
- 다양한 Controller들을 하나의 프로세스로 관리하는 바이너리
주요 Controller
| Controller | 역할 |
|---|---|
| Node Controller | 5초 간격 노드 상태 감시, 40초 후 unreachable 처리, 5분 후 pod eviction |
| Replication Controller | 원하는 수의 pod 복제본 유지 |
| Deployment Controller | Deployment 리소스 관리 |
| Namespace Controller | Namespace 생명주기 관리 |
| ServiceAccount Controller | ServiceAccount 자동 생성 |
| Job Controller | Job 리소스 관리 |
Node Controller 타이밍
Node Monitor Period: 5초 (상태 체크 간격)
Node Monitor Grace: 40초 (응답 없으면 unreachable)
Pod Eviction Timeout: 5분 (unreachable 노드의 pod 퇴출)
설정 확인
# kubeadm 환경
cat /etc/kubernetes/manifests/kube-controller-manager.yaml
# 프로세스 확인
ps -aux | grep kube-controller-manager15. Kube Scheduler
공식문서: Kubernetes Scheduler
- Pod를 어느 노드에 배치할지 결정만 함 (실제 배치는 Kubelet이 담당)
스케줄링 2단계
1단계: Filter (필터링)
→ 리소스 부족한 노드 제외
2단계: Rank/Score (점수 매기기)
→ 남은 노드들에 점수 부여
→ 예: pod 배치 후 남는 리소스가 많을수록 높은 점수
설정 확인
# kubeadm 환경
cat /etc/kubernetes/manifests/kube-scheduler.yaml
# 프로세스 확인
ps -aux | grep kube-scheduler16. Kubelet
공식문서: kubelet Reference
- Worker Node의 “선장” - 노드의 모든 활동을 관리
- API Server로부터 지시를 받아 컨테이너 생성/삭제
- 정기적으로 노드 및 pod 상태를 API Server에 보고
주요 역할
- 클러스터에 노드 등록
- 컨테이너 런타임(ContainerD 등)에 이미지 다운로드 및 컨테이너 실행 지시
- Pod/컨테이너 상태 모니터링 및 보고
kubeadm은 kubelet을 자동 배포하지 않음. Worker Node에 수동 설치 필요
# kubelet 프로세스 확인
ps -aux | grep kubelet17. Kube Proxy
공식문서: kube-proxy Reference
- 모든 노드에서 실행되는 네트워크 프로세스
- Service 생성을 감시하고 iptables 규칙 설정
- Pod 간 통신을 안정적으로 유지
동작 원리
- Pod A (Node 1) → Service IP (가상 IP) → iptables 규칙 → Pod B (Node 2)
- Service에 IP가 할당되면, Kube Proxy가 각 노드의 iptables에 규칙 추가
- 해당 Service IP로 향하는 트래픽을 실제 Pod IP로 포워딩
Kube Proxy는 DaemonSet으로 배포되어 모든 노드에서 실행됨
kubectl get daemonset -n kube-system | grep kube-proxy18. Pods
공식문서: Pods
Pod란?
“Kubernetes에서 컨테이너를 직접 다루지 않고, 한 겹 감싸놓은 것”
왜 이렇게 감쌀까?
- 컨테이너 하나로 끝나지 않는 경우가 많음 (앱 + 로그 수집기 같이 붙여 배포)
- 같은 운명공동체로 묶으면 네트워크/볼륨 공유가 자연스러움
- 스케줄링 단위를 통일해 관리 복잡도↓
비유: 컨테이너 = 선원, Pod = 선원이 일하는 작업 구역 — 한 방에 있는 선원끼리는 서로 바로 대화하고(localhost), 같은 물품 창고를 쓴다(volume).
- Kubernetes에서 가장 작은 배포 단위
- Pod = 하나의 애플리케이션 인스턴스
핵심 개념
- 스케일링 = Pod 수 증가 (컨테이너 수 증가가 아님)
- 보통 1 Pod = 1 컨테이너 (메인 애플리케이션)
- Multi-container Pod도 가능 (보조/사이드카 컨테이너)
Pod 안의 컨테이너들은 같은 네트워크/볼륨 공유
- Main Container — 보통 이것만 (1 Pod = 1 컨테이너 패턴)
- Helper Container — 사이드카 등 보조 (선택)
kubectl 기본 명령
# Pod 생성 및 실행
kubectl run nginx --image nginx
# Pod 목록 조회
kubectl get pods
# Pod 상세 정보
kubectl describe pod nginx
# Pod 삭제
kubectl delete pod nginx19. Pods with YAML
Kubernetes YAML 필수 4개 필드
apiVersion: # API 버전
kind: # 리소스 종류
metadata: # 이름, 라벨 등 메타데이터
spec: # 리소스 상세 사양API Version 참고
| kind | apiVersion |
|---|---|
| Pod | v1 |
| Service | v1 |
| ReplicaSet | apps/v1 |
| Deployment | apps/v1 |
Pod YAML 예시
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx# YAML로 Pod 생성
kubectl apply -f pod-definition.yml
# YAML로 Pod 정의 확인
kubectl get pod myapp-pod -o yaml20. Demo - Pods with YAML
# 1. YAML 파일 작성
vim pod.yml
# 2. Pod 생성
kubectl apply -f pod.yml
# 3. 상태 확인
kubectl get pods
# 4. 상세 정보 확인 (이벤트, 컨테이너 상태 등)
kubectl describe pod myapp-pod
# 5. Pod 내부 로그 확인
kubectl logs myapp-pod
kubectl describe로 Pod 문제 디버깅 시 Events 섹션을 가장 먼저 확인
21-25. Practice Tests & Labs - Pods
# 유용한 명령어 모음
# 현재 네임스페이스의 pod 수 확인
kubectl get pods --no-headers | wc -l
# 특정 pod의 이미지 확인
kubectl describe pod <pod-name> | grep -i image
# pod 생성 (imperative)
kubectl run redis --image=redis
# YAML 파일 생성 (dry-run)
kubectl run redis --image=redis --dry-run=client -o yaml > redis-pod.yaml
# pod 수정
kubectl edit pod <pod-name>
# 강제 교체
kubectl replace --force -f pod.yaml26. Recap - ReplicaSets
공식문서: ReplicaSet
ReplicaSet이란?
“Pod 개수를 원하는 숫자로 유지해주는 감시자”
왜 필요한가?
- Pod는 노드 장애나 OOM 등으로 언제든 죽을 수 있음
- 사람이 매번 재생성하면 SRE가 잠을 못 잠
- ReplicaSet이 “replicas: 3” 선언하면 항상 3개로 자동 복구
Label/Selector로 동작: ReplicaSet은 자기가 만든 Pod가 아니어도 selector에 맞는 Pod라면 관리 대상으로 취급. 이미 떠있는 Pod를 흡수하기도 함.
Replication Controller vs ReplicaSet
| 구분 | Replication Controller | ReplicaSet |
|---|---|---|
| apiVersion | v1 | apps/v1 |
| selector | 선택적 | 필수 (matchLabels) |
| 상태 | 구버전 (deprecated) | 현재 권장 |
Replication Controller 정의
apiVersion: v1
kind: ReplicationController
metadata:
name: myapp-rc
labels:
app: myapp
type: front-end
spec:
replicas: 3
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginxReplicaSet 정의
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myapp-replicaset
labels:
app: myapp
type: front-end
spec:
replicas: 3
selector:
matchLabels:
type: front-end
template:
metadata:
name: myapp-pod
labels:
app: myapp
type: front-end
spec:
containers:
- name: nginx-container
image: nginx스케일링 방법
# 방법 1: YAML 파일 수정 후 교체
kubectl replace -f replicaset-definition.yml
# 방법 2: scale 명령어
kubectl scale --replicas=6 -f replicaset-definition.yml
kubectl scale --replicas=6 replicaset myapp-replicaset
# ReplicaSet 확인
kubectl get replicaset
kubectl describe replicaset myapp-replicaset
kubectl scale명령어로 스케일링하면 YAML 파일에는 반영되지 않음
27-28. Labs - ReplicaSets
# ReplicaSet 조회
kubectl get rs
# ReplicaSet 상세 정보
kubectl describe rs <name>
# ReplicaSet 삭제 (관련 pod도 함께 삭제)
kubectl delete rs <name>
# ReplicaSet 수정
kubectl edit rs <name>
# YAML 에러 디버깅 팁
# apiVersion이 v1이면 에러 → apps/v1로 변경
# selector.matchLabels와 template.metadata.labels가 일치해야 함29. Deployments
공식문서: Deployment
Deployment란?
“ReplicaSet을 감싼 배포 관리자”
ReplicaSet만 있어도 Pod 개수 유지는 되는데 왜 Deployment가 필요한가?
- 이미지를 v1 → v2로 바꿀 때 하나씩 교체해서 다운타임 없이 업데이트하고 싶다
- 문제 생기면 이전 버전으로 즉시 롤백하고 싶다
- 배포 히스토리(revision)를 남기고 싶다
Deployment는 이걸 대신 해주는 고수준 리소스. 내부적으로 ReplicaSet을 새로 만들어 점진적으로 트래픽을 이동시킴.
비유: ReplicaSet = “항상 3명 있어”, Deployment = “3명에서 5명으로 서서히 바꿔줘, 문제 생기면 되돌려”
- ReplicaSet 상위 개념으로, 롤링 업데이트, 롤백, 일시정지/재개 기능 제공
- 프로덕션에서 가장 많이 사용하는 리소스
Deployment 정의
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: nginx
image: nginx:1.14.2Deployment YAML은 ReplicaSet YAML과 거의 동일 (kind만 다름)
주요 명령어
# 생성
kubectl create -f deployment-definition.yml
# 조회 (Deployment → ReplicaSet → Pod 계층 확인)
kubectl get deployments
kubectl get rs
kubectl get pods
# 모든 리소스 한번에 확인
kubectl get all
# 이미지 업데이트 (롤링 업데이트)
kubectl set image deployment/myapp-deployment nginx=nginx:1.16.0
# 롤아웃 상태 확인
kubectl rollout status deployment/myapp-deployment
# 롤아웃 히스토리
kubectl rollout history deployment/myapp-deployment
# 롤백
kubectl rollout undo deployment/myapp-deployment
# 스케일링
kubectl scale deployment myapp-deployment --replicas=530. Certification Tip!
# 시험에서 YAML 빠르게 생성하는 방법
# Pod
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
# Deployment
kubectl create deployment nginx --image=nginx --replicas=3 --dry-run=client -o yaml > deploy.yaml
# Service (ClusterIP)
kubectl expose pod nginx --port=80 --target-port=8080 --dry-run=client -o yaml > svc.yaml
--dry-run=client -o yaml조합을 반드시 외워두기
31-32. Labs - Deployments
# Deployment 생성
kubectl create deployment httpd-frontend --image=httpd:2.4-alpine --replicas=3
# Deployment 상세 확인
kubectl describe deployment <name>
# Deployment가 관리하는 ReplicaSet과 Pod 확인
kubectl get all33. Services
공식문서: Service
Service란?
“여러 Pod를 대표하는 고정 주소 + 로드밸런서”
왜 필요한가?
- Pod는 재시작/재배포 시 IP가 바뀜 — 다른 Pod가 이 IP를 하드코딩할 수 없음
- 동일한 앱이 여러 Pod로 떠 있는데, 요청을 알아서 분산해줘야 함
Service가 해결하는 것:
- 고정 DNS 이름 (
web-service.default.svc.cluster.local) - 고정 가상 IP (ClusterIP)
- selector 라벨로 대상 Pod 자동 묶기 + 부하 분산
Label/Selector가 Kubernetes의 모든 리소스 연결 방식의 핵심. Service → Pod, ReplicaSet → Pod, NetworkPolicy → Pod 전부 라벨로 연결.
- Pod 간 통신 및 외부 접근을 위한 안정적인 엔드포인트 제공
- Pod IP는 동적이므로 Service가 고정 접점 역할
Service 3가지 타입
| 타입 | 외부 접근 | 포함 관계 | 용도 |
|---|---|---|---|
| ClusterIP (기본) | ❌ | — | 클러스터 내부 통신용 가상 IP |
| NodePort | 노드 IP:30000~32767 | ClusterIP + 외부 포트 | 외부 테스트 |
| LoadBalancer | LB 외부 IP | NodePort + 클라우드 LB | 프로덕션 외부 |
상위 타입은 하위 타입 기능을 모두 포함: LoadBalancer ⊃ NodePort ⊃ ClusterIP
NodePort 서비스 포트 개념
- 외부 사용자 → 노드 IP의
nodePort: 30008접속 - (Node 내부)
nodePort: 30008→ Service의port: 80 - Service의
port: 80→ Pod의targetPort: 80
외부 → 노드 → Service → Pod, 3단계 포트 매핑
NodePort 정의
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: NodePort
ports:
- port: 80 # Service 포트
targetPort: 80 # Pod 포트
nodePort: 30008 # 노드 포트 (30000-32767)
selector:
app: myapp# Service 생성
kubectl create -f service-definition.yml
# Service 조회
kubectl get svc
# Service 상세
kubectl describe svc myapp-service34. Services - ClusterIP
- 기본 Service 타입 (type 생략 시 ClusterIP)
- 클러스터 내부에서만 접근 가능한 안정적 IP 제공
- 마이크로서비스 간 통신에 사용
멀티 티어 애플리케이션 예시
- Frontend Pods → frontend-svc (ClusterIP) → Backend Pods → backend-svc (ClusterIP) → DB Pods
- Pod 간 통신을 직접 IP 대신 Service를 거쳐 안정적으로 — Pod IP가 바뀌어도 영향 없음
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: backendDNS 기반 접근
# 같은 namespace 내
backend-service
# 다른 namespace
backend-service.default.svc.cluster.localHeadless Service
# 개별 Pod IP에 직접 접근이 필요한 경우 (예: StatefulSet)
spec:
clusterIP: None
selector:
app: db
ports:
- port: 330635. Services - LoadBalancer
- 클라우드 환경에서 외부 트래픽 분산을 위한 Service 타입
- 클라우드 프로바이더의 LB와 자동 연동 (AWS ELB, Azure LB, GCP LB)
NodePort vs LoadBalancer
| 구분 | NodePort | LoadBalancer |
|---|---|---|
| 외부 접근 | 노드IP:포트 | LB의 외부 IP |
| 포트 범위 | 30000-32767 | 표준 포트 (80, 443) |
| IP 안정성 | 노드 장애 시 변경 | 안정적 외부 IP |
| 클라우드 필요 | X | O |
| 비용 | 무료 | 유료 (클라우드 과금) |
| 용도 | 테스트/내부 | 프로덕션/공개 |
apiVersion: v1
kind: Service
metadata:
name: voting-service
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: voting-app온프레미스 환경에서는 MetalLB 같은 오픈소스 LB 구현체 사용 가능
36-37. Labs - Services
# Service 조회
kubectl get svc
# Deployment를 Service로 노출
kubectl expose deployment webapp --type=NodePort --port=8080 --name=webapp-service
# Service 접근 테스트
curl <node-ip>:<node-port>Service 생성 3가지 방법 비교 (시험 필수)
| 방법 | 장점 | 한계 | Selector |
|---|---|---|---|
kubectl run --expose | Pod + Service 한 번에 | ClusterIP만, 옵션 제한 | 자동 추출 |
kubectl expose | 기존 리소스 기반 빠름 | nodePort 직접 지정 불가 | 기존 리소스에서 자동 추출 |
kubectl create service | nodePort 지정 가능, 세밀 제어 | selector 수동 지정 필요 | 이름과 동일하게 자동 |
방법 1: kubectl run —expose (Pod + Service 동시)
# Pod 생성과 동시에 ClusterIP Service 생성
kubectl run nginx --image=nginx --port=80 --expose
# → Pod "nginx" + Service "nginx" (ClusterIP, port 80)
# 한계: ClusterIP만 지원, NodePort 불가방법 2: kubectl expose (권장 - 기존 리소스)
# ── 기본 (ClusterIP) ──────────────────────────────────────
kubectl expose pod redis --port=6379 --name=redis-svc
kubectl expose deploy nginx --port=80 --name=web-svc
# ── NodePort ──────────────────────────────────────────────
kubectl expose deploy nginx --port=80 --type=NodePort --name=web-np
# ❌ 한계: --node-port 옵션 없음 → 무작위 할당됨 (30000-32767 중)
# ── LoadBalancer ──────────────────────────────────────────
kubectl expose deploy nginx --port=80 --type=LoadBalancer
# ── targetPort 지정 ───────────────────────────────────────
kubectl expose deploy web --port=80 --target-port=8080
# ── YAML 뽑아서 nodePort 수정 ─────────────────────────────
kubectl expose deploy nginx --port=80 --type=NodePort --dry-run=client -o yaml > svc.yaml
# vi svc.yaml에서 ports 아래 nodePort: 30080 추가방법 3: kubectl create service (NodePort 지정 필요시)
# ── ClusterIP ─────────────────────────────────────────────
kubectl create service clusterip my-svc --tcp=80:8080
# ── NodePort (nodePort 직접 지정 가능!) ───────────────────
kubectl create service nodeport my-svc --tcp=80:8080 --node-port=30080
# ── LoadBalancer ──────────────────────────────────────────
kubectl create service loadbalancer my-svc --tcp=80:8080
# ── ExternalName ──────────────────────────────────────────
kubectl create service externalname my-db --external-name=db.example.com
# ── Headless Service ──────────────────────────────────────
kubectl create service clusterip my-svc --clusterip=None --tcp=80:80NodePort를 정확히 지정해야 하면
kubectl create service nodeport --node-port=XXXXX사용.kubectl expose는 nodePort 옵션이 없음.
Selector 차이 주의
# expose: 기존 리소스의 selector를 그대로 승계
kubectl expose deploy web --port=80
# → Service selector는 deploy의 matchLabels 그대로
# create service: Service 이름과 동일한 selector로 자동 설정
kubectl create service clusterip my-svc --tcp=80:80
# → selector: app=my-svc (Pod에 이 라벨이 있어야 연결됨)
# → 기존 Pod 라벨이 다르면 Endpoint 안 잡힘 → 수정 필요38. Namespaces
공식문서: Namespaces
Namespace란?
“하나의 클러스터를 여러 개의 ‘논리적 공간’으로 나누는 폴더 같은 것”
왜 필요한가?
- 개발/스테이징/운영 환경을 한 클러스터 안에서 분리하고 싶다
- 팀별로 리소스 이름 충돌을 방지 (A팀
web, B팀web이 공존) - 리소스 사용량(CPU/메모리) 팀별로 쿼터 제한 가능
- RBAC으로 팀별 접근 권한 분리
무엇이 namespace를 가지나?
- Pod, Service, Deployment, ConfigMap, Secret 등 대부분의 리소스
- 반면 Node, PV, ClusterRole 등 클러스터 전역 리소스는 namespace 없음
기본 4개 namespace는 클러스터 생성과 동시에 만들어짐.
default는 사용자용, 나머지는 시스템용.
- 클러스터 내 리소스를 논리적으로 분리하는 가상 클러스터
기본 Namespace
| Namespace | 용도 |
|---|---|
| default | 기본 작업 공간 |
| kube-system | Kubernetes 시스템 컴포넌트 |
| kube-public | 모든 사용자 접근 가능한 리소스 |
| kube-node-lease | 노드 하트비트 관리 |
리소스 접근 방식
# 같은 namespace 내
mysql.connect("db-service")
# 다른 namespace
mysql.connect("db-service.dev.svc.cluster.local")db-service . dev . svc . cluster.local
───────── ─── ─── ────────────
서비스 이름 NS 서비스 도메인
Namespace 명령어
# 특정 namespace의 pod 조회
kubectl get pods -n kube-system
# 모든 namespace의 pod 조회
kubectl get pods --all-namespaces
kubectl get pods -A
# Namespace 생성
kubectl create namespace dev
# 기본 namespace 변경
kubectl config set-context --current --namespace=devResourceQuota (네임스페이스 리소스 제한)
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 5Gi
limits.cpu: "10"
limits.memory: 10Gi39-40. Labs - Namespaces
# namespace 목록
kubectl get ns
# 특정 namespace의 pod 수
kubectl get pods -n <namespace> --no-headers | wc -l
# 다른 namespace에 리소스 생성
kubectl run redis --image=redis -n finance
# YAML에서 namespace 지정
metadata:
name: myapp
namespace: dev41. Imperative vs Declarative
Imperative (명령형)
- 어떻게 할지 하나하나 지시 (How)
- 빠르고 간편하지만, 추적/재현 어려움
# Imperative 명령 예시
kubectl run nginx --image=nginx
kubectl create deployment nginx --image=nginx --replicas=3
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl set image deployment/nginx nginx=nginx:1.18
kubectl scale deployment nginx --replicas=5
kubectl edit deployment nginxDeclarative (선언형)
- 무엇을 원하는지 선언 (What)
- YAML 파일로 원하는 상태를 정의하고
kubectl apply로 적용 - GitOps, 버전 관리에 적합
# Declarative 방식
kubectl apply -f nginx.yaml
kubectl apply -f /path/to/configs/비교
| 구분 | Imperative | Declarative |
|---|---|---|
| 방식 | 명령어로 직접 실행 | YAML 파일 + apply |
| 추적 | 어려움 | Git으로 관리 가능 |
| 시험 | O (빠른 작업에 유리) | O (복잡한 작업에 유리) |
| 프로덕션 | 비추천 | 권장 |
CKA 시험에서는 Imperative + Declarative 모두 잘 활용해야 함
- 간단한 작업: Imperative (
kubectl run,kubectl create)- 복잡한 작업:
--dry-run=client -o yaml로 YAML 생성 후 수정
42. Certification Tips - Imperative Commands with Kubectl
# Pod 생성
kubectl run nginx --image=nginx --port=80 --labels="tier=frontend"
# Deployment 생성
kubectl create deployment webapp --image=nginx --replicas=3
# Service 생성 (ClusterIP)
kubectl expose pod redis --port=6379 --name=redis-service
# Service 생성 (NodePort) - YAML 생성 후 nodePort 수동 추가
kubectl expose pod nginx --port=80 --type=NodePort --name=nginx-service --dry-run=client -o yaml > svc.yaml
# Namespace 생성
kubectl create namespace dev-ns
# ConfigMap 생성
kubectl create configmap app-config --from-literal=key1=value1
# Secret 생성
kubectl create secret generic app-secret --from-literal=password=pass12343. Kubectl Explain Command
# 리소스 필드 설명 확인
kubectl explain pod
kubectl explain pod.spec
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy
# 재귀적으로 모든 필드 확인
kubectl explain pod --recursive | less시험 중 YAML 필드가 기억나지 않을 때
kubectl explain활용
44-45. Labs - Imperative Commands
# 유용한 조합 패턴
# 1. dry-run으로 YAML 생성 → 수정 → 적용
kubectl run custom-nginx --image=nginx --port=8080 --dry-run=client -o yaml > custom.yaml
vim custom.yaml
kubectl apply -f custom.yaml
# 2. Deployment + expose 한번에
kubectl create deployment redis-deploy --image=redis --replicas=2 -n dev-ns
# 3. Pod를 Service로 노출
kubectl run httpd --image=httpd:alpine --port=80 --expose
# 위 명령은 Pod와 ClusterIP Service를 동시에 생성46. Kubectl Apply Command
3-way Merge 동작 원리
kubectl apply는 3가지 설정을 비교하여 변경사항을 결정:
1. Local YAML 파일 (로컬에 저장된 파일)
2. Live Object Config (클러스터에 실제 존재하는 설정)
3. Last Applied Config (마지막으로 apply한 설정 - annotation에 JSON으로 저장)
Local YAML 과 Last Applied Config 두 입력을 함께 비교 → Live Object 에 어떤 필드를 추가/수정/삭제할지 결정
Last Applied Config는 Live Object의
metadata.annotations에kubectl.kubernetes.io/last-applied-configuration키로 JSON 형태로 저장됨
kubectl create나kubectl replace는 Last Applied Config를 저장하지 않음. Declarative 방식에서는 항상kubectl apply사용
47-49. 마무리
- Core Concepts는 CKA 시험의 기본이 되는 가장 중요한 섹션
- 모든 컴포넌트의 역할과 관계를 이해하는 것이 핵심
- Practice Test를 반복하여 명령어에 익숙해지기
핵심 컴포넌트 요약 표
| 컴포넌트 | 위치 | 핵심 역할 |
|---|---|---|
| ETCD | Master | 클러스터 상태 저장소 |
| API Server | Master | 모든 통신의 중앙 허브 |
| Scheduler | Master | Pod 배치 결정 |
| Controller Manager | Master | 원하는 상태 유지 |
| Kubelet | Worker | 컨테이너 관리 실행 |
| Kube Proxy | Worker | 네트워크 규칙 관리 |
핵심 리소스 계층 구조
graph TD DEP["Deployment<br/>배포 관리, 롤링 업데이트"] --> RS["ReplicaSet<br/>복제본 수 유지"] RS --> POD["Pod<br/>컨테이너 실행 단위"] POD --> CTR["Container<br/>실제 애플리케이션"] SVC["Service (네트워크 접근점)"] --> CIP["ClusterIP<br/>내부 통신"] SVC --> NP["NodePort<br/>외부 테스트"] SVC --> LB["LoadBalancer<br/>프로덕션 외부 접근"]