Прим. перев.: В этой статье, написанной техническим консультантом и сертифицированным администратором Kubernetes из Великобритании — Daniele Polencic, — наглядно показывается и рассказывается о том, какую роль играет kube-proxy в доставке пользовательских запросов до подов и что происходит, когда на одном из узлов кластера возникают проблемы.
Код приложений, развёрнутых в Kubernetes, запускается на одном или более рабочих узлов. Узел может располагаться как на физической или виртуальной машине, так и в AWS EC2 или Google Compute Engine, а наличие множества таких площадок означает возможность эффективного запуска и масштабирования приложения. Например, если кластер состоит из трёх узлов и вы решаете отмасштабировать приложение на четыре реплики, Kubernetes равномерно распределит их среди узлов следующим образом:
Такая архитектура хорошо справляется и с падениями. Если один узел окажется недоступным, приложение продолжит работать на двух других. А в это время Kubernetes переназначит четвёртую реплику на другой (доступный) узел.
Более того, даже если все узлы окажутся изолированными, они всё равно смогут обслуживать запросы. Например, уменьшим число реплик приложения до двух:
Поскольку каждый узел может обслуживать приложение, как же третий (Node 3) узнает, что на нём не запущено приложение и ему следует перенаправить трафик на один из других узлов?
У Kubernetes есть бинарник kube-proxy
, запускаемый на каждом узле и ответственный за маршрутизацию трафика на конкретный под. Его можно сравнить с администратором отеля, сидящим за стойкой регистрации. Kube-proxy
принимает весь трафик, приходящий на узел, и пересылает на правильный под.
kube-proxy
знает, где расположены все поды?kube-proxy
проверяет эти правила и приводит их в действие. В простом сценарии, описанном выше, список правил сводится к следующему:kube-proxy
знает, куда необходимо перенаправить трафик в соответствии с этим списком правил.$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready <none> 17h v1.8.8-gke.0
node2 Ready <none> 18h v1.8.8-gke.0
$ kubectl create -f https://raw.githubusercontent.com/manabusakai/k8s-hello-world/master/kubernetes/deployment.yml
$ kubectl create -f https://raw.githubusercontent.com/manabusakai/k8s-hello-world/master/kubernetes/service.yml
$ kubectl scale --replicas 10 deployment/k8s-hello-world
$ kubectl get pods
NAME READY STATUS NODE
k8s-hello-world-55f48f8c94-7shq5 1/1 Running node1
k8s-hello-world-55f48f8c94-9w5tj 1/1 Running node1
k8s-hello-world-55f48f8c94-cdc64 1/1 Running node2
k8s-hello-world-55f48f8c94-lkdvj 1/1 Running node2
k8s-hello-world-55f48f8c94-npkn6 1/1 Running node1
k8s-hello-world-55f48f8c94-ppsqk 1/1 Running node2
k8s-hello-world-55f48f8c94-sc9pf 1/1 Running node1
k8s-hello-world-55f48f8c94-tjg4n 1/1 Running node2
k8s-hello-world-55f48f8c94-vrkr9 1/1 Running node1
k8s-hello-world-55f48f8c94-xzvlc 1/1 Running node2
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-hello-world NodePort 100.69.211.31 <none> 8080:30000/TCP 3h
kubernetes ClusterIP 100.64.0.1 <none> 443/TCP 18h
NodePort
и доступен по порту 30000. Другими словами, у каждого узла открывается порт 30000 для внешнего интернета и начинает принимать входящий трафик.kube-proxy
.$ curl <node ip>:30000
kubectl get nodes -o wide
.Hello world! via <hostname>
.kube-proxy
работает как балансировщик нагрузки, проверяет маршрутизацию и распределяет трафик по десяти подам.kube-proxy
, перенаправляют трафик с узла на под.$ while sleep 1; do date +%X; curl -sS http://<your load balancer ip>/ | grep ^Hello; done
10:14:41 Hello world! via k8s-hello-world-55f48f8c94-vrkr9
10:14:43 Hello world! via k8s-hello-world-55f48f8c94-tjg4n
kube-proxy
может работать в трёх режимах: userspace, iptables и ipvs. Режимом по умолчанию со времён Kubernetes 1.2 является iptables. (Прим. перев.: Последний режим, ipvs, появился в релизе K8s 1.8 и получил статус бета-версии в 1.9.)kube-proxy
составляет список правил маршрутизации на узле с помощью правил iptables. Таким образом, можно зайти на любой узел и удалить эти правила командой iptables -F
.iptables -F
может оборвать SSH-подключение.10:14:41 Hello world! via k8s-hello-world-55f48f8c94-xzvlc
10:14:43 Hello world! via k8s-hello-world-55f48f8c94-tjg4n
# в этот момент выполнена команда `iptables -F`
10:15:10 Hello world! via k8s-hello-world-55f48f8c94-vrkr9
10:15:11 Hello world! via k8s-hello-world-55f48f8c94-vrkr9
11:29:55 Hello world! via k8s-hello-world-55f48f8c94-xzvlc
11:29:56 Hello world! via k8s-hello-world-55f48f8c94-tjg4n
# в этот момент выполнена команда `iptables -F`
11:30:25 Hello world! via k8s-hello-world-55f48f8c94-npkn6
11:30:27 Hello world! via k8s-hello-world-55f48f8c94-vrkr9
$ while sleep 1; printf %"s\n" $(curl -sS http://<ip of the node>:30000); done
Hello world! via k8s-hello-world-55f48f8c94-xzvlc
Hello world! via k8s-hello-world-55f48f8c94-tjg4n
# в этот момент выполнена команда `iptables -F`
curl: (28) Connection timed out after 10003 milliseconds
curl: (28) Connection timed out after 10004 milliseconds
Hello world! via k8s-hello-world-55f48f8c94-npkn6
Hello world! via k8s-hello-world-55f48f8c94-vrkr9
curl
ждёт ответа по 10 секунд.$ iptables -L
kube-proxy
? Да! В официальной документации kube-proxy можно найти два интересных флага:--iptables-sync-period
— максимальный интервал, за который правила iptables будут обновлены (например: ‘5s’, ‘1m’, ‘2h22m’). Должен быть больше 0. По умолчанию — 30s;--iptables-min-sync-period
— минимальный интервал, за который правила iptables должны быть обновлены, когда происходят изменения в endpoints и services (например: ‘5s’, ‘1m’, ‘2h22m’). По умолчанию — 10s.kube-proxy
обновляет правила iptables каждые 10—30 секунд. Если мы сбросим правила iptables, для kube-proxy
потребуется до 30 секунд, чтобы осознать это и восстановить их.kube-proxy
. Другими словами, каждый раз при добавлении или удалении пода главный узел переделывает список маршрутов, а kube-proxy
регулярно синхронизирует правила с текущим узлом.kube-proxy
восстанавливаются, если кто-то испортил правила iptables на узле:kube-proxy
восстанавливает правила iptables.kube-proxy
. Где эти настройки и как их изменить?kube-proxy
как статичного пода на каждом узле. Документация по статичным подам предполагает, что kubelet проверяет содержимое определённого каталога и создаёт все ресурсы из него.--pod-manifest-path=/etc/kubernetes/manifests
. Элементарный ls
приоткрывает завесу тайны:$ ls -l /etc/kubernetes/manifests
total 4 -rw-r--r-- 1 root root 1398 Feb 24 08:08 kube-proxy.manifest
kube-proxy.manifest
?apiVersion: v1
kind: Pod
metadata:
name: kube-proxy
spec:
hostNetwork: true
containers:
- name: kube-proxy
image: gcr.io/google_containers/kube-proxy:v1.8.7-gke.1
command:
- /bin/sh
- -c
->
echo -998 > /proc/$$$/oom_score_adj &&
exec kube-proxy
--master=https://35.190.207.197
--kubeconfig=/var/lib/kube-proxy/kubeconfig
--cluster-cidr=10.4.0.0/14
--resource-container=""
--v=2
--feature-gates=ExperimentalCriticalPodAnnotation=true
--iptables-sync-period=30s
1>>/var/log/kube-proxy.log 2>&1
--iptables-sync-period=30s
. Здесь же можно изменить минимальное и максимальное время обновления правил на конкретном узле.К сожалению, не доступен сервер mySQL