Kubernetes/쿠버네티스 모범 사례 스터디

네트워킹, 네트워크 보안, 서비스 메시

막이86 2023. 11. 14. 15:24
728x90

쿠버네티스 모범 사례을 요약한 내용입니다.

  • 쿠버네티스는 서로 연결된 시스템으로 구성된 클러스터의 관리자
  • 서비스가 효과적으로 통신하려면 쿠버네티스가 관리하는 분산 서비스 사이에 통신이 이루어지는 방법을 이해야함

9.1 쿠버네티스 네트워크 원칙

  • 효과적인 애플리케이션 아키텍처를 설계하기 위해서는 쿠버네티스의 내부 네트워크를 통해 서비스 사이의 통신이 이루어지는 방법을 이해해야 함
  • 쿠버네티스의 네트워크 규칙(컴포넌트 사이에서 통신하는 방법)
    • 동일한 파드 내의 모든 컨테이너는 동일한 네트워크 공간을 공유
      • 컨테이너 사이의 localhost 통신이 가능
    • 동일 파드 내의 컨테이너는 다른 포트를 열어야함
    • 리눅스 네임스페이스와 도커 네트워크를 통해 이루어짐
    • 파드의 네트워킹을 담당하는 모든 파드에서 일시 중지된 컨테이너를 사용해 파드 내의 모든 컨테이너가 동일한 로컬 네트워크에 존제하게 됨</aside>
    • <aside> ❓ 잘 이해가 안감
    • [그림 9-1]은 컨테이너 A가 localhost와 컨테이너 B가 열어 놓은 포트를 통해 직접 통신하는 것을 보여줌
    파드 간의 통신
    • 모든 파드는 네트워크 주소 변환(NAT) 없이 통신할 수 있어야 함
      • 수신하는 파드에서 볼수 있는 송신자의 파드 IP주소가 실제 IP 주소
      • 사용하는 네트워크 플러그인에 따라 처리 방식이 달라짐
    • 동일한 클러스터의 서로 다른 노드에 존재하는 파드 사이에서도 적용됨
    • NAT 없이 파드와 직접 통신할 수 있는 노드에도 이 규칙이 적용
    • 필요에 따라 호스트 기반의 에이전트와 시스템 데몬이 파드와 통신할 수 있음
    • [그림 9-2]는 동일한 노드의 파드와 동일한 클러스터의 각기 다른 노드에 있는 파드간의 통신 과정을 보여줌
    서비스와 파드 간의 통신
    • 서비스는 견고한 IP 주소와 포트를 나타내며 각 노드는 서비스에 연계된 엔드포인트로 트래픽을 전달 함
    • 서비스 구현하는 기술은 주로 iptables를 이용하는 방법과 IP 가상 서비를 이용하는 방법이 있음
    • 대부분 의사계층 4로드 밸런서 기능을 제공하는 iptables로 구현함
    • [그림 9-3]은 레이블 셀렉터를 통해 서비스를 파드에 연계시키는 것을 보여줌
  • 동일한 파드내의 컨테이너 간 통신

9.2 네트워크 플러그인

  • 초창기에 SIG(Special Interest Group)에서는 플러그인이 가능한 아키텍터를 지향한 네트워크 표준을 제시함
  • 표준을 통해 많은 서드파트 네트워킹 프로젝트가 연동되었으며 워크로드에 향상된 기능을 사용할 수 있게 됨
  • 쿠버네티스가 제공하는 플러그인이 Kubenet, 컨테이너 네트워크 인터페이스(CNI) 명세를 준수하는 플러그인

9.2.1 Kubenet

  • 쿠버네티스에서 바로 사용할 수 있는 가장 기본적인 네트워크 플러그인
  • 파드가 연결될 가상 이더넷쌍인 리눅스 브릿지 cbr0를 제공
  • 파드가 연결되면 클러스터의 노드에 분산되어 있는 사이더(Classless Inter-Domain Routing CIDER) 범위 내의 IP 주소를 얻게 됨
    • IP 위장(masquerade) 플래그도 있음
    • 파드 CIDR 범위 외부의 IP 전달되는 트래픽이 위장하려면 플래그를 활성화 해야함
    • 파드 간의 통신 규칙을 따르지 않음, 파드 CIDR 외부로 전달되는 트래픽은 NAT를 거치기 때문
  • 패킷이 다른 노드로 전송될 때 일종의 라우팅은 이 트래픽을 올바른 노드로 전달하는 역확

9.2.2 Kubenet 모범 사례

  • 가장 단순한 네트워크 스택을 구축할수 잇으며 복잡한 네트워크에서 귀중한 IP 주소를 절약할 수 있음
    • 대표적으로 온프레미스 데이터 센터에 확장된 클라우드 네트워크가 있음
  • 파드 CIDR 범위가 각 클러스터의 파드의 잠재적인 최대 크기를 처리할 만큼 충분히 큰지 확인 해야함
    • kubelet에 설정된 노드당 기본 파드는 110이지만 조정 가능
  • 적합한 노드의 파드로 트래픽이 전송될 수 있도록 경로 규칙을 이해하고 올바른 계획을 세워야함
    • 클라우드 공급자 환경에서는 일반적으로 자동화되지만 온프레미스 또는 예외적인 사례에서는 자동화와 함께 견고한 네트워크 관리가 필요

9.2.3 CNI 플러그인

  • CNI 플러그인 명세에는 몇가지 기본적인 요구사항이 있음
    • CNI와의 인터페이스, 기본적인 API 동작, 클러스터에서 사용되는 컨테이너 런타임과의 인터페이스
  • 네트워크 관리 컴포넌트는 CNI에 의해 정의되지만, 이들은 모두 IP 주소 관리를 포함해야 하며 적어도 네트워크에 컨테이너 추가와 삭제를 허용해야 함
  • 코어CNI 프로젝트는 CNI플러그인 명세의 기본 요구사항을 만족하는 플러그인을 구현할 수 있는 라이브러리를 제공
  • 다양한 기능을 구행하는 다른 플러그인을 호출할 수도 있음
  • 유연성 덕분에 컨테이너 네트워크에서 사용할 수 있는 수많은 CNI 플러그인이 만들어졌음
  • CNI 플러그인의 예시로는 애저 네이티브 CNI, 아마존 VPC CNI, 누아지CNI, 주니퍼 네트워크 콘트레일/텅스텐 패브릭, VM웨어 NSX가 있음

9.2.4 CNI 플러그인 모범 사례

  • 인프라 전반적인 네트워킹 목표를 달성하는 데 필요한 기능을 평가해야 함
    • 일부 CNI 플러그인은 고가용성, 다중 클라우드 연결성, 쿠버네티스 네트워킹 정책 지원 등 다양한 기능 제공
  • 공개 클라우드 공급자를 통해 클러스터를 실행 중이라면 클라우드 공급자의 소프트웨어 정의 네트워크(software defined network SDN)가 CNI 플러그인을 실제로 지원하는지 확인 해야함
  • 네트워크 보안 도구, 네트워크 관찰성, 관리 도구가 CNI 플러그인과 호환되는지 확인해보고 그렇지 않다면 대체할 수 있는 도구를 조사 해야함
    • 대규모 분산 시스템으로 전환할 때는 이러한 필요성이 확대되기 때문에, 관찰설이나 보안 기능에 문제가 없는지 확인 해야함
    • 위브웍스의 위브 스코프, 다이나트레이스, 시스딕 같은 도구를 쿠버네티스 환경에 추가할 수 있음
    • 최소한 네트워크 스택과 네가지 황금신호에 대한 통찰력을 제공하는 도구를 사용해야함
      • 네가지 황금신호: 레이턴시, 트래픽, 오류, 포화도
  • SDN 네트워크 공간과 분리된 별도의 오버레이 네트워크를 제공하지 않는 CNI를 사용하는 경우, 노드 IP, 파드 IP, 내부 로드 밸런서와 클러스터 업그레이드, 프로세스 확장에 따른 오버헤드를 감당할 수 있는 적절한 네트워크 주소 공간이 존재하는지 확인해야 함

9.3 쿠버네티스의 서비스

  • 파드가 클러스터에 배포되면 쿠버네티스 네트워크 기본 규칙과 이 규칙을 실현하는 네트워크 플러그인 때문에 파드는 오직 같은 플러스터 내의 다른 파드와 직접 통신할 수 있음
  • 노드와 동일 네트워크 공간의 IP를 파드에 부여하는 CNI 플러그인이라면 기술적으로는 파드 IP를 알면 클러스터 외부에서 직접 접근할 수 있음
    • 파드는 수명이 짧기 때문에 이 방법은 효율적이지 않음
    • 자발적 또는 비자발적으로 중단으로 인해 파드가 사라질지도 모름
  • 서비스 API는 내구성 있는 IP와 포트를 클러스터 내에 할당하고, 서비스의 엔드포인트를 적절한 파드에 자동으로 매핑
    • iptables 또는 리눅스 노드의 IP 가상 서버를 통해 할당된 서비스 IP와 포트를 엔드포인트 또는 파드의 실제 IP에 매핑
    • 서비스 API를 관리하는 컨트롤러는 kube-proxy 서비스
      • 클러스터의 각 노드에서 실행되어 iptables 규칙을 조작
  • 서비스 객체를 정의할 때 서비스 타입도 정의 해야함
    • 엔드포인트가 클러스터 내부에만 노출되는지 혹은 클러스터 외부에도 노출되는지를 결정함

9.3.1 ClusterIP 서비스 타입

  • 서비스 타입을 명시하지 않을 때 기본값은 ClusterIP
  • ClusterIP는 CIDR 범위 내에서 IP가 할당됨
  • IP 서비스는 객체와 함께 오래 지속되므로 셀렉터 필드를 통해 백엔드 파드에 IP, 포트, 프로토콜을 매핑
  • 서비스를 선언하면 서비스의 DNS 이름이 만들어짐
    • DNS 이름을 통해 클러스터 내에서 서비스 검색을 용이하게 하고, 워크로드는 서비스 이름으로 DNS를 조회해 클러스터 내의 다른 서비스와 통신할 수 있음
  • ClusterIP 예제
    • 클라이언트가 서비스와 동일한 네임스페이스에 존재하면 간단히 http://web1-svc를 호출할 수 있음
    apiVersion: v1
    kind: Service
    metadata:
    	name: web1-svc
    spec: 
    	selector:
    		app: web1
    	ports:
    	- port: 80
    		targetPort: 8081
    
  • 다른 네임스페이스에서 서비스를 찾을 때 DNS 패턴은 **<service_name>.<namepace_name>.svc.cluster.local**
  • 서비스 정의에 셀렉터가 없다면 엔드포인트 API를 사용해 엔드포인트를 명시적으로 정의할 수 있음
    • 특정 엔드포인트인 IP와 포트를 서비스에 추가함
    • 몇가지 유용한 시나리오가 있음
      • 테스트 시점에는 클러스터에 없는 데이터베이스를 사용하고 나중에 쿠버네티스에 배포되는 데이터베이스로 서비스를 변경하는 시나리오
    • 다른 서비스처럼 kube-proxy에 의해 관리되지 않으므로 헤드리스 서비스라고 불림
    <aside> ❓ 잘 이해가 안감
  • </aside>

9.3.2 NodePort 서비스 타입

  • NodePort 서비스 타입은 클러스터의 각 노드의 고수준 포트를 각 노드의 서비스 IP와 포트에 할당
  • NodePort의 고수준 포트의 범위는 30,000 ~ 32,767 사이로 정적으로 할당 되거나 서비스 명세 안에 명시할 수 있음
  • NodePort는 일반적으로 자동 로드 밸런스 구성을 제공하지 않는 온프레미스 클러스터 또는 맞춤형 솔루션에서 사용됨

9.3.3 ExternalName 서비스 타입

  • 현업에서는 거의 사용되지 않지만, 클러스터 수준의 내구성을 가진 DNS 이름을 외부 DNS 서비스에 전달할 때 유용
    • ex) mymongodb.doucments.azure.com 과 같은 클라우드 공급자가 제공하는 고유한 DNS를 가지는 클라우드 외부 데이터베이스 서비스
  • 기술적으로는 Environment 변수를 사용해 파드 명세에 간단히 추가할 수 있음
  • 실제로 가리키는 데이터베이스를 변경할 때 서비스명세만 바꾸면 되지만, Environment 변수를 변경하려면 파드를 재시작 해야함
apiVersion: v1
kind: Service
metadata:
	name: prod-mongodb
	namespace: prod
spec:
	type: ExternalName
	externalName: [mymongodb.doucments.azure.com](<http://mymongodb.doucments.azure.com>)

<aside> ❓ Environment를 사용하면 파드를 재시작 해야하기 때문에 ExternalName 서비스를 사용?

</aside>

9.3.4 로드 밸런서 서비스 타입

  • 로드 밸런서는 특별한 서비스 타입
  • 클라우드 공급자나 프로그램이 가능한 클라우드 인프라 서비스를 통해 자동화할 수 있음
  • 클러스터의 인프라 공급자가 제공하는 로드 밸런싱 메커니즘을 배포할 수 있는 유일한 방법이 LoadBalancer 타입
  • LoadBalancer 동작 방식은 AWS, 애저, GCE, 오픈스택 등에서 거의 동일함
  • 일반적으로 공개된 로드 밸런스 서비스를 생성하지만 각 클라우드 공급자 내부 전용 로드밸런서 설정 기능을 활성화 하기 위한 특별한 애너테이션이 존재함
  • 서비스 명세에 실제로 사용하는 로드 밸런서 IP와 허용할 소스 범위를 정의할 수 있음
  • apiVersion: v1 kind: Service metadata: name: web-svc spec: type: LoadBalancer selector: app: web ports: - protocol: TCP port: 80 targetPort: 8081 loadBalancerIP: 13.12.21.31 loadBalancerSourceRanges: - "142.43.0.0/16"

9.3.5 인그레스와 인그레스 컨트롤러

  • 기술적으로 서비스 타입은 아니지만, 이그레스 명세에는 워크로드가 트래픽을 수신할 때 중요한 개념이 있음
  • 인그레스 API는 HTTP 수준의 라우터로, 호스트와 경로 기반 규칙으로 특정 백엔드 서비스에게 트래픽을 전달함
    • ex) www.aaa.com 웹 사이트에 /registration, /labaccess 두가지 경로가 있을 경우 각각 쿠버네티스에 등록된 서비스인 reg-svc, labaccess-svc를 제공
      • 인그레스 규칙을 정의하여 /registration에 대한 요청은 reg-svc 서비스와 해당 엔드포인트 파드로 전달하고 /labaccess에 대한 요청은 labaccess-svc 서비스의 적절한 엔드포인트로 전달 할 수 있음
  • 인그레스 API는 호스트 기반 라우팅을 허용해 단일 인그레스에서 여러 호스트를 지원
  • 인그레스 컨트롤러는 인그레스 API와 분리되어 있음
  • 운영자는 Nginx, Traefik, HAProxy 등과 같은 인그레스 컨트롤러를 선택해 배포 가능
  • 인그레스 컨트롤러는 다른 컨트롤러와 마찬가지로 컨트롤러지만 시스템의 일부가 아님
  • 동적 구성을 위한 쿠버네티스 인그레스 API와 인터페이스하는 서드파트 컨트롤러임
  • 가장 대중적인 인그레스 컨트롤러는 NGINX이며 쿠버네티스 프로젝트에서 부분적으로 관리됨
  •  

9.3.6 서비스와 인그레스 컨트롤러 모범 사례

  • 상호 연결된 애플리케이션이 존재하는 복잡한 가상 네트워크 환경을 구축할 때는 신중하게 계획해야함
  • 여러 서비스가 서로 통신하거나 외부와 통신하는 것을 효과적으로 관리하려면 애플리케이션이 변경될 때마다 지속적으로 주의를 기울여야 함
  • 클러스터 외부에서 접근하는 서비스의 수를 제한해야함
    • 대부분의 서비스는 ClusterIP로 두고 외부 접근 서비스만 노출하는 것이 이상적
  • 노출해야 하는 서비스가 주로 HTTP/HTTPS 기반이라면 인그레스 API와 컨트롤러를 사용하여 TLS 종료와 함께 트래픽을 서비스로 라우팅하는 것이 가장 좋음
  • 사용하는 인그레스 컨트롤러 타입에 따라 속도제한, 해더 재작성, OAuth 인증, 관찰 가능성 등의 기능을 자체에 빌드하지 않고도 사용가능
  • 웹 기반 워크로드의 안전한 수신에 필요한 기능을 가진 인그레스 컨트롤러를 선택해야함
    • 하나로 표준화하여 전사적으로 사용
    • 컨트롤러 구현마다 설정 애너테이션이 다르므로 배포 코드가 쿠버네티스 구현 간에 이식되는 것을 방지해야함
  • 인프라 관리와 인그레스 부하를 클러스터 외부로 옮길 수 있는 기능이 클라우드 서비스 공급자의 인그레스 컨트롤러에 있는지 평가 해야함
  • API를 외부에 주로 제공한다면 API 기반 워크로드를 세부적으로 조절할 수 있는 Kong 또는 엠버서더 같은 인그레스 컨트롤러를 평가함
    • NGINX, Traefik등 일부 API 튜닝을 제공하지만 특정 API 프록시 시스템만큼 세밀하지 않음
  • 인그레스 컨트롤러를 쿠버네티스 파드 기반 워크로드로 배포할 때 고가용성이 설계되었는지 확인하고 처리량의 성능을 집계해야함
  • 메트릭을 관찰해 인그레스 규모를 적절하게 확장하고, 워크로드가 확장되는 동안 클라이언트 중단을 막을수 있는 충분한 대비채기 있어야함

9.4 네트워크 보안 정책

  • 네트워크폴리시(NetworkPolicy) API를 사용해 워크로드에 정의된 네트워크 수준의 인그레스와 이그레스 접근을 제어할 수 있음
  • 파드 그룹 간 또는 다른 엔드포인트로 통신하는 것을 제어할 수 있음
  • 네트워크 정책은 단순한 YAML 구조이며 데이터 센터 내의 간단한 트래픽 방화벽으로 볼수 있음
    • 정책 명세에는 podSelector, ingress, egress, polityType 필드가 있음
    • 필수 필드는 podSelector 이며 matchLabels를 가진 셀렉터와 동일한 규약을 따름
  • 네트워크폴리시 객체는 네임스페이스 수준의 객체이므로 podSelector에 셀렉터가 없으면 네임스페이스의 모든 파드에 정책이 적용됨
  • 인그레스 또는 이그레스 규칙이 정의되어 있으면 파드에 인그레스 또는 이그레스가 허용되는 화이트리스트가 생성됨
  • 셀렉터와 일치하는 파드에 정책이 적용되면 인그레스 또는 이그레스 규칙에 명시되지 않은 모든 트래픽은 차단됨
  • 셀렉터와 일치하지 않은 파드는 아무런 정책에 속하지 않기 때문에 모든 인그레스와 이그레스가 허용됨
  • 인그레스와 이그레스 필드는 기본적으로 소스 또는 대상에 대한 규칙 목록으로 특정 CIDR범위, podSelector, namespaceSelector 임
  • 인그레스 필드를 비워두면 모든 인바운드는 차단됨
  • 이그레스를 비워두면 모든 아웃바운드는 차단됨
  • policyType 필드에는 정책 객체와 연관돈 네트워크 정책 규칙 타입을 지정
    • policyType 필드가 없으면 인그레스와 이그레스 목록 필드를 참조
    • 이그레스는 policyType에 반드시 이그레스를 명시하고 이그레스 규칙 목록에도 존재해야 동작함
    • 인그레스는 명시적으로 정의할 필요가 없음
  • 기본 거부 규칙 코드
  •  
  • 웹 계층 네트워크 정책 코드
  •  
  • API 계층 네트워크 정책 코드
  •  
  • 데이터베이스 계층 네트워크 정책 코드
  •  

9.4.1 네트워크 정책 모범 사례

  • 천천히 진행하면서 파드로 인그레스되는 트래픽에 집중
    • 인그레스와 이그레스 규칙을 복잡하게 만들면 네트워크 추적이 어려워짐
    • 중요한 워크로드로의 흐름을 제어하기 위해 이그레스 규칙을 살펴보기
    • 인그레스 명세는 인그레스 규칙 목록이 비어있더라도 많은 옵션을 기본값으로 설정
  • 사용중인 네트워크 플러그인에 네트워크폴리시 API에 대한 자체 인터페이스가 있거나 잘 알려진 다른 플러그인을 지원하는지 확인 필요
  • 네트워크 팀이 기본 거부 정책을 자주 사용한다면 보안이 필요한 워크로드를 가진 클러스터의 각 네임스페이스 다음과 같은 네트워크 정책을 만들기
    • 다른 네트워크 정책을 삭제하더라도 실수로 파드가 노출되지 않음
  • 인터넷에 접근해야하는 파드가 있는 경우, 레이블을 사용해 수신을 허용하는 네트워크 정책을 명시적으로 적용
    • 패킷이 들어오는 실제 IP가 인터넷이 아니라 로드 밸런서, 방화벽, 그외 네트워크 장치의 내부 IP라면 전체 흐름을 알아야함
     
    
  • 정책을 간단하게 만들기 위해 애플리케이션 워크로드를 단일 네임스페이스에 배치
    • 네임스페이스 간 통신이 필요할 때는 흐름을 식별하기 위해 최대한 명시적인 이름과 구체적인 레이블을 사용
  • 제한 정책 수가 적은 테스트 네임스페이스를 만들어 정확한 트래픽 패턴을 조사 필요
728x90