Chapter 22

파드/서비스 네트워킹과 DNS

  • 22.1 파드 네트워킹
  • 22.2 Kubernetes의 CNI
  • 22.3 Weave CNI
  • 22.4 IP 주소 관리
  • 22.5 서비스 네트워킹
  • 22.6 Kubernetes DNS
  • 22.7 CoreDNS

기초 네트워킹을 다 깔았으니 이제 진짜 핵심이야. 파드끼리 어떻게 통신하는지, 서비스가 뭔데 IP가 있는 건지, 이름으로 서비스를 찾는 DNS는 어떻게 돌아가는지. CNI 플러그인부터 CoreDNS까지 Kubernetes 네트워킹의 실질적인 동작 원리를 파헤쳐보자.

Kubernetes의 파드 네트워킹에서 핵심은, Kubernetes가 네트워킹 솔루션을 직접 제공하지 않는다는 거야. 대신 요구사항만 명확히 제시하고 해결은 우리한테 맡겨. 그 요구사항은 이래: 모든 파드는 고유한 IP 주소를 가져야 하고, 같은 노드 내의 다른 모든 파드와 해당 IP로 통신할 수 있어야 하고, 다른 노드의 파드와도 같은 IP 주소를 사용해서 NAT 없이 통신할 수 있어야 해. IP 주소 범위나 서브넷은 뭐든 상관없어.

이미 라우팅, IP 주소 관리, 네임스페이스, CNI에 대해 배웠으니까 그 지식으로 직접 해결해보자. 이렇게 해보면 Weave나 Calico 같은 솔루션이 어떻게 동작하는지 이해하는 데 도움이 돼.

3노드 클러스터가 있다고 하자. 어느 쪽이 마스터인지 워커인지는 상관없어, 다 파드를 실행하니까. 노드들은 외부 네트워크에 있고 IP가 192.168.1.11, .12, .13이야. 컨테이너가 생성되면 Kubernetes가 네트워크 네임스페이스를 만들어. 이 네임스페이스를 네트워크에 연결해야 하는데, 각 노드에 브리지 네트워크를 만들어서 거기에 연결하면 돼. 각 노드의 브리지 네트워크에는 서로 다른 서브넷을 할당해. 예를 들어 10.244.1.0/24, 10.244.2.0/24, 10.244.3.0/24 이런 식으로.

각 컨테이너에 대해 해야 할 일을 스크립트로 만들어두면 매번 반복 실행할 수 있어. 컨테이너를 네트워크에 연결하려면 veth pair(가상 케이블)를 만들고, 한쪽 끝을 컨테이너에, 다른 쪽을 브리지에 연결해. ip addr 명령으로 IP를 할당하고, 기본 게이트웨이에 대한 경로도 추가해. 마지막으로 인터페이스를 올려. 같은 노드의 다른 컨테이너에도 이 스크립트를 실행하면, 같은 노드 내 파드끼리 통신이 가능해. 이게 첫 번째 부분 해결이야.

다음은 다른 노드의 파드에 도달하는 건데, 노드 1의 파드(10.244.1.2)가 노드 2의 파드(10.244.2.2)를 핑하려고 하면, 10.244.2.2가 어디 있는지 모르니까 자기 네트워크가 아닌 걸로 판단하고 기본 게이트웨이인 노드 1 IP로 보내. 노드 1도 10.244.2.2가 어디인지 모르거든. 해결 방법은 노드의 라우팅 테이블에 경로를 추가하는 거야:

# 노드 1에서
ip route add 10.244.2.0/24 via 192.168.1.12
ip route add 10.244.3.0/24 via 192.168.1.13

모든 호스트에서 다른 모든 호스트의 네트워크에 대한 경로를 설정해. 간단한 환경에서는 잘 작동하지만, 네트워크 아키텍처가 복잡해지면 이것만으로는 부족해. 네트워크에 라우터가 있으면 라우터의 라우팅 테이블에서 경로를 중앙 관리하는 게 더 나은 방법이야. 이렇게 하면 각 노드에 만든 개별 가상 네트워크(10.244.1.0/24 등)가 하나의 큰 네트워크 10.244.0.0/16을 형성하게 돼.

