서비스 메시를 위한 사용자 지정 프록시 통합
서비스 메시를 위한 사용자 지정 프록시 통합 (Use a custom proxy integration for service mesh)
이 주제에서는 Consul과 통합하기 위해 프록시를 확장하는 데 사용할 수 있는 프로세스와 API 엔드포인트를 설명해요. 어떤 프록시든 Consul 서비스 메시를 지원하도록 확장할 수 있어요.
출처: 문서
본문
참고 (Note)
Connect Native Golang SDK와
v1/agent/connect/authorize,v1/agent/connect/ca/leaf,v1/agent/connect/ca/rootsAPI는 더 이상 사용되지 않으며(deprecated) 향후 릴리스에서 제거될 예정입니다. Connect Native는 설계된 대로 계속 작동하지만, 이 기능은 네이티브 애플리케이션 통합(예: proxyless gRPC 서비스 메시 통합)에 대한 장기 대체제가 제공될 때 제거될 예정이므로 사용하지 않는 것을 권장합니다. 추가 정보와 대체 기능으로 추적되는 잠재적 솔루션의 진행 상황은 GH-10339을 참조하세요.
Native App Integration은 Consul의 서비스 메시 기능 중 상당수를 지원하지 않으며 활발히 개발되지 않습니다. 대부분의 프로덕션 환경에서는 Envoy 프록시를 사용해야 합니다.
이 주제에서는 Consul과 통합하기 위해 프록시를 확장하는 데 사용할 수 있는 프로세스와 API 엔드포인트를 설명합니다.
개요 (Overview)
어떤 프록시든 Consul 서비스 메시를 지원하도록 확장할 수 있습니다. Consul은 바로 사용할 수 있는 개발 경험에 적합한 기본 제공 프록시와 함께 제공되지만, 프로덕션 환경에서는 더 강력한 프록시 솔루션이 필요할 수 있습니다.
통합하는 프록시는 특정 서비스로 식별되는 인바운드 연결을 수락하고/하거나 아웃바운드 연결을 설정할 수 있어야 합니다. 어떤 경우에는 둘 중 하나만으로도 충분할 수 있지만, 일반적으로 완전한 사이드카 기능을 지원하려면 둘 다 필요합니다.
사이드카 프록시는 L4 또는 L7 네트워크 기능을 지원할 수 있습니다. L4 통합은 더 간단하고 모든 트래픽을 보호하기에 적합합니다. 그러나 L4는 모든 트래픽을 TCP로 취급하므로 고급 라우팅이나 메트릭 기능은 지원되지 않습니다.
완전한 L7 지원은 L4 지원 위에 구축됩니다. L7 프록시 통합은 라우팅, 재시도 및 기타 L7 기능을 동적으로 구성하여 Consul 서비스 메시의 L7 트래픽 라우팅 기능 대부분 또는 전부를 지원합니다. 기본 제공 프록시는 L4만 지원하는 반면, Envoy는 전체 L7 기능 세트를 지원합니다.
이 주제에서는 L4와 L7 간에 통합 방식이 다른 영역을 식별합니다.
이 문서 전반에 걸쳐 명사 connect 는 Consul의 서비스 메시 기능을 제공하는 connect 하위 시스템을 가리키는 데 사용됩니다.
인바운드 연결 수락 (Accepting Inbound Connections)
프록시는 인바운드 연결을 수락하려면 일부 포트에서 TLS 연결을 수락해야 합니다.
클라이언트 인증서 획득 및 검증 (Obtaining and validating client certificates)
클라이언트 인증서를 얻으려면 /v1/agent/connect/ca/leaf/ API 엔드포인트를 호출하세요. 예:
$ curl http://<host-ip>:8500/v1/agent/connect/ca/leaf/<service-name>
인바운드 연결의 클라이언트 인증서는 서비스 메시 CA 루트 인증서에 대해 검증되어야 합니다. 서비스 메시 CA에서 루트 인증서를 얻으려면 /v1/agent/connect/ca/roots 엔드포인트를 호출하세요. 예:
$ curl http://<host-ip>:8500/v1/agent/connect/ca/roots
연결 인가 (Authorizing the connection)
호출자의 클라이언트 인증서를 검증한 후 프록시는 전체 연결(L4) 또는 각 요청(L7)을 인가할 수 있습니다. 프록시된 서비스의 프로토콜에 따라 인가는 연결별(L4) 또는 요청별(L7)로 수행됩니다. 인증은 "서비스 아이덴티티"(TLS)를 기반으로 하며 전송 계층에서 구현됩니다.
참고 (Note): (로컬) 비율 제한 또는 최대 연결과 같은 일부 기능은 인가 호출이 이루어질 때 별도로 시행되는 프록시 수준 구성으로 예상됩니다. 프록시는 이미 사용 가능해야 하는 요청 비율 및 기타 상태에 대한 정보를 기반으로 구성을 시행할 수 있습니다.
프록시는 /v1/agent/connect/authorize API 엔드포인트를 호출하거나 intention match API 엔드포인트를 쿼리하여 연결을 인가할 수 있습니다.
/v1/agent/connect/authorize 엔드포인트는 수신된 각 연결에 대해 연결 경로에서 호출해야 합니다. 로컬 Consul 에이전트가 다운되거나 응답하지 않으면 새 연결의 성공률이 손상됩니다. 에이전트는 로컬 캐시된 데이터를 사용하여 연결을 인가하며 일반적으로 마이크로초 내에 응답합니다. 결과적으로 TLS 핸드셰이크는 일반적으로 마이크로초에 걸쳐 진행됩니다.
참고 (Note): 이 엔드포인트는 L4(예: TCP) 통합에만 적합합니다. 이 엔드포인트는 Permissions(즉, L7 기준)가 정의된 의도를 평가 중 항상 deny 의도로 취급합니다.
프록시는 시작 시 intention match API 엔드포인트를 쿼리하여 프록시 대상과 일치하는 의도 목록을 검색할 수 있습니다. 일치 항목은 Envoy의 RBAC와 같은 프록시의 네이티브 필터 구성에 저장해야 합니다.
성능과 신뢰성 이유로 intention match API 엔드포인트를 쿼리하는 것이 의도 시행을 구현하는 권장 방법입니다. 캐시된 의도는 각 수신 연결(L4) 또는 요청(L7)에 대해 참조하여 연결 또는 요청을 수락하거나 거부할지 결정해야 합니다.
영구 TCP 연결과 의도 (Persistent TCP connections and intentions)
TCP 프로토콜로 구성된 프록시된 서비스의 경우 잠재적으로 오래 지속되는 TCP 연결은 연결이 처음 설정될 때만 인가됩니다. 그러나 데이터베이스와 같은 많은 서비스는 일반적으로 영구 연결 풀을 사용하므로, 액세스를 거부하도록 의도를 변경해도 기존 연결이 종료되지 않습니다. 이 동작은 업데이트된 의도를 위반합니다. 이러한 경우 의도가 적용되지 않는 것처럼 보일 수 있습니다.
연결을 닫으려면 다음 전략 중 하나를 구현하세요:
- 연결이 최대 수명 후 종료되도록 구성합니다(예: 몇 시간). 이는 새 연결을 설정하는 오버헤드와 의도 변경 후 기존 연결이 열려 있는 시간을 결정하는 것 사이의 균형을 맞춥니다.
- 열려 있는 모든 연결을 주기적으로 재인가합니다. 인가 호출은 비용이 저렴하며 Consul 에이전트의 로컬 인메모리 작업이어야 합니다. 수천 개의 열린 연결을 주기적으로(예: 1분마다) 인가하는 것은 무시할 수 있는 오버헤드일 가능성이 높지만, 영구 연결의 프로토콜 효율성에 영향을 주지 않으면서 의도 변경을 시행하는 데 걸리는 시간에 더 엄격한 상한을 적용합니다.
인가의 인증서 일련번호 (Certificate serial in authorization)
의도는 현재 시행을 위해 TLS URI SAN(주체 대체 이름)을 사용합니다. Go SDK의 AuthZ API에는 일련번호를 전달하는 필드가 포함되어 있습니다(consul/connect/tls.go). 프록시는 인가 중에 이 값을 제공할 수 있습니다.
데이터 업데이트 (Updating data)
이 섹션에서 설명하는 API 엔드포인트는 백그라운드에서 업데이트되는 에이전트 로컬 데이터로 작동합니다. 리프, 루트, 의도는 프록시가 백그라운드에서 업데이트해야 합니다.
리프 인증서, 루트 인증서, 의도 엔드포인트는 blocking queries를 지원하며, 이를 사용하여 루트 키 회전, 만료 전의 새 리프 인증서, 의도 변경에 대한 거의 즉각적인 업데이트를 받아야 합니다.
SPIFFE 인증서 (SPIFFE certificates)
Consul은 인증서에 대해 SPIFFE 사양을 따르지만 일부 CA 제공자는 엄격한 준수를 허용하지 않습니다. 예를 들어, CA 인증서에 클러스터에 대한 올바른 trust-domain SPIFFE URI SAN이 없을 수 있습니다. 프록시에서 SPIFFE 검증을 수행하는 경우, 옵트아웃(opt out)이 가능해야 한다는 점을 인지하세요. 그렇지 않으면 Consul이 지원하는 일부 CA 제공자가 해당 프록시 사용과 호환되지 않습니다. Envoy와 기본 제공 프록시 모두 현재 리프 인증서 너머의 체인 SPIFFE URI를 검증하지 않습니다.
아웃바운드 연결 설정 (Establishing Outbound Connections)
아웃바운드 연결의 경우 프록시는 서비스의 mesh 지원 엔드포인트와 통신하고 /v1/agent/connect/ca/leaf/ API 엔드포인트의 클라이언트 인증서를 제공해야 합니다. 프록시는 /v1/agent/connect/ca/roots 엔드포인트에서 얻은 루트 인증서를 사용하여 대상 엔드포인트에서 제공된 인증서를 검증해야 합니다.
구성 발견 (Configuration Discovery)
/v1/agent/service/:service_id API 엔드포인트는 모든 프록시가 로컬 서비스에 등록된 프록시 구성을 발견할 수 있게 합니다. 이 엔드포인트는 해시 기반 blocking을 지원하므로 등록/구성 변경에 대한 long-polling이 가능합니다. 등록/구성의 변경은 새 구성을 즉시 반환합니다.
구현 예제는 built-in proxy를 참조하세요. Go SDK를 사용하면 프록시가 watch 패키지를 통해 HTTP "pull" API를 호출합니다: consul/connect/proxy/config.go.
각 업스트림 서비스에 대한 discovery chain은 /v1/discovery-chain/:service_id API 엔드포인트에서 가져와야 합니다. 이 엔드포인트는 특정 업스트림 서비스에 대해 사이드카가 필요한 구성의 컴파일된 그래프를 반환합니다.
프록시에서 L4 지원만 구현하는 경우 discovery chain을 가져올 때 OverrideProtocol 값을 tcp로 설정하여 HTTP 라우팅 규칙과 같은 L7 기능이 반환되지 않도록 하세요.
결과 discovery chain의 각 target에 대해 Service Discovery 섹션에 설명된 대로 [/v1/health/connect/:service_id] API 엔드포인트에서 정상 mesh 지원 엔드포인트 목록을 가져올 수 있습니다.
체인의 나머지 노드에는 HTTP 라우팅, 연결 시간 초과, 연결 풀 설정, 비율 제한 등과 같은 기능에 대한 가장 가까운 동등물로 변환해야 하는 구성이 포함됩니다. 지원되는 구성 매개변수에 대한 자세한 내용은 전체 discovery chain 문서와 관련 config entry 문서를 참조하세요.
서비스 발견 (Service Discovery)
프록시는 Consul의 service discovery API를 사용하여 주어진 서비스에 대한 모든 사용 가능한 mesh 지원 엔드포인트를 반환할 수 있습니다. 이 엔드포인트는 agent caching을 사용하여 성능을 개선하는 cached 쿼리 매개변수를 지원합니다. API 패키지는 캐싱을 활용하기 위해 UseCache 쿼리 옵션을 제공합니다. 성능 개선 외에도 캐시를 사용하면 Consul 서버 중단에 대해 메시가 더 탄력적입니다. 이는 메시가 새 연결에서 오류를 발생시키는 대신 마지막으로 알려진 서비스 인스턴스 집합을 계속 사용하여 "정적으로 실패(fail static)"하기 때문입니다.
프록시는 새 연결을 라우팅해야 할 때 API에 적시(just-in-time) 쿼리를 수행할지, 아니면 blocking queries를 사용하여 서비스의 현재 엔드포인트 집합을 로드하고 해당 목록을 최신으로 유지할지 결정할 수 있습니다. SDK와 기본 제공 프록시는 현재 적시 해석을 사용하지만, 많은 기존 프록시는 엔드포인트 집합을 가져와 blocking queries로 로컬 메모리에 유지하는 것이 통합하기 더 쉬울 가능성이 높습니다.
업스트림은 Prepared Query 대상 유형으로 정의될 수 있습니다. 이러한 업스트림은 서비스에 대한 업스트림 엔드포인트 목록을 결정하기 위해 Consul의 prepared query API를 사용해야 합니다. PreparedQuery API는 blocking을 지원하지 않으므로, 엔드포인트를 메모리에 채우기로 선택한 프록시는 적절하고 이상적으로는 구성 가능한 빈도로 엔드포인트를 폴링해야 합니다.
service-resolver 구성 항목에 대한 장기 지원. service-resolver 구성은 향후 Consul 버전에서 prepared query를 완전히 대체할 것입니다. 그러나 일부 경우에는 prepared query가 여전히 사용됩니다.
사이드카 인스턴스화 (Sidecar Instantiation)
Consul은 사이드카 프록시 프로세스를 시작하거나 관리하지 않습니다. 물리적 호스트나 VM에서 실행되는 프록시는 init, systemd, supervisord 등과 같은 프로세스 감독 시스템이 시작하고 실행하도록 설계되었습니다. 클러스터 스케줄러(Kubernetes, Nomad) 내에 배포된 경우 프록시는 동일한 namespace의 사이드카 컨테이너로 실행되어야 합니다.
프록시는 CONSUL_HTTP_TOKEN 및 CONSUL_HTTP_ADDR 환경 변수를 사용하여 Consul에 접속하고 인증서를 가져옵니다. 이는 CONSUL_HTTP_TOKEN 환경 변수에 해당 서비스의 구성을 읽는 데 필요한 권한이 있는 Consul ACL 토큰이 포함된 경우 발생합니다. Go api 패키지를 사용하면 환경 변수가 자동으로 읽히고 클라이언트가 구성됩니다.
또는 -token 또는 -token-file 플래그를 사용하여 Consul ACL 토큰을 제공할 수도 있습니다.
Providing a Consul ACL Token
Envoy:
$ consul connect envoy -sidecar-for "web" -token-file=/etc/consul.d/consul.token
Proxy:
$ consul connect proxy -sidecar-for "web" -token-file=/etc/consul.d/consul.token
Consul에서 TLS가 활성화된 경우 프록시를 시작하기 전에 다음 환경 변수를 추가해야 합니다:
CONSUL_CACERT, CONSUL_CLIENT_CERT, CONSUL_CLIENT_KEY는 CLI 플래그로도 제공할 수 있습니다. 자세한 내용은 consul connect proxy 문서를 참조하세요.
프록시 서비스 ID는 사용자가 제공합니다. 예제는 consul connect envoy를 참조하세요. -proxy-id 플래그를 사용하여 로컬 에이전트에 이미 등록한 프록시 서비스의 ID를 지정할 수 있습니다.
또는 -sidecar-for=<service> 옵션을 사용하여 서비스를 시작할 수 있습니다. 이 옵션은 지정된 <service>의 사이드카로 등록된 프록시를 Consul에 쿼리합니다. 프록시와 연결된 서비스가 정확히 하나 반환되면 해당 ID로 프록시가 시작됩니다. 컨트롤러는 -proxy-id를 인수로만 수락하면 됩니다. Consul CLI가 -sidecar-for 플래그에 지정된 이름의 ID를 해석합니다.