- PVSM.RU - https://www.pvsm.ru -
Разработка собственной Kubernetes-платформы — большой и сложный проект со множеством взаимодействующих компонентов. В процессе неизбежно сталкиваешься с различными трудностями. Иногда их даже создаешь себе сам. В статье кратко рассмотрим три проблемы, с которыми нам пришлось столкнуться во время подготовки Deckhouse [1] 1.43 к релизу, как мы их устраняли и какие выводы из всего этого сделали.
Началось все с ошибки [2] в upstream-версии containerd 1.6.14, которая коварно проникла в DH 1.43 и доехала до Stable незамеченной.
Баг заключался в рассинхронизации информации о поде на диске при обновлении указателя на его sandbox. К сожалению, заметить его можно было только после рестарта kubelet’а. Мы сразу выпустили фикс, но все оказалось глубже, чем просто рестарт проблемного containerd и последующий перезапуск kubelet’а.
Поды, создававшиеся в тот момент, когда в кластере был релиз с ошибкой, оставались с неправильной спецификацией. В результате kubelet после рестарта начинал перезапускать и эти поды. Проблема затронула все релизные каналы Deckhouse от Alpha до Stable.
Мы узнали о происходящем после выката Deckhouse 1.44 в каналы Alpha и Beta. В нем версия Kubernetes обновилась до 1.23 — соответственно, kubelet перезапустился и «убил» все «неправильные» поды в кластерах (включая клиентские), что привело к простоям.
Осознав размах проблемы, мы поняли, что самый простой путь ее решения — вручную перезапустить все поды. С помощью небольшого скрипта (под наблюдением дежурного, чтобы исключить простои) перебрали все поды и вручную перезапустили проблемные.
После чего в патче 1.43.8 обновили [3] версию containerd до 1.6.18 — в ней эта проблема уже была устранена.
На момент обновления в Deckhouse информация об ошибке в upstream-компоненте уже появилась в Сети. Было решено непосредственно перед выкатом проверять changelog [4] той версии компонента, на которую мы переходим в релизе.
Обновили сертификат kube-rbac-proxy, но забыли добавить его в сайдкар-контейнер Alertmanager'а. В результате при проверке сертификатов kube-rbac-proxy использовал старый CA и возвращал ошибку авторизации.
Проблема обнаружилась в версии 1.42.6 — мы узнали о ней из телеграм-чата по Deckhouse [5].
Фикс [6] был проведен в версии 1.42.7 и затем перенесен в 1.43.2.
Было решено перенести [7] kube-rbac-proxy в helm_lib. Это избавит нас от необходимости проводить множество одинаковых правок в разных местах, и, соответственно, значительно снизит вероятность ошибок. Свежая версия kube-rbac-proxy будет «подтягиваться» в Deckhouse, и правки автоматом «приедут» во все нужные места.
Также мы в очередной раз поняли, насколько важна оперативная обратная связь от пользователей и насколько полезным решением был выпуск community-версии Deckhouse в виде Open Source.
В Linux есть две независимых реализации сетевого фильтра iptables: iptables-nft (nftables [8]) и iptables-legacy (всем привычный iptables). Это два разных модуля ядра, отвечающих за маршрутизацию сетевых пакетов.
iptables-nft непривычен для тех, кто привык к классическому iptables. Поэтому разработчики ядра сделали эмуляцию старого формата с помощью нескольких утилит (iptables-translate, iptables-restore-translate, iptables-nft-restore), транслирующих привычные правила iptables в nft-формат.
Например, правило:
iptables -A INPUT -i eth0 -p tcp --dport 80 -j DROP
будет приведено к такому формату:
nft add rule ip filter INPUT iifname "eth0" tcp dport 80 counter dro
и уже затем попадет в ядро.
В отличие от правил iptables, nft-формат — это JSON. Например, посмотреть текущие правила в системе можно посмотреть так:
$ cat /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
}
chain forward {
type filter hook forward priority 0;
}
chain output {
type filter hook output priority 0;
}
}
Этот файл может быть огромным. Разобраться, что к чему, в таком файле практически невозможно, поэтому многие предпочитают использовать привычные инструменты, такие как iptables -A
.
В ОС для управления системой фильтрации сетевых пакетов имеется одноименная команда iptables
. С ее помощью можно просматривать/редактировать существующие таблицы маршрутизации и создавать новые.
Вот так выглядит список существующих правил, выведенных этой командой:
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-USER all -- anywhere anywhere
DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.20.0.2 tcp dpt:https
ACCEPT tcp -- anywhere 172.20.0.2 tcp dpt:http
В зависимости от дистрибутива по умолчанию может быть включен nftables или iptables-legacy. Также могут быть включены сразу оба формата, а команда iptables
просто ссылаться на один из них. Аналогично и с iptables-restore
.
Одной из особенностей этих двух систем можно назвать их параллельную работу. Т.е. пользователь может писать правила и в одну, и в другую, и обе системы будут работать независимо друг от друга.
Более того, они даже не будут мешать друг другу: можно одновременно добавить разрешающее правило в одну систему и запрещающее — в другую. Отработают оба, но какое из них будет первым — мы так и не поняли.
Istio для перехвата запросов настраивает DNAT, перенаправляя исходящие запросы на порт 15001, а входящие — на 15006.
За настройку DNAT'ов отвечает init-контейнер: к каждому поду добавляется initContainer, выполняющий команды iptables-restore для цепочки из десятка файлов. Эти команды добавляются в ядро, причем по умолчанию используется nftables.
На современных дистрибутивах все работает как положено, но на некоторых устаревших CentOS-подобных системах возникает следующая ошибка:
2023-01-18T17:17:47.706257Z info Running command: iptables-restore --noflush /tmp/iptables-rules-1674062267706031953.txt694377717
2023-01-18T17:17:47.728011Z error Command error output: xtables resource problem: line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or directory): table nat
line 24: TABLE_ADD failed (No such file or dire
2023-01-18T17:17:47.728076Z error Failed to execute: iptables-restore --noflush /tmp/iptables-rules-1674062267706031953.txt694377717, exit status 4
При этом iptables в таких условиях работает нормально.
В качестве возможного решения мы воспользовались iptables-wrapper [9]. Он определяет правильный iptables системы и меняет соответствующий симлинк. К сожалению оказалось, что скрипт не рассчитан на работу внутри пода и может работать только внутри host network.
Тогда мы написали свой wrapper, который пытался использовать iptables-restore с nftables, а если это приводило к ошибке — переключался на iptables-legacy. Самое главное — он работал в проблемном дистрибутиве.
Увы, с другими дистрибутивами нам не повезло: правила добавлялись, но не действовали. То есть скрипт срабатывал, записывал правило в nftables (и оно там действительно появлялось — его можно увидеть), но по какой-то причине вместо nftables запускался iptables-legacy.
После нескольких неудачных попыток найти корень проблемы и заставить систему работать как положено решили отказаться от всей затеи и вернуться к upstream-версии: там все правила помещаются только в nftables. Дистрибутивы, которые так не умеют, считаются неподдерживаемыми. Понять, что возникли проблемы, можно по состоянию проблемного пода — он будет висеть с ошибкой CrashLoopBackOff.
Этот случай заставил нас задуматься о необходимости расширить [10] покрытие e2e-тестами для проверки различных конфигураций.
Читайте также в нашем блоге:
Автор: Константин
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/iptables/384497
Ссылки в тексте:
[1] Deckhouse: https://deckhouse.ru/
[2] с ошибки: https://github.com/containerd/containerd/pull/7848
[3] обновили: https://github.com/deckhouse/deckhouse/pull/3929
[4] changelog: https://github.com/deckhouse/deckhouse/issues/4063
[5] из телеграм-чата по Deckhouse: https://t.me/deckhouse_ru
[6] Фикс: https://github.com/deckhouse/deckhouse/pull/3723
[7] перенести: https://github.com/deckhouse/deckhouse/issues/4064
[8] nftables: https://wiki.nftables.org/wiki-nftables/index.php/Main_Page
[9] iptables-wrapper: https://github.com/kubernetes-sigs/iptables-wrappers
[10] необходимости расширить: https://github.com/deckhouse/deckhouse/issues/4062
[11] «Istio в разрезе: что умеет и не умеет самый популярный Service Mesh (обзор и видео доклада)»: https://habr.com/ru/companies/oleg-bunin/articles/726958/
[12] «Тернистый путь к eBPF, или Как мы Cilium в Deckhouse внедряли»: https://habr.com/ru/companies/flant/articles/682520/
[13] «Наш опыт миграции PostgreSQL с AWS RDS на свою (self-hosted) инсталляцию»: https://habr.com/ru/companies/flant/articles/676860/
[14] Источник: https://habr.com/ru/companies/flant/articles/732854/?utm_source=habrahabr&utm_medium=rss&utm_campaign=732854
Нажмите здесь для печати.