구성 스코핑
구성 스코핑 (Configuration Scoping)
Istio 컨트롤 플레인(Istiod)이 서비스 메시를 프로그래밍하기 위해 읽는 구성을 어떻게 범위를 제한할 수 있는지 배워요. 대규모 배포에서 과도한 리소스 소비를 피하기 위한 메커니즘들을 소개해요.
출처: Istio 문서
본문
서비스 메시를 프로그래밍하기 위해 Istio 컨트롤 플레인(Istiod)은 Service와 Node 같은 핵심 쿠버네티스 타입과, Gateway 같은 Istio 자체 타입을 포함한 다양한 구성을 읽어요. 이것들은 그다음 데이터 플레인으로 전송돼요(자세한 내용은 Architecture 참고).
기본적으로 컨트롤 플레인은 모든 네임스페이스의 모든 구성을 읽어요. 각 프록시 인스턴스도 모든 네임스페이스의 구성을 받아요. 여기에는 메시에 등록되지 않은 워크로드에 대한 정보도 포함돼요.
이 기본값은 별다른 설정 없이도 올바른 동작을 보장하지만, 확장성 비용이 따르요. 각 구성은 유지하고 최신 상태로 관리하는 데 (주로 CPU와 메모리의) 비용이 들어요. 대규모에서는 과도한 리소스 소비를 피하기 위해 구성 범위를 제한하는 것이 중요해요.
스코핑 메커니즘
Istio는 다양한 사용 사례를 충족하기 위해 구성의 범위를 제어하는 데 도움이 되는 몇 가지 도구를 제공해요. 요구사항에 따라 이들을 단독으로 또는 함께 사용할 수 있어요.
Sidecar는 특정 워크로드가 구성 집합을 가져오기(import) 위한 메커니즘을 제공해요exportTo는 워크로드 집합에 구성을 내보내기(export) 위한 메커니즘을 제공해요discoverySelectors는 Istio가 구성 집합을 완전히 무시하도록 하는 메커니즘을 제공해요
Sidecar 가져오기
Sidecar의 egress.hosts 필드는 가져올 구성 목록을 지정할 수 있게 해줘요. 지정된 기준과 일치하는 구성만 Sidecar 리소스의 영향을 받는 sidecar에 보여요.
예를 들어:
apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
name: default
spec:
egress:
- hosts:
- "./*" # Import all configuration from our own namespace
- "bookinfo/*" # Import all configuration from the bookinfo namespace
- "external-services/example.com" # Import only 'example.com' from the external-services namespace
exportTo
Istio의 VirtualService, DestinationRule, ServiceEntry는 spec.exportTo 필드를 제공해요. 마찬가지로 Service는 networking.istio.io/exportTo 어노테이션으로 구성할 수 있어요.
Sidecar가 워크로드 소유자가 자신이 가질 의존성을 제어할 수 있게 하는 것과 달리, exportTo는 그 반대로 작동해서 서비스 소유자가 자신의 서비스의 가시성을 제어할 수 있게 해줘요.
예를 들어 이 구성은 details Service를 자신의 네임스페이스와 client 네임스페이스에서만 볼 수 있게 해요.
apiVersion: v1
kind: Service
metadata:
name: details
annotations:
networking.istio.io/exportTo: ".,client"
spec: ...
DiscoverySelectors
이전 제어들이 워크로드나 서비스 소유자 수준에서 작동하는 반면, DiscoverySelectors는 구성 가시성에 대해 메시 전체적인 제어를 제공해요. Discovery selectors는 컨트롤 플레인에 보여야 할 네임스페이스에 대한 기준을 지정할 수 있게 해줘요. 일치하지 않는 네임스페이스는 컨트롤 플레인이 완전히 무시해요.
이는 설치 시 meshConfig의 일부로 구성할 수 있어요. 예를 들어:
meshConfig:
discoverySelectors:
- matchLabels:
# Allow any namespaces with `istio-discovery=enabled`
istio-discovery: enabled
- matchLabels:
# Allow "kube-system"; Kubernetes automatically adds this label to each namespace
kubernetes.io/metadata.name: kube-system
자주 묻는 질문
특정 구성의 비용을 어떻게 이해할 수 있나요?
구성 스코핑을 위한 최상의 투자 수익을 얻으려면 각 객체의 비용을 이해하는 것이 도움이 될 수 있어요. 안타깝게도 명확한 답은 없어요. 확장성은 매우 많은 요소에 달려 있기 때문이에요. 하지만 몇 가지 일반적인 지침이 있어요.
Istio에서는 구성 변경이 비싸요. 재계산이 필요하기 때문이에요. Endpoints 변경(일반적으로 Pod 스케일 업/다운에서)은 크게 최적화되어 있지만, 대부분의 다른 구성은 꽤 비싸요. 컨트롤러가 객체를 계속 변경할 때 특히 해로울 수 있어요(가끔 실수로 그렇게 되는 경우도 있어요!).
어떤 구성이 변경되고 있는지 감지하는 몇 가지 도구가 있어요.
- Istiod는 각 변경을 다음과 같이 로그로 남겨요:
Push debounce stable 1 for config Gateway/default/gateway: ..., full=true. 이는default네임스페이스의Gateway객체가 변경됐다는 것을 보여줘요.full=false는Endpoint같은 최적화된 업데이트를 나타내요. 참고:Service와Endpoints의 변경은 모두ServiceEntry로 표시돼요. - Istiod는 각 변경에 대해
pilot_k8s_cfg_events와pilot_k8s_reg_events메트릭을 노출해요. kubectl get <resource> --watch -oyaml --show-managed-fields는 객체(들)의 변경을 보여줄 수 있어서 무엇이, 누구에 의해 변경되는지 이해하는 데 도움이 돼요.
Headless 서비스(HTTP로 선언된 것들 제외)는 인스턴스 수에 따라 확장돼요. 이는 큰 headless 서비스를 비싸게 만들고, exportTo나 그에 상응하는 것으로 제외하기 좋은 후보가 돼요.
스코프 밖의 서비스에 연결하면 어떻게 되나요?
스코핑 메커니즘 중 하나로 제외된 서비스에 연결하면 데이터 플레인은 목적지에 대해 아무것도 모르기 때문에 Unmatched traffic으로 처리돼요.
Gateway는 어떻나요?
Gateway는 exportTo와 DiscoverySelectors를 존중하지만, Sidecar 객체는 Gateway에 영향을 미치지 않아요. 그러나 sidecar와 달리 게이트웨이는 기본적으로 전체 클러스터에 대한 구성이 없어요. 대신 각 구성이 게이트웨이에 명시적으로 연결되어 있어서 대부분 이 문제를 피할 수 있어요.
하지만 현재 데이터 플레인 구성의 일부(Envoy 용어의 "cluster")는 명시적으로 참조되지 않더라도 항상 전체 클러스터에 대해 전송돼요.