Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Istio ServiceEntry로 외부 서비스 등록하기

Istio ServiceEntry는 문서에서 다음과 같이 설명한다.

ServiceEntry를 사용하면 Istio 내부 서비스 레지스트리에 항목을 추가해 메시 내에서 자동으로 발견된 서비스가 수동으로 지정한 서비스에 접근하거나 라우팅할 수 있다. ServiceEntry는 서비스의 속성(DNS 이름, VIP, 포트, 프로토콜, 엔드포인트)를 설정한다. 이러한 서비스는 메시 외부에 있을 수도 있고 메시 내부 서비스일 수도 있다.

outboundTrafficPolicy

이 글은 Istio의 Sidecar 모드를 전제로 설명한다.

이전 Sidecar 글에서 봤듯이, Istio 서비스 메시를 사용하면 Pod의 요청은 함께 구성된 istio-proxy를 통해 나간다. 메시 내 서비스는 자동으로 등록되지만, 외부 서비스로 요청을 보내면 메시가 목적지를 알지 못한다.

이런 경우 외부 API를 Istio 내부 서비스 레지스트리에 수동으로 등록해 메시 서비스처럼 관리하려면 ServiceEntry를 사용한다.

ServiceEntry가 없으면 전역 설정인 meshConfigoutboundTrafficPolicy를 따르게 된다.

1meshConfig:
2  outboundTrafficPolicy:
3    mode: REGISTRY_ONLY

outboundTrafficPolicy는 애플리케이션이 알 수 없는 아웃바운드 트래픽을 어떻게 다룰지 정하는 설정이다. 모드는 다음 세 가지 중 하나를 선택할 수 있다.

  • REGISTRY_ONLY : 알지 못하는 아웃바운드 트래픽을 드랍한다. 트래픽의 목적지는 명시적으로 ServiceEntry를 통해 서비스 레지스트리에 선언해야 한다.
  • ALLOW_ANY : 알지 못하는 목적지로의 트래픽을 허용한다. PassthroughCluster를 통해 원래 목적지 IP로 전달한다.
  • ALLOW_ANY_DYNAMIC_DNS : 알 수 없는 목적지로의 트래픽을 동적 DNS 해결로 허용한다.

outboundTrafficPolicySidecar에서 설정할 수 있다.

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 이름도 가능하다.
    • VirtualServiceDestinationRule에서 일치하는 호스트를 찾을 때 사용한다.
    • 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

다음은 ServiceEntryVirtualService의 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
Valid HTML5 Valid CSS WCAG 2.1 AA tested