서비스, 로드밸런싱, 네트워킹쿠버네티스의 네트워킹에 대한 개념과 리소스에 대해 설명한다. Show
쿠버네티스 네트워크 모델클러스터의 모든 쿠버네티스는 모든 네트워킹 구현에 대해 다음과 같은 근본적인 요구사항을 만족할 것을 요구한다. (이를 통해, 의도적인 네트워크 분할 정책을 방지)
참고: 이 모델은 전반적으로 덜 복잡할 뿐만 아니라, 무엇보다도 VM에 있던 앱을 컨테이너로 손쉽게 포팅하려는 쿠버네티스 요구사항을 만족시킬 수 있다. 작업을 기존에는 VM에서 실행했었다면, VM은 IP주소를 가지며 프로젝트 내의 다른 VM과 통신할 수 있었을 것이다. 이는 동일한 기본 모델이다. 쿠버네티스 IP 주소는 이것이 어떻게 구현되는지는 사용하는 컨테이너 런타임의 상세사항이다.
쿠버네티스 네트워킹은 다음의 네 가지 문제를 해결한다.
1 - 서비스파드 집합에서 실행중인 애플리케이션을 네트워크 서비스로 노출하는 추상화 방법 쿠버네티스를 사용하면 익숙하지 않은 서비스 디스커버리 메커니즘을 사용하기 위해 애플리케이션을 수정할 필요가 없다. 쿠버네티스는 파드에게 고유한 IP 주소와 파드 집합에 대한 단일 DNS 명을 부여하고, 그것들 간에 로드-밸런스를 수행할 수 있다. 동기쿠버네티스 파드는 클러스터 목표 상태(desired state)와 일치하도록 생성되고 삭제된다. 파드는 비영구적 리소스이다. 만약 앱을 실행하기 위해 디플로이먼트를 사용한다면, 동적으로 파드를 생성하고 제거할 수 있다. 각 파드는 고유한 IP 주소를 갖지만, 디플로이먼트에서는 한 시점에 실행되는 파드 집합이 잠시 후 실행되는 해당 파드 집합과 다를 수 있다. 이는 다음과 같은 문제를 야기한다. ("백엔드"라 불리는) 일부 파드 집합이 클러스터의 ("프론트엔드"라 불리는) 다른 파드에 기능을 제공하는 경우, 프론트엔드가 워크로드의 백엔드를 사용하기 위해, 프론트엔드가 어떻게 연결할 IP 주소를 찾아서 추적할 수 있는가? 서비스 로 들어가보자. 서비스 리소스쿠버네티스에서 서비스는 파드의 논리적 집합과 그것들에 접근할 수 있는 정책을 정의하는 추상적 개념이다. (때로는 이 패턴을 마이크로-서비스라고 한다.) 서비스가 대상으로 하는 파드 집합은 일반적으로 셀렉터가 결정한다. 서비스 엔드포인트를 정의하는 다른 방법에 대한 자세한 내용은 셀렉터가 없는 서비스를 참고한다. 예를 들어, 3개의 레플리카로 실행되는 스테이트리스 이미지-처리 백엔드를 생각해보자. 이러한 레플리카는 대체 가능하다. 즉, 프론트엔드는 그것들이 사용하는 백엔드를 신경쓰지 않는다. 백엔드 세트를 구성하는 실제 파드는 변경될 수 있지만, 프론트엔드 클라이언트는 이를 인식할 필요가 없으며, 백엔드 세트 자체를 추적해야 할 필요도 없다. 서비스 추상화는 이러한 디커플링을 가능하게 한다. 클라우드-네이티브 서비스 디스커버리애플리케이션에서 서비스 디스커버리를 위해 쿠버네티스 API를 사용할 수 있는 경우, 서비스 내 파드 세트가 변경될 때마다 업데이트되는 엔드포인트를 API 서버에 질의할 수 있다. 네이티브 애플리케이션이 아닌 (non-native applications) 경우, 쿠버네티스는 애플리케이션과 백엔드 파드 사이에 네트워크 포트 또는 로드 밸런서를 배치할 수 있는 방법을 제공한다. 서비스 정의쿠버네티스의 서비스는 파드와 비슷한 REST 오브젝트이다. 모든 REST 오브젝트와 마찬가지로, 서비스 정의를 API 서버에 예를 들어, 각각 TCP 포트 9376에서 수신하고
이 명세는 "my-service"라는 새로운 서비스 오브젝트를 생성하고, 쿠버네티스는 이 서비스에 서비스 프록시가 사용하는 IP 주소 ("cluster IP"라고도 함) 를 할당한다. (이하 가상 IP와 서비스 프록시 참고) 서비스 셀렉터의 컨트롤러는 셀렉터와 일치하는 파드를 지속적으로 검색하고, "my-service"라는 엔드포인트 오브젝트에 대한 모든 업데이트를 POST한다. 파드의 포트 정의에 이름이 있으므로, 서비스의
이것은 서로 다른 포트 번호를 통해 가용한 동일 네트워크 프로토콜이 있고, 단일 구성 이름을 사용하는 서비스 내에 혼합된 파드가 존재해도 가능하다. 이를 통해 서비스를 배포하고 진전시키는 데 많은 유연성을 제공한다. 예를 들어, 클라이언트를 망가뜨리지 않고, 백엔드 소프트웨어의 다음 버전에서 파드가 노출시키는 포트 번호를 변경할 수 있다. 서비스의 기본 프로토콜은 TCP이다. 다른 지원되는 프로토콜을 사용할 수도 있다. 많은 서비스가 하나 이상의 포트를 노출해야 하기 때문에, 쿠버네티스는 서비스 오브젝트에서 다중 포트 정의를 지원한다. 각 포트는 동일한 셀렉터가 없는 서비스서비스는 일반적으로 셀렉터를 이용하여 쿠버네티스 파드에 대한 접근을 추상화하지만, 셀렉터 대신 매칭되는(corresponding) 엔드포인트와 함께 사용되면 다른 종류의 백엔드도 추상화할 수 있으며, 여기에는 클러스터 외부에서 실행되는 것도 포함된다. 예시는 다음과 같다.
이러한 시나리오 중에서 파드 셀렉터 없이 서비스를 정의 할 수 있다. 예를 들면
이 서비스에는 셀렉터가 없으므로, 해당 엔드포인트 오브젝트가 자동으로 생성되지 않는다. 엔드포인트 오브젝트를 수동으로 추가하여, 서비스를 실행 중인 네트워크 주소 및 포트에 서비스를 수동으로 매핑할 수 있다.
엔드포인트 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다. 서비스를 위한 객체인 엔드포인트를 만들 때, 새로운 객체의 이름을 그것의 서비스 이름과 같게 설정해야 한다. 셀렉터가 없는 서비스에 접근하면 셀렉터가 있는 것처럼 동일하게 작동한다. 위의 예에서, 트래픽은 YAML에 정의된 단일 엔드 포인트로 라우팅된다. ExternalName 서비스는 셀렉터가 없고 DNS명을 대신 사용하는 특수한 상황의 서비스이다. 자세한 내용은 이 문서 뒷부분의 ExternalName 섹션을 참조한다. 초과 용량 엔드포인트엔드포인트 리소스에 1,000개가 넘는 엔드포인트가 있는 경우 쿠버네티스 v1.22(또는 그 이상) 클러스터는 해당 엔드포인트에 엔드포인트슬라이스기능 상태: 엔드포인트슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는 API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트슬라이스를 사용하면 여러 리소스에 네트워크 엔드포인트를 분산시킬 수 있다. 기본적으로, 엔드포인트슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며, 추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트슬라이스가 생성된다. 엔드포인트슬라이스는 엔드포인트슬라이스에서 자세하게 설명된 추가적인 속성 및 기능을 제공한다. 애플리케이션 프로토콜기능 상태:
이 필드는 표준 쿠버네티스 레이블 구문을 따른다. 값은 IANA 표준 서비스 이름 또는 가상 IP와 서비스 프록시쿠버네티스 클러스터의 모든 노드는 라운드-로빈 DNS를 사용하지 않는 이유항상 발생하는 질문은 왜 쿠버네티스가 인바운드 트래픽을 백엔드로 전달하기 위해 프록시에 의존하는가 하는 점이다. 다른 접근법이 있는가? 예를 들어, 여러 A 값 (또는 IPv6의 경우 AAAA)을 가진 DNS 레코드를 구성하고, 라운드-로빈 이름 확인 방식을 취할 수 있는가? 서비스에 프록시를 사용하는 데는 몇 가지 이유가 있다.
본 페이지의 뒷 부분에서 다양한 kube-proxy 구현의 동작에 대해 읽을 수 있다. 우선 알아두어야 할 것은, 구성kube-proxy는 구성에 따라 결정되는 여러 모드에서 기동될 수 있다.
유저 스페이스(User space) 프록시 모드이 모드에서는, kube-proxy는 쿠버네티스 컨트롤 플레인의 서비스 및 엔드포인트 오브젝트의 추가와 제거를 감시한다. 각 서비스는 로컬 노드에서 포트(임의로 선택됨)를 연다. 이 "프록시 포트"에 대한 모든 연결은 (엔드포인트를 통해 보고된 대로) 서비스의 백엔드 파드 중 하나로 프록시된다. kube-proxy는 사용할 백엔드 파드를 결정할 때 서비스의 마지막으로, 유저-스페이스 프록시는 서비스의 기본적으로, 유저스페이스 모드의 kube-proxy는 라운드-로빈 알고리즘으로 백엔드를 선택한다. iptables 프록시 모드이 모드에서는, kube-proxy는 쿠버네티스 컨트롤 플레인의 서비스, 엔드포인트 오브젝트의 추가와 제거를 감시한다. 각 서비스에 대해, 서비스의 기본적으로, iptables 모드의 kube-proxy는 임의의 백엔드를 선택한다. 트래픽을 처리하기 위해 iptables를 사용하면 시스템 오버헤드가 줄어드는데, 유저스페이스와 커널 스페이스 사이를 전환할 필요없이 리눅스 넷필터(netfilter)가 트래픽을 처리하기 때문이다. 이 접근 방식은 더 신뢰할 수 있기도 하다. kube-proxy가 iptables 모드에서 실행 중이고 선택된 첫 번째 파드가 응답하지 않으면, 연결이 실패한다. 이는 userspace 모드와 다르다. 해당 시나리오에서는, kube-proxy는 첫 번째 파드에 대한 연결이 실패했음을 감지하고 다른 백엔드 파드로 자동으로 재시도한다. 파드 준비성 프로브(readiness probe)를 사용하여 백엔드 파드가 제대로 작동하는지 확인할 수 있으므로, iptables 모드의 kube-proxy는 정상으로 테스트된 백엔드만 볼 수 있다. 이렇게 하면 트래픽이 kube-proxy를 통해 실패한 것으로 알려진 파드로 전송되는 것을 막을 수 있다. IPVS 프록시 모드기능 상태:
IPVS 프록시 모드는 iptables 모드와 유사한 넷필터 후크 기능을 기반으로 하지만, 해시 테이블을 기본 데이터 구조로 사용하고 커널 스페이스에서 동작한다. 이는 IPVS 모드의 kube-proxy는 iptables 모드의 kube-proxy보다 지연 시간이 짧은 트래픽을 리다이렉션하고, 프록시 규칙을 동기화할 때 성능이 훨씬 향상됨을 의미한다. 다른 프록시 모드와 비교했을 때, IPVS 모드는 높은 네트워크 트래픽 처리량도 지원한다. IPVS는 트래픽을 백엔드 파드로 밸런싱하기 위한 추가 옵션을 제공한다. 다음과 같다.
이 프록시 모델에서 클라이언트가 쿠버네티스 또는 서비스 또는 파드에 대해 알지 못하는 경우 서비스의 IP:포트로 향하는 트래픽은 적절한 백엔드로 프록시된다. 특정 클라이언트의 연결이 매번 동일한 파드로 전달되도록 하려면, 멀티-포트 서비스일부 서비스의 경우, 둘 이상의 포트를 노출해야 한다. 쿠버네티스는 서비스 오브젝트에서 멀티 포트 정의를 구성할 수 있도록 지원한다. 서비스에 멀티 포트를 사용하는 경우, 모든 포트 이름을 명확하게 지정해야 한다. 예를 들면
자신의 IP 주소 선택
선택한 IP 주소는 API 서버에 대해 구성된 트래픽 정책외부 트래픽 정책
내부 트래픽 정책기능 상태:
서비스 디스커버리하기쿠버네티스는 서비스를 찾는 두 가지 기본 모드를 지원한다. - 환경 변수와 DNS 환경 변수파드가 노드에서 실행될 때, kubelet은 각 활성화된 서비스에 대해 환경 변수 세트를 추가한다. 예를 들어, TCP 포트 6379를 개방하고 클러스터 IP 주소 10.0.0.11이 할당된 서비스
DNS애드-온을 사용하여 쿠버네티스 클러스터의 DNS 서비스를 설정할 수(대개는 필수적임) 있다. CoreDNS와 같은, 클러스터-인식 DNS 서버는 새로운 서비스를 위해 쿠버네티스 API를 감시하고 각각에 대한 DNS 레코드 세트를 생성한다. 클러스터 전체에서 DNS가 활성화된 경우 모든 파드는 DNS 이름으로 서비스를 자동으로 확인할 수 있어야 한다. 예를 들면, 쿠버네티스 네임스페이스 다른 네임스페이스의 파드들은 이름을 쿠버네티스는 또한 알려진 포트에 대한 DNS SRV (서비스) 레코드를 지원한다. 쿠버네티스 DNS 서버는 헤드리스(Headless) 서비스때때로 로드-밸런싱과 단일 서비스 IP는 필요치 않다. 이 경우, "헤드리스" 서비스라는 것을 만들 수 있는데, 명시적으로 클러스터 IP ( 쿠버네티스의 구현에 묶이지 않고, 헤드리스 서비스를 사용하여 다른 서비스 디스커버리 메커니즘과 인터페이스할 수 있다. 헤드리스 셀렉터가 있는 경우셀렉터를 정의하는 헤드리스 서비스의 경우, 엔드포인트 컨트롤러는 API에서 셀렉터가 없는 경우셀렉터를 정의하지 않는 헤드리스 서비스의 경우, 엔드포인트 컨트롤러는
서비스 퍼블리싱 (ServiceTypes)애플리케이션 중 일부(예: 프론트엔드)는 서비스를 클러스터 밖에 위치한 외부 IP 주소에 노출하고 싶은 경우가 있을 것이다. 쿠버네티스
인그레스를 사용하여 서비스를 노출시킬 수도 있다. 인그레스는 서비스 유형이 아니지만, 클러스터의 진입점 역할을 한다. 동일한 IP 주소로 여러 서비스를 노출시킬 수 있기 때문에 라우팅 규칙을 단일 리소스로 통합할 수 있다. NodePort 유형
포트를 프록시하기 위해 특정 IP를 지정하려면, kube-proxy에 대한 이 플래그는 쉼표로 구분된 IP 블록 목록(예: 예를 들어, 특정
포트 번호를 원한다면, NodePort를 사용하면 자유롭게 자체 로드 밸런싱 솔루션을 설정하거나, 쿠버네티스가 완벽하게 지원하지 않는 환경을 구성하거나, 하나 이상의 노드 IP를 직접 노출시킬 수 있다. 이 서비스는 예를 들면
로드밸런서 유형외부 로드 밸런서를 지원하는
클라우드 공급자 상에서,
외부 로드 밸런서의 트래픽은 백엔드 파드로 전달된다. 클라우드 공급자는 로드 밸런싱 방식을 결정한다. 일부 클라우드 공급자는 프로토콜 유형이 혼합된 로드밸런서기능 상태:
기본적으로 로드밸런서 서비스 유형의 경우 둘 이상의 포트가 정의되어 있을 때 모든 포트는 동일한 프로토콜을 가져야 하며 프로토콜은 클라우드 공급자가 지원하는 프로토콜이어야 한다.
로드밸런서 NodePort 할당 비활성화기능 상태:
로드 밸런서 구현 클래스 지정기능 상태:
내부 로드 밸런서혼재된 환경에서는 서비스의 트래픽을 동일한 (가상) 네트워크 주소 블록 내로 라우팅해야 하는 경우가 있다. 수평 분할 DNS 환경에서는 외부와 내부 트래픽을 엔드포인트로 라우팅 할 수 있는 두 개의 서비스가 필요하다. 내부 로드 밸런서를 설정하려면, 사용 중인 클라우드 서비스 공급자에 따라 다음의 어노테이션 중 하나를 서비스에 추가한다.
AWS에서 TLS 지원AWS에서 실행되는 클러스터에서 부분적으로 TLS / SSL을 지원하기 위해,
첫 번째는 사용할 인증서의 ARN을 지정한다. IAM에 업로드된 써드파티 발급자의 인증서이거나 AWS Certificate Manager에서 생성된 인증서일 수 있다.
두 번째 어노테이션은 파드가 알려주는 프로토콜을 지정한다. HTTPS와 SSL의 경우, ELB는 인증서를 사용하여 암호화된 연결을 통해 파드가 스스로를 인증할 것으로 예상한다. HTTP와 HTTPS는 7 계층 프록시를 선택한다. ELB는 요청을
전달할 때 사용자와의 연결을 종료하고, 헤더를 파싱하고 사용자의 IP 주소로 TCP 및 SSL은 4 계층 프록시를 선택한다. ELB는 헤더를 수정하지 않고 트래픽을 전달한다. 일부 포트는 보안성을 갖추고 다른 포트는 암호화되지 않은 혼재된 사용 환경에서는 다음 어노테이션을 사용할 수 있다.
위의 예에서, 서비스에 쿠버네티스 v1.9부터는 서비스에 대한 HTTPS 또는 SSL 리스너와 함께
사전에 정의된 AWS SSL 정책을 사용할 수 있다. 사용 가능한 정책을 확인하려면,
그리고 "
AWS에서 지원하는 프록시 프로토콜AWS에서 실행되는 클러스터에 대한 프록시 프로토콜 지원을 활성화하려면, 다음의 서비스 어노테이션을 사용할 수 있다.
버전 1.3.0 부터, 이 어노테이션의 사용은 ELB에 의해 프록시되는 모든 포트에 적용되며 다르게 구성할 수 없다. AWS의 ELB 접근 로그AWS ELB 서비스의 접근 로그를 관리하기 위한 몇 가지 어노테이션이 있다.
AWS의 연결 드레이닝(Draining)Classic ELB의 연결 드레이닝은
다른 ELB 어노테이션이하는 클래식 엘라스틱 로드 밸런서(Classic Elastic Load Balancers)를 관리하기 위한 다른 어노테이션이다.
AWS의 네트워크 로드 밸런서 지원기능 상태: AWS에서 네트워크 로드 밸런서를 사용하려면,
클래식
엘라스틱 로드 밸런서와 달리, 네트워크 로드 밸런서 (NLB)는 클라이언트의 IP 주소를 노드로 전달한다. 서비스의
트래픽을 균일하게 하려면, DaemonSet을 사용하거나, 파드 안티어피니티(pod anti-affinity) 를 지정하여 동일한 노드에 위치하지 않도록 한다. 내부 로드 밸런서 어노테이션과 함께 NLB 서비스를 사용할 수도 있다. 클라이언트 트래픽이 NLB 뒤의 인스턴스에 도달하기 위해, 노드 보안 그룹은 다음 IP 규칙으로 수정된다.
네트워크 로드 밸런서에 접근할 수 있는 클라이언트 IP를 제한하려면,
엘라스틱 IP에 대한 설명 문서와 기타 일반적 사용 사례를 AWS 로드 밸런서 컨트롤러 문서에서 볼 수 있다. Tencent Kubernetes Engine (TKE)의 다른 CLB 어노테이션아래 표시된 것처럼 TKE에서 클라우드 로드 밸런서를 관리하기 위한 다른 어노테이션이 있다.
ExternalName 유형ExternalName 유형의 서비스는 예를 들면, 이 서비스 정의는
외부 IP하나 이상의 클러스터 노드로 라우팅되는 외부 IP가 있는 경우, 쿠버네티스 서비스는 이러한 서비스 명세에서,
단점VIP용 유저스페이스 프록시를 사용하면 중소 규모의 스케일에서는 동작하지만, 수천 개의 서비스가 포함된 대규모 클러스터로는 확장되지 않는다. 포털에 대한 독창적인 설계 제안에 이에 대한 자세한 내용이 있다. 유저스페이스 프록시를 사용하면 서비스에 접근하는 패킷의 소스 IP 주소가 가려진다. 이것은 일종의 네트워크 필터링 (방화벽)을 불가능하게 만든다. iptables 프록시 모드는 클러스터 내 소스 IP를 가리지 않지만, 여전히 로드 밸런서 또는 노드-포트를 통해 오는 클라이언트에 영향을 미친다.
가상 IP 구현서비스를 사용하려는 많은 사람들에게 이전 정보가 충분해야 한다. 그러나, 이해가 필요한 부분 뒤에는 많은 일이 있다. 충돌 방지쿠버네티스의 주요 철학 중 하나는 잘못한 것이 없는 경우 실패할 수 있는 상황에 노출되어서는 안된다는 것이다. 서비스 리소스 설계 시, 다른 사람의 포트 선택과 충돌할 경우에 대비해 자신의 포트 번호를 선택하지 않아도 된다. 그것은 격리 실패이다. 서비스에 대한 포트 번호를 선택할 수 있도록 하기 위해, 두 개의 서비스가 충돌하지 않도록 해야 한다. 쿠버네티스는 API 서버에 설정되어 있는 각 서비스가 고유한 IP를 받도록 하기 위해, 내부 할당기는 각 서비스를 만들기 전에 etcd에서 글로벌 할당 맵을 원자적으로(atomically) 업데이트한다. 서비스가 IP 주소 할당을 가져오려면 레지스트리에 맵 오브젝트가 있어야 하는데, 그렇지 않으면 IP 주소를 할당할 수 없다는 메시지와 함께 생성에 실패한다. 컨트롤 플레인에서, 백그라운드 컨트롤러는 해당 맵을 생성해야 한다. (인-메모리 잠금을 사용하는 이전 버전의 쿠버네티스에서 마이그레이션 지원 필요함) 쿠버네티스는 또한 컨트롤러를 사용하여 유효하지 않은 할당 (예: 관리자 개입으로)을 체크하고 더 이상 서비스에서 사용하지 않는 할당된 IP 주소를 정리한다.
|
종류 | 경로 | 요청 경로 | 일치 여부 |
---|---|---|---|
Prefix | /
| (모든 경로) | 예 |
Exact | /foo
| /foo
| 예 |
Exact | /foo
| /bar
| 아니오 |
Exact | /foo
| /foo/
| 아니오 |
Exact | /foo/
| /foo
| 아니오 |
Prefix | /foo
| /foo , /foo/
| 예 |
Prefix | /foo/
| /foo , /foo/
| 예 |
Prefix | /aaa/bb
| /aaa/bbb
| 아니오 |
Prefix | /aaa/bbb
| /aaa/bbb
| 예 |
Prefix | /aaa/bbb/
| /aaa/bbb
| 예, 마지막 슬래시 무시함 |
Prefix | /aaa/bbb
| /aaa/bbb/
| 예, 마지막 슬래시 일치함 |
Prefix | /aaa/bbb
| /aaa/bbb/ccc
| 예, 하위 경로 일치함 |
Prefix | /aaa/bbb
| /aaa/bbbxyz
| 아니오, 문자열 접두사 일치하지 않음 |
Prefix | / , /aaa
| /aaa/ccc
| 예, /aaa 접두사 일치함
|
Prefix | / , /aaa , /aaa/bbb
| /aaa/bbb
| 예, /aaa/bbb 접두사 일치함
|
Prefix | / , /aaa , /aaa/bbb
| /ccc
| 예, / 접두사 일치함
|
Prefix | /aaa
| /ccc
| 아니오, 기본 백엔드 사용함 |
Mixed | /foo (Prefix), /foo (Exact)
| /foo
| 예, Exact 선호함 |
다중 일치
경우에 따라 인그레스의 여러 경로가 요청과 일치할 수 있다. 이 경우 가장 긴 일치하는 경로가 우선하게 된다. 두 개의 경로가 여전히 동일하게 일치하는 경우 접두사(prefix) 경로 유형보다 정확한(exact) 경로 유형을 가진 경로가 사용 된다.
호스트네임 와일드카드
호스트는 정확한 일치(예: "foo.bar.com
") 또는 와일드카드(예: "* .foo.com
")일 수 있다. 정확한 일치를 위해서는 HTTP host
헤더가 host
필드와 일치해야 한다. 와일드카드 일치를 위해서는 HTTP host
헤더가 와일드카드 규칙의 접미사와 동일해야 한다.
호스트 | 호스트 헤더 | 일치 여부 |
---|---|---|
*.foo.com
| bar.foo.com
| 공유 접미사를 기반으로 일치함 |
*.foo.com
| baz.bar.foo.com
| 일치하지 않음, 와일드카드는 단일 DNS 레이블만 포함함 |
*.foo.com
| foo.com
| 일치하지 않음, 와일드카드는 단일 DNS 레이블만 포함함 |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
인그레스 클래스
인그레스는 서로 다른 컨트롤러에 의해 구현될 수 있으며, 종종 다른 구성으로 구현될 수 있다. 각 인그레스에서는 클래스를 구현해야하는 컨트롤러 이름을 포함하여 추가 구성이 포함된 IngressClass 리소스에 대한 참조 클래스를 지정해야 한다.
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: example.com/ingress-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
인그레스클래스의 .spec.parameters
필드를 사용하여 해당 인그레스클래스와 연관있는 환경 설정을 제공하는 다른 리소스를 참조할 수 있다.
사용 가능한 파라미터의 상세한 타입은 인그레스클래스의 .spec.parameters
필드에 명시한 인그레스 컨트롤러의 종류에 따라 다르다.
인그레스클래스 범위
인그레스 컨트롤러의 종류에 따라, 클러스터 범위로 설정한 파라미터의 사용이 가능할 수도 있고, 또는 한 네임스페이스에서만 사용 가능할 수도 있다.
- 클러스터
- 네임스페이스
인그레스클래스 파라미터의 기본 범위는 클러스터 범위이다.
.spec.parameters
필드만 설정하고 .spec.parameters.scope
필드는 지정하지 않거나, .spec.parameters.scope
필드를 Cluster
로 지정하면, 인그레스클래스는
클러스터 범위의 리소스를 참조한다. 파라미터의 kind
(+apiGroup
)는 클러스터 범위의 API (커스텀 리소스일 수도 있음) 를 참조하며, 파라미터의 name
은 해당 API에 대한 특정 클러스터 범위 리소스를 가리킨다.
예시는 다음과 같다.
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-1
spec:
controller: example.com/ingress-controller
parameters:
# 이 인그레스클래스에 대한 파라미터는 "external-config-1" 라는
# ClusterIngressParameter(API 그룹 k8s.example.net)에 기재되어 있다.
# 이 정의는 쿠버네티스가
# 클러스터 범위의 파라미터 리소스를 검색하도록 한다.
scope: Cluster
apiGroup: k8s.example.net
kind: ClusterIngressParameter
name: external-config-1
기능 상태: Kubernetes v1.23 [stable]
.spec.parameters
필드를 설정하고 .spec.parameters.scope
필드를 Namespace
로 지정하면, 인그레스클래스는 네임스페이스 범위의 리소스를 참조한다. 사용하고자 하는 파라미터가 속한 네임스페이스를 .spec.parameters
의 namespace
필드에 설정해야 한다.
파라미터의 kind
(+apiGroup
)는
네임스페이스 범위의 API (예: 컨피그맵) 를 참조하며, 파라미터의 name
은 namespace
에 명시한 네임스페이스의 특정 리소스를 가리킨다.
네임스페이스 범위의 파라미터를 이용하여, 클러스터 운영자가 워크로드에 사용되는 환경 설정(예: 로드 밸런서 설정, API 게이트웨이 정의)에 대한 제어를 위임할 수 있다. 클러스터 범위의 파라미터를 사용했다면 다음 중 하나에 해당된다.
- 다른 팀의 새로운 환경 설정 변경을 적용하려고 할 때마다 클러스터 운영 팀이 매번 승인을 해야 한다. 또는,
- 애플리케이션 팀이 클러스터 범위 파라미터 리소스를 변경할 수 있게 하는 RBAC 롤, 바인딩 등의 특별 접근 제어를 클러스터 운영자가 정의해야 한다.
인그레스클래스 API 자신은 항상 클러스터 범위이다.
네임스페이스 범위의 파라미터를 참조하는 인그레스클래스 예시가 다음과 같다.
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-2
spec:
controller: example.com/ingress-controller
parameters:
# 이 인그레스클래스에 대한 파라미터는
# "external-configuration" 네임스페이스에 있는
# "external-config" 라는 IngressParameter(API 그룹 k8s.example.com)에 기재되어 있다.
scope: Namespace
apiGroup: k8s.example.com
kind: IngressParameter
namespace: external-configuration
name: external-config
사용중단(Deprecated) 어노테이션
쿠버네티스 1.18에 IngressClass 리소스 및 ingressClassName
필드가 추가되기 전에 인그레스 클래스는 인그레스에서 kubernetes.io/ingress.class
어노테이션으로 지정되었다. 이 어노테이션은 공식적으로 정의된 것은 아니지만, 인그레스 컨트롤러에서 널리 지원되었었다.
인그레스의 최신 ingressClassName
필드는 해당 어노테이션을 대체하지만, 직접적으로 해당하는 것은 아니다. 어노테이션은 일반적으로 인그레스를 구현해야 하는 인그레스 컨트롤러의 이름을 참조하는 데 사용되었지만, 이 필드는 인그레스 컨트롤러의 이름을 포함하는 추가 인그레스 구성이 포함된 인그레스 클래스 리소스에 대한 참조이다.
기본 IngressClass
특정 IngressClass를 클러스터의 기본 값으로 표시할 수 있다. IngressClass 리소스에서 ingressclass.kubernetes.io/is-default-class
를 true
로 설정하면 ingressClassName
필드가 지정되지 않은 새 인그레스에게 기본 IngressClass가 할당된다.
몇몇 인그레스 컨트롤러는 기본 IngressClass
가 정의되어 있지 않아도 동작한다. 예를 들어, Ingress-NGINX 컨트롤러는 --watch-ingress-without-class
플래그를 이용하여 구성될 수 있다. 하지만 다음과 같이 기본 IngressClass
를 명시하는 것을
권장한다.
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: nginx-example
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
인그레스 유형들
단일 서비스로 지원되는 인그레스
단일 서비스를 노출할 수 있는 기존 쿠버네티스 개념이 있다 (대안을 본다). 인그레스에 규칙 없이 기본 백엔드 를 지정해서 이를 수행할 수 있다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: test
port:
number: 80
만약 kubectl apply -f
를 사용해서 생성한다면 추가한 인그레스의 상태를 볼 수 있어야 한다.
kubectl get ingress test-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress external-lb * 203.0.113.123 80 59s
여기서 203.0.113.123
는 인그레스 컨트롤러가 인그레스를 충족시키기 위해 할당한 IP 이다.
간단한 팬아웃(fanout)
팬아웃 구성은 HTTP URI에서 요청된 것을 기반으로 단일 IP 주소에서 1개 이상의 서비스로 트래픽을 라우팅 한다. 인그레스를 사용하면 로드 밸런서의 수를 최소로 유지할 수 있다. 예를 들어 다음과 같은 설정을 한다.
그림. 인그레스 팬아웃
다음과 같은 인그레스가 필요하다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /bar
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
kubectl apply -f
를 사용해서 인그레스를 생성 할 때 다음과 같다.
kubectl describe ingress simple-fanout-example
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
인그레스 컨트롤러는 서비스(service1
, service2
)가 존재하는 한, 인그레스를 만족시키는 특정한 로드 밸런서를 프로비저닝한다. 이렇게 하면, 주소 필드에서 로드 밸런서의 주소를 볼 수 있다.
이름 기반의 가상 호스팅
이름 기반의 가상 호스트는 동일한 IP 주소에서 여러 호스트 이름으로 HTTP 트래픽을 라우팅하는 것을 지원한다.
그림. 이름 기반의 가상 호스팅 인그레스
다음 인그레스는 호스트 헤더에 기반한 요청을 라우팅 하기 위해 뒷단의 로드 밸런서를 알려준다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: bar.foo.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
만약 규칙에 정의된 호스트 없이 인그레스 리소스를 생성하는 경우, 이름 기반 가상 호스트가 없어도 인그레스 컨트롤러의 IP 주소에 대한 웹 트래픽을 일치 시킬 수 있다.
예를 들어, 다음 인그레스는 first.bar.com
에 요청된 트래픽을 service1
로, second.bar.com
는 service2
로, 그리고 요청 헤더가 first.bar.com
또는 second.bar.com
에 해당되지 않는 모든 트래픽을 service3
로 라우팅한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress-no-third-host
spec:
rules:
- host: first.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: second.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service3
port:
number: 80
TLS
TLS 개인 키 및 인증서가 포함된
시크릿(Secret)을 지정해서 인그레스를 보호할 수 있다. 인그레스 리소스는 단일 TLS 포트인 443만 지원하고 인그레스 지점에서 TLS 종료를 가정한다(서비스 및 해당 파드에 대한 트래픽은 일반 텍스트임). 인그레스의 TLS 구성 섹션에서 다른 호스트를 지정하면, SNI TLS 확장을 통해 지정된 호스트이름에 따라 동일한 포트에서 멀티플렉싱 된다(인그레스 컨트롤러가 SNI를 지원하는 경우). TLS secret에는 tls.crt
와 tls.key
라는 이름의 키가 있어야 하고, 여기에는 TLS에 사용할
인증서와 개인 키가 있다. 예를 들어 다음과 같다.
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls
인그레스에서 시크릿을 참조하면 인그레스 컨트롤러가 TLS를 사용하여 클라이언트에서 로드 밸런서로 채널을 보호하도록 지시한다. 생성한 TLS 시크릿이 https-example.foo.com
의 정규화 된 도메인 이름(FQDN)이라고 하는 일반 이름(CN)을 포함하는 인증서에서 온 것인지 확인해야 한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
로드 밸런싱
인그레스 컨트롤러는 로드 밸런싱 알고리즘, 백엔드 가중치 구성표 등 모든 인그레스에 적용되는 일부 로드 밸런싱 정책 설정으로 부트스트랩된다. 보다 진보된 로드 밸런싱 개념 (예: 지속적인 세션, 동적 가중치)은 아직 인그레스를 통해 노출되지 않는다. 대신 서비스에 사용되는 로드 밸런서를 통해 이러한 기능을 얻을 수 있다.
또한, 헬스 체크를 인그레스를 통해 직접 노출되지 않더라도, 쿠버네티스에는 준비 상태 프로브와 같은 동일한 최종 결과를 얻을 수 있는 병렬 개념이 있다는 점도 주목할 가치가 있다. 컨트롤러 별 설명서를 검토하여 헬스 체크를 처리하는 방법을 확인한다(예: nginx, 또는 GCE).
인그레스 업데이트
기존 인그레스를 업데이트해서 새 호스트를 추가하려면, 리소스를 편집해서 호스트를 업데이트 할 수 있다.
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
kubectl edit ingress test
YAML 형식의 기존 구성이 있는 편집기가 나타난다. 새 호스트를 포함하도록 수정한다.
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
service:
name: service1
port:
number: 80
path: /foo
pathType: Prefix
- host: bar.baz.com
http:
paths:
- backend:
service:
name: service2
port:
number: 80
path: /foo
pathType: Prefix
..
변경사항을 저장한 후, kubectl은 API 서버의 리소스를 업데이트하며, 인그레스 컨트롤러에게도 로드 밸런서를 재구성하도록 지시한다.
이것을 확인한다.
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
bar.baz.com
/foo service2:80 (10.8.0.91:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
수정된 인그레스 YAML 파일을 kubectl replace -f
를 호출해서 동일한 결과를 얻을 수 있다.
가용성 영역에 전체에서의 실패
장애 도메인에 트래픽을 분산시키는 기술은 클라우드 공급자마다 다르다. 자세한 내용은 인그레스 컨트롤러 설명서를 확인한다.
대안
사용자는 인그레스 리소스를 직접적으로 포함하지 않는 여러가지 방법으로 서비스를 노출할 수 있다.
- Service.Type=LoadBalancer 사용.
- Service.Type=NodePort 사용.
다음 내용
- 인그레스 API에 대해 배우기
- 인그레스 컨트롤러에 대해 배우기
- NGINX 컨트롤러로 Minikube에서 인그레스 구성하기
7 - 서비스 내부 트래픽 정책
기능 상태: Kubernetes v1.23 [beta]
서비스 내부 트래픽 정책 을 사용하면 내부 트래픽 제한이 트래픽이 시작된 노드 내의 엔드포인트로만 내부 트래픽을 라우팅하도록 한다. 여기서 "내부" 트래픽은 현재 클러스터의 파드로부터 시작된 트래픽을 지칭한다. 이를 통해 비용을 절감하고 성능을 개선할 수 있다.
서비스 내부 트래픽 정책 사용
ServiceInternalTrafficPolicy
기능 게이트는 베타 기능이며 기본적으로 활성화되어 있다. 이 기능이 활성화되어 있으면, 서비스의 .spec.internalTrafficPolicy
를 Local
로 설정하여 내부 전용 트래픽 정책을 활성화 할 수 있다. 이것은 kube-proxy가 클러스터 내부 트래픽을 위해 노드 내부 엔드포인트로만 사용하도록 한다.
다음 예제는 서비스의
.spec.internalTrafficPolicy
를 Local
로 설정하는 것을 보여 준다:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
internalTrafficPolicy: Local
작동 방식
kube-proxy는 spec.internalTrafficPolicy
의 설정에 따라서 라우팅되는 엔드포인트를 필터링한다. 이것을 Local
로 설정하면, 노드 내부 엔드포인트만 고려한다. 이 설정이 Cluster
이거나 누락되었다면 모든 엔드포인트를 고려한다. 기능 게이트의 ServiceInternalTrafficPolicy
를 활성화한다면, spec.internalTrafficPolicy
는 기본값 "Cluster"로 설정된다.
다음 내용
- 토폴로지 인지 힌트에 대해서 읽기
- 서비스 외부 트래픽 정책에 대해서 읽기
- 서비스와 애플리케이션 연결하기 읽기
8 - 엔드포인트슬라이스
기능 상태: Kubernetes v1.21 [stable]
엔드포인트슬라이스 는 쿠버네티스 클러스터 내의 네트워크 엔드포인트를 추적하는 간단한 방법을 제공한다. 이것은 엔드포인트를 더 확장하고, 확장 가능한 대안을 제안한다.
사용동기
엔드포인트 API는 쿠버네티스에서 네트워크 엔드포인트를 추적하는 간단하고 직접적인 방법을 제공한다. 불행하게도 쿠버네티스 클러스터와 서비스가 더 많은 수의 백엔드 파드로 더 많은 트래픽을 처리하고 전송하는 방향으로 성장함에 따라, 이 API의 한계가 더욱 눈에 띄게 되었다. 특히나, 많은 수의 네트워크 엔드포인트로 확장하는 것에 어려움이 있었다.
이후로 서비스에 대한 모든 네트워크 엔드포인트가 단일 엔드포인트 리소스에 저장되기 때문에 엔드포인트 리소스가 상당히 커질 수 있다. 이것은 쿠버네티스 구성요소 (특히 마스터 컨트롤 플레인)의 성능에 영향을 미쳤고 엔드포인트가 변경될 때 상당한 양의 네트워크 트래픽과 처리를 초래했다. 엔드포인트슬라이스는 이러한 문제를 완화하고 토폴로지 라우팅과 같은 추가 기능을 위한 확장 가능한 플랫폼을 제공한다.
엔드포인트슬라이스 리소스
쿠버네티스에서 엔드포인트슬라이스는 일련의 네트워크 엔드포인트에 대한 참조를 포함한다. 쿠버네티스 서비스에 셀렉터가 지정되면 컨트롤 플레인은 자동으로 엔드포인트슬라이스를 생성한다. 이 엔드포인트슬라이스는 서비스 셀렉터와 매치되는 모든 파드들을 포함하고 참조한다. 엔드포인트슬라이스는 프로토콜, 포트 번호 및 서비스 이름의 고유한 조합을 통해 네트워크 엔드포인트를 그룹화한다. 엔드포인트슬라이스 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.
예를 들어, 여기에 example
쿠버네티스 서비스를 위한 엔드포인트슬라이스 리소스 샘플이 있다.
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-abc
labels:
kubernetes.io/service-name: example
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.1.2.3"
conditions:
ready: true
hostname: pod-1
nodeName: node-1
zone: us-west2-a
기본적으로, 컨트롤 플레인은 각각 100개 이하의 엔드포인트를 갖도록 엔드포인트슬라이스를 생성하고 관리한다. --max-endpoints-per-slice
kube-controller-manager 플래그를 사용하여, 최대 1000개까지 구성할 수 있다.
엔드포인트슬라이스는 내부 트래픽을 라우트하는 방법에 대해 kube-proxy에 신뢰할 수 있는 소스로 역할을 할 수 있다. 이를 활성화 하면, 많은 수의 엔드포인트를 가지는 서비스에 대해 성능 향상을 제공해야 한다.
주소 유형
엔드포인트슬라이스는 다음 주소 유형을 지원한다.
- IPv4
- IPv6
- FQDN (전체 주소 도메인 이름)
조건
엔드포인트슬라이스 API는 컨슈머에게 유용한 엔드포인트에 대한 조건을 저장한다. 조건은 준비
, 제공
및 종료
세 가지가 있다.
준비
ready
는 파드의 Ready
조건에 매핑되는 조건이다. Ready
조건이 True
로 설정된 실행 중인 파드는 이 엔드포인트슬라이스 조건도 true
로 설정되어야 한다. 호환성의 이유로, 파드가 종료될 때 ready
는 절대 true
가 되면 안 된다. 컨슈머는
serving
조건을 참조하여 파드 종료 준비 상태(readiness)를 검사해야 한다. 이 규칙의 유일한 예외는 spec.publishNotReadyAddresses
가 true
로 설정된 서비스이다. 이러한 서비스의 엔드 포인트는 항상 ready
조건이 true
로 설정된다.
제공(Serving)
기능 상태: Kubernetes v1.20 [alpha]
serving
은 종료 상태를 고려하지 않는다는 점을 제외하면 ready
조건과 동일하다. 엔드포인트슬라이스 API 컨슈머는 파드가 종료되는 동안 파드 준비 상태에 관심이 있다면 이 조건을 확인해야 한다.
종료(Terminating)
기능 상태: Kubernetes v1.20 [alpha]
종료(Terminating)
는 엔드포인트가 종료되는지 여부를 나타내는 조건이다. 파드의 경우 삭제 타임 스탬프가 설정된 모든 파드이다.
토폴로지 정보
엔드포인트슬라이스 내의 각 엔드 포인트는 관련 토폴로지 정보를 포함할 수 있다. 토폴로지 정보에는 엔드 포인트의 위치와 해당 노드 및 영역에 대한 정보가 포함된다. 엔드포인트슬라이스의 다음의 엔드 포인트별 필드에서 사용할 수 있다.
*nodeName
- 이 엔드 포인트가 있는 노드의 이름이다. *zone
- 이 엔드 포인트가 있는 영역이다.
관리
대부분의 경우, 컨트롤 플레인(특히, 엔드포인트슬라이스 컨트롤러)는 엔드포인트슬라이스 오브젝트를 생성하고 관리한다. 다른 엔티티나 컨트롤러가 추가 엔드포인트슬라이스 집합을 관리하게 할 수 있는 서비스 메시 구현과 같이 엔드포인트슬라이스에 대한 다양한 다른 유스케이스가 있다.
여러 엔티티가 서로 간섭하지 않고 엔드포인트슬라이스를 관리할 수 있도록 쿠버네티스는 엔드포인트슬라이스를 관리하는 엔티티를 나타내는 endpointslice.kubernetes.io/managed-by
레이블을 정의한다. 엔드포인트슬라이스 컨트롤러는 관리하는 모든 엔드포인트슬라이스에 레이블의 값으로 endpointslice-controller.k8s.io
를 설정한다. 엔드포인트슬라이스를 관리하는 다른 엔티티도 이 레이블에 고유한 값을 설정해야 한다.
소유권
대부분의 유스케이스에서, 엔드포인트슬라이스 오브젝트가 엔드포인트를 추적하는 서비스가 엔드포인트슬라이스를 소유한다. 이 소유권은 각 엔드포인트슬라이스의 소유자 참조와 서비스에 속한 모든 엔드포인트슬라이스의 간단한 조회를 가능하게 하는
kubernetes.io/service-name
레이블로 표시된다.
엔드포인트슬라이스 미러링
경우에 따라, 애플리케이션이 사용자 지정 엔드포인트 리소스를 생성한다. 이러한 애플리케이션이 엔드포인트와 엔드포인트슬라이스 리소스에 동시에 쓸 필요가 없도록 클러스터의 컨트롤 플레인은 대부분의 엔드포인트 리소스를 해당 엔드포인트슬라이스에 미러링한다.
컨트롤 플레인은 다음을 제외하고 엔드포인트 리소스를 미러링한다.
- 엔드포인트 리소스에는
endpointslice.kubernetes.io/skip-mirror
레이블이true
로 설정되어 있다. - 엔드포인트 리소스에는
control-plane.alpha.kubernetes.io/leader
어노테이션이 있다. - 해당 서비스 리소스가 존재하지 않는다.
- 해당 서비스 리소스에 nil이 아닌 셀렉터가 있다.
개별 엔드포인트 리소스는 여러 엔드포인트슬라이스로 변환될 수 있다. 엔드포인트 리소스에 여러 하위 집합이 있거나 여러 IP 제품군(IPv4 및 IPv6)이 있는 엔드포인트가 포함된 경우 변환이 일어난다. 하위 집합 당 최대 1000개의 주소가 엔드포인트슬라이스에 미러링된다.
엔드포인트슬라이스의 배포
각 엔드포인트슬라이스에는 리소스 내에 모든 엔드포인트가 적용되는 포트 집합이 있다. 서비스에 알려진 포트를 사용하는 경우 파드는 동일하게 알려진 포트에 대해 다른 대상 포트 번호로 끝날 수 있으며 다른 엔드포인트슬라이스가 필요하다. 이는 하위 집합이 엔드포인트와 그룹화하는 방식의 논리와 유사하다.
컨트롤 플레인은 엔드포인트슬라이스를 최대한 채우려고 노력하지만, 적극적으로 재조정하지는 않는다. 로직은 매우 직관적이다.
- 기존 엔드포인트슬라이스에 대해 반복적으로, 더 이상 필요하지 않는 엔드포인트를 제거하고 변경에 의해 일치하는 엔드포인트를 업데이트 한다.
- 첫 번째 단계에서 수정된 엔드포인트슬라이스를 반복해서 필요한 새 엔드포인트로 채운다.
- 추가할 새 엔드포인트가 여전히 남아있으면, 이전에 변경되지 않은 슬라이스에 엔드포인트를 맞추거나 새로운 것을 생성한다.
중요한 것은, 세 번째 단계는 엔드포인트슬라이스를 완벽하게 전부 배포하는 것보다 엔드포인트슬라이스 업데이트 제한을 우선시한다. 예를 들어, 추가할 새 엔드포인트가 10개이고 각각 5개의 공간을 사용할 수 있는 엔드포인트 공간이 있는 2개의 엔드포인트슬라이스가 있는 경우, 이 방법은 기존 엔드포인트슬라이스 2개를 채우는 대신에 새 엔드포인트슬라이스를 생성한다. 다른 말로, 단일 엔드포인트슬라이스를 생성하는 것이 여러 엔드포인트슬라이스를 업데이트하는 것 보다 더 선호된다.
각 노드에서 kube-proxy를 실행하고 엔드포인트슬라이스를 관찰하면, 엔드포인트슬라이스에 대한 모든 변경 사항이 클러스터의 모든 노드로 전송되기 때문에 상대적으로 비용이 많이 소요된다. 이 방법은 여러 엔드포인트슬라이스가 가득 차지 않은 결과가 발생할지라도, 모든 노드에 전송해야 하는 변경 횟수를 의도적으로 제한하기 위한 것이다.
실제로는, 이러한 이상적이지 않은 분배는 드물 것이다. 엔드포인트슬라이스 컨트롤러에서 처리하는 대부분의 변경 내용은 기존 엔드포인트슬라이스에 적합할 정도로 적고, 그렇지 않은 경우 새 엔드포인트슬라이스가 필요할 수 있다. 디플로이먼트의 롤링 업데이트도 모든 파드와 해당 교체되는 엔드포인트에 대해서 엔드포인트슬라이스를 자연스럽게 재포장한다.
중복 엔드포인트
엔드포인트슬라이스 변경의 특성으로 인해, 엔드포인트는 동시에 둘 이상의 엔드포인트슬라이스에 표시될 수 있다. 이는 다른 엔드포인트슬라이스 오브젝트에 대한 변경 사항이 다른 시간에서의 쿠버네티스 클라이언트 워치(watch)/캐시에 도착할 수 있기 때문에 자연스럽게 발생한다. 엔드포인트슬라이스를 사용하는 구현은 엔드포인트가 둘 이상의 슬라이스에
표시되도록 할 수 있어야 한다. 엔드포인트 중복 제거를 수행하는 방법에 대한 레퍼런스 구현은 kube-proxy
의 EndpointSliceCache
구현에서 찾을 수 있다.
다음 내용
- 서비스와 애플리케이션 연결하기를 읽어보기
9 - 토폴로지 인지 힌트
기능 상태: Kubernetes v1.23 [beta]
토폴로지 인지 힌트(Topology Aware Hints) 는 클라이언트가 엔드포인트를 어떻게 사용해야 하는지에 대한 제안을 포함시킴으로써 토폴로지 인지 라우팅을 가능하게 한다. 이러한 접근은 엔드포인트슬라이스(EndpointSlice) 및 엔드포인트(Endpoint) 오브젝트의 소비자(consumer)가 이용할 수 있는 메타데이터를 추가하며, 이를 통해 해당 네트워크 엔드포인트로의 트래픽이 근원지에 더 가깝게 라우트될 수 있다.
예를 들어, 비용을 줄이거나 네트워크 성능을 높이기 위해, 인접성을 고려하여 트래픽을 라우트할 수 있다.
동기(motivation)
쿠버네티스 클러스터가 멀티-존(multi-zone) 환경에 배포되는 일이 점점 많아지고 있다. 토폴로지 인지 힌트 는 트래픽이 발생한 존 내에서 트래픽을 유지하도록 처리하는 메커니즘을 제공한다. 이러한 개념은 보통 "토폴로지 인지 라우팅"이라고 부른다. 서비스의 엔드포인트를 계산할 때, 엔드포인트슬라이스 컨트롤러는 각 엔드포인트의 토폴로지(지역(region) 및 존)를 고려하여, 엔드포인트가 특정 존에 할당되도록 힌트 필드를 채운다. 그러면 kube-proxy와 같은 클러스터 구성 요소는 해당 힌트를 인식하고, (토폴로지 상 가까운 엔드포인트를 사용하도록) 트래픽 라우팅 구성에 활용한다.
토폴로지 인지 힌트 사용하기
service.kubernetes.io/topology-aware-hints
어노테이션을 auto
로 설정하여 서비스에 대한 토폴로지 인지 힌트를 활성화할 수 있다. 이는 엔드포인트슬라이스 컨트롤러가 안전하다고 판단되는 경우 토폴로지 힌트를 설정하도록 지시하는 것이다. 명심할 점은, 이를 수행한다고
해서 힌트가 항상 설정되는 것은 아니라는 것이다.
동작 방법
이 기능을 동작시키는 요소는 엔드포인트슬라이스 컨트롤러와 kube-proxy 두 구성요소로 나눠져 있다. 이 섹션에서는 각 구성요소가 어떻게 이 기능을 동작시키는지에 대한 고차원 개요를 제공한다.
엔드포인트슬라이스 컨트롤러
엔드포인트슬라이스 컨트롤러는 이 기능이 활성화되어 있을 때 엔드포인트슬라이스에 힌트를 설정하는 일을 담당한다. 컨트롤러는 각 존에 일정 비율의 엔드포인트를 할당한다. 이 비율은 해당 존에 있는 노드의 할당 가능한(allocatable) CPU 코어에 의해 결정된다. 예를 들어, 한 존에 2 CPU 코어가 있고 다른 존에 1 CPU 코어만 있는 경우, 컨트롤러는 2 CPU 코어가 있는 존에 엔드포인트를 2배 할당할 것이다.
다음 예시는 엔드포인트슬라이스에 힌트가 채워졌을 때에 대한 예시이다.
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: example-hints
labels:
kubernetes.io/service-name: example-svc
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.1.2.3"
conditions:
ready: true
hostname: pod-1
zone: zone-a
hints:
forZones:
- name: "zone-a"
kube-proxy
kube-proxy 구성요소는 엔드포인트슬라이스 컨트롤러가 설정한 힌트를 기반으로 자신이 라우팅하는 엔드포인트를 필터링한다. 대부분의 경우, 이는 kube-proxy가 동일 존 내에서 트래픽을 엔드포인트로 라우팅할 수 있음을 뜻한다. 때때로 컨트롤러는 존 사이에 보다 균등한 엔드포인트 분배를 위해 다른 존으로부터 엔드포인트를 할당하기도 한다. 이러한 경우 일부 트래픽은 다른 존으로 라우팅될 것이다.
보호 규칙
쿠버네티스 컨트롤 플레인과 각 노드의 kube-proxy는 토폴로지 인지 힌트를 사용하기 전에 몇 가지 보호 규칙을 적용한다. 이들이 만족되지 않으면, kube-proxy는 존에 상관없이 클러스터의 모든 곳으로부터 엔드포인트를 선택한다.
엔드포인트 수가 충분하지 않음: 존의 숫자보다 엔드포인트의 숫자가 적으면, 컨트롤러는 어떤 힌트도 할당하지 않을 것이다.
균형잡힌 할당이 불가능함: 일부 경우에, 존 간 균형잡힌 엔드포인트 할당이 불가능할 수 있다. 예를 들어, zone-a가 zone-b보다 2배 큰 상황에서, 엔드포인트가 2개 뿐이라면, zone-a에 할당된 엔드포인트는 zone-b에 할당된 엔드포인트보다 2배의 트래픽을 수신할 것이다. 컨트롤러는 이 "예상 과부하" 값을 각 존에 대해 허용 가능한 임계값보다 작게 낮출 수 없는 경우에는 힌트를 할당하지 않는다. 명심할 점은, 이것이 실시간 피드백 기반이 아니라는 것이다. 개별 엔드포인트가 과부하 상태로 바뀔 가능성도 여전히 있다.
하나 이상의 노드에 대한 정보가 불충분함:
topology.kubernetes.io/zone
레이블이 없는 노드가 있거나 할당 가능한 CPU 값을 보고하지 않는 노드가 있으면, 컨트롤 플레인은 토폴로지 인지 엔드포인트를 설정하지 않으며 이로 인해 kube-proxy는 존 별로 엔드포인트를 필터링하지 않는다.하나 이상의 엔드포인트에 존 힌트가 없음: 이러한 상황이 발생하면, kube-proxy는 토폴로지 인지 힌트로부터의 또는 토폴로지 인지 힌트로의 전환이 진행 중이라고 가정한다. 이 상태에서 서비스의 엔드포인트를 필터링하는 것은 위험할 수 있으므로 kube-proxy는 모든 엔드포인트를 사용하는 모드로 전환된다.
힌트에 존이 기재되지 않음: kube-proxy가 실행되고 있는 존을 향하는 힌트를 갖는 엔드포인트를 하나도 찾지 못했다면, 모든 존에서 오는 엔드포인트를 사용하는 모드로 전환된다. 이러한 경우는 기존에 있던 클러스터에 새로운 존을 추가하는 경우에 발생할 가능성이 가장 높다.
제약사항
토폴로지 인지 힌트는 서비스의
externalTrafficPolicy
또는internalTrafficPolicy
가Local
로 설정된 경우에는 사용되지 않는다. 동일 클러스터의 서로 다른 서비스들에 대해 두 기능 중 하나를 사용하는 것은 가능하며, 하나의 서비스에 두 기능 모두를 사용하는 것은 불가능하다.이러한 접근 방법은 존의 일부분에서 많은 트래픽이 발생하는 서비스에는 잘 작동하지 않을 것이다. 대신, 들어오는 트래픽이 각 존 내 노드 용량에 대략 비례한다고 가정한다.
엔드포인트슬라이스 컨트롤러는 각 존 내의 비율을 계산할 때 준비되지 않은(unready) 노드는 무시한다. 이 때문에 많은 노드가 준비되지 않은 상태에서는 의도하지 않은 결과가 나타날 수도 있다.
엔드포인트슬라이스 컨트롤러는 각 존 내의 비율을 계산할 때 톨러레이션은 고려하지 않는다. 서비스를 구성하는 파드가 클러스터의 일부 노드에만 배치되어 있는 경우, 이러한 상황은 고려되지 않을 것이다.
오토스케일링 기능과는 잘 동작하지 않을 수 있다. 예를 들어, 하나의 존에서 많은 트래픽이 발생하는 경우, 해당 존에 할당된 엔드포인트만 트래픽을 처리하고 있을 것이다. 이로 인해 Horizontal Pod Autoscaler가 이 이벤트를 감지하지 못하거나, 또는 새롭게 추가되는 파드가 다른 존에 추가될 수 있다.
다음 내용
- 서비스와 애플리케이션 연결하기를 읽어본다.
10 - 네트워크 정책
IP 주소 또는 포트 수준(OSI 계층 3 또는 4)에서 트래픽 흐름을 제어하려는 경우, 클러스터의 특정 애플리케이션에 대해 쿠버네티스 네트워크폴리시(NetworkPolicy) 사용을 고려할 수 있다. 네트워크폴리시는 파드가 네트워크 상의 다양한 네트워크 "엔티티"(여기서는 "엔티티"를 사용하여 쿠버네티스에서 특별한 의미로 사용되는 "엔드포인트" 및 "서비스"와 같은 일반적인 용어가 중의적으로 표현되는 것을 방지함)와 통신할 수 있도록 허용하는 방법을 지정할 수 있는 애플리케이션 중심 구조이다. 네트워크폴리시는 한쪽 또는 양쪽 종단이 파드인 연결에만 적용되며, 다른 연결에는 관여하지 않는다.
파드가 통신할 수 있는 엔티티는 다음 3개의 식별자 조합을 통해 식별된다.
- 허용되는 다른 파드(예외: 파드는 자신에 대한 접근을 차단할 수 없음)
- 허용되는 네임스페이스
- IP 블록(예외: 파드 또는 노드의 IP 주소와 관계없이 파드가 실행 중인 노드와의 트래픽은 항상 허용됨)
pod- 또는 namespace- 기반의 네트워크폴리시를 정의할 때, 셀렉터를 사용하여 셀렉터와 일치하는 파드와 주고받는 트래픽을 지정한다.
한편, IP 기반의 네트워크폴리시가 생성되면, IP 블록(CIDR 범위)을 기반으로 정책을 정의한다.
전제 조건
네트워크 정책은 네트워크 플러그인으로 구현된다. 네트워크 정책을 사용하려면 네트워크폴리시를 지원하는 네트워킹 솔루션을 사용해야만 한다. 이를 구현하는 컨트롤러 없이 네트워크폴리시 리소스를 생성해도 아무런 효과가 없기 때문이다.
파드 격리의 두 가지 종류
파드 격리에는 이그레스에 대한 격리와 인그레스에 대한 격리의 두 가지 종류가 있다. 이들은 어떤 연결이 성립될지에 대해 관여한다. 여기서 "격리"는 절대적인 것이 아니라, "일부 제한이 적용됨"을 의미한다. 반대말인 "이그레스/인그레스에 대한 비격리"는 각 방향에 대해 제한이 적용되지 않음을 의미한다. 두 종류의 격리(또는 비격리)는 독립적으로 선언되며, 두 종류 모두 파드 간 연결과 연관된다.
기본적으로, 파드는 이그레스에 대해 비격리되어 있다. 즉, 모든 아웃바운드 연결이 허용된다. 해당 파드에 적용되면서 policyTypes
에 "Egress"가 있는 NetworkPolicy가 존재하는 경우, 파드가 이그레스에 대해 격리된다. 이러한 정책은 파드의 이그레스에 적용된다고 말한다. 파드가 이그레스에 대해 격리되면, 파드에서 나가는 연결 중에서 파드의 이그레스에 적용된 NetworkPolicy의 egress
리스트에 허용된 연결만이 허용된다. egress
리스트 각 항목의 효과는 합산되어 적용된다.
기본적으로, 파드는 인그레스에 대해 비격리되어 있다. 즉, 모든 인바운드 연결이 허용된다. 해당 파드에 적용되면서 policyTypes
에 "Ingress"가 있는 NetworkPolicy가 존재하는 경우, 파드가 인그레스에 대해 격리된다. 이러한 정책은 파드의 인그레스에 적용된다고 말한다. 파드가 인그레스에 대해 격리되면, 파드로
들어오는 연결 중에서 파드의 인그레스에 적용된 NetworkPolicy의 ingress
리스트에 허용된 연결만이 허용된다. ingress
리스트 각 항목의 효과는 합산되어 적용된다.
네트워크 폴리시가 충돌하는 경우는 없다. 네트워크 폴리시는 합산되어 적용된다. 특정 파드의 특정 방향에 대해 하나 또는 여러 개의 폴리시가 적용되면, 해당 파드의 해당 방향에 대해 허용된 연결은 모든 폴리시가 허용하는 연결의 합집합이다. 따라서, 판별 순서는 폴리시 결과에 영향을 미치지 않는다.
송신 파드에서 수신 파드로의 연결이 허용되기 위해서는, 송신 파드의 이그레스 폴리시와 수신 파드의 인그레스 폴리시가 해당 연결을 허용해야 한다. 만약 어느 한 쪽이라도 해당 연결을 허용하지 않으면, 연결이 되지 않을 것이다.
네트워크폴리시 리소스
리소스에 대한 전체 정의에 대한 참조는 네트워크폴리시 를 본다.
네트워크폴리시 의 예시는 다음과 같다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
필수 필드들: 다른 모든 쿠버네티스 설정과 마찬가지로 네트워크폴리시 에는 apiVersion
, kind
, 그리고 metadata
필드가 필요하다. 구성 파일 작업에 대한 일반적인 정보는 컨피그맵을 사용하도록 파드 구성하기,
그리고 오브젝트 관리 를 본다.
spec: 네트워크폴리시 사양에는 지정된 네임스페이스에서 특정 네트워크 정책을 정의하는데 필요한 모든 정보가 있다.
podSelector: 각 네트워크폴리시에는 정책이 적용되는 파드 그룹을 선택하는 podSelector
가 포함된다. 예시 정책은 "role=db" 레이블이 있는 파드를 선택한다.
비어있는 podSelector
는 네임스페이스의 모든 파드를 선택한다.
policyTypes: 각 네트워크폴리시에는 Ingress
, Egress
또는 두 가지 모두를 포함할 수 있는 policyTypes
목록이 포함된다. policyTypes
필드는 선택한 파드에 대한 인그레스 트래픽 정책, 선택한 파드에 대한 이그레스 트래픽 정책 또는 두 가지 모두에 지정된 정책의 적용 여부를 나타낸다. 만약 네트워크폴리시에 policyTypes
가 지정되어 있지 않으면 기본적으로 Ingress
가 항상 설정되고, 네트워크폴리시에 Egress
가 있으면 이그레스 규칙이 설정된다.
ingress: 각 네트워크폴리시에는 화이트리스트 ingress
규칙 목록이 포함될 수 있다. 각 규칙은 from
과 ports
부분과 모두 일치하는 트래픽을 허용한다. 예시 정책에는 단일 규칙이 포함되어 있는데 첫 번째 포트는
ipBlock
을 통해 지정되고, 두 번째는 namespaceSelector
를 통해 그리고 세 번째는 podSelector
를 통해 세 가지 소스 중 하나의 단일 포트에서 발생하는 트래픽과 일치 시킨다.
egress: 각 네트워크폴리시에는 화이트리스트 egress
규칙이 포함될 수 있다. 각 규칙은 to
와 ports
부분과 모두 일치하는 트래픽을 허용한다. 예시 정책에는 단일 포트의 트래픽을 10.0.0.0/24
의 모든 대상과 일치시키는 단일 규칙을 포함하고 있다.
따라서 예시의 네트워크폴리시는 다음과 같이 동작한다.
인그레스 및 이그레스 트래픽에 대해 "default" 네임스페이스에서 "role=db"인 파드를 격리한다(아직 격리되지 않은 경우).
(인그레스 규칙)은 "role=db" 레이블을 사용하는 "default" 네임스페이스의 모든 파드에 대해서 TCP 포트 6397로의 연결을 허용한다. 인그레스을 허용 할 대상은 다음과 같다.
- "role=frontend" 레이블이 있는 "default" 네임스페이스의 모든 파드
- 네임스페이스와 "project=myproject" 를 레이블로 가지는 모든 파드
- 172.17.0.0–172.17.0.255 와 172.17.2.0–172.17.255.255 의 범위를 가지는 IP 주소(예: 172.17.0.0/16 전체에서 172.17.1.0/24 를 제외)
(이그레스 규칙)은 "role=db" 레이블이 있는 "default" 네임스페이스의 모든 파드에서 TCP 포트 5978의 CIDR 10.0.0.0/24 로의 연결을 허용한다.
자세한 설명과 추가 예시는 네트워크 정책 선언을 본다.
to 및 from 셀럭터의 동작
ingress
from
부분 또는 egress
to
부분에 지정할 수 있는 네 종류의 셀렉터가 있다.
podSelector: 네트워크폴리시를 통해서, 인그레스 소스 또는 이그레스 목적지로 허용되야 하는 동일한 네임스페이스에 있는 특정 파드들을 선택한다.
namespaceSelector: 모든 파드가 인그레스 소스 또는 이그레스를 대상으로 허용되어야 하는 특정 네임스페이스를 선택한다.
namespaceSelector
와 podSelector: namespaceSelector
와 podSelector
를 모두 지정하는 단일 to
/from
항목은 특정 네임스페이스 내에서 특정 파드를 선택한다. 올바른 YAML 구문을 사용하도록 주의해야 한다. 이 정책:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
네임스페이스에서 레이블이 role=client
인 것과 레이블이 user=alice
인 파드의 연결을 허용하는 단일 from
요소가 포함되어 있다. 그러나 이 정책:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
from
배열에 두 개의 요소가 포함되어 있으며, 로컬 네임스페이스에 레이블을 role=client
로 가지는 파드 또는 네임스페이스에 레이블을 user=alice
로 가지는 파드의 연결을 허용한다.
의심스러운 경우, kubectl describe
를 사용해서 쿠버네티스가 정책을 어떻게 해석하는지 확인해본다.
ipBlock: 인그레스 소스 또는 이그레스 대상으로 허용할 IP CIDR 범위를 선택한다. 파드 IP는 임시적이고 예측할 수 없기에 클러스터 외부 IP이어야 한다.
클러스터 인그레스 및 이그레스 매커니즘은 종종 패킷의 소스 또는 대상 IP의 재작성을 필요로 한다. 이러한 상황이 발생하는 경우, 네트워크폴리시의 처리 전 또는 후에 발생한 것인지 정의되지 않으며, 네트워크 플러그인, 클라우드 공급자, 서비스
구현 등의 조합에 따라 동작이 다를 수 있다.
인그레스 사례에서의 의미는 실제 원본 소스 IP를 기준으로 들어오는 패킷을 필터링할 수 있는 반면에 다른 경우에는 네트워크폴리시가 작동하는 "소스 IP"는 LoadBalancer
또는 파드가 속한 노드 등의 IP일 수 있다.
이그레스의 경우 파드에서 클러스터 외부 IP로 다시 작성된 서비스
IP로의 연결은 ipBlock
기반의 정책의 적용을 받거나 받지 않을 수 있다는 것을 의미한다.
기본 정책
기본적으로 네임스페이스 정책이 없으면 해당 네임스페이스의 파드에 대한 모든 인그레스와 이그레스 트래픽이 허용된다. 다음 예시에서는 해당 네임스페이스의 기본 동작을 변경할 수 있다.
기본적으로 모든 인그레스 트래픽 거부
모든 파드를 선택하지만 해당 파드에 대한 인그레스 트래픽은 허용하지 않는 네트워크폴리시를 생성해서 네임스페이스에 대한 "기본" 인그레스 격리 정책을 생성할 수 있다.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
이렇게 하면 다른 네트워크폴리시에서 선택하지 않은 파드도 인그레스에 대해 여전히 격리된다. 이 정책은 다른 파드로부터의 이그레스 격리에는 영향을 미치지 않는다.
모든 인그레스 트래픽 허용
한 네임스페이스의 모든 파드로의 인입(incoming) 연결을 허용하려면, 이를 명시적으로 허용하는 정책을 만들 수 있다.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
이 정책이 존재하면, 해당 파드로의 인입 연결을 막는 다른 정책은 효력이 없다. 이 정책은 모든 파드로부터의 이그레스 격리에는 영향을 미치지 않는다.
기본적으로 모든 이그레스 트래픽 거부
모든 파드를 선택하지만, 해당 파드의 이그레스 트래픽을 허용하지 않는 네트워크폴리시를 생성해서 네임스페이스에 대한 "기본" 이그레스 격리 정책을 생성할 수 있다.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
이렇게 하면 다른 네트워크폴리시에서 선택하지 않은 파드조차도 이그레스 트래픽을 허용하지 않는다. 이 정책은 모든 파드의 인그레스 격리 정책을 변경하지 않는다.
모든 이그레스 트래픽 허용
한 네임스페이스의 모든 파드로부터의 모든 연결을 허용하려면, 해당 네임스페이스의 파드로부터 나가는(outgoing) 모든 연결을 명시적으로 허용하는 정책을 생성할 수 있다.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
이 정책이 존재하면, 해당 파드에서 나가는 연결을 막는 다른 정책은 효력이 없다. 이 정책은 모든 파드로의 인그레스 격리에는 영향을 미치지 않는다.
기본적으로 모든 인그레스와 모든 이그레스 트래픽 거부
해당 네임스페이스에 아래의 네트워크폴리시를 만들어 모든 인그레스와 이그레스 트래픽을 방지하는 네임스페이스에 대한 "기본" 정책을 만들 수 있다.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
이렇게 하면 다른 네트워크폴리시에서 선택하지 않은 파드도 인그레스 또는 이그레스 트래픽을 허용하지 않는다.
SCTP 지원
기능 상태: Kubernetes v1.20 [stable]
안정된 기능으로, 기본 활성화되어 있다. 클러스터 수준에서 SCTP를 비활성화하려면, 사용자(또는 클러스터 관리자)가 API 서버에 --feature-gates=SCTPSupport=false,…
를 사용해서 SCTPSupport
기능 게이트를 비활성화해야 한다. 해당 기능 게이트가 활성화되어 있는 경우, 네트워크폴리시의 protocol
필드를 SCTP
로 지정할 수 있다.
포트 범위 지정
기능 상태: Kubernetes v1.22 [beta]
네트워크폴리시를 작성할 때, 단일 포트 대신 포트 범위를 대상으로 지정할 수 있다.
다음 예와 같이 endPort
필드를 사용하면, 이 작업을 수행할 수 있다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
위 규칙은 대상 포트가 32000에서 32768 사이에 있는 경우, 네임스페이스 default
에 레이블이 role=db
인 모든 파드가 TCP를 통해 10.0.0.0/24
범위 내의 모든 IP와 통신하도록
허용한다.
이 필드를 사용할 때 다음의 제한 사항이 적용된다.
- 베타 기능으로, 기본적으로 활성화되어 있다. 클러스터 수준에서
endPort
필드를 비활성화하려면, 사용자(또는 클러스터 관리자)가 API 서버에 대해--feature-gates=NetworkPolicyEndPort=false,…
명령을 이용하여NetworkPolicyEndPort
기능 게이트를 비활성화해야 한다. endPort
필드는port
필드보다 크거나 같아야 한다.endPort
는port
도 정의된 경우에만 정의할 수 있다.- 두 포트 모두 숫자여야 한다.
이름으로 네임스페이스 지정
기능 상태: Kubernetes 1.22 [stable]
쿠버네티스 컨트롤 플레인은 NamespaceDefaultLabelName
기능 게이트가 활성화된 경우 모든 네임스페이스에 변경할 수 없는(immutable) 레이블 kubernetes.io/metadata.name
을 설정한다. 레이블의 값은 네임스페이스 이름이다.
네트워크폴리시는 일부 오브젝트 필드가 있는 이름으로 네임스페이스를 대상으로 지정할 수 없지만, 표준화된 레이블을 사용하여 특정 네임스페이스를 대상으로 지정할 수 있다.
네트워크 정책으로 할 수 없는 것(적어도 아직은 할 수 없는)
쿠버네티스 1.25부터 다음의 기능은 네트워크폴리시 API에 존재하지 않지만, 운영 체제 컴포넌트(예: SELinux, OpenVSwitch, IPTables 등) 또는 Layer 7 기술(인그레스 컨트롤러, 서비스 메시 구현) 또는 어드미션 컨트롤러를 사용하여 제2의 해결책을 구현할 수 있다. 쿠버네티스의 네트워크 보안을 처음 사용하는 경우, 네트워크폴리시 API를 사용하여 다음의 사용자 스토리를 (아직) 구현할 수 없다는 점에 유의할 필요가 있다.
- 내부 클러스터 트래픽이 공통 게이트웨이를 통과하도록 강제한다(서비스 메시나 기타 프록시와 함께 제공하는 것이 가장 좋을 수 있음).
- TLS와 관련된 모든 것(이를 위해 서비스 메시나 인그레스 컨트롤러 사용).
- 노드별 정책(이에 대해 CIDR 표기법을 사용할 수 있지만, 특히 쿠버네티스 ID로 노드를 대상으로 지정할 수 없음).
- 이름으로 서비스를 타겟팅한다(그러나, 레이블로 파드나 네임스페이스를 타겟팅할 수 있으며, 이는 종종 실행할 수 있는 해결 방법임).
- 타사 공급사가 이행한 "정책 요청"의 생성 또는 관리.
- 모든 네임스페이스나 파드에 적용되는 기본 정책(이를 수행할 수 있는 타사 공급사의 쿠버네티스 배포본 및 프로젝트가 있음).
- 고급 정책 쿼리 및 도달 가능성 도구.
- 네트워크 보안 이벤트를 기록하는 기능(예: 차단되거나 수락된 연결).
- 명시적으로 정책을 거부하는 기능(현재 네트워크폴리시 모델은 기본적으로 거부하며, 허용 규칙을 추가하는 기능만 있음).
- 루프백 또는 들어오는 호스트 트래픽을 방지하는 기능(파드는 현재 로컬 호스트 접근을 차단할 수 없으며, 상주 노드의 접근을 차단할 수 있는 기능도 없음).
다음 내용
- 자세한 설명과 추가 예시는 네트워크 정책 선언을 본다.
- 네트워크폴리시 리소스에서 사용되는 일반적인 시나리오는 레시피를 본다.
11 - IPv4/IPv6 이중 스택
기능 상태: Kubernetes v1.23 [stable]
IPv4/IPv6 이중 스택 네트워킹을 사용하면 파드와 서비스에 IPv4와 IPv6 주소를 모두 할당할 수 있다.
IPv4/IPv6 이중 스택 네트워킹은 1.21부터 쿠버네티스 클러스터에 기본적으로 활성화되어 있고, IPv4 및 IPv6 주소를 동시에 할당할 수 있다.
지원되는 기능
쿠버네티스 클러스터의 IPv4/IPv6 이중 스택은 다음의 기능을 제공한다.
- 이중 스택 파드 네트워킹(파드 당 단일 IPv4와 IPv6 주소 할당)
- IPv4와 IPv6 지원 서비스
- IPv4와 IPv6 인터페이스를 통한 파드 오프(off) 클러스터 이그레스 라우팅(예: 인터넷)
필수 구성 요소
IPv4/IPv6 이중 스택 쿠버네티스 클러스터를 활용하려면 다음의 필수 구성 요소가 필요하다.
쿠버네티스 1.20 및 이후 버전
예전 버전 쿠버네티스에서 이중 스택 서비스를 사용하는 방법에 대한 정보는 해당 버전의 쿠버네티스에 대한 문서를 참조한다.
이중 스택 네트워킹을 위한 공급자의 지원. (클라우드 공급자 또는 다른 방식으로 쿠버네티스 노드에 라우팅 가능한 IPv4/IPv6 네트워크 인터페이스를 제공할 수 있어야 함.)
이중 스택 네트워킹을 지원하는 네트워크 플러그인.
IPv4/IPv6 이중 스택 구성
IPv4/IPv6 이중 스택을 구성하려면, 이중 스택 클러스터 네트워크 할당을 설정한다.
- kube-apiserver:
--service-cluster-ip-range=<IPv4 CIDR>,<IPv6 CIDR>
- kube-controller-manager:
--cluster-cidr=<IPv4 CIDR>,<IPv6 CIDR>
--service-cluster-ip-range=<IPv4 CIDR>,<IPv6 CIDR>
--node-cidr-mask-size-ipv4|--node-cidr-mask-size-ipv6
IPv4의 기본값은 /24 이고 IPv6의 기본값은 /64 이다.
- kube-proxy:
--cluster-cidr=<IPv4 CIDR>,<IPv6 CIDR>
- kubelet:
--cloud-provider
가 명시되지 않았다면 관리자는 해당 노드에 듀얼 스택.status.addresses
를 수동으로 설정하기 위해 쉼표로 구분된 IP 주소 쌍을--node-ip
플래그로 전달할 수 있다. 해당 노드의 파드가 HostNetwork 모드로 실행된다면, 파드는 이 IP 주소들을 자신의.status.podIPs
필드에 보고한다. 노드의 모든podIPs
는 해당 노드의.status.addresses
필드에 의해 정의된 IP 패밀리 선호사항을 만족한다.
서비스
IPv4, IPv6 또는 둘 다를 사용할 수 있는 서비스를 생성할 수 있다.
서비스의 주소 계열은 기본적으로 첫 번째 서비스 클러스터 IP 범위의 주소 계열로 설정된다. (--service-cluster-ip-range
플래그를 통해 kube-apiserver에 구성)
서비스를 정의할 때 선택적으로 이중 스택으로 구성할 수 있다. 원하는 동작을 지정하려면 .spec.ipFamilyPolicy
필드를 다음 값 중 하나로 설정한다.
SingleStack
: 단일 스택 서비스. 컨트롤 플레인은 첫 번째로 구성된 서비스 클러스터 IP 범위를 사용하여 서비스에 대한 클러스터 IP를 할당한다.PreferDualStack
:- 서비스에 IPv4 및 IPv6 클러스터 IP를 할당한다.
RequireDualStack
: IPv4 및 IPv6 주소 범위 모두에서 서비스.spec.ClusterIPs
를 할당한다..spec.ipFamilies
배열의 첫 번째 요소의 주소 계열을 기반으로.spec.ClusterIPs
목록에서.spec.ClusterIP
를 선택한다.
단일 스택에 사용할 IP 계열을 정의하거나 이중 스택에 대한 IP 군의 순서를 정의하려는 경우, 서비스에서 옵션 필드 .spec.ipFamilies
를 설정하여 주소 군을 선택할 수 있다.
.spec.ipFamilies
를 다음 배열 값 중 하나로 설정할 수 있다.
["IPv4"]
["IPv6"]
["IPv4","IPv6"]
(이중 스택)["IPv6","IPv4"]
(이중 스택)
나열한 첫 번째 군은 레거시.spec.ClusterIP
필드에
사용된다.
이중 스택 서비스 구성 시나리오
이 예제는 다양한 이중 스택 서비스 구성 시나리오의 동작을 보여준다.
새로운 서비스에 대한 이중 스택 옵션
- 이 서비스 사양은
.spec.ipFamilyPolicy
를 명시적으로 정의하지 않는다. 이 서비스를 만들 때 쿠버네티스는 처음 구성된service-cluster-ip-range
에서 서비스에 대한 클러스터 IP를 할당하고.spec.ipFamilyPolicy
를SingleStack
으로 설정한다. (셀렉터가 없는 서비스 및 헤드리스 서비스와 같은 방식으로 동작한다.)
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
이 서비스 사양은
.spec.ipFamilyPolicy
에PreferDualStack
을 명시적으로 정의한다. 이중 스택 클러스터에서 이 서비스를 생성하면 쿠버네티스는 서비스에 대해 IPv4 및 IPv6 주소를 모두 할당한다. 컨트롤 플레인은 서비스의.spec
을 업데이트하여 IP 주소 할당을 기록한다. 필드.spec.ClusterIPs
는 기본 필드이며 할당된 IP 주소를 모두 포함한다..spec.ClusterIP
는 값이.spec.ClusterIPs
에서 계산된 보조 필드이다..spec.ClusterIP
필드의 경우 컨트롤 플레인은 첫 번째 서비스 클러스터 IP 범위와 동일한 주소 계열의 IP 주소를 기록한다.- 단일 스택 클러스터에서
.spec.ClusterIPs
및.spec.ClusterIP
필드는 모두 하나의 주소만 나열한다. - 이중 스택이 활성화된 클러스터에서
.spec.ipFamilyPolicy
에RequireDualStack
을 지정하면PreferDualStack
과 동일하게 작동한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
ipFamilyPolicy: PreferDualStack
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
- 이 서비스 사양은
.spec.ipFamilies
에IPv6
과IPv4
를 명시적으로 정의하고.spec.ipFamilyPolicy
에PreferDualStack
을 정의한다. 쿠버네티스가.spec.ClusterIPs
에 IPv6 및 IPv4 주소를 할당할 때.spec.ClusterIP
는.spec.ClusterIPs
배열의 첫 번째 요소이므로 IPv6 주소로 설정되어 기본값을 재정의한다.
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app.kubernetes.io/name: MyApp
spec:
ipFamilyPolicy: PreferDualStack
ipFamilies:
- IPv6
- IPv4
selector:
app.kubernetes.io/name: MyApp
ports:
- protocol: TCP
port: 80
기존 서비스의 이중 스택 기본값
이 예제는 서비스가 이미 있는 클러스터에서 이중 스택이 새로 활성화된 경우의 기본 동작을 보여준다. (기존 클러스터를 1.21 이상으로 업그레이드하면 이중 스택이 활성화된다.)
클러스터에서 이중 스택이 활성화된 경우 기존 서비스 (
IPv4
또는IPv6
)는 컨트롤 플레인이.spec.ipFamilyPolicy
를SingleStack
으로 지정하고.spec.ipFamilies
를 기존 서비스의 주소 계열로 설정한다. 기존 서비스 클러스터 IP는.spec.ClusterIPs
에 저장한다.apiVersion: v1 kind: Service metadata: name: my-service labels: app.kubernetes.io/name: MyApp spec: selector: app.kubernetes.io/name: MyApp ports: - protocol: TCP port: 80
kubectl을 사용하여 기존 서비스를 검사하여 이 동작을 검증할 수 있다.
kubectl get svc my-service -o yaml
apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/name: MyApp name: my-service spec: clusterIP: 10.0.197.123 clusterIPs: - 10.0.197.123 ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app.kubernetes.io/name: MyApp type: ClusterIP status: loadBalancer: {}
클러스터에서 이중 스택이 활성화된 경우, 셀렉터가 있는 기존 헤드리스 서비스는
.spec.ClusterIP
가None
이라도 컨트롤 플레인이.spec.ipFamilyPolicy
을SingleStack
으로 지정하고.spec.ipFamilies
는 첫 번째 서비스 클러스터 IP 범위(kube-apiserver에 대한--service-cluster-ip-range
플래그를 통해 구성)의 주소 계열으로 지정한다.apiVersion: v1 kind: Service metadata: name: my-service labels: app.kubernetes.io/name: MyApp spec: selector: app.kubernetes.io/name: MyApp ports: - protocol: TCP port: 80
kubectl을 사용하여 셀렉터로 기존 헤드리스 서비스를 검사하여 이 동작의 유효성을 검사 할 수 있다.
kubectl get svc my-service -o yaml
apiVersion: v1 kind: Service metadata: labels: app.kubernetes.io/name: MyApp name: my-service spec: clusterIP: None clusterIPs: - None ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app.kubernetes.io/name: MyApp
단일 스택과 이중 스택 간 서비스 전환
서비스는 단일 스택에서 이중 스택으로, 이중 스택에서 단일 스택으로 변경할 수 있다.
서비스를 단일 스택에서 이중 스택으로 변경하려면 원하는 대로
.spec.ipFamilyPolicy
를SingleStack
에서PreferDualStack
또는RequireDualStack
으로 변경한다. 이 서비스를 단일 스택에서 이중 스택으로 변경하면 쿠버네티스는 누락된 주소 계열의 것을 배정하므로 해당 서비스는 이제 IPv4와 IPv6 주소를 갖는다..spec.ipFamilyPolicy
를SingleStack
에서PreferDualStack
으로 업데이트하는 서비스 사양을 편집한다.이전:
spec: ipFamilyPolicy: SingleStack
이후:
spec: ipFamilyPolicy: PreferDualStack
서비스를 이중 스택에서 단일 스택으로 변경하려면
.spec.ipFamilyPolicy
를PreferDualStack
에서 또는RequireDualStack
을SingleStack
으로 변경한다. 이 서비스를 이중 스택에서 단일 스택으로 변경하면 쿠버네티스는.spec.ClusterIPs
배열의 첫 번째 요소 만 유지하고.spec.ClusterIP
를 해당 IP 주소로 설정하고.spec.ipFamilies
를.spec.ClusterIPs
의 주소 계열로 설정한다.
셀렉터가 없는 헤드리스 서비스
셀렉터가 없는 서비스 및 .spec.ipFamilyPolicy
가 명시적으로 설정되지 않은 경우 .spec.ipFamilyPolicy
필드의 기본값은 RequireDualStack
이다.
로드밸런서 서비스 유형
서비스에 이중 스택 로드밸런서를 프로비저닝하려면
.spec.type
필드를LoadBalancer
로 설정.spec.ipFamilyPolicy
필드를PreferDualStack
또는RequireDualStack
으로 설정
이그레스(Egress) 트래픽
비공개로 라우팅할 수 있는 IPv6 주소를 사용하는 파드에서 클러스터 외부 대상 (예: 공용 인터넷)에 도달하기 위해 이그레스 트래픽을 활성화하려면 투명 프록시 또는 IP 위장과 같은 메커니즘을 통해 공개적으로 라우팅한 IPv6 주소를 사용하도록 파드를 활성화해야 한다. ip-masq-agent 프로젝트는 이중 스택 클러스터에서 IP 위장을 지원한다.
윈도우 지원
윈도우에 있는 쿠버네티스는 싱글 스택(single-stack) "IPv6-only" 네트워킹을 지원하지 않는다. 그러나, 싱글 패밀리(single-family) 서비스로 되어 있는 파드와 노드에 대해서는 듀얼 스택(dual-stack) IPv4/IPv6 네트워킹을 지원한다.
l2bridge
네트워크로 IPv4/IPv6 듀얼 스택 네트워킹을 사용할 수 있다.
윈도우의 다른 네트워크 모델에 대한 내용은 윈도우에서의 네트워킹을 살펴본다.
다음 내용
- IPv4/IPv6 이중 스택 검증 네트워킹
- kubeadm을 사용하여 이중 스택 네트워킹 활성화
12 - 윈도우에서의 네트워킹
쿠버네티스는 리눅스 및 윈도우 노드를 지원한다. 단일 클러스터 내에 두 종류의 노드를 혼합할 수 있다. 이 페이지에서는 윈도우 운영 체제에서의 네트워킹에 대한 개요를 제공한다.
윈도우에서의 컨테이너 네트워킹
윈도우 컨테이너에 대한 네트워킹은 CNI 플러그인을 통해 노출된다. 윈도우 컨테이너는 네트워킹과 관련하여 가상 머신과 유사하게 작동한다. 각 컨테이너에는 Hyper-V 가상 스위치(vSwitch)에 연결된 가상 네트워크 어댑터(vNIC)가 있다. 호스트 네트워킹 서비스(HNS)와 호스트 컴퓨팅 서비스(HCS)는 함께 작동하여 컨테이너를 만들고 컨테이너 vNIC을 네트워크에 연결한다. HCS는 컨테이너 관리를 담당하는 반면 HNS는 다음과 같은 네트워킹 리소스 관리를 담당한다.
- 가상 네트워크(vSwitch 생성 포함)
- 엔드포인트 / vNIC
- 네임스페이스
- 정책(패킷 캡슐화, 로드 밸런싱 규칙, ACL, NAT 규칙 등)
윈도우 HNS(호스트 네트워킹 서비스)와 가상 스위치는 네임스페이스를 구현하고 파드 또는 컨테이너에 필요한 가상 NIC을 만들 수 있다. 그러나 DNS, 라우트, 메트릭과 같은 많은 구성은 리눅스에서와 같이 /etc/
내의 파일이 아닌 윈도우 레지스트리 데이터베이스에 저장된다. 컨테이너의 윈도우 레지스트리는 호스트 레지스트리와 별개이므로 호스트에서 컨테이너로 /etc/resolv.conf
를 매핑하는 것과 같은
개념은 리눅스에서와 동일한 효과를 갖지 않는다. 해당 컨테이너의 컨텍스트에서 실행되는 윈도우 API를 사용하여 구성해야 한다. 따라서 CNI 구현에서는 파일 매핑에 의존하는 대신 HNS를 호출하여 네트워크 세부 정보를 파드 또는 컨테이너로 전달해야 한다.
네트워크 모드
윈도우는 L2bridge, L2tunnel, Overlay, Transparent 및 NAT의 다섯 가지 네트워킹 드라이버/모드를 지원한다. 윈도우와 리눅스 워커 노드가 있는 이기종 클러스터에서는 윈도우와 리눅스 모두에서 호환되는 네트워킹 솔루션을 선택해야 한다. 윈도우에서 다음과 같은 out-of-tree 플러그인이 지원되며, 어떠한 경우에 각 CNI를 사용하면 좋은지도 소개한다.
네트워크 드라이버 | 설명 | 컨테이너 패킷 수정 | 네트워크 플러그인 | 네트워크 플러그인 특성 |
---|---|---|---|---|
L2bridge | 컨테이너는 외부 vSwitch에 연결된다. 컨테이너는 언더레이 네트워크에 연결된다. 하지만 인그레스/이그레스시에 재작성되기 때문에 물리적 네트워크가 컨테이너 MAC을 학습할 필요가 없다. | MAC은 호스트 MAC에 다시 쓰여지고, IP는 HNS OutboundNAT 정책을 사용하여 호스트 IP에 다시 쓰여질 수 있다. | win-bridge, Azure-CNI, Flannel 호스트-게이트웨이는 win-bridge를 사용한다. | win-bridge는 L2bridge 네트워크 모드를 사용하고, 컨테이너를 호스트의 언더레이에 연결하여 최상의 성능을 제공한다. 노드 간 연결을 위해 사용자 정의 경로(user-defined routes, UDR)가 필요하다. |
L2Tunnel | 이것은 Azure에서만 사용되는 l2bridge의 특별 케이스다. 모든 패킷은 SDN 정책이 적용되는 가상화 호스트로 전송된다. | MAC 재작성되고, 언더레이 네트워크 상에서 IP가 보인다. | Azure-CNI | Azure-CNI를 사용하면 컨테이너를 Azure vNET과 통합할 수 있으며, Azure Virtual Network에서 제공하는 기능 집합을 활용할 수 있다. 예를 들어, Azure 서비스에 안전하게 연결하거나 Azure NSG를 사용한다. azure-cni 예제를 참고한다. |
Overlay | 컨테이너에는 외부 vSwitch에 연결된 vNIC이 제공된다. 각 오버레이 네트워크는 사용자 지정 IP 접두사로 정의된 자체 IP 서브넷을 가져온다. 오버레이 네트워크 드라이버는 VXLAN 캡슐화를 사용한다. | 외부 헤더로 캡슐화된다. | win-overlay, Flannel VXLAN (win-overlay 사용) | win-overlay는 가상 컨테이너 네트워크를 호스트의 언더레이에서 격리하려는 경우(예: 보안 상의 이유로) 사용해야 한다. 데이터 센터의 IP에 제한이 있는 경우, (다른 VNID 태그가 있는) 다른 오버레이 네트워크에 IP를 재사용할 수 있다. 이 옵션을 사용하려면 Windows Server 2019에서 KB4489899가 필요하다. |
Transparent (ovn-kubernetes의 특수한 유스케이스) | 외부 vSwitch가 필요하다. 컨테이너는 논리적 네트워크(논리적 스위치 및 라우터)를 통해 파드 내 통신을 가능하게 하는 외부 vSwitch에 연결된다. | 패킷은 GENEVE 또는 STT 터널링을 통해 캡슐화되는데, 동일한 호스트에 있지 않은 파드에 도달하기 위한 터널링을 한다. 패킷은 ovn 네트워크 컨트롤러에서 제공하는 터널 메타데이터 정보를 통해 전달되거나 삭제된다. NAT는 north-south 통신(데이터 센터와 클라이언트, 네트워크 상의 데이터 센터 외부와의 통신)을 위해 수행된다. | ovn-kubernetes | Ansible을 통해 배포한다. 분산 ACL은 쿠버네티스 정책을 통해 적용할 수 있다. IPAM을 지원한다. kube-proxy 없이 로드 밸런싱을 수행할 수 있다. NAT를 수행할 때 iptables/netsh를 사용하지 않고 수행된다. |
NAT (쿠버네티스에서 사용되지 않음) | 컨테이너에는 내부 vSwitch에 연결된 vNIC이 제공된다. DNS/DHCP는 WinNAT라는 내부 컴포넌트를 사용하여 제공된다. | MAC 및 IP는 호스트 MAC/IP에 다시 작성된다. | nat | 완전성을 위해 여기에 포함되었다. |
위에서 설명한 대로, 플란넬(Flannel) CNI 플러그인은 VXLAN 네트워크 백엔드(베타 지원, win-overlay에 위임) 및 host-gateway network backend(안정적인 지원, win-bridge에 위임)를 통해 윈도우에서도 지원한다.
이 플러그인은 자동 노드 서브넷 임대 할당과 HNS 네트워크 생성을 위해 윈도우의 Flannel 데몬(Flanneld)과 함께 작동할 수 있도록 참조 CNI 플러그인(win-overlay, win-bridge) 중 하나에 대한 위임을 지원한다. 이 플러그인은 자체 구성 파일 (cni.conf)을 읽고, 이를 FlannelD가 생성한 subnet.env
파일의 환경 변수와 결합한다. 이후 이를 네트워크 연결을 위한 참조 CNI 플러그인 중 하나에 위임하고, 노드-할당 서브넷을 포함하는 올바른 구성을 IPAM 플러그인(예: host-local
)으로 보낸다.
노드, 파드 및 서비스 오브젝트의 경우, TCP/UDP 트래픽에 대해 다음 네트워크 흐름이 지원된다.
- 파드 → 파드(IP)
- 파드 → 파드(이름)
- 파드 → 서비스(Cluster IP)
- 파드 → 서비스(PQDN, 단 "."이 없는 경우에만)
- 파드 → 서비스(FQDN)
- 파드 → External(IP)
- 파드 → External(DNS)
- 노드 → 파드
- 파드 → 노드
IP 주소 관리 (IPAM)
The following IPAM options are supported on Windows:
- host-local
- azure-vnet-ipam(azure-cni 전용)
- Windows Server IPAM (IPAM이 설정되지 않은 경우에 대한 폴백(fallback) 옵션)
Load balancing and Services
쿠버네티스 서비스는 논리적 파드 집합 및 네트워크에서 해당 파드로 접근할 수 있는 수단을 정의하는 추상화이다. 윈도우 노드가 포함된 클러스터에서, 다음과 같은 종류의 서비스를 사용할 수 있다.
NodePort
ClusterIP
LoadBalancer
ExternalName
윈도우 컨테이너 네트워킹은 리눅스 네트워킹과 몇 가지 중요한 차이점을 갖는다. 윈도우 컨테이너 네트워킹에 대한 마이크로소프트 문서에서 상세 사항과 배경 지식을 제공한다.
윈도우에서는 다음 설정을 사용하여 서비스 및 로드 밸런싱 동작을 구성할 수 있다.
기능 | 설명 | 지원하는 최소 윈도우 OS 빌드 | 활성화하는 방법 |
---|---|---|---|
세션 어피니티 | 특정 클라이언트의 연결이 매번 동일한 파드로 전달되도록 한다. | Windows Server 2022 | service.spec.sessionAffinity 를 "ClientIP"로 설정
|
서버 직접 반환 (DSR, Direct Server Return) | IP 주소 수정 및 LBNAT가 컨테이너 vSwitch 포트에서 직접 발생하는 로드 밸런싱 모드. 서비스 트래픽은 소스 IP가 원래 파드 IP로 설정된 상태로 도착한다. | Windows Server 2019 | kube-proxy에 --feature-gates="WinDSR=true" --enable-dsr=true 플래그를 설정한다.
|
목적지 보존(Preserve-Destination) | 서비스 트래픽의 DNAT를 스킵하여, 백엔드 파드에 도달하는 패킷에서 목적지 서비스의 가상 IP를 보존한다. 또한 노드-노드 전달을 비활성화한다. | Windows Server, version 1903 | 서비스 어노테이션에 "preserve-destination": "true" 를 설정하고 kube-proxy에 DSR을 활성화한다.
|
IPv4/IPv6 이중 스택 네트워킹 | 클러스터 내/외부에 네이티브 IPv4-to-IPv4 통신 및 IPv6-to-IPv6 통신 활성화 | Windows Server 2019 | IPv4/IPv6 이중 스택을 참고한다. |
클라이언트 IP 보존 | 인그레스 트래픽의 소스 IP가 유지되도록 한다. 또한 노드-노드 전달을 비활성화한다. | Windows Server 2019 | Set service.spec.externalTrafficPolicy 를 "Local"로 설정하고 kube-proxy에 DSR을 활성화한다.
|
제한
다음 네트워킹 기능은 윈도우 노드에서 지원되지 않는다.
- 호스트 네트워킹 모드
- 노드 자체에서 로컬 NodePort로의 접근(다른 노드 또는 외부 클라이언트에서는 가능)
- 단일 서비스에 대해 64개를 초과하는 백엔드 파드 (또는 고유한 목적지 주소)
- 오버레이 네트워크에 연결된 윈도우 파드 간의 IPv6 통신
- non-DSR 모드에서의 로컬 트래픽 정책(Local Traffic Policy)
- win-overlay, win-bridge, Azure-CNI 플러그인을 통해 ICMP 프로토콜을 사용하는 아웃바운드 통신. 특히, 윈도우 데이터
플레인(VFP)은 ICMP 패킷 치환을 지원하지 않는다. 이것은 다음을 의미한다.
- 동일한 네트워크 내의 목적지로 전달되는 ICMP 패킷(예: ping을 통한 파드 간 통신)은 예상대로 제한 없이 작동한다.
- TCP/UDP 패킷은 예상대로 제한 없이 작동한다.
- 원격 네트워크를 통과하도록 지정된 ICMP 패킷(예: ping을 통한 파드에서 외부 인터넷으로의 통신)은 치환될 수 없으므로 소스로 다시 라우팅되지 않는다.
- TCP/UDP 패킷은 여전히 치환될 수 있기 때문에
ping <destination>
을curl <destination>
으로 대체하여 외부와의 연결을 디버깅할 수 있다.
다른 제한도 존재한다.
- 윈도우
참조 네트워크 플러그인 win-bridge와 win-overlay는 현재
CHECK
구현 누락으로 인해 CNI 사양 v0.4.0을 구현하지 않는다. - Flannel VXLAN CNI는 윈도우에서 다음과 같은 제한이 있다.
- 노드-파드 연결은 Flannel v0.12.0(또는 그 이상) 상의 로컬 파드에서만 가능하다.
- Flannel은 VNI 4096 및 UDP 4789 포트만 사용하도록 제한된다. 이 파라미터에 대한 더 자세한 사항은 공식 Flannel VXLAN 백엔드 문서를 참조한다.