이 모든 걸 수동으로 하고 싶은 사람은 없잖아. 매분 수천 개의 파드가 생성되는 대규모 환경에서는 불가능해. 그래서 CNI가 필요한 거야. CNI는 중개자 역할을 해. CNI가 Kubernetes한테 "컨테이너를 생성하자마자 이 스크립트를 호출해"라고 알려주고, CNI가 스크립트한테 "이런 형태로 만들어야 해"라고 알려줘. 스크립트에는 네트워크에 컨테이너를 추가하는 add 섹션과 네트워크에서 컨테이너를 제거하는 del 섹션이 있어야 해.

각 노드의 컨테이너 런타임이 컨테이너를 만들 때마다, 명령줄 인수로 전달된 CNI 구성을 확인하고 스크립트 이름을 알아내. CNI bin 디렉터리에서 해당 스크립트를 찾아서, add 명령과 컨테이너 이름, 네임스페이스 ID를 전달해서 실행하면 스크립트가 나머지를 처리해.

이어서 Kubernetes에서 CNI 플러그인을 어떻게 구성하고 어디에서 설정하는지 보자. CNI에 따르면 Kubernetes는 컨테이너 네트워크 네임스페이스를 생성하고, 올바른 네트워크 플러그인을 호출해서 해당 네임스페이스를 식별하고 올바른 네트워크에 연결하는 역할을 담당해. CNI 플러그인을 호출하는 건 컨테이너 생성을 담당하는 컴포넌트여야 하는데, 그게 바로 컨테이너 런타임이야. ContainerdCRI-O가 대표적이지. 예전에는 Docker가 원래 컨테이너 런타임이었는데, 나중에 Containerd라는 추상화로 대체됐어.

그러면 특정 플러그인을 사용하도록 어떻게 구성하냐? 두 개의 디렉터리가 중요해.

첫 번째는 /opt/cni/bin/ 디렉터리야. 여기에 사용 가능한 모든 CNI 플러그인 실행 파일이 들어 있어. bridge, DHCP, flannel 같은 것들이 실행 파일로 있거든. 컨테이너 런타임이 플러그인을 찾는 곳이야.

두 번째는 /etc/cni/net.d/ 디렉터리야. 여기에 어떤 플러그인을 사용할지, 어떻게 사용할지를 정의하는 구성 파일들이 있어. 파일이 여러 개 있으면 알파벳 순서로 선택해. 컨테이너 런타임은 이 디렉터리에서 구성 파일을 찾아서 어떤 플러그인을 써야 하는지 결정하는 거야.

bridge 구성 파일을 보면 CNI 표준에 정의된 형식이야. 이름이 있고, 타입이 bridge로 설정되어 있어. 그리고 필수 강의에서 논의한 개념들과 연결되는 설정들이 있어. **isGateway**는 브리지 인터페이스가 게이트웨이 역할을 하도록 IP 주소를 할당할지 정의하는 거고, **ipMasq**는 IP 마스커레이드를 위해 NAT 규칙을 추가할지 정의하는 거야.

ipam 섹션에서는 IP 주소 관리 구성을 정의해. 파드에 할당할 서브넷 범위와 필요한 경로를 지정할 수 있어. host-local 타입은 IP 주소가 이 호스트에서 로컬로 관리된다는 뜻이야. DHCP 서버에서 원격으로 관리하는 것과 대비되는 거지. 타입을 dhcp로 설정해서 외부 DHCP 서버를 구성할 수도 있어.

결국 파드가 생성되면 kubelet이 컨테이너 런타임에 전달하고, 컨테이너 런타임이 컨테이너를 생성한 다음, /etc/cni/net.d/에서 구성 파일을 확인해서 어떤 플러그인인지 알아내고, /opt/cni/bin/에서 해당 플러그인을 실행해서 네트워크 네임스페이스 연결, IP 할당 등을 처리하는 흐름이야.

