Трансляция исходного IP-адреса для внутрикластерного трафика

Я пытаюсь погрузиться в сетевая модель K8s, и я думаю, что до сих пор хорошо ее понимаю, но есть одна вещь, которую я не могу понять. В руководстве Cluster Networking упоминается следующее:

Kubernetes предъявляет следующие фундаментальные требования к любой сетевой реализации (запрещая любые политики преднамеренной сегментации сети):

  • все контейнеры могут взаимодействовать со всеми другими контейнерами без NAT
  • все узлы могут связываться со всеми контейнерами (и наоборот) без NAT
  • IP-адрес, который контейнер видит в себе, - это тот же IP-адрес, который другие видят в нем.

Второй пункт указывает, что связь контейнера x-узла должна быть возможна без NAT. Однако это неверно, когда kube-proxy работает в режиме iptables. Это дамп iptables с одного из моих узлов:

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
KUBE-POSTROUTING  all  --  anywhere             anywhere             /* kubernetes postrouting rules */

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere             /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000

/* sample target pod chain being marked for MASQ */
Chain KUBE-SEP-2BKJZA32HM354D5U (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  all  --  xx.yyy.zzz.109       anywhere             /* kube-system/heapster: */
DNAT       tcp  --  anywhere             anywhere             /* kube-system/heapster: */ tcp to:xx.yyy.zzz.109:8082

Chain KUBE-MARK-MASQ (156 references)
target     prot opt source               destination         
MARK       all  --  anywhere             anywhere             MARK or 0x4000

Похоже, K8s меняет исходный IP-адрес отмеченных исходящих пакетов на IP-адрес узла (для службы ClusterIP). И они даже прямо упоминают об этом в Исходный IP-адрес для служб с Type = ClusterIP:

Пакеты, отправленные в ClusterIP из кластера, никогда не являются исходным NAT, если вы используете kube-proxy в режиме iptables, который используется по умолчанию, начиная с Kubernetes 1.2. Если клиентский модуль и серверный модуль находятся в одном узле, client_address является IP-адресом клиентского модуля. Однако, если клиентский модуль и серверный модуль находятся в разных узлах, client_address является фланельным IP-адресом узла клиентского модуля.

Это начинается с того, что пакеты в кластере никогда не используют SNAT, но затем переходит к утверждению, что пакеты, отправленные в модули на других узлах, на самом деле являются SNAT. Я сбит с толку - неправильно ли я интерпретирую, что все узлы могут связываться со всеми контейнерами (и наоборот) без требования NAT?


person PoweredByOrange    schedule 26.10.2018    source источник


Ответы (1)


Если вы прочитали пункт 2:

Связь между модулями: это основная тема данного документа.

Это по-прежнему относится ко всем контейнерам и модулям, работающим в вашем кластере, потому что все они находятся в PodCidr:

  • все контейнеры могут взаимодействовать со всеми другими контейнерами без NAT
  • все узлы могут связываться со всеми контейнерами (и наоборот)
  • без NAT IP-адрес, который контейнер видит в себе, - это тот же IP-адрес, который его видят другие.

По сути, все модули имеют уникальные IP-адреса, находятся в одном пространстве и могут взаимодействовать с каждым на уровне IP.

Кроме того, если вы посмотрите на маршруты на одном из ваших узлов Kubernetes, вы увидите что-то вроде этого для Calico, где podCidr равен 192.168.0.0/16:

default via 172.0.0.1 dev ens5 proto dhcp src 172.0.1.10 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.31.0.0/20 dev ens5 proto kernel scope link src 172.0.1.10
172.31.0.1 dev ens5 proto dhcp scope link src 172.0.1.10 metric 100
blackhole 192.168.0.0/24 proto bird
192.168.0.42 dev calixxxxxxxxxxx scope link
192.168.0.43 dev calixxxxxxxxxxx scope link
192.168.4.0/24 via 172.0.1.6 dev tunl0 proto bird onlink
192.168.7.0/24 via 172.0.1.55 dev tunl0 proto bird onlink
192.168.8.0/24 via 172.0.1.191 dev tunl0 proto bird onlink
192.168.9.0/24 via 172.0.1.196 dev tunl0 proto bird onlink
192.168.11.0/24 via 172.0.1.147 dev tunl0 proto bird onlink

Вы видите, что пакеты с 192.168.x.x напрямую пересылаются на туннельный интерфейс, подключенный к узлам, поэтому там нет NAT.

Теперь, когда вы подключаетесь к PodCidr извне, ваши пакеты определенно преобразованы в NAT, скажем, через службы через внешний хост. Вы также определенно видите такие правила iptable:

# Completed on Sat Oct 27 00:22:39 2018
# Generated by iptables-save v1.6.1 on Sat Oct 27 00:22:39 2018
*nat
:PREROUTING ACCEPT [65:5998]
:INPUT ACCEPT [1:60]
:OUTPUT ACCEPT [28:1757]
:POSTROUTING ACCEPT [61:5004]
:DOCKER - [0:0]
:KUBE-MARK-DROP - [0:0]
person Rico    schedule 27.10.2018
comment
спасибо, но ваше объяснение по-прежнему не соответствует тому, что я вижу в настройке моего кластера. Мы используем EKS с CNI (не Calico), и правила iptables, которые я опубликовал, похоже, маскируют все исходящие пакеты, что означает, что запросы от узла A к узлу B обрабатываются SNAT, даже если Pod A может напрямую вызывать IP-адрес Pod B без необходимости NAT. ... - person PoweredByOrange; 29.10.2018
comment
Как ваш ip route выглядит с одного из ваших узлов? Кроме того, что такое podCidr? - person Rico; 29.10.2018
comment
форматирование испорчено, я могу сообщить вам об этом, если хотите. Также как определить podCidr? - person PoweredByOrange; 29.10.2018
comment
С этим: $ kubectl -n kube-system describe configmap kube-proxy | grep clusterCIDR - person Rico; 29.10.2018
comment
Странно ... может быть, AWS CNI делает забавные правила iptables. Вы также можете проверить любой из файлов в /etc/cni/net.d на любом из ваших узлов. - person Rico; 29.10.2018
comment
это работает в aws, cidr кластера совпадает с cidr vpc / подсети? - person PoweredByOrange; 29.10.2018
comment
Так не должно быть. - person Rico; 29.10.2018
comment
Хмм хорошо. единственный файл под /etc/cni/net.d, похоже, тоже не содержит информации об этом: # cat /etc/cni/net.d/aws.conf {type: aws-cni, name: aws-cni, vethPrefix: eni} - person PoweredByOrange; 29.10.2018
comment
да, похоже, AWS CNI использует veth, которые являются настоящими ENI в облаке AWS - person Rico; 29.10.2018
comment
Так можно ли с уверенностью сказать / предположить, что именно AWS CNI добавляет эти явные правила SNAT для исходящих пакетов, а не k8s? - person PoweredByOrange; 30.10.2018