netfilter가 UDP 응답 패킷의 대상 IP를 올바르게 대체할 수 없습니다.

netfilter가 UDP 응답 패킷의 대상 IP를 올바르게 대체할 수 없습니다.

우리는 소규모 kuberentes 클러스터(CentOS 7, Kuberenetes 1.13 + Flannel)를 실행하고 있으며 TCP 구성을 약간 조정한 후(아래 참조) DNS가 제대로 작동하지 않는 것을 발견했습니다.

나는 우리의 변경 사항이 내가 관찰한 것과 직접적인 관련이 없다고 생각하며 쿠버네티스도 책임이 없다고 생각합니다. IP 테이블을 확인했는데 내가 알 수 있는 한 모든 것이 괜찮아 보입니다. 내가 관찰한 내용은 다음과 같습니다.

  1. Pod 10.23.118.10은 UDP(53) 패킷을 DNS ClusterIP 10.22.0.10으로 보냅니다.
  2. 그런 다음 패킷의 대상 IP를 ClusterIP(10.22.0.10)에서 DNS 서버 Pod(10.23.118.2)의 IP(DNAT)로 변경합니다.
  3. 서버는 요청을 수신하고 처리한 후 응답을 다시 10.23.118.10으로 보냅니다.
  4. 이 시점에서 netfilter는 패킷을 전달하기 전에 소스 IP 10.23.118.2를 10.22.0.10으로 바꿔야 하지만 어떤 이유로 그렇게 하지 않습니다.
  5. Libc는 패킷을 수신하고 10.22.0.10 대신 10.23.118.2에서 오는 응답을 보거나 포트에 연결할 수 없다는 ICMP 패킷을 수신하기 때문에 이를 거부합니다.

여기에 이미지 설명을 입력하세요.

이상하게도 이는 DNS 요청이 동일한 시스템에서 실행되는 포드로 전송될 때만 발생합니다. DNS 요청이 다른 시스템에서 실행 중인 포드에서 오는 경우 모든 것이 잘 작동합니다.

이 모습을 우리만 본 것은 아닌 것 같습니다. 비슷한 상황이 있나요? 이것이 Linux netfilter의 버그인지 또는 브리지 인터페이스를 구성할 때 docker/kubernetes가 문제를 일으킨 것인지 확실하지 않습니다. 자세한 내용은 어디에서 찾아봐야 합니까?

이것은 우리가 적용하려는 TCP 구성입니다.

net.core.somaxconn = 1000
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_wmem = 4096 12582912 16777216
net.ipv4.tcp_rmem = 4096 12582912 16777216
net.ipv4.tcp_max_syn_backlog = 8096
net.ipv4.tcp_slow_start_after_idle = 0

답변1

문제는 CentOS 7 기본 구성인 것 같습니다.

구성이 다시 로드되면 구성 sysctl -p --system도 다시 로드됩니다 /usr/lib/sysctl.d/00-system.conf. 우리 는 /usr/lib/sysctl.d/00-system.conf다음을 볼 수 있습니다:

# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

이 작업이 완료되면(브리지에서 netfilter 비활성화) NAT 기능이 docker0브리지에서 제대로 작동하지 않습니다.

흥미롭게도 docker를 다시 시작하고 시스템에 쿼리하면 sysctl -a다음을 볼 수 있습니다.

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

이 설정은 시작 중에 Docker 자체에 의해 변경된다고 가정할 수 있습니다.

이는 Docker를 다시 시작하는 것이 종종 도움이 되는 이유를 설명합니다.

관련 정보