nginx 변수 proxy_pass와 resolver — 일부 요청만 실패하는 DNS 조회

네트워킹3분조회 –

사용자 환경에 붙는 실시간 연결이 어떤 건 되고 어떤 건 안 됐습니다. 대부분은 멀쩡한데 일부만 간헐적으로 499 나 응답 없음으로 끝납니다.

이 연결은 앞단의 nginx 를 한 번 거쳐 갑니다. 사용자가 환경을 만들면 컨테이너가 하나 뜨고 그 이름으로 DNS 레코드가 잡힙니다. 컨테이너는 수시로 생기고 사라지니 upstream 에 목록으로 박아 둘 수가 없어서, 붙을 곳을 요청 경로에 실어 보냅니다.

/app/<컨테이너 이름>/<포트>/socket.io/...

nginx 가 여기서 이름과 포트를 꺼내 proxy_pass 에 넘기고, 목적지에 변수를 쓰면 동작이 하나 달라집니다. 시작할 때 이름을 한 번 풀어 두는 대신 resolver 로 매 요청마다 DNS 를 새로 조회합니다.

변수 proxy_pass — 매 요청 DNS 재조회

proxy_pass http://$host:$port; 처럼 목적지에 변수를 쓰면, nginx 는 시작할 때 한 번 이름을 푸는 게 아니라 매 요청마다 resolver 지시자로 DNS 를 새로 조회합니다.

이게 일반 upstream 블록과 갈리는 지점이라, upstream 은 재시도와 health check 가 있지만, 변수 proxy_pass 의 동적 조회는 재시도도 health check 도 없습니다. 조회가 한 번 실패하거나 이상하게 돌아오면 그대로 그 요청 전체가 죽습니다.

resolver에 섞인, 그 존을 모르는 서버

문제가 된 설정입니다.

resolver 192.0.2.1:5300 192.0.2.2:5300 coredns.kube-system.svc.cluster.local valid=10s;

location ~ /app/(.*)/(.*)/socket.io/(.*) {
    rewrite /app/(.*)/(.*)/socket.io/(.*) /socket.io/$3 break;
    proxy_pass http://$1:$2;
}

192.0.2.1/2:5300 은 커스텀 DNS 존을 아는 서버(PowerDNS)지만, 같은 목록에 올려 둔 클러스터의 coredns 는 이 커스텀 존을 전혀 모릅니다.

resolver 에 여러 서버를 나열하면 nginx 가 어느 서버로 조회를 보내고 응답을 어떻게 처리할지가 상황에 따라 갈릴 수 있습니다. 그래서 이 도메인을 찾는 조회가 간헐적으로 실패한 것이었고, 커스텀 존을 아는 서버로 조회가 가면 성공, coredns 로 가면 실패라, 요청의 일부만 죽은 겁니다.

resolver엔 해당 존을 아는 서버만

resolver 192.0.2.1:5300 192.0.2.2:5300 valid=10s;

이 위치 블록이 조회하는 도메인은 커스텀 존이니 그 존을 아는 서버만 남기고 coredns 는 뺐습니다.

클러스터 내부 서비스(*.svc.cluster.local)도 같은 블록에서 조회해야 한다면 resolver 를 하나로 합치지 말고 위치 블록을 분리해서 각각 맞는 resolver 를 쓰는 게 낫습니다. 한 resolver 목록에 서로 다른 존을 아는 서버를 섞지 않는 게 규칙입니다.

비슷하지만 다른 증상 — DNS 캐시 이슈

nginx 의 동적 DNS 조회에서 나오는 간헐적 실패는 원인이 두 갈래라 헷갈립니다.

하나는 캐시 쪽입니다. resolver 자체는 정상이지만 캐싱된 옛날 IP 를 계속 쓰다 보니 로드밸런서 뒤의 서버 IP 가 바뀌면 없는 주소로 붙다가 timeout 이 납니다. 이건 resolver ... valid=10s 로 캐시 TTL 을 짧게 잡으면 풀립니다.

다른 하나가 이번 건으로, resolver 후보에 애초에 그 존을 모르는 서버가 섞여서 조회 자체가 불안정한 경우고, 이쪽은 관련 없는 서버를 목록에서 빼야 고쳐집니다.

둘 다 간헐적 실패로 보이니 valid 값만 만지작거리기 쉬운데, 후자는 목록 구성이 문제라 TTL 을 아무리 바꿔도 그대로입니다. resolver 에 나열한 서버가 정말 그 도메인을 아는지부터 확인하면 어느 쪽인지 갈립니다.

  1. 불러오는 중