이제 실제 CNI 솔루션 중 하나인 Weave를 살펴보자. Weave가 실제로 어떻게 동작하는지 제대로 이해해두면 다른 CNI 솔루션도 연관 지어 이해할 수 있거든. 이전에 직접 만든 스크립트를 CNI를 통해 kubelet에 통합하는 방법을 봤잖아. 이번에는 그 자리에 Weave 플러그인을 넣어서 어떻게 돌아가는지 보자.

이전 방식은 각 호스트의 라우팅 테이블에 다른 노드의 네트워크에 대한 경로를 직접 넣는 거였어. 패킷이 파드에서 나가면 네트워크를 거쳐 라우터로 가고, 라우터가 해당 파드를 호스트하는 노드로 보내는 식이지. 작은 환경에서는 되는데, 노드 수백 개에 파드 수백 개인 클러스터에서는 비현실적이야.

Weave의 동작 원리를 택배 회사에 비유해서 설명하면 이래. Kubernetes 클러스터가 회사고, 노드가 각각 다른 사무실이라고 생각해봐. 사무실마다 부서가 있고, 부서마다 사무실이 있어. 처음에는 1번 사무실에서 3번 사무실로 소포를 보내려면 사환이 직접 주소를 찾아서 차를 타고 가야 했어. 가까운 데는 괜찮은데, 여러 지역이나 국가로 확장하면 사환이 모든 경로를 파악하는 건 불가능해.

그래서 배송 전문 회사(Weave)에 위탁하는 거야. 이 회사가 제일 먼저 하는 건 모든 사무실(노드)에 자기 에이전트를 배치하는 거야. 이 에이전트들은 서로 계속 연락하면서 모든 사이트, 부서, 사무실 정보를 공유해. 소포가 보내지면 해당 사이트의 에이전트가 가로채서, 목표 사무실이 어디 있는지 자기 네트워크로 확인하고, 원본 소포를 새 소포 안에 넣어서(캡슐화) 목적지 사이트 주소로 보내. 목적지 에이전트가 소포를 받으면 열어서(디캡슐화) 원본을 찾아 해당 부서에 전달해.

이걸 Kubernetes로 다시 번역하면, Weave CNI 플러그인이 클러스터에 배포되면 각 노드에 에이전트(피어)를 배치해. 이 에이전트들은 서로 통신하면서 전체 토폴로지를 저장해 -- 다른 노드의 파드와 IP를 다 알고 있는 거지. Weave는 각 네트워크에 IP 주소를 할당하고, 파드에 브리지 네트워크를 붙여. 파드 하나에 여러 브리지가 붙을 수 있어, Weave 브리지에도 Docker가 만든 docker0 브리지에도 연결될 수 있다는 뜻이야. 패킷이 어디로 가는지는 컨테이너에 구성된 라우팅 경로에 달려 있는데, Weave는 파드가 올바른 경로를 설정해서 에이전트에게 도달하도록 해.

패킷을 다른 노드로 보낼 때 Weave가 패킷을 가로채서 별도의 네트워크에 있는지 확인해. 맞으면 이 패킷을 새로운 소스와 대상으로 캡슐화해서 네트워크로 보내. 다른 쪽의 Weave 에이전트가 패킷을 받아서 디캡슐화하고 올바른 파드로 전달해.

Weave를 배포하는 방법은 두 가지야. 클러스터 노드에 서비스나 데몬으로 직접 설치하는 방법도 있지만, Kubernetes가 이미 설정되어 있다면 더 쉬운 방법은 클러스터에 파드처럼 배포하는 거야. 기본 Kubernetes 시스템이 준비되고 노드 간 네트워킹이 되면, 단일 kubectl apply 명령으로 Weave에 필요한 모든 구성 요소를 배포할 수 있어. Weave 피어들은 DaemonSet으로 배포되는데, DaemonSet은 특정 종류의 파드 하나가 클러스터의 모든 노드에 반드시 배포되도록 보장하는 리소스야. 네트워크 플러그인처럼 모든 노드에 하나씩 필요한 경우에 딱 맞는 방식이지. 배포 후에는 각 노드에 Weave 피어가 돌아가는 걸 확인할 수 있고, 문제 해결이 필요하면 kubectl logs 명령으로 로그를 볼 수 있어.

그러면 IP 주소는 어떻게 관리될까? Kubernetes에서 **IP 주소 관리(IPAM)**의 핵심은, 파드에 IP를 할당하는 건 CNI 플러그인의 책임이라는 거야. Kubernetes 자체는 어떻게 하든 상관없어, 중복 IP만 안 나오게 적절히 관리하면 돼.

여기서 다루는 건 노드 자체의 IP가 아니야. 노드의 가상 브리지 네트워크에 IP 서브넷이 어떻게 할당되고, 파드에 IP가 어떻게 부여되는지에 대한 거야.

이전에 직접 만든 스크립트에서 컨테이너 네트워크 네임스페이스에 IP를 할당하는 섹션이 있었잖아. 그때 IP를 어떻게 관리했느냐면, IP 목록을 파일에 저장하고 스크립트에 이 파일을 관리하는 코드를 넣는 방식이었어. 이 파일은 각 호스트에 배치돼서 해당 노드에 있는 파드의 IP만 관리해.

근데 이걸 스크립트에서 직접 코딩하는 대신 CNI에 기본 제공되는 IPAM 플러그인에 위임할 수 있어. 두 가지가 있는데, host-local은 각 호스트에서 로컬로 IP를 관리하는 방식이고, DHCP는 외부 DHCP 서버에서 동적으로 할당하는 방식이야. host-local이 우리가 직접 했던 접근법을 구현한 플러그인인 거야. 어떤 플러그인을 쓰든 스크립트에서 호출하는 건 우리 책임이야.

CNI 구성 파일에는 ipam이라는 섹션이 있어서, 사용할 플러그인 타입, 서브넷, 경로를 지정할 수 있어. host-local을 하드 코딩하는 대신 스크립트가 이 구성 파일에서 타입을 읽어서 적절한 플러그인을 호출하면 더 유연해지는 거지.

결국 IP 할당의 책임 흐름은 이래: Kubernetes가 CNI 플러그인에게 위임하고, CNI 플러그인이 IPAM 플러그인에게 위임하고, IPAM 플러그인이 실제 IP 할당과 관리를 해. Weave나 Calico 같은 CNI 솔루션들은 각자의 방식으로 이 IPAM을 구현하고 있어.

여기까지가 파드 수준의 네트워킹이었다면, 이제 한 단계 위로 올라가서 서비스 네트워킹을 보자. 서비스 네트워킹에서 제일 중요한 건, 서비스는 가상의 객체라는 거야. 서비스에는 프로세스도 없고, 네임스페이스도 없고, 인터페이스도 없어. 서비스의 IP에서 실제로 수신 대기 중인 서버나 서비스 같은 건 존재하지 않아. 그런데 IP 주소가 있고, 모든 노드에서 접근 가능하지. 어떻게 가능한 걸까?

답은 kube-proxy야. 각 노드에서 실행되는 kube-proxy가 서비스 IP로 오는 트래픽을 실제 파드 IP로 포워딩하는 iptables 규칙을 만들어주는 거거든.

먼저 서비스 유형을 간단히 정리하면, ClusterIP는 클러스터 내부에서만 접근 가능한 서비스야. 파드가 어떤 노드에 있든 상관없이 클러스터 내 모든 파드에서 접근할 수 있어. 데이터베이스 같은 내부 서비스에 적합하지. NodePort는 ClusterIP 기능에다가 클러스터 외부에서도 접근할 수 있게 해줘. 클러스터의 모든 노드에서 특정 포트로 애플리케이션을 노출시키는 거야. 서비스에도 IP 주소가 할당되고 ClusterIP처럼 내부에서 사용할 수 있으면서, 추가로 외부 접근도 되는 거지.

동작 원리를 보면, 각 노드에서 kubelet은 파드 생성을 담당하고 CNI 플러그인을 호출해서 네트워크를 구성해. 마찬가지로 각 노드에서 kube-proxy도 실행되면서 kube API 서버를 통해 클러스터 변경사항을 감시해. 새 서비스가 생성될 때마다 kube-proxy가 작동하는 거야. 파드와 달리 서비스는 특정 노드에 생성되거나 할당되지 않아. 클러스터 전반의 개념이야.

서비스가 생성되면 미리 정의된 범위에서 IP 주소가 할당돼. 그러면 각 노드의 kube-proxy가 그 IP 주소를 가져다가 포워딩 규칙을 만들어 -- "이 IP로 오는 트래픽은 저 파드의 IP로 보내라"는 식으로. IP뿐만 아니라 IP와 포트의 조합이야. 서비스가 생성되거나 삭제될 때마다 이 규칙을 만들거나 지워.

kube-proxy는 여러 방식을 지원해. userspace 모드에서는 각 서비스 포트에서 직접 수신하며 프록시해. ipvs 모드에서는 IPVS 규칙을 만들어. 그리고 기본값이자 가장 익숙한 iptables 모드에서는 iptables NAT 규칙을 만들어. 프록시 모드는 kube-proxy 서비스 설정에서 --proxy-mode 옵션으로 지정하고, 설정하지 않으면 기본값이 iptables야.

실제 예시를 보자. 노드 1에 db라는 파드가 있고 IP가 10.244.1.2야. 이 파드를 클러스터 내에서 사용할 수 있도록 ClusterIP 서비스를 만들면, 서비스에 IP 10.103.132.104가 할당돼. 이 IP 범위는 kube API 서버의 --service-cluster-ip-range 옵션에 지정돼 있어, 기본값이 10.0.0.0/24인데, 실제로는 10.96.0.0/12 같은 식으로 설정하기도 해.

여기서 중요한 게 있는데, 파드 네트워크 CIDR 범위와 서비스 CIDR 범위가 절대 겹치면 안 돼. 파드 네트워크가 10.244.0.0/16이고 서비스 범위가 10.96.0.0/12이면, 이 둘은 겹치지 않아서 같은 IP가 파드와 서비스에 동시에 할당되는 일이 없어.

kube-proxy가 만든 iptables 규칙은 이렇게 확인할 수 있어:

iptables -L -t nat | grep <서비스이름>

kube-proxy가 만든 모든 규칙에는 서비스 이름이 포함된 주석이 있어서 검색하기 쉬워. 규칙을 보면 서비스 IP(10.103.132.104)와 포트 3306으로 가는 모든 트래픽의 대상 주소를 파드 IP(10.244.1.2)와 포트 3306으로 변경하라는 NAT 규칙이야. NodePort 서비스도 마찬가지로, 모든 노드의 해당 포트에서 들어오는 트래픽을 백엔드 파드로 포워딩하는 iptables 규칙을 만들어.

kube-proxy 로그에서도 이런 항목이 생성되는 걸 확인할 수 있어. 로그에서 어떤 프록시 모드를 사용하는지, 새 서비스 추가 시 항목이 만들어지는지 볼 수 있지. 로그 파일 위치는 설치 환경에 따라 다를 수 있고, 항목이 안 보이면 로그 상세도(verbosity) 수준도 확인해봐야 해.

서비스까지 됐으면 마지막 퍼즐은 DNS야. Kubernetes 클러스터에서 DNS의 핵심은, 서비스를 만들면 자동으로 DNS 레코드가 생성되어 이름으로 접근할 수 있다는 거야. 클러스터를 설정할 때 기본적으로 내장 DNS 서버가 배포돼 (수동 설정이면 직접 해야 하지만). 여기서 다루는 건 노드의 DNS가 아니라, 클러스터 내부의 파드와 서비스 간 DNS 확인이야.

서비스의 DNS 이름 체계를 보자. 왼쪽에 테스트 파드(IP: 10.244.1.5), 오른쪽에 웹 파드(IP: 10.244.2.5)가 있고, 웹 파드에 접근할 수 있도록 web-service라는 서비스를 만들었다고 해. 서비스가 생성되면 Kubernetes DNS가 자동으로 레코드를 만들어서 서비스 이름을 IP 주소에 매핑해. 그래서 클러스터 내 모든 파드는 서비스 이름으로 접근할 수 있어.

네임스페이스에 대해 이야기할 때, 같은 네임스페이스 안에서는 이름만으로 서로를 부르고, 다른 네임스페이스에 있는 사람을 부를 때는 성명을 사용한다고 했잖아. 같은 네임스페이스(예: default)에 있으면 web-service라는 이름만으로 접근 가능해. 하지만 web-service가 apps라는 다른 네임스페이스에 있으면 web-service.apps라고 해야 해. 서비스 이름이 이름이고, 네임스페이스가 성인 셈이지.

DNS 서버는 각 네임스페이스에 대해 하위 도메인을 만들어. 네임스페이스의 모든 파드와 서비스가 네임스페이스 이름의 하위 도메인 안에 그룹화되는 거야. 그리고 모든 서비스는 svc라는 또 다른 하위 도메인으로 그룹화돼. 마지막으로 모든 서비스와 파드는 클러스터의 루트 도메인으로 묶이는데, 기본값이 **cluster.local**이야. 그래서 서비스의 **정규화된 도메인 이름(FQDN)**은 이렇게 돼:

web-service.apps.svc.cluster.local

web-service가 서비스 이름, apps가 네임스페이스, svc가 서비스를 나타내는 하위 도메인, cluster.local이 루트 도메인이야.

파드에 대한 DNS 레코드는 기본적으로 생성되지 않아. 명시적으로 활성화해야 하는데, 활성화하면 파드에 대한 레코드도 만들어져. 다만 파드 이름을 쓰는 게 아니라, IP 주소의 점을 대시로 바꿔서 이름을 만들어. 예를 들어 IP가 10.244.1.5인 default 네임스페이스의 파드라면:

10-244-1-5.default.pod.cluster.local

네임스페이스는 동일하게 유지되고, 타입이 svc 대신 pod으로 설정되고, 루트 도메인은 항상 cluster.local이야.

마지막으로 이 DNS가 실제로 어떻게 구현되는지 보자. 두 파드가 서로 resolve 하게 하려면 어떻게 할까? 가장 단순한 방법은 각 파드의 /etc/hosts 파일에 상대방 항목을 추가하는 거야. 근데 파드가 수천 개이고 매분 수백 개씩 생기고 사라지면 그건 현실적이지 않아. 그래서 중앙 DNS 서버에 이 항목들을 모으고, 각 파드의 /etc/resolv.conf에 네임서버를 지정해서 DNS 서버를 가리키게 해. 새 파드가 만들어질 때마다 DNS 서버에 레코드를 추가하고, 파드의 resolv.conf도 DNS 서버를 가리키도록 설정하면 돼. 이게 바로 Kubernetes가 DNS를 구현하는 방식과 비슷해. 다만 파드 이름을 IP에 매핑하는 건 안 하고, IP 주소의 점을 대시로 바꿔서 호스트 이름을 만드는 식이야.

Kubernetes는 클러스터 내에 DNS 서버를 파드로 배포해. 1.12 이전에는 kube-dns를 썼고, 1.12부터는 CoreDNS가 표준이야. CoreDNS는 kube-system 네임스페이스에 Deployment로 배포되는데, 중복성을 위해 복제본이 2개야. 실제로는 ReplicaSet의 일부이고.

CoreDNS 파드는 CoreDNS 실행 파일을 돌리면서 **/etc/coredns/Corefile**이라는 설정 파일을 사용해. 이 파일에는 여러 플러그인이 구성되어 있어. 에러 처리, 상태 모니터링, 메트릭, 캐시 같은 일반적인 플러그인들이 있고, 핵심은 kubernetes 플러그인이야. 여기서 클러스터의 최상위 도메인 이름이 cluster.local로 설정돼. CoreDNS 서버의 모든 레코드가 이 도메인에 속하는 거지.

kubernetes 플러그인에는 pods 옵션이 있는데, 이게 파드에 대한 DNS 레코드 생성을 담당해. IP를 대시 형식으로 변환해서 각 파드에 레코드를 만드는 거야. 기본적으로 비활성화되어 있지만 여기서 활성화할 수 있어. forward 플러그인은 CoreDNS가 모르는 도메인(예: google.com)을 어디로 보낼지 정하는 건데, /etc/resolv.conf에 지정된 네임서버로 포워딩해. 이건 Kubernetes 노드의 resolv.conf를 사용하도록 설정되어 있어.

이 Corefile은 ConfigMap 오브젝트로 파드에 전달돼. 그래서 설정을 바꾸고 싶으면 ConfigMap을 편집하면 돼.

CoreDNS가 돌아가면서 Kubernetes 클러스터를 감시하다가 새 파드나 서비스가 만들어지면 자동으로 데이터베이스에 레코드를 추가해. 그다음 파드가 이 DNS 서버를 어떻게 찾느냐? DNS 솔루션을 배포할 때 kube-dns라는 이름의 서비스도 함께 만들어져. 이 서비스의 ClusterIP가 모든 파드의 네임서버로 설정되는 거야.

직접 설정할 필요는 없어. 파드가 생성될 때 kubelet이 자동으로 해주거든. kubelet 설정 파일을 보면 DNS 서버 IP와 도메인이 들어 있어. 파드 안의 /etc/resolv.conf를 보면 이렇게 돼 있어:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local

search 항목 덕분에 여러 형태로 서비스에 접근 가능해. web-service만 써도 되고, web-service.default도 되고, web-service.default.svc도 되고, 전체 FQDN인 web-service.default.svc.cluster.local도 돼. nslookup이나 host 명령으로 조회하면 FQDN이 반환되는데, 그냥 web-service만 입력해도 search 도메인을 자동으로 붙여서 전체 이름을 찾아내는 거야.

한 가지 주의할 점은, search 항목이 서비스에 대해서만 설정되어 있다는 거야. 파드에 접근할 때는 10-244-1-5.default.pod.cluster.local처럼 전체 FQDN을 써야 해. 짧은 이름으로는 파드에 도달할 수 없어.


정리

22장 읽고 기억할 거 세 가지:

  1. 파드 네트워킹은 CNI 플러그인이 전담한다. Kubernetes는 "모든 파드가 고유 IP로 NAT 없이 통신" 요구사항만 제시하고, 실제 구현은 Weave/Calico 같은 CNI가 veth pair, 브리지, 캡슐화로 해결한다. 플러그인 바이너리는 /opt/cni/bin/, 구성은 /etc/cni/net.d/에 있다.
  2. 서비스는 가상 객체고 kube-proxy의 iptables 규칙이 실체다. 서비스 IP에는 실제 프로세스가 없고, kube-proxy가 NAT 규칙으로 트래픽을 파드 IP로 포워딩한다. 파드 CIDR과 서비스 CIDR이 겹치면 안 된다.
  3. CoreDNS가 서비스 이름을 IP로 매핑한다. FQDN은 서비스.네임스페이스.svc.cluster.local 형태이고, resolv.conf의 search 도메인 덕분에 같은 네임스페이스에서는 서비스 이름만으로 접근 가능하다. 파드는 FQDN 필수.