LabHub
배우기 러닝패스 코스

Envoy Internals

Screen Before Deploy, Then Run a Second Proxy

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

부트스트랩을 손으로 쓰고, 배포 전에 설정만 검사하고, 한 기계에 두 번째 Envoy 를 띄운다.

왜 중요한가

설정이 잘못된 프록시는 재시작하는 순간 드러난다. 그때는 이미 옛 프로세스가 내려간 뒤라 되돌릴 시간이 없다. --mode validate 는 포트를 잡지 않고 설정만 읽어 이 사고를 배포 전으로 옮겨 준다. 부트스트랩의 층 구조를 짚을 줄 알면 남이 쓴 설정도 몇 초 만에 읽히고, --base-id 와 관리 포트의 위험은 한 번 겪어 두지 않으면 반드시 운영에서 처음 만난다.

단계

  1. /root/envd-boot/boot.yaml 에 부트스트랩을 쓰세요 — 관리 포트 9911, 리스너 이름 edge127.0.0.1:10011, stat_prefixedge, 클러스터 이름 origin127.0.0.1:8081 입니다. envoy --mode validate -c /root/envd-boot/boot.yaml 을 돌려 그 출력과 종료 코드를 /root/envd-boot/01-validate.txt 에 저장하세요. 마지막 줄은 rc=0 이어야 합니다.
  2. /root/envd-boot/boot.yaml/root/envd-boot/boot-typo.yaml 로 복사한 뒤 HttpConnectionManagerHttpConnectionManger 로 한 글자 지우세요. envoy --mode validate 로 검사해 출력과 종료 코드를 /root/envd-boot/02-typo.txt 에 저장하세요 (마지막 줄은 rc=1).
  3. /root/envd-boot/boot.yamlnode 를 더하세요 — idedge-1, clusterenvd-edge 입니다. 업스트림을 8081 에 띄우고 Envoy 를 띄운 뒤, 관리 포트의 /config_dump 에서 부트스트랩 절의 node 만 뽑아 /root/envd-boot/03-node.json 에 저장하세요.
  4. /root/envd-boot/boot.yamlyq 로 읽어 다섯 값을 /root/envd-boot/04-layers.txt열쇠=값 다섯 줄로 적으세요 — listener=(리스너 이름), filter=(네트워크 필터 이름), stat_prefix=, route_cluster=(라우트가 가리키는 클러스터), cluster_endpoint=(그 클러스터의 엔드포인트, 주소:포트 형식).
  5. /root/envd-boot/boot.yaml 의 포트만 바꾼 사본 /root/envd-boot/boot-second.yaml 을 만드세요(관리 9912, 리스너 10012). 먼저 옵션 없이 띄워 실패를 확인하고, 그다음 --base-id 7 을 붙여 성공시키세요. /root/envd-boot/05-baseid.txtwithout_base_id_rc=(0 이 아닌 값), 실패 이유가 담긴 줄, with_base_id_ready=(두 번째 Envoy 의 /ready 응답) 을 적으세요.
  6. Envoy 를 --concurrency 1 --log-level info 로 다시 띄우고, 관리 포트의 /server_info 에서 command_line_options 만 뽑아 /root/envd-boot/06-cli.json 에 저장하세요. concurrency 가 1, log_levelinfo 여야 합니다.
  7. 관리 포트에 /quitquitquit 를 POST 해 Envoy 를 끝내고, /root/envd-boot/07-quit.txtafter_quit=(그 뒤 /ready 의 HTTP 코드) 를 적으세요. 그다음 다시 띄우고 after_restart=(/ready 의 응답 문자열) 을 덧붙이세요. 마지막에는 Envoy 가 9911 에서 살아 있어야 합니다.
  8. /root/envd-boot/08-report.mdvalidate_rc=, typo_rc=, second_envoy=, admin_bind= 네 줄을 적고(각각 1단계·2단계의 종료 코드, 두 번째 Envoy 에 필요했던 옵션 이름, 관리 포트를 묶어야 하는 주소), 그 아래 배운 것을 네 줄 이상으로 적으세요.

참고

배포하기 전에 설정만 먼저 검사한다

/root/envd-boot/boot.yaml 에 부트스트랩을 쓰세요 — 관리 포트 9911, 리스너 이름 edge127.0.0.1:10011, stat_prefixedge, 클러스터 이름 origin127.0.0.1:8081 입니다. envoy --mode validate -c /root/envd-boot/boot.yaml 을 돌려 그 출력과 종료 코드를 /root/envd-boot/01-validate.txt 에 저장하세요. 마지막 줄은 rc=0 이어야 합니다.

--mode validate 는 설정을 읽어 스키마까지 확인하고 포트는 하나도 잡지 않은 채 끝납니다. 그래서 이미 Envoy 가 떠 있는 기계에서도, CI 에서도 돌릴 수 있습니다. 종료 코드를 따로 적어야 하는 이유는 출력만 보면 사람이 착각하기 때문입니다 — 파이프를 거치면 $? 는 마지막 명령의 것이 되니 파이프 없이 받아 적으세요.

이름 한 글자를 틀리면 프로세스가 아예 뜨지 않는다

/root/envd-boot/boot.yaml/root/envd-boot/boot-typo.yaml 로 복사한 뒤 HttpConnectionManagerHttpConnectionManger 로 한 글자 지우세요. envoy --mode validate 로 검사해 출력과 종료 코드를 /root/envd-boot/02-typo.txt 에 저장하세요 (마지막 줄은 rc=1).

@type 은 주석이 아니라 어느 프로토콜 버퍼 메시지로 해석할지를 고르는 열쇠입니다. 이름이 목록에 없으면 Envoy 는 그 필터를 해석할 방법이 없어 설정을 통째로 거절합니다. 운영에서는 이 오타가 재시작하는 순간 드러나는데, 그때는 이미 옛 프로세스가 내려간 뒤입니다.

이 프록시가 누구인지 설정에 적는다

/root/envd-boot/boot.yamlnode 를 더하세요 — idedge-1, clusterenvd-edge 입니다. 업스트림을 8081 에 띄우고 Envoy 를 띄운 뒤, 관리 포트의 /config_dump 에서 부트스트랩 절의 node 만 뽑아 /root/envd-boot/03-node.json 에 저장하세요.

node 는 이 프록시가 컨트롤 플레인에게 자기를 소개하는 이름표입니다. 정적 설정만 쓸 때는 없어도 뜨지만, xDS 를 붙이는 순간 서버가 이 값으로 누구에게 무슨 설정을 줄지 고릅니다. /config_dump 의 첫 절이 BootstrapConfigDump 이고, 그 안에 bootstrap.node 가 있습니다. jq 로 그 자리만 뽑으세요.

다섯 층을 경로로 짚어 본다

/root/envd-boot/boot.yamlyq 로 읽어 다섯 값을 /root/envd-boot/04-layers.txt열쇠=값 다섯 줄로 적으세요 — listener=(리스너 이름), filter=(네트워크 필터 이름), stat_prefix=, route_cluster=(라우트가 가리키는 클러스터), cluster_endpoint=(그 클러스터의 엔드포인트, 주소:포트 형식).

Envoy 설정을 읽는 순서는 언제나 같습니다 — listener → filter_chain → http_connection_manager → route_config → cluster. 이 다섯 자리를 손가락으로 짚을 수 있으면 처음 보는 설정도 길을 잃지 않습니다. yq '.static_resources.listeners[0].name' 처럼 한 층씩 내려가 보세요. 값을 눈으로 베끼지 말고 도구로 뽑아야 틀리지 않습니다.

두 번째 Envoy 가 뜨지 않는다

/root/envd-boot/boot.yaml 의 포트만 바꾼 사본 /root/envd-boot/boot-second.yaml 을 만드세요(관리 9912, 리스너 10012). 먼저 옵션 없이 띄워 실패를 확인하고, 그다음 --base-id 7 을 붙여 성공시키세요. /root/envd-boot/05-baseid.txtwithout_base_id_rc=(0 이 아닌 값), 실패 이유가 담긴 줄, with_base_id_ready=(두 번째 Envoy 의 /ready 응답) 을 적으세요.

Envoy 는 뜨면서 공유 메모리 영역을 하나 잡습니다(핫 리스타트 때 통계를 넘겨주려고 쓰는 자리입니다). 그 영역의 이름은 base id 로 정해지고 기본값은 0 이라, 같은 기계의 두 번째 프로세스는 포트를 다 비켜 놓아도 그 자리에서 부딪힙니다. 실패 로그의 첫 줄이 그대로 말해 줍니다. 실패한 쪽은 곧바로 끝나므로 setsid 없이 그냥 돌려 종료 코드를 받으면 됩니다.

명령줄 옵션이 어디에 남는지 확인한다

Envoy 를 --concurrency 1 --log-level info 로 다시 띄우고, 관리 포트의 /server_info 에서 command_line_options 만 뽑아 /root/envd-boot/06-cli.json 에 저장하세요. concurrency 가 1, log_levelinfo 여야 합니다.

설정 파일에 없는 것이 동작을 바꾸는 자리가 바로 명령줄입니다. --concurrency 는 워커 스레드 수인데, 기본값이 코어 수라 워커마다 부하 분산 상태가 따로 놉니다 — 분배를 세는 실험이 흔들리는 가장 흔한 원인입니다. 실제로 무엇이 적용됐는지는 추측하지 말고 /server_info 에서 읽으세요. jq '.command_line_options' 로 그 자리만 뽑습니다.

관리 포트는 죽이는 단추까지 들고 있다

관리 포트에 /quitquitquit 를 POST 해 Envoy 를 끝내고, /root/envd-boot/07-quit.txtafter_quit=(그 뒤 /ready 의 HTTP 코드) 를 적으세요. 그다음 다시 띄우고 after_restart=(/ready 의 응답 문자열) 을 덧붙이세요. 마지막에는 Envoy 가 9911 에서 살아 있어야 합니다.

관리 포트에는 통계만 있는 것이 아닙니다 — /quitquitquit 는 프로세스를 끝내고 /drain_listeners 는 트래픽을 끊습니다. 인증이 없으므로 이 포트에 닿을 수 있는 사람은 누구나 프록시를 내릴 수 있습니다. 그래서 admin.address0.0.0.0 으로 두면 안 됩니다. 죽은 서버에 curl 하면 연결 자체가 안 되므로 HTTP 코드는 000 으로 나옵니다.

배포 전 점검표로 정리한다

/root/envd-boot/08-report.mdvalidate_rc=, typo_rc=, second_envoy=, admin_bind= 네 줄을 적고(각각 1단계·2단계의 종료 코드, 두 번째 Envoy 에 필요했던 옵션 이름, 관리 포트를 묶어야 하는 주소), 그 아래 배운 것을 네 줄 이상으로 적으세요.

점검표는 남이 읽는 글입니다. 값을 적을 때는 어디서 나온 값인지 알 수 있게 쓰고, 설명 줄에는 '무엇을 했다' 대신 '그래서 다음부터 무엇을 하겠다' 를 적으세요. second_envoy= 에는 옵션 이름을 그대로 적습니다.