Задумывались ли вы почему балансировка через Ingress NGINX Controller показывает более ровное распределение трафика по Подам в сравнении с ClusterIP (IPtables)?
Я до недавнего времени не очень, но "сигналы с мест" требовали разобраться.
Балансировка через ClusterIP (IPtables)
ClusterIP (далее svc) это сущность Kubernetes, позволяющая приземлять трафик в Под.
В свою очередь svc это просто набор IPtables правил (или правил аналогичных инструментов), "приклеивающий" запрос к конкретному Поду.
Примерно так:
iptables -t nat -A KUBE-SVC -m random --probability 0.33 -j DNAT --to <Pod1>
iptables -t nat -A KUBE-SVC -m random --probability 0.50 -j DNAT --to <Pod2>
iptables -t nat -A KUBE-SVC -j DNAT --to <Pod3>
Что можно интерпретировать как:
* Pod1 будет выбран в качестве апстрима в 33% случаев;
* далее в 50% Pod2;
* иначе апстримом станет Pod3.
Таким образом, если есть три входящих коннекта, они могут распределиться как по одному на каждый Под, так и все три упасть в один конкрентный.
Теория вероятностей.
Балансировка через Ingress NGINX Controller
Зная о том как функционирует svc, я по наивности полагал, что и Ingress Controller (далее IC) оперирует в качестве апстримов сущностью svc, что будет в итоге давать тот же "уровень" баланcировки.
Факты говорили об обратном, потому я пошел перепроверять.
Под каждый объект Ingress рендерится секция
server{} шаблона nginx.tmpl (пруф):{{ range $tcpServer := .TCPBackends }}
server {...}
{{ end }}В ней директива
proxy_pass указывает на некий upstream_balancer: ### Attention!!!
# We no longer create "upstream" section for every backend.
# Backends are handled dynamically using Lua....
...
balancer_by_lua_block {
balancer.balance()
}
...
В
balancer.balance() и живет логика выбора апстрима, где peer == endpoint (считай Pod):...
local peer = balancer:balance()
if not peer then
ngx.log(ngx.WARN, "no peer was returned, balancer: " .. balancer.name)
return
end
...
——
Да и как иначе IC сможет обеспечивать разные типы балансировки? А по умолчанию используется round-robin.
