部署前先筛查,再启动第二个代理
한국어 원문으로 표시합니다.
목표
부트스트랩을 손으로 쓰고, 배포 전에 설정만 검사하고, 한 기계에 두 번째 Envoy 를 띄운다.
왜 중요한가
설정이 잘못된 프록시는 재시작하는 순간 드러난다. 그때는 이미 옛 프로세스가 내려간 뒤라 되돌릴 시간이 없다. --mode validate 는 포트를 잡지 않고 설정만 읽어 이 사고를 배포 전으로 옮겨 준다. 부트스트랩의 층 구조를 짚을 줄 알면 남이 쓴 설정도 몇 초 만에 읽히고, --base-id 와 관리 포트의 위험은 한 번 겪어 두지 않으면 반드시 운영에서 처음 만난다.
단계
/root/envd-boot/boot.yaml에 부트스트랩을 쓰세요 — 관리 포트9911, 리스너 이름edge가127.0.0.1:10011,stat_prefix는edge, 클러스터 이름origin이127.0.0.1:8081입니다.envoy --mode validate -c /root/envd-boot/boot.yaml을 돌려 그 출력과 종료 코드를/root/envd-boot/01-validate.txt에 저장하세요. 마지막 줄은rc=0이어야 합니다./root/envd-boot/boot.yaml을/root/envd-boot/boot-typo.yaml로 복사한 뒤HttpConnectionManager를HttpConnectionManger로 한 글자 지우세요.envoy --mode validate로 검사해 출력과 종료 코드를/root/envd-boot/02-typo.txt에 저장하세요 (마지막 줄은rc=1)./root/envd-boot/boot.yaml에node를 더하세요 —id는edge-1,cluster는envd-edge입니다. 업스트림을8081에 띄우고 Envoy 를 띄운 뒤, 관리 포트의/config_dump에서 부트스트랩 절의node만 뽑아/root/envd-boot/03-node.json에 저장하세요./root/envd-boot/boot.yaml을yq로 읽어 다섯 값을/root/envd-boot/04-layers.txt에열쇠=값다섯 줄로 적으세요 —listener=(리스너 이름),filter=(네트워크 필터 이름),stat_prefix=,route_cluster=(라우트가 가리키는 클러스터),cluster_endpoint=(그 클러스터의 엔드포인트,주소:포트형식)./root/envd-boot/boot.yaml의 포트만 바꾼 사본/root/envd-boot/boot-second.yaml을 만드세요(관리 9912, 리스너 10012). 먼저 옵션 없이 띄워 실패를 확인하고, 그다음--base-id 7을 붙여 성공시키세요./root/envd-boot/05-baseid.txt에without_base_id_rc=(0 이 아닌 값), 실패 이유가 담긴 줄,with_base_id_ready=(두 번째 Envoy 의/ready응답) 을 적으세요.- Envoy 를
--concurrency 1 --log-level info로 다시 띄우고, 관리 포트의/server_info에서command_line_options만 뽑아/root/envd-boot/06-cli.json에 저장하세요.concurrency가 1,log_level이info여야 합니다. - 관리 포트에
/quitquitquit를 POST 해 Envoy 를 끝내고,/root/envd-boot/07-quit.txt에after_quit=(그 뒤/ready의 HTTP 코드) 를 적으세요. 그다음 다시 띄우고after_restart=(/ready의 응답 문자열) 을 덧붙이세요. 마지막에는 Envoy 가9911에서 살아 있어야 합니다. /root/envd-boot/08-report.md에validate_rc=,typo_rc=,second_envoy=,admin_bind=네 줄을 적고(각각 1단계·2단계의 종료 코드, 두 번째 Envoy 에 필요했던 옵션 이름, 관리 포트를 묶어야 하는 주소), 그 아래 배운 것을 네 줄 이상으로 적으세요.
참고
- Envoy 를 띄울 때는
setsid --fork nohup envoy -c <파일> --log-level warn > <로그> 2>&1 </dev/null로 셸에서 완전히 떼어 놓으세요. 그냥&로 띄우면 다음 단계에서 이미 죽어 있습니다. - 다시 띄우기 전에는
pkill -x envoy로 정리하세요.pkill -f 'envoy -c'는 그 문자열이 든 셸 자신까지 죽입니다. - 기동을 기다릴 때는 고정
sleep대신/ready가 LIVE 를 돌려줄 때까지 도는 루프를 쓰세요. - 업스트림 흉내용 서버가 이미 이미지에 있습니다:
python3 /opt/lab/envoy/upstream.py <포트> ok. 최소 설정 본보기는/opt/lab/envoy/minimal.yaml에 있습니다. - 흔한 실수 —
envoy --mode validate ... | tee처럼 파이프를 걸면$?가 Envoy 의 종료 코드가 아니라 파이프 마지막 명령의 것이 됩니다.
배포하기 전에 설정만 먼저 검사한다
/root/envd-boot/boot.yaml 에 부트스트랩을 쓰세요 — 관리 포트 9911, 리스너 이름 edge 가 127.0.0.1:10011, stat_prefix 는 edge, 클러스터 이름 origin 이 127.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 로 복사한 뒤 HttpConnectionManager 를 HttpConnectionManger 로 한 글자 지우세요. envoy --mode validate 로 검사해 출력과 종료 코드를 /root/envd-boot/02-typo.txt 에 저장하세요 (마지막 줄은 rc=1).
@type 은 주석이 아니라 어느 프로토콜 버퍼 메시지로 해석할지를 고르는 열쇠입니다. 이름이 목록에 없으면 Envoy 는 그 필터를 해석할 방법이 없어 설정을 통째로 거절합니다. 운영에서는 이 오타가 재시작하는 순간 드러나는데, 그때는 이미 옛 프로세스가 내려간 뒤입니다.
이 프록시가 누구인지 설정에 적는다
/root/envd-boot/boot.yaml 에 node 를 더하세요 — id 는 edge-1, cluster 는 envd-edge 입니다. 업스트림을 8081 에 띄우고 Envoy 를 띄운 뒤, 관리 포트의 /config_dump 에서 부트스트랩 절의 node 만 뽑아 /root/envd-boot/03-node.json 에 저장하세요.
node 는 이 프록시가 컨트롤 플레인에게 자기를 소개하는 이름표입니다. 정적 설정만 쓸 때는 없어도 뜨지만, xDS 를 붙이는 순간 서버가 이 값으로 누구에게 무슨 설정을 줄지 고릅니다. /config_dump 의 첫 절이 BootstrapConfigDump 이고, 그 안에 bootstrap.node 가 있습니다. jq 로 그 자리만 뽑으세요.
다섯 층을 경로로 짚어 본다
/root/envd-boot/boot.yaml 을 yq 로 읽어 다섯 값을 /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.txt 에 without_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_level 이 info 여야 합니다.
설정 파일에 없는 것이 동작을 바꾸는 자리가 바로 명령줄입니다. --concurrency 는 워커 스레드 수인데, 기본값이 코어 수라 워커마다 부하 분산 상태가 따로 놉니다 — 분배를 세는 실험이 흔들리는 가장 흔한 원인입니다. 실제로 무엇이 적용됐는지는 추측하지 말고 /server_info 에서 읽으세요. jq '.command_line_options' 로 그 자리만 뽑습니다.
관리 포트는 죽이는 단추까지 들고 있다
관리 포트에 /quitquitquit 를 POST 해 Envoy 를 끝내고, /root/envd-boot/07-quit.txt 에 after_quit=(그 뒤 /ready 의 HTTP 코드) 를 적으세요. 그다음 다시 띄우고 after_restart=(/ready 의 응답 문자열) 을 덧붙이세요. 마지막에는 Envoy 가 9911 에서 살아 있어야 합니다.
관리 포트에는 통계만 있는 것이 아닙니다 — /quitquitquit 는 프로세스를 끝내고 /drain_listeners 는 트래픽을 끊습니다. 인증이 없으므로 이 포트에 닿을 수 있는 사람은 누구나 프록시를 내릴 수 있습니다. 그래서 admin.address 를 0.0.0.0 으로 두면 안 됩니다. 죽은 서버에 curl 하면 연결 자체가 안 되므로 HTTP 코드는 000 으로 나옵니다.
배포 전 점검표로 정리한다
/root/envd-boot/08-report.md 에 validate_rc=, typo_rc=, second_envoy=, admin_bind= 네 줄을 적고(각각 1단계·2단계의 종료 코드, 두 번째 Envoy 에 필요했던 옵션 이름, 관리 포트를 묶어야 하는 주소), 그 아래 배운 것을 네 줄 이상으로 적으세요.
점검표는 남이 읽는 글입니다. 값을 적을 때는 어디서 나온 값인지 알 수 있게 쓰고, 설명 줄에는 '무엇을 했다' 대신 '그래서 다음부터 무엇을 하겠다' 를 적으세요. second_envoy= 에는 옵션 이름을 그대로 적습니다.