CKAD — Kubernetes Application Developer
Service, Ingress and NetworkPolicy
한국어 원문으로 표시합니다.
목표
Service 의 포트 세 종류를 구분해서 지정하고, named port·헤드리스·StatefulSet DNS·Ingress 라우팅·NetworkPolicy 화이트리스트를 매니페스트로 작성할 수 있게 된다.
왜 중요한가
Service 에서 나오는 실수는 거의 전부 두 가지다. 셀렉터가 파드 라벨과 다른 것과 포트 세 개를 헷갈리는 것. 셀렉터가 어긋나면 오류 없이 엔드포인트가 비고, 클라이언트는 연결 거부만 본다. kubectl get endpoints 가 비어 있는지 확인하는 습관 하나로 대부분의 시간을 아낀다.
포트는 방향으로 외우면 헷갈리지 않는다. port 는 들어오는 쪽(클라이언트가 Service 에 붙는 포트), targetPort 는 나가는 쪽(Service 가 파드에 붙는 포트), nodePort 는 바깥에서 들어오는 쪽(노드에서 여는 포트)이다.
헤드리스 Service 는 로드밸런싱을 포기하는 선택이다. 가상 IP 를 만들지 않고 DNS 가 파드 IP 목록을 그대로 돌려주며, StatefulSet 과 짝지으면 파드마다 고유 이름이 생긴다. 클라이언트가 특정 인스턴스를 지목해야 하는 워크로드(DB 프라이머리, 샤드)에 쓴다.
NetworkPolicy 는 기본 허용, 정책이 붙으면 화이트리스트라는 두 문장으로 요약된다. 그래서 실무에서는 먼저 네임스페이스 전체에 기본 차단을 걸고 필요한 통신만 열어 준다. 정책들은 서로를 덮어쓰지 않고 합집합으로 더해진다는 점도 기억한다.
단계
- 네임스페이스
ckad-net을 만든다. Deploymentfrontend(레플리카 2, 라벨app=frontend, 이미지nginx:1.27, 컨테이너 포트80에 이름http)와 Servicefrontend(ClusterIP,port: 80,targetPort: 80, 셀렉터app=frontend)를 만든다. - Deployment
backend(레플리카 2, 라벨app=backend, 이미지nginx:1.27, 컨테이너 포트8080에 이름api)와 Servicebackend(ClusterIP,port: 80,targetPort: api— 이름으로, 셀렉터app=backend)를 만든다. - Service
frontend-np를 만든다. 타입NodePort,port: 80,targetPort: 80,nodePort: 30080, 셀렉터app=frontend. - 헤드리스 Service
cache-hs(clusterIP: None,port: 6379, 셀렉터app=cache)와 StatefulSetcache(레플리카 3,serviceName: cache-hs, 라벨app=cache, 이미지nginx:1.27)를 만든다. 그리고 0번 파드의 완전한 DNS 이름을/root/ckad-net/dns.txt에 한 줄로 적는다. - Ingress
shop을 만든다.ingressClassName: nginx, 호스트shop.ckad.local, 경로/(pathTypePrefix) → Servicefrontend포트 80, 경로/api(pathTypePrefix) → Servicebackend포트 80. - NetworkPolicy
backend-allow-frontend를 만든다. 대상은app=backend파드,policyTypes: [Ingress], 허용 출발지는app=frontend파드, 포트는 TCP8080. - NetworkPolicy
default-deny-ingress를 만든다.podSelector: {}(네임스페이스 전체),policyTypes: [Ingress], ingress 규칙은 비워 둔다. 이 시점에 Servicebackend의 셀렉터가 실제로 파드 2개 이상을 고르는지kubectl get pods -n ckad-net -l app=backend로 확인한다.
참고
kubectl create deployment frontend --image=nginx:1.27 --replicas=2 -n ckad-net --dry-run=client -o yaml로 뼈대를 뽑고ports에 이름을 붙인다.kubectl expose deployment frontend --port=80 --target-port=80 -n ckad-net은 셀렉터를 자동으로 채워 준다.- 4단계 DNS 이름 형식:
<파드이름>.<서비스이름>.<네임스페이스>.svc.cluster.local - 흔한 실수 1: NetworkPolicy 에서
podSelector(적용 대상)와from[].podSelector(허용 출발지)를 바꿔 쓰는 것. - 흔한 실수 2:
nodePort를 30000 미만으로 지정하는 것. 기본 허용 범위는 30000~32767 이다. - 흔한 실수 3:
targetPort에 이름을 쓸 때 Service 가 아니라 컨테이너의 포트 이름을 써야 한다는 것. - 이 환경에는 Ingress 컨트롤러와 실제 CNI 데이터플레인이 없으므로 라우팅과 정책이 실제로 동작하는지는 확인할 수 없다. 오브젝트를 정확히 쓰는 것이 목표다.
Deployment 와 ClusterIP Service
네임스페이스 ckad-net 을 만든다. Deployment frontend(레플리카 2, 라벨 app=frontend, 이미지 nginx:1.27, 컨테이너 포트 80 에 이름 http)와 Service frontend(ClusterIP, port: 80, targetPort: 80, 셀렉터 app=frontend)를 만든다.
kubectl expose deployment 를 쓰거나 Service 를 직접 쓴다. Service 의 셀렉터가 파드 라벨과 정확히 같아야 엔드포인트가 붙는다. 컨테이너 포트에 이름을 붙여 두면 다음 단계가 편하다.
named port 로 targetPort 연결
Deployment backend(레플리카 2, 라벨 app=backend, 이미지 nginx:1.27, 컨테이너 포트 8080 에 이름 api)와 Service backend(ClusterIP, port: 80, targetPort: api — 이름으로, 셀렉터 app=backend)를 만든다.
컨테이너의 ports[].name 에 붙인 이름을 Service 의 targetPort 에 문자열로 쓴다. 이름은 15자 이하 소문자/숫자/하이픈이어야 한다.
NodePort 로 바깥에 열기
Service frontend-np 를 만든다. 타입 NodePort, port: 80, targetPort: 80, nodePort: 30080, 셀렉터 app=frontend.
타입을 NodePort 로 두고 nodePort 를 직접 지정한다. 허용 범위는 30000~32767 이고, 지정하지 않으면 자동 할당된다. port 와 targetPort 는 그대로 남는다.
헤드리스 Service 와 StatefulSet
헤드리스 Service cache-hs(clusterIP: None, port: 6379, 셀렉터 app=cache)와 StatefulSet cache(레플리카 3, serviceName: cache-hs, 라벨 app=cache, 이미지 nginx:1.27)를 만든다. 그리고 0번 파드의 완전한 DNS 이름을 /root/ckad-net/dns.txt 에 한 줄로 적는다.
헤드리스는 clusterIP: None 이다. StatefulSet 의 serviceName 에 그 Service 이름을 적어야 파드별 DNS 이름이 생긴다. 이름 규칙은 파드이름·서비스이름·네임스페이스 순으로 점을 찍는다.
Ingress 로 호스트와 경로 라우팅
Ingress shop 을 만든다. ingressClassName: nginx, 호스트 shop.ckad.local, 경로 / (pathType Prefix) → Service frontend 포트 80, 경로 /api (pathType Prefix) → Service backend 포트 80.
networking.k8s.io/v1 이고 백엔드는 service.name 과 service.port.number 로 지정한다. 각 경로에는 pathType 이 필수다. 규칙은 rules[].host 와 rules[].http.paths[] 구조다.
NetworkPolicy 로 프런트엔드만 허용
NetworkPolicy backend-allow-frontend 를 만든다. 대상은 app=backend 파드, policyTypes: [Ingress], 허용 출발지는 app=frontend 파드, 포트는 TCP 8080.
podSelector 는 정책이 적용될 대상을, ingress[].from[].podSelector 는 허용할 출발지를 가리킨다. 둘을 바꿔 쓰기 쉬우니 주의한다. 포트도 함께 좁힌다.
기본 차단 정책과 셀렉터 점검 (종합)
NetworkPolicy default-deny-ingress 를 만든다. podSelector: {} (네임스페이스 전체), policyTypes: [Ingress], ingress 규칙은 비워 둔다. 이 시점에 Service backend 의 셀렉터가 실제로 파드 2개 이상을 고르는지 kubectl get pods -n ckad-net -l app=backend 로 확인한다.
빈 podSelector: {} 는 네임스페이스의 모든 파드를 뜻한다. 여기에 ingress 규칙을 하나도 두지 않으면 기본 차단이 된다. 그리고 Service 셀렉터가 실제 파드를 고르는지 kubectl get pods -l 로 직접 확인한다.