k8s network

yeongjin·2026년 1월 24일

네트워크 관련 리눅스 명령어

ip link : network interface 목록 확인

ip addr : interface 에 할당된 ip 확인

route 또는 ip route : 라우팅 테이블 확인

리눅스로 패킷포워딩 하기

/proc/sys/net/ipv4/ip_forward 파일을 변경하여 Linux host가 패킷 포워딩 하게 할수도 있다. (기본적으로는 off)

  • 이 설정을 키면 해당 리눅스 입장에서 나한테 도착한 패킷의 목적지 ip가 내가 아닐경우, 해당 목적지 ip로 다시 패킷을 전달한다. 설정이 off일경우 그냥 내 패킷이 아니므로 드랍.

DNS

  • /etc/hosts 에 정의하여 Domain Name 정의 할수 있지만, ip가 바뀔때마다 파일을 수정해줘야 하기때문에 보통 중앙에서 관리하는 DNS 서버를 사용함.
  • dns 서버 정보는 /etc/resolv.conf 에 설정함
  • /etc/hosts와 dns 서버간의 우선순위는 /etc/nsswitch.conf에 정의됨

DNS 레코드 타입

  • A : IPv4 주소 ↔ 이름
  • AAAA : IPv6주소 ↔ 이름
  • CNAME : 이름 ↔ 이름 (별칭)

DNS 관련 명령어

  • ping, nslookup(dns 서버정보만 보고 /etc/hosts는 무시), dig(nslookup보다 더 자세히 보여주는 도구)

linux network namespace

  • linux namespace는 컨테이너가 호스트와 격리된 환경을 갖도록 만들수 있게 해줌.
  • namespace 내부 네트워크 정보도 호스트와 분리됨. 처음 namespace 생성시 아무 네트워크 연결이 없는 상태.
  • veth를 만들어 두 namespace 를 연결할 수 있음
  • namespace가 많아지면 1:1 연결보다 linux bridge (가상스위치) 를 생성하여 연결 (host입장에서는 linux bridge도 하나의 인터페이스 처럼 보임) 이 상황에서는 veth를 서로 연결하는게 아니라 veth를 bridge(가상 스위치)에 연결함
  • 가상스위치 인터페이스에 ip를 부여하면 호스트 ↔ 네임스페이스간 통신도 가능
  • namespace에서 외부 lan으로 패킷을 도달하게 하려면, 가상스위치 인터페이스에 부여한 ip를 namespace routing table (ip route)에 추가하고, 패킷응답을 돌려받을수 있게 호스트에서 패킷 출발지 주소를 자기 주소로 바꿔줘야 함 (snat) (iptable 이용)
  • namespace의 라우팅테이블에서 default gateway를 host의 linux bridge(가상 스위치)로 연결하면 외부 인터넷으로 나가게 할수있음. 그리고 반대로 외부에서 namespace로 접근하게 하려면. 호스트의 특정 포트로 들어오는 요청을 namespace ip의 포트로 전달하도록 포트포워딩(dnat)를 해야함. (iptable 이용)

docker networking

docker의 네트워크 옵션

  • none : 어떤 네트워크에도 연결되지 않음
  • host : 컨테이너가 호스트의 네트워크를 그대로 사용), 같은 포트를 쓰는 컨테이너를 여러개 실행 불가능
  • bridge : 기본, host 내부에 사설 네트워크를 생성해서 사용

docker 설치시 호스트에 네트워크 인터페이스 docker0 (bridge)이 추가됨. 이건 컨테이너 입장에서 가상 스위치임.

  • 컨테이너가 생성되면 network namespace가 생성되고 veth pair가 만들어져서 한쪽은 namespace 내부로 한쪽은 docker0 브리지에 연결됨. 그리고 컨테이너에는 특정 ip가 할당됨. 그래서 컨테이너들은 같은 bridge 네트워크에서 서로 통신이 가능함.

외부 접근을 위해서는 호스트 포트와 컨테이너 내부 포트의 port mapping이 필요

  • port mapping의 원리는 포트포워딩을 위해 iptable을 이용한 DNAT을 이용한 것임. 목적지에는 컨테이너IP:컨테이너포트가 들어감

CNI

컨테이너 네트워킹은 비슷한 작업을 반복하기 때문에 이런 설정 방법들을 표준화한 규칙을 CNI라 한다.

CNI가 Container Runtime / CNI Plugin 의 역할

  • Container Runtime : 컨테이너 생성시 namespace 생성, 컨테이너가 붙을 network 결정, 컨테이너 생성/삭제시 CNI Plugin 실행
  • CNI Plugin : 컨테이너에 IP주소할당, 라우터 설정, 필요한 네트워크 연결 구성
  • 이렇게 표준을 맞추면 런타임/플러그인 조합이 자유로워짐

k8s cluster 사용 포트

쿠버네티스 클러스터 환경에서는 기본적으로 사용되는 포트들을 다음에서 열어줘야 함

  • linux 방화벽, cloud service 보안 설정

Master Node

  • 6443(api server), 10250(kubelet), 10259(kube-scheduler), 10257(kube-controller-manager)

Worker Node

  • 30000~32767(NodePort 서비스), 10250(kubelet)

멀티 마스터일 때 etcd 관련포트

  • 2379(etcd client), 2380(etcd peer)

pod network를 수동으로 만든다면?

일단 k8s의 pod network는 모든 pod가 고유한 ip를 가지고 노드가 같든 다르든 pod끼리 nat없이도 서로 통신이 가능해야 한다. 수동으로 이를 구축한다면 다음과 같은 과정을 따라야한다.

  1. 컨테이너가 생길때마다 네임스페이스생성
  2. 각 노드에 브리지(가상스위치) 생성 및 IP 할당, veth pair 만들고 pod와 브리지 연결.
  3. pod에 ip할당하고 default gateway 설정한다음에 interface up
  4. 다른 노드끼리도 통신이 되야하므로 모든 노드가 서로의 pod subnet으로 가는 route를 알아야함( 노드마다 직접 추가도 가능하지만, 노드들이 포함된 네트워크의 라우터에 pod network 라우팅 정보를 몰아서 설정하는것이 좋음. 결과적으로 전체 pod 네트워크는 하나의 큰 네트워크 처럼 보임)

CNI Plugin은 컨테이너 런타임 호출에 의해 2~4번 과정이 담긴 네트워크 스크립트를 실행하는 역할을 함.

  • cni plugin 실행 파일은 /opt/cni/bin, cni 설정 파일은 /etc/cni/net.d 하위에 존재

Weave CNI Plugin

어떤 pod network가 어느 노드에 있는지 라우팅 테이블로 관리한다면, 노드나 pod가 많아질때 라우팅 테이블 엔트리가 너무 많아져서 관리가 힘듬. 이에 대한 해결책으로 weave cni plugin을 쓸수 있음.

  • weave cni 가 설치되면 각 노드에 Weave Peer Agent가 배포되고 서로 어떤 pod가 어떤 노드에 있는지 정보를 공유함.
  • weave는 노드마다 자체 브리지를 생성. pod는 이 브리지에 연결되고 ip를 할당받음. (pod가 weave bridge, docker bridge와 동시에 연결된 상황) 대신 이렇게 되면 pod가 어떤 경로로 통신하는지는 k8s 클러스터가 위치한 네트워크의 라우팅 테이블이 아닌 pod 내부의 라우팅 설정에 따라 결정됨
  • 특정 pod가 다른 node에 있는 pod로 패킷을 보낼때 weave가 이를 가로채(pod의 기본게이트웨이를 weave 브릿지로 설정하는 방식.) 캡슐화하여 노드간 네트워크를 통해 목적지 노드의 weave peer에게 전달하는 방식

IPAM(IP Address Management)

  • pod마다 ip가 중복되지않게 설정하고 노드안의 브리지네트워크에 어떤 서브넷을 설정할지는 CNI Plugin의 책임임.
  • cni에서는 ip할당을 도와주는 ipam plugin을 제공함.

Service Networking

  • 실제 k8s 운영환 경에서는 pod ip로 직접 접근하기보다 service를 통해 접근. service는 ip와 이름을 가짐
  • service의 종류 : ClusterIP(클러스터 내에서만 접근), NodePort(모든노드의 특정포트를 열어서 외부에서 접근 가능)
  • service는 실제 프로세스나 네트워크 인터페이스가 없는 가상의 개념임. 실제 원리는 kube-proxy가 각 노드의 iptable 규칙을 통해 포워딩을 설정함.
  • service 생성시 service ip는 api server 설정에 있는 service CIDR에서 결정됨. 단 이것은 pod cidr과 겹치면 안됨.

Kubernetes DNS

  • service를 만들면 dns 레코드가 자동 생성됨
  • web-service.apps.svc.cluster.local 같은 구조
    • web-service : 서비스 이름
    • apps : 네임스페이스
    • svc : 서비스 그룹
    • 클러스터 루트 도메인 : cluster.local (기본값)
  • 같은 namespace에 있으면 서비스이름 만으로 접근 가능. 다른 namespace에 있으면 서비스이름.네임스페이스 형태로 접근 (pod에 search 도메인이 설정되어 있기 때문)
  • pod dns 레코드는 자동 생성되지 않지만 명시적으로 활성화 가능

Core DNS

  • pod끼리 통신하려면 결국 이름→ip로 변환할 dns가 필요함. pod의 /etc/hosts에 직접 등록하는건 너무 불편하니 중앙 dns 서버가 필요한 것임.
  • k8s는 중앙 dns 서버를 core dns라는 이름의 pod 형태로 배포
  • CoreDNS가 처리못하는 클러스터 외부도메인에 대한 질의는 pod에 설정된 상위 DNS 서버(노드 설정 따라감)로 포워딩.

Ingress

Service vs Ingress

  • Service : Pod들을 묶어 로드밸런싱 하고 접근 경로를 제공
  • Ingress : 클러스터 내부에 있는 L7 로드밸런서/리버스 프록시 역할, 하나의 url로 들어온 요청을 url 파라미터, host(domain) 기반 여러 서비스로 라우팅 가능. ssl 적용도 중앙에서 처리 가능

Ingress 구성 요소

  • Ingress Controller : 실제 트래픽을 처리하는 엔진 (ex: nginx, gce, haproxy, traefik, istio 등)
  • Ingress Resource : Ingress Controller에 적용할 라우팅 규칙 정의 (YAML)

Ingress 라우팅 방식

  • 단일 backend : 모든 트래픽 하나의 서비스로 전달
  • url path 기반 라우팅: / → web-service, /watch → video-service
  • host(도메인) 기반 라우팅: mystore.com → web-service, watch.mystore.com → video-service

Gateway API

Ingress의 문제점

  • Ingress는 결국 단일 리소스라 한 팀이 소유/관리해야 하는 구조라서 서비스가 서로 다른 팀들이 하나의 Ingress를 사용하면 관리가 어렵고 충돌 가능성이 큼, (멀티 테넌시 환경에서의 문제점)
  • Ingress에는 트래픽 비율 분배, 헤더 조작, 인증 같은 고급 기능들이 표준 spec에 없어서 각 Ingress Controller들이 각자 구현함 → 특정 컨트롤러에 종속되는 문제 발생

Ingress의 문제를 해결하기위해 k8s 공식 프로젝트인 Gate API가 나옴

Gateway API의 오브젝트별 역할 분리 (Ingress의 멀티 테넌시 환경에서의 문제점을 해결하기 위해 서로 다른 담당자가 서로 다른 리소스를 관리하도록 설계됨)

  • GatewayClass (인프라 제공자 담당) : 어떤 네트워크/로드밸런서 구현을 쓸지 정의 (nginx 등)
  • Gateway (클러스터 운영자 담당): Gateway Class의 실제 인스턴스 실제 Listener(포트/프로토콜)등을 정의
  • Route (애플리케이션 개발자 담당): 실제 서비스 라우팅 규칙 정의

0개의 댓글