LabHub
배우기 러닝패스 코스

Envoy 내부 구조 · 설정이 밖에서 들어온다 · 이론

컨트롤 플레인이 죽으면 무엇이 멈추나

LabHub 에서 이어서 보기

한 줄 요약

xDS 는 프록시가 설정을 밖에서 받아 오는 통로다. 리스너를 주면 LDS, 클러스터를 주면 CDS, 엔드포인트만 주면 EDS 라고 부른다. 핵심 성질은 두 가지다 — 재시작 없이 갈아 끼운다는 것, 그리고 잘못된 갱신은 거절하고 옛 설정을 그대로 쓴다는 것.

왜 이게 필요했나

지금까지의 모든 설정은 파일에 적고 프로세스를 다시 띄우는 방식이었다. 서버가 몇 대면 견딜 만하다. 그런데 쿠버네티스에서는 파드가 하루에도 수백 번 뜨고 진다. 엔드포인트 목록이 바뀔 때마다 프록시를 재시작하면, 재시작하는 동안의 요청은 어떻게 되며 재시작이 재시작을 부르는 상황은 어떻게 막을 것인가.

그래서 방향을 뒤집었다. 프록시는 그대로 두고 설정만 밀어 넣는다. 프록시는 뜨면서 "나는 이런 프록시입니다(node)" 라고 소개하고 필요한 자원을 구독한다. 컨트롤 플레인은 클러스터 상태를 보고 있다가 바뀐 것을 그 프록시에 보낸다. 이것이 서비스 메시의 데이터 플레인과 컨트롤 플레인이 나뉘는 자리이고, 인그레스 컨트롤러가 하는 일의 전부이기도 하다.

어떻게 동작하나

무엇을 주느냐로 이름이 갈린다.

| 이름 | 주는 것 | 언제 바뀌나 |
| --- | --- | --- |
| LDS | 리스너 | 포트나 필터 사슬이 바뀔 때 |
| CDS | 클러스터 | 서비스가 늘고 줄 때 |
| EDS | 엔드포인트만 | 파드가 뜨고 질 때(가장 자주) |
| RDS | 라우트 표 | 라우팅 규칙이 바뀔 때 |
| SDS | 인증서 | 인증서가 갱신될 때 |

엔드포인트가 따로 있는 이유는 가장 자주 바뀌기 때문이다. 파드 하나가 뜰 때마다 클러스터 정의 전체를 다시 보내는 것은 낭비다.

받아 오는 방법은 세 가지다. gRPC 로 스트림을 열어 두는 방식이 실제 메시가 쓰는 것이고, REST 로 주기적으로 물어보는 방식도 있고, 파일을 구독하는 방식도 있다. 마지막 것은 실험과 테스트에 쓰이는데, 프로토콜의 알맹이(구독 · 갱신 · 거절 · 버전)는 셋이 같다.

갱신은 원자적이고, 실패하면 되돌린다. 이것이 xDS 에서 가장 중요한 성질이다. 받은 설정이 스키마에 맞지 않거나 해석할 수 없으면 프록시는 그 갱신 전체를 거절하고 마지막으로 성공한 설정을 그대로 쓴다. 트래픽은 끊기지 않는다. 그래서 "컨트롤 플레인이 죽으면 메시가 죽는다" 는 말은 정확하지 않다 — 새 설정을 받지 못할 뿐 지금 설정으로는 계속 돈다.

대신 아무도 알려 주지 않는다. 그래서 감시할 숫자가 정해져 있다.

cluster_manager.cds.update_success     갱신이 도착해 반영된 횟수cluster_manager.cds.update_rejected    도착했지만 거절된 횟수listener_manager.lds.update_success    리스너 쪽 같은 숫자

update_success 가 멈춰 있으면 설정이 오지 않는 것이고, update_rejected 가 올라가면 오긴 오는데 받아들이지 못하는 것이다. 둘은 전혀 다른 문제이고 고칠 곳도 다르다.

도착했는지 확인하는 자리도 따로 있다. /config_dump 는 정적 자원과 동적 자원을 나눠 보여 준다(static_clustersdynamic_active_clusters). "내가 보낸 설정이 도착했나" 를 볼 때는 동적 쪽을 본다.

현장에서 만나는 모습

"설정을 바꿨는데 반영이 안 됩니다." 두 갈래로 나뉜다. 동적 쪽 덤프에 없으면 도착하지 않은 것이고(구독·연결 문제), 있는데 동작이 다르면 설정 자체가 의도와 다른 것이다. 이 두 가지를 먼저 가르면 찾는 범위가 절반으로 준다.

"컨트롤 플레인을 재시작했더니 아무 일도 없었습니다." 정상이다. 프록시는 마지막 설정을 들고 계속 돈다. 문제는 그 상태가 오래가면 새로 뜬 파드가 메시에 들어오지 못한다는 것이다. 지금 멀쩡하다는 사실과 곧 문제가 된다는 사실이 함께 참이다.

거절이 조용히 쌓이는 경우. 컨트롤 플레인이 만든 설정에 문제가 생겨도 트래픽은 흐르므로 아무도 모른다. 몇 주 뒤 "이 서비스만 옛 라우팅으로 갑니다" 로 드러난다. update_rejected 에 알림을 걸어 두는 것이 답이다.

공식 문서: [xDS REST and gRPC protocol](https://www.envoyproxy.io/docs/envoy/v1.38.3/api-docs/xds_protocol) · [Bootstrap configuration](https://www.envoyproxy.io/docs/envoy/v1.38.3/configuration/overview/bootstrap) · [Administration interface](https://www.envoyproxy.io/docs/envoy/v1.38.3/operations/admin)

다음 실습에서 할 것

정적 설정이 파일을 고쳐도 바뀌지 않는 것을 먼저 확인한 뒤, 같은 프록시를 파일 구독 방식으로 바꾼다. 클러스터 자원에서 엔드포인트를 빼 재시작 없이 반영되는 것을 세어 보고, 리스너 자원도 무중단으로 갈아 끼우고, 마지막으로 일부러 망가진 설정을 보내 거절되는데도 트래픽이 계속 흐르는 것을 직접 본다. 그리고 그 사건이 어느 숫자에 남는지 확인한다.

이 실습 환경에는 진짜 gRPC 컨트롤 플레인이 없어서 파일 구독으로 대신한다. 보내는 내용의 모양과 프록시가 처리하는 방식은 같지만, 연결이 끊겼을 때의 재구독 같은 전송 계층의 동작은 여기서 볼 수 없다.