Istio ServiceEntry로 외부 서비스 등록하기
Istio ServiceEntry는 문서에서 다음과 같이 설명한다.
ServiceEntry를 사용하면 Istio 내부 서비스 레지스트리에 항목을 추가해 메시 내에서 자동으로 발견된 서비스가 수동으로 지정한 서비스에 접근하거나 라우팅할 수 있다. ServiceEntry는 서비스의 속성(DNS 이름, VIP, 포트, 프로토콜, 엔드포인트)를 설정한다. 이러한 서비스는 메시 외부에 있을 수도 있고 메시 내부 서비스일 수도 있다.
outboundTrafficPolicy
이 글은 Istio의 Sidecar 모드를 전제로 설명한다.
이전 Sidecar 글에서 봤듯이, Istio 서비스 메시를 사용하면 Pod의 요청은 함께 구성된 istio-proxy를 통해 나간다. 메시 내 서비스는 자동으로 등록되지만, 외부 서비스로 요청을 보내면 메시가 목적지를 알지 못한다.
이런 경우 외부 API를 Istio 내부 서비스 레지스트리에 수동으로 등록해 메시 서비스처럼 관리하려면 ServiceEntry를 사용한다.
ServiceEntry가 없으면 전역 설정인 meshConfig의 outboundTrafficPolicy를 따르게 된다.
1meshConfig:
2 outboundTrafficPolicy:
3 mode: REGISTRY_ONLY
outboundTrafficPolicy는 애플리케이션이 알 수 없는 아웃바운드 트래픽을 어떻게 다룰지 정하는 설정이다. 모드는 다음 세 가지 중 하나를 선택할 수 있다.
REGISTRY_ONLY: 알지 못하는 아웃바운드 트래픽을 드랍한다. 트래픽의 목적지는 명시적으로ServiceEntry를 통해 서비스 레지스트리에 선언해야 한다.ALLOW_ANY: 알지 못하는 목적지로의 트래픽을 허용한다.PassthroughCluster를 통해 원래 목적지 IP로 전달한다.ALLOW_ANY_DYNAMIC_DNS: 알 수 없는 목적지로의 트래픽을 동적 DNS 해결로 허용한다.
이 outboundTrafficPolicy는 Sidecar에서 설정할 수 있다.
ServiceEntry
알 수 없는 목적지는 ServiceEntry로 허용 여부만 선택할 수도 있다. 하지만 Istio가 이를 인식하면 타임아웃, 재시도 규칙, 서킷 브레이커 같은 트래픽 정책을 적용할 수 있다. 또한 실제 서비스 이름으로 식별하므로 로그와 메트릭의 관측성도 높아진다.
다음은 간단한 ServiceEntry 예시이다.
1apiVersion: networking.istio.io/v1
2kind: ServiceEntry
3metadata:
4 name: external-svc-https
5spec:
6 hosts:
7 - api.dropboxapi.com
8 - www.googleapis.com
9 - api.facebook.com
10 ports:
11 - number: 443
12 name: https
13 protocol: TLS
14 location: MESH_EXTERNAL
15 resolution: DNS
주요 필드를 살펴보자.
hosts: Istio에 등록할 호스트명이다.- 와일드카드 접두사를 쓴 DNS 이름도 가능하다.
VirtualService와DestinationRule에서 일치하는 호스트를 찾을 때 사용한다.- HTTP에서는 Host/Authority 헤더와 매칭한다.
- HTTPS/TLS에서는 SNI 값과 매칭한다.
ports: 서비스가 제공하는 포트와 프로토콜이다.name: (필수) 포트에 할당된 레이블number: (필수) 정수 형식의 포트 번호protocol:HTTP|HTTPS|HTTP2|GRPC|MONGO|TCP|TLS중 하나의 값이다.targetPort: 트래픽을 수신할 포트 번호
location: 서비스가 메시 외부(MESH_EXTERNAL)인지 메시 내부(MESH_INTERNAL)인지를 정한다.resolution:istio-proxy가 최종 엔드포인트 주소를 결정하는 방법을 지정하며, 아래 값 중 하나를 사용한다.DNS: Envoy가 DNS를 조회해 엔드포인트를 결정하며, 외부 API에는 보통 가장 안전한 선택이다.DNS_ROUND_ROBIN: DNS 결과 중 첫 주소를 사용한다.- 이름을 보면 여러 주소를 돌려서 사용할 것 같지만, 실제로는 새 연결이 계속 첫 주소를 사용하는 방식이다. DNS 변경이 잦아 기존 엔드포인트를 제거하고 커넥션 풀을 드레인한 뒤 새로 연결해야 할 때, 커넥션 풀이 너무 자주 생성되는 문제를 막기 위해 사용한다.
STATIC:endpoints필드에 선언한 정적 IP 주소를 사용한다.NONE: 들어오는 요청이 이미 IP로 해석되었다고 가정하고 아무것도 하지 않는다.
endpoints: 서비스에 연결된 IP 주소workloadSelector:MESH_INTERNAL에서만 사용할 수 있으며,endpoints와 둘 중 하나만 사용할 수 있다.addresses: 서비스에 연결된 가상 IP 주소exportTo: 해당 ServiceEntry를 어느 네임스페이스에 노출할지를 정한다. 생략하면 모든 네임스페이스에 노출한다.".": ServiceEntry가 생성된 네임스페이스에만 노출"*": 모든 네임스페이스에 노출
구성이 간단하므로 몇 가지 예시를 보면 어떤 상황에 쓰는지 이해할 수 있다.
추가 예시
다음은 MongoDB를 ServiceEntry에 등록한 예시이다.
1apiVersion: networking.istio.io/v1
2kind: ServiceEntry
3metadata:
4 name: external-svc-mongocluster
5spec:
6 hosts:
7 - mymongodb.somedomain # not used
8 addresses:
9 - 192.192.192.192/24 # VIPs
10 ports:
11 - number: 27018
12 name: mongodb
13 protocol: MONGO
14 location: MESH_INTERNAL
15 resolution: STATIC
16 endpoints:
17 - address: 2.2.2.2
18 - address: 3.3.3.3
19
20----------
21
22apiVersion: networking.istio.io/v1
23kind: DestinationRule
24metadata:
25 name: mtls-mongocluster
26spec:
27 host: mymongodb.somedomain
28 trafficPolicy:
29 tls:
30 mode: MUTUAL
31 clientCertificate: /etc/certs/myclientcert.pem
32 privateKey: /etc/certs/client_private_key.pem
33 caCertificates: /etc/certs/rootcacerts.pem
다음은 ServiceEntry와 VirtualService의 TLS 라우팅을 이용해서 SNI 값으로 방화벽에 연결하는 예시다.
1apiVersion: networking.istio.io/v1
2kind: ServiceEntry
3metadata:
4 name: external-svc-redirect
5spec:
6 hosts:
7 - wikipedia.org
8 - "*.wikipedia.org"
9 location: MESH_EXTERNAL
10 ports:
11 - number: 443
12 name: https
13 protocol: TLS
14 resolution: NONE
15
16-------
17
18apiVersion: networking.istio.io/v1
19kind: VirtualService
20metadata:
21 name: tls-routing
22spec:
23 hosts:
24 - wikipedia.org
25 - "*.wikipedia.org"
26 tls:
27 - match:
28 - sniHosts:
29 - wikipedia.org
30 - "*.wikipedia.org"
31 route:
32 - destination:
33 host: internal-egress-firewall.ns1.svc.cluster.local
Comments