KubeCon2024 - Comparing Sidecar-Less Service Mesh from Cilium and Istio
https://youtu.be/91oylZSoYzM?si=HPMFGBtma5rbIUrI
발표자: Christian
- solo.io의 Global Field CTO. service mesh 쪽 오픈소스 2017년부터 참여 중.
cloud native 환경의 Networking infra 역할.
- Security, Compilance, Zero Trust, Mandates, Multi Cloud...
- mTLS나 Observability, traffic control 등의 기능
Architecture history: Shared Node or Sidecar
구현을 위한 architectural tradeoff를 설명하려면, service Mesh 진영의 역사가 조금 필요하다.
Linkerd: first & modern service Mesh. Sidecarless Service Mesh이기도 하다.
- 1.x 시절: proxy 역할을 하는 Daemonset 형태. 애플리케이션이 proxy에 opt-in 되는 구조
- proxy에서 circuit breaker, timeout, retry, TLS 등의 로직을 수행
- JVM 기반의 scala로 만들었었음.
아키텍처 문제 / 구현체의 문제로 생겼던 이슈들
- JVM-based... GC나 size 등의 작업 커스텀이 어렵고, sidecar로 쓰기엔 사이즈가 너무 큰 구현체.
- high tail latency
- ...
기타 여러 문제들을 해결해가면서, Modern Service Mesh 구조를 Shared, Multi-Tenant, Per Node, Layer 7 Proxy 로 정의하게 됨.
무슨 뜻이냐면
- Each node has its own proxy, that handles all of the capabilities of the service mesh for the applications.
- K8s에서는, 어떤 애플리케이션 (컨테이너)이 어디에 스케줄될지 미리 알 수 없는 환경. 따라서 proxy has to handle EveryThing.
- Any Type of Application / configuration 설정과 무관하게 Quality of Service 제공해야 함.
- Node 단위로 proxy 설정... 같은 노드에 올라간 애플리케이션 간 isolation이 필수
- i.e. Starvation / Noisy Neighbor...
- 이외에도 L7 layer가 해야 하는 기능 - Security 등 - 구현이 필요.
Linkerd와는 정반대의 접근방식을 취한 Service Mesh가 Envoy.
- 노드 레벨로 proxy 관리하지 않고, networking layer를 application에 최대한 밀착시킨 형태.
- k8s에서는 sidecar 형태로, pod에 sidecar container를 띄우는 식.
이 경우의 특징은
- transparent.
- application lifecycle에 포함. application up = networking up, application down = networking down.
- single-tenant. (multi tenant는 고려하지 않았다)
- isolation은 자동 적용. 한 애플리케이션의 Config이 다른 앱에 영향을 주지 않음.
- cryptograph identity로, sidecar 간 통신에 필요한 credential도 간소화.
k8s 환경에서 특히 장점이 많은 방식이라서, Sidecar 패턴은 일종의 Necessary Point in time Implementation 취급.
단점이 없는 게 아니다.
- k8s 환경에서 container lifecycle 관리할 때 발생할 수 있는 race condition 문제.
- security: service mesh에서 사용하는 cert / key 정보가 application과 밀접하게 붙어 있는 게 싫다.
- ...
-> 대부분 Application과 networking layer가 같은 lifecycle에 포함되어 있기 때문에 발생.
sidecar 방식의 한계점과 성능 개선을 위한 시도로 eBPF가 있음.
- way to extend the kernel.
- 단, kernel을 건드리는 작업이므로 L7 수준의 다양한 기능은 기대하지 않아야 한다.
작년 KubeCon에서 eBPF 적용이 가능한 영역 / 불가능한 영역을 발표한 바 있음
Service Mesh Functionality | Networking Layer | Where Impl? |
---|---|---|
Request load balancing, retry, timeout, circuit breaking, JWT validation, header manipulation, traffic splitting, mirroring, locality-aware routing, request fault injection. | L7 | User space |
Request-level authorizations JWT claims, headers, OIDC, ExtAuth, Rate Limit | L7 | User space |
Observing request count, HTTP 5xx, request latency, request size | L7 | User space / Kernel space |
mTLS mutual authentication, protocol/port authorizations | L4 | User space && Kernel space |
Connection metrics, connection load balancing | L4 | User space / Kernel space |
Network policy | L4 / L3 | Kernel space |
결국 핵심은 'Where does the L7 Proxy Runs'.
- request 레벨에서 필요한 여러 기능 - retries, timeout, circult breaking.. - 은 eBPF로 해결할 수 없는 것들이다. Proxy가 필요하다.
- deploying / impelementing kernel으로도 가능한 몇몇 기능이 있음. 이런 요구사항의 구현체가 Cilium이다.
Digging into Cilium & istio Service Mesh
Cilium을 Service Mesh로 활용하기 위한 접근법 / istio 등 기존 service Mesh에서는 어떤 형태로 구현했는지 확인해보자.
기본적으로 Sidecarless Approach의 장점은 아래와 같다.
- Fully transparent. application cannot opt-out. (sidecar는, sidecar 안 쓰면 not transparent.)
- k8s의 race condition 문제에서 자유롭다
- application에 결합된 구조가 아니므로 performance 향상 / optimize routing이 가능하다
- 구현체 각각의 장점도 있는데, 구현체 설명하면서 추가로 다룸
Cilium: OpenSource CNI
- eBPF data plane의 Networking Policy / Routing 활용
- bypass some of IPtables / filters...
- very specific / fine-grained behavior control이 가능하다
- kubeProxy Replacement 가능
- 몇 가지 L7 Stuff에도 대응 가능함.
- 기본적으로는 L3 ~ L4 layer 기반 sidecarless service mesh 방식.
Cilium Functionality
- Gateway API implementation for ingress
- 외부 트래픽 받아서 networkpolicy 타고 내부 workload로 전달
- Mutual Authentication 가능
- 보통 service Mesh를 사용하려는 가장 큰 요인이 security, mTLS, Mutual Authentication임.
- CiliumNetworkPolicy
- L7 feature 기능의 일부 / service Mesh Capabilities
- Configure Envoy Directly 가능.
istio: Envoy 기반, Sidecar Service Mesh의 대표주자
- Workload Identity based on SPIFFE
- mTLS, Authorization 기능 지원
- Observability, Logging, tracing, auditing... 지원
Ambient Mode라는, sidecarless Service Mesh 기능도 있다.
- L4와 L7을 composable pieces로 분리.
- ANY CNI와도 호환됨. Cilium과 함께 사용 가능
- mTLS 지원, sidecar 떠 있는 앱과도 backward compatibility 지원
- Gateway API 지원
- v1.22 부터 Production Ready로 공식 제공됨.
Sidecarless Approach를, 위 5가지 관점에서 설명할 예정.
- Control Plane
- Data Plane
- mTLS
- Observability
- Traffic Control
Control Plane
Cilium
k8s의 worker node에 배포된 cilium agent.
- watching the state of the rest of the cluster by k8s API
- pod 뜨면, networking 관련 리소스인 cilium endpoint, cilium identity 등을 생성한다.
- 각각의 agent에서 data plane을 관리하고, k8s API로 state만 확인할 뿐 개별 agent끼리는 통신하지 않는다.
- 어디 하나가 Fail나도, 다른 노드에 배포된 agent에 영향을 주지 않는다.
control plane API 구성요소
- Gateway API
- CiliumNetworkPolicy
- L7 Authorization, Path / Header based routing, 통신 가능한 workload와 불가능한 workload 구분하는 기능...
- CiliumEnvoyConfig / CiliumClusterWideEnvoyConfig
- 최초 설계가 cilium data plane 위에 다양한 control plane (istio 등..) 이 동작하도록 하는 것이 목표였기 때문에 control plane 자체의 feature가 많지는 않다. Envoy 정도만 Direct Access
단 Cilium의 Envoy config 생성 로직은 caution이라고 명시했는데,
- gateway api에서도 envoy config을 만들어줄 수 있다.
- envoy config 자체가 필드도 많고 지저분함.
- 따라서 ciliumEnvoyConfig으로 만든 것과 gateway api로 만든 거 conflict나지 않도록 조심해서 써라.
Istio
istio의 경우
- Data plane은 Worker node에 배포됨.
- Control Plane의 경우, xDS implementation으로 되어 있다.
- xDS: Protocol, Delivering endpoints, services, routes, etc.
- k8s API에서 resource watch -> push out to the data plane.
다양한 리소스 (API) 를 지원함. envoy와 직접 통신할 필요 없다.
- 다만 sidecarless 구조인 Ambient Mesh의 경우 약간 다른데, 뒤에서 설명할 예정
Data Plane
Cilium
각 노드에 배포된 Cilium Agent가 Control Plane과 통신하면서 state를 확인한다.
- pod starting up on local node도 관리
- eBPF layer 관리.
- connection handling, load balancing, network policy 등 Service Mesh에서 필요한 것들을 처리해준다.
L7의 경우 eBPF가 아니라 Envoy를 쓴다. 즉 L7과 L4를 완전히 분리해뒀음.
- L7 Policy가 필요하다거나, L7 Observability가 필요하면 Envoy Config을 건드리는 식.
- Envoy Proxy는 각 worker node에 daemonset으로 배포되어 있다.
Cross Node Communication
- L7 Authorization on ingress / egress -> Envoy 사용
- 만약 L7 통신이 필요없다면 completely bypass Envoy.
cf. L7 로직 자체가 Compute intensive & Expensive... 가급적이면 피하고 싶지만, 서비스에서 필수라 어쩔 수 없다
노드 간 통신에도 Encryption이 필요할 경우 (Transparent Encryption)
- Wireguard in kernal, IPSec 등을 활용함
istio Ambient Mode (L4)
ZTunnel
- node에 배포된 workload들의 mTLS와 L4 로직 담당하는 Daemonset
- 예컨대 mTLS enabled 상태에서 pod가 외부로 트래픽을 내보낸다면
- ZTunnel 통과하면서 mTLS 기능 보장
- Any CNI / eBPF 통과하면서 외부로 트래픽 전달
L4 역할을 하는 ZTunnel은 pod individual network namespaces와 직접 통신. (ports are mapped)
- pod에서 외부로 트래픽이 나갈 때, mTLS는 활성화됨.
- ZTunnel knows which certificates to associate with the mTLS connection on both sides.
따라서, L4 간 통신은 CNI와 eBPF 통해서 하면 된다.
Ambient Mesh로 L7 기능이 필요한 경우
- ZTunnel에서 Where to route to that L7 proxy를 알고 있음. Envoy로 트래픽이 전달된다.
위와 같이 L7과 L4 기능이 분리되어 있기 때문에, 필요한 부분만 scale out 가능.
- sidecar 모드일 경우 scale out하려면 application의 scale out이 필수였고, scale out할 때마다 sidecar 리소스 점유도 선형적으로 증가하는 구조였음.
- proxy가 필요하면 application도 커질 수밖에 없던 구조를 개선했다
Extra Network Hop 생겨서 불편해진 거 아니냐고 할 수 있는데, 우리가 테스트해보니까
- L7은 expensive하다고 이야기했는데, sidecar to sidecar (L7 to L7) 통신은 꽤 비싸다.
- 반면 eBPF 사용하는 L3(L4) - L7 - L3(L4) 통신이 cheaper
라는 결론이 나왔음. Extra Hop이라서 무조건 expensive한 건 아니었다.
mTLS
Cilium
Cilium과 istio에서 mTLS 구현한 방식을 각각 살펴본다.
L3 / L4에서 network policy가 cilium에 어떻게 applied되는지 알아야 한다.
- pod A가 pod B에 요청을 보내고 싶다
- traffic은 kernel into eBPF data plane.
- policy Engine이 하는 일은 cilium Identity와 IP address를 매핑하는 것.
- ip주소로 cilium identity 확인하고, "can this identity talks to this identity?" 를 확인한다.
- 가능하면 트래픽 전송, 불가능하면 트래픽 차단.
mTLS의 경우, ip address와 cilium identity 매핑하기 전에 하나의 query를 먼저 수행하는 것
- has this connection / traffic been authenticated?
- true이면 그대로 진행,
- false이면 connection drop & trigger another process in user space (= cilium agent) to do authentication.
Cilium Agent의 동작을 좀더 보면
- SPIFFE 사용한 mTLS Connection 시도
- connection 성공 = authentication 성공.
- 성공하면, connection은 종료하고 eBPF에 'mTLS Connection 성공함' 이라는 mark를 표시하는 식.
mTLS 구현 방식이 istio나 다른 service mesh 방식과는 다름.
- 다양한 종류의 프로토콜에서 mTLS가 지원되도록 하기 위함
- TLS handshake는 한 번만 수행
- encrypted 데이터를 node to node로 전달해야 하는 경우는 wireguard 같은 걸 쓰고 있음.
이 구조에서 해결해야 하는 문제는 IP <-> Cilium Identity 매핑에 confuse 발생하면 안 됨.
- stateful process
- caches on both sides of the node have to be up to date.
그래서 기능 자체는 아직 베타고, 해결중임.
istio Ambient Mesh
- SPIFFE Implementation.
- 요청은 ZTunnel로 proxy.
- ZTunnel은 http based overlay network 생성. 목적지가 될 pod에 있는 ZTunnel과 통신
- 예컨대 pod A가 pod C로 10 connection을 요청하면, 10개의 mTLS가 만들어지는 대신 하나만 만들어진다.
- 1개의 connection에 multiplexing 적용하는 식으로 동작함.
- 위 예시에서 ZTunnel은 본인의 노드에 있는 pod A에 해당하는 certificate를 선택해서 TLS를 연결하는 역할
특징
Observability
Cilium
- L3 / L4의 경우, kernel에서 발생하는 metric은 Hubble로 확인 가능.
- pod간 traffic flow를 시각화해서 보여주는 툴
- L7인 Envoy의 경우 Prometheus, DataDog, Elastic 등등... metric 수집하는 거 붙여 쓰면 됨
istio
istio는 Layer 상관없이 prometheus 같은 걸로 한번에 다 수집가능
Traffic Control / Ingress
Cilium
트래픽이 들어오면, L7 envoy proxy 기능 활용한다.
- 지금은 east / west mechanism이 same proxy 활용하는 구조이지만, 조만간 각각 proxy 받아서 직접 핸들링할 수 있도록 변경될 듯.
- dedicated ingress node를 원하는 사용자가 많아서...
istio
istio는 그동안 제공하던 envoy 기반 ingress 로직 그대로임.
Recap
Service Mesh Functionality | Networking Layer | Where Impl? |
---|---|---|
Request load balancing, retry, timeout, circuit breaking, JWT validation, header manipulation, traffic splitting, mirroring, locality-aware routing, request fault injection. | L7 | User space |
Request-level authorizations JWT claims, headers, OIDC, ExtAuth, Rate Limit | L7 | User space |
Observing request count, HTTP 5xx, request latency, request size | L7 | User space / Kernel space |
mTLS mutual authentication, protocol/port authorizations | L4 | User space && Kernel space |
Connection metrics, connection load balancing | L4 | User space / Kernel space |
Network policy | L4 / L3 | Kernel space |
Service Mesh의 핵심 기능이 어디에 구현되어 있는지 정리한 표
- L7 기능의 경우 Cilium의 Envoy handling 기능을 활용한다
- mTLS의 경우 eBPF와 cilium agent에서 담당.
아키텍처 요약
- node-based proxy이므로 리소스 효율성은 sidecar보다 높다
- sidecar 방식보다는 isolation이 약함
- proxy에 문제 생기면, 그 노드에 있는 모든 workload에 문제가 생기므로 security면에서는 주의 필요
istio는 L7은 Envoy, L4의 경우 ZTunnel 이라는 컴포넌트로 해결함
아키텍처의 경우
- sidecar 방식을 쓰지 않으므로, resource overhead가 크게 줄어든다
- shared tenancy 없으므로 isolation 확보됨
- ZTunnel에 문제 생기면 node 단위로 트래픽 유실될 수 있음.
오픈소스 기반 Cloud Native Networking Stack