Комментарии 55
Если не отключить swap, то kubeadm откажется поднимать кластер и потребует его отключения перед тем как продолжить. А с технической точки зрения, свап отключается из-за того, что при нехватке памяти (если свап включен) под будет записан на диск. При многочисленном удалении и создании подов в таком состоянии (например обновили deployment) вызовет деградацию перформанса всей вм-ки (или сервера). При выключенном свапе, сам kubelet способен обработать ситуацию когда нет памяти. Он тупо не поднимет под и в описании пода (kubectl describe pod my-pod) укажет что мало памяти. Для такого сценария ответственность за правильный scheduling пода на нужных нодах ложится на администратора (taint-ы и toleration-ы + node selector-ы, к тому же есть возможность установки ресурсных лимитов для самих подов)
А как настроить так терминал? Так удобно выглядит.
Если не вдаваться сильно в детали, которые под копотом, то основные детали это конфигурация tmux через пакетный мемеджер tpm и плагин dracula, и настройщик командной строки starship.
Так что вот этапы:
Устанавливаем tmux, устанавливаем tpm и заносим мой tmux.conf в
~/.config/tmux/tmux.conf
Устанавливаем starship и не забываем добавить в
~/.bashrc
(или .zshrc, config.fish, тд). Заносим мой starship.conf в~/.config/starship.toml
Остальные подробности придется как-нибудь описать в отдельном посте)
Простите, а что именно starship делает? Выглядит как просто tmux с вертикальным сплитом панелей.
Не совсем. Tmux и starship это совсем разные вещи. Tmux — это терминальный оконный менеджер. Starship — это конфигуратор самой строки в терминале. Он, например, позволяет превратить вот эту унылую строку:
user@ubuntu: ~/#
В вот такие красивые и полезные штуки:

Или вот такую:

То есть, starship это аналог Oh My Zsh для Zsh shell и ohmybash для Bash. Но у starship есть одно явное преимущество: он совместим с Bash, Fish, Zsh, Powershell, Elvish, Tcsh и со многими другими терминальными средами. То есть, один конфиг будет работать во всех этих средах. Плюс, starship написан на языке Rust, что делает его гораздо шустрее при генерации всех этих "красивых и полезных штук", в отличие от ohmyzsh и ohmybash, которые написаны на ответствующих терминальных средах.
del
Спасибо что не только изложили порядок действий, но и разъяснили смысл каждого шага!
Помню как-то раз приходилось поднимать кластер таким способом, и я тогда еще не мог понять. Вот есть список шагов которые надо выполнить чтобы подготовиться к установке кластера, он досконально описан в официальных доках. Почему было просто не включить эти шаги в утилиту kubeadm? А там, где от пользователя требуется какое-то осознанное решение, например выбор движка для контейнеров, делать промпт? В этом есть какой-то тайный смысл, или просто у мейнтейнеров руки не дошли?
Видимо решили разделить роли. kubeadm это инструмент исключительно настройки кубера. Он не занимается настройкой ОС и ее компонентов. Для последнего есть kubespray - он предварительно все настроит, даст выбор контейнерного рантайма и много чего еще (статья, например, не коснулась вообще выбора CNI), а потом использует тот же kubeadm, чтобы настроить специфические куберовские вещи.
Дело в том, что Kubernetes — это прежде всего контейнрный оркестратор и на этом его, так скажем, "ответственность", почти заканчивается. Боллее того, сам Kubernetes отдаляется от поддержки отдельных компонентов, которые не связаны с его основной должностью. Например, с версии 1.24, Kubernetes больше не поддерживает dockershim официально. Это означает, что выбор контейнерного рантайма (containerd, cri-o, Docker Engine и другие) теперь стоит за Kubernetes администратором и kubeadm теперь делает гораздо меньше за тебя. С другой стороны, kubeadm делает достаточно проверок настроек перед созданием кластера.
Более того, сам Kubernetes кластер может быть настроен по разному, в зависимости от технических требований. Например, БД etcd может быть настроена вне нод мастеров, а сами мастера могут быть настроены через Load Balancer, которые осуществляют бесперебойность кластера. Это всё усложняет количество возможных конфигураций Kubernetes кластера. Поэтому, включать шаги настройки Kubernetes в утилиту kubeadm было бы достаточно трудно и кропотливо. С другой стороны, есть не мало утилит, которые упрощают настройку Kubernetes. Я думаю, всё зависит от требований.
Это машинный перевод? 'Debian-основной' это типа 'debian-based' что ли?
А можно ссылку на оригинал? Такой перевод что-то очень тяжело читать.
Шож так сложно-то...
Ставим убунту
sudo snap install microk8s --classic
Вы великолепны
Можно ли получить ссылку на официальную документацию, где было сказано про отключение файл подкачки?
Если бы автор хоть чуть-чуть шарил принципах работы операционной системы, он бы не рекомендовал отключать swap.
Я не рекомендую использовать этот гайд никому.
Ну тогда напишите гид, который объясняет почему не стоит отключать файл подкачки и я с удовольствием включу это в статью ;)
Потом про необоснованность отключения файла подкачки при настройки Kubernetes можно будет написать вот на эти ресурсы. Уверен, что там будет кому удивится:
Это особенность Kubelet и для его предсказуемого поведения SWAP должен быть отключен.
Если не отключить swap, то kubeadm откажется поднимать кластер и потребует его отключения перед тем как продолжить. А с технической точки зрения, свап отключается из-за того, что при нехватке памяти (если свап включен) под будет записан на диск. При многочисленном удалении и создании подов в таком состоянии (например обновили deployment) вызовет деградацию перформанса всей вм-ки (или сервера). При выключенном свапе, сам kubelet способен обработать ситуацию когда нет памяти. Он тупо не поднимет под и в описании пода (kubectl describe pod my-pod) укажет что мало памяти. Для такого сценария ответственность за правильный scheduling пода на нужных нодах ложится на администратора (taint-ы и toleration-ы + node selector-ы, к тому же есть возможность установки ресурсных лимитов для самих подов)
Спасибо за это лаконичнoe разъяснение. Думаю это стоит закрепить, так как тема про отключение swap при настройки kubeadm вызвало комичное количество недоумений)
Тем не менее, в официальной документации (редакция 23 апреля, 2023 года ) твердится в жирном шрифте следующее:
"You MUST disable swap in order for the kubelet to work properly."
Если цель нашей дискуссии просто пофилософствовать от том, является ли бредом отключение swap памяти при настройки Kubernetes кластера, то можно хоть обфилософствоваться целами томами, на подобии софистов в Древней Греции. С практической же точки зрения, особенно в случаях, когда приходится настраивать Kubernetes в проде (таким, как мне), наверное, стоит придерживаться совету "вы ДОЛЖНЫ отключить swap память", который, в официальной документации, озвучивается соответствующим жирным шрифтом. Нет так ли?)
Оно fixed, но реализация в alpha стадии и не видно, чтобы что-то изменилось с тех пор https://kubernetes.io/blog/2021/08/09/run-nodes-with-swap-alpha/ Плюс реализация, по сути, никакая - кублет просто запускается с включенным свапом и может позволить подам использовать свап или не использовать. Все.
А рекомендация отключать свап все так же в силе, т.к. имеем непредсказуемое поведение нагрузок с ним. Плюс кубер все так же не способен оценить использовать свапа процессами, а значит не имеет полного контроля над ситуацией.
Собственно, я всегда отключал свап на любых продовых серваках, не только кубера. От этого всегда становилось только лучше. Многий софт точно так же рекомендует это делать.
Ну кубику свап реально мешает ресурсы планировать.
Вообще есть софт который заточен на максимально прямое управление памятью и ему своп мешает.
Да к примеру та-же Cassandra сама очень хорошо управляет памятью, а включение свопа под нагрузкой точно ее замедляет тк она очень хитро внутренними буферами пользуется.
Если оставаться в рамках кубика. Вот представьте себе ситуацию. Прод кластер под кубиком. Есть два типа подов. Мелкие - кушают 2-4 ГБ склероза, и крупные - по 20 ГБ. Падает одна из нод и кубер должен пераспределить поды с этой ноды на оставшиеся. Если ну нас включен своп то большой под может попасть на ноду у которой физическая память уже загружена и ему придется бороться за ресурсы. Если своп выключен - произойдет перераспределение мелких подов так чтобы все помещались в памяти.
И если прям супер надо - своп можно включить в поде.
Каким образом отключение swap помогает избавиться от OOM? Если нет swap'а - он придёт еще раньше)
Просто со свап все будет умирать очень долго, в чем практически нет смысла. Если у вас la 20+ на 4х ядерном проце, то поверьте свап вас уже не спасет
Мой вопрос был не в этом, а в том как отключение swap решит проблему с OOM. ответ - никак =)
Что подразумевается под проблемой OOM ?
Вы статью читали?
"Кроме того, отключение swap может помочь предотвратить риск вызова так называемого "OOM killer"."
Ну бред же. Высокий la может быть потому что вся система ждёт I/O, который некуда закешировать, потому что выключили свап (а если бы он был включен, то в него бы выпихнулись неактивные процессы, и появилась память для кэширования I/O).
И какой процент таких случаев 0,00001% ? В личной практике за 20 лет свап ни разу не помогал, а только мешал
Так кубер и решает это тем что не запускает нагрузку которую не выдержит кластер. В продакшн fast-fail гораздо лучше "очень медленно работает". Первое сразу детекится мониторингом и орет везде. Второе - очень сложно искать и ещё сложнее отлаживать.
Чтобы убедиться, что swap остается отключенным после запуска, нам необходимо закомментировать строку в файле /etc/fstab
Всё пытался по инструкции сделать, первое с чем столкнулся - ключ репозитория кубера, помогает добавить ключ руками и убрать из строчки параметр, указывающий на файл.
А второе с чем я столкнулся - файла нет /etc/kubernetes/admin.conf
его самому нужно создать или как?
Нужно ли инициализировать сеть кубера на воркерах? Или там просто джоин достаточно ввести после установки cri-o и докера?
Привет, Павел. Действительно, почему-то в последние дни ключ от репозитория кубера отвалился. Причем, если следовать инструкции установки на уже мною поднятых узлах месяц назад, скаченный ключ отваливается, пришлось его вручную подменять уже скаченным и работающим ключом. Пока не до конца разобрался в чём дело. Как вариант, можно установить необходимые компоненты без пакетного менеджера.
А второе с чем я столкнулся - файла нет /etc/kubernetes/admin.conf
Файл /etc/kubernetes/admin.conf
должен генерироваться при успешном выполнении kubeadm init
. Стоит проверить, если инициализация первой ноды кластера прошла успешно.
С ключиком разобрался, делается примерно так
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list
По файлу админ внимательно почитал, там написана команда после инита, оно куда то в другое место кладется
sudo cp -i /etc/kubernetes/tmp/kubeadm-init-dryrun3374606150/admin.conf $HOME/.kube/config
Но дальше вот ни приджойинться с других узлов, ни даже локально посмотреть статус не удается
user@kubi1:~$ kubectl get nodes
E0523 22:33:48.619600 5722 memcache.go:265] couldn't get current server API group list: Get "https://192.168.200.30:6443/api?timeout=32s": dial tcp 192.168.200.30:6443: connect: connection refused
E0523 22:33:48.619743 5722 memcache.go:265] couldn't get current server API group list: Get "https://192.168.200.30:6443/api?timeout=32s": dial tcp 192.168.200.30:6443: connect: connection refused
E0523 22:33:48.621086 5722 memcache.go:265] couldn't get current server API group list: Get "https://192.168.200.30:6443/api?timeout=32s": dial tcp 192.168.200.30:6443: connect: connection refused
E0523 22:33:48.622409 5722 memcache.go:265] couldn't get current server API group list: Get "https://192.168.200.30:6443/api?timeout=32s": dial tcp 192.168.200.30:6443: connect: connection refused
E0523 22:33:48.623691 5722 memcache.go:265] couldn't get current server API group list: Get "https://192.168.200.30:6443/api?timeout=32s": dial tcp 192.168.200.30:6443: connect: connection refused
The connection to the server 192.168.200.30:6443 was refused - did you specify the right host or port?
Вроде инит прошел успешно, но такое ощущение что какой-то сервис не запустился
P.s. понял что я от рута всё делал, когда через sudo запустил, то вдруг заработало...
тоже все пробовал внутри виртуалки sudo не был установлен в принципе, вряд ли в этом первопричина, да и по логике так быть не должно)
У меня удалось поднять кластер, присоединить к нему ноду, но хотелось бы продолжения статьи о назначении ролей нодам, о поднятии веб-админки)))
Боюсь, если всё описывать подробно, как я пытался это делать в этой статье (и при этом, всё равно пришлось вырезать десяток нюансов), то для описании правильной настройки RBAC ролей, придется писать целую книгу)
Я сейчас работаю над продолжением этой статьи, как раз примерно по этой теме, но мне предстоит ещё очень много протестировать, и понять, как это всё преподнести в формате статьи.
Мне интересно как вообще в кластер попадать, вот крутится на 5 нодах копия приложения, и куда на какой айпи заходить, как оно перераспределится? На работе мы крутим istio в опеншифте, но многие моменты за моими компетенциями, я обычно получаю проект, прокидываю в него 2-3 роута, дальше внутри кручу по урлам и портам, всякие там виртуалсервисы и гатевеи поднимаю, ингресс и эгресс, но вот когда дома поднял опеншифт, то даже к веб-панели не смог пробраться, запустил прокси с особым параметром чтобы пускало напрямую, а там мне вместо сайта отдает какой то json, будто это апи для сайта а не сайт.
Другой момент, что у меня есть в финале вашей инструкции одна пода контрол план, а вторая без роли, как назначить роль типа воркер или мастер и каких ролей минимально достаточно тоже надо гуглить собирать по крупицам.
Я вдруг понял что прочитал невнимательно, выполнял команду dry-run, и думал на этом всё, а эта команда ничего не делает кроме как проверки, простите.
может упустил, но где развертывание CNI?
Спасибо за статью, очень доступно изложено, но столкнулся с проблемой, возможно Вы сможете помочь. Поды на разных нодах не видят друг друга. В рамках одной ноды без проблем, но на разных что при доступе через сервис, что напрямую по ip - недоступны.
Спасибо, рад, что статья оказалась полезной.
Сперва, наверное стоит проверить самые элементарные вещи. Выполняем команду ip a
на одной VM, получаем IP адрес, пингуем этот адрес с другой машины при помощи ping 192.168.1.23
где 192.168.1.23 является адрес первой машины. Если не пингуется, разбираемся почему сеть между двумя VM неправильно настроена.
Надеюсь, проблема только в этом, иначе придётся разбираться глубже)
К сожалению, ноды пингуют друг друга без проблем без проблем :)
Тогда стоит почитать документацию по kubeadm init
. Для начала, стоит обратить внимание на флаг --apiserver-advertise-address
и --control-plane-endpoint
. Возможно, дефолтные значения присваиваются неправильно. В качестве обеих этих значений, присваиваем адрес первой мастер ноды:kubeadm init --pod-network-cidr=10.100.0.0/16 --dry-run --apiserver-advertise-address 192.168.1.23 --control-plane-endpoint 192.168.1.23
Где 192.168.1.23 является адрес первой мастер ноды на которой мы инициализируем кластер. При добавлении воркера через команду с токеном, дополнительно указывать эти два флага (--apiserver-advertise-address
и --control-plane-endpoint
), думаю, тоже не помешает.
Сделал "kubeadm reset" на всех нодах и указал явно apiserver-advertise-address и
control-plane-endpoint и ничего не изменилось.
root@k8s-master:~/yamls# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 13m v1.27.2
k8s-worker1 Ready <none> 11m v1.27.2
k8s-worker2 Ready <none> 11m v1.27.2
root@k8s-master:~/yamls# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
testapp-2p5gd 1/1 Running 0 2m37s 10.85.0.67 k8s-worker1 <none> <none>
testapp-b6cb5 1/1 Running 0 2m37s 10.85.0.21 k8s-worker2 <none> <none>
testapp-bnstn 1/1 Running 0 2m37s 10.85.0.66 k8s-worker1 <none> <none>
root@k8s-master:~/yamls# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m
testapp ClusterIP 10.109.131.36 <none> 80/TCP 3m
# Выполняю на мастере - запросы не проходят
root@k8s-master:~/yamls# curl 10.109.131.36
curl: (7) Failed to connect to 10.109.131.36 port 80: No route to host
# Выполняю на первом воркере - запросы проходят только к тем подам которые крутятся на этом же воркере, запрос к поду на worker2 не проходит
root@k8s-worker1:~# curl 10.109.131.36
You've hit testapp-2p5gd
root@k8s-worker1:~# curl 10.109.131.36
You've hit testapp-bnstn
root@k8s-worker1:~# curl 10.109.131.36
curl: (7) Failed to connect to 10.109.131.36 port 80: No route to host
# Со второго воркера запросы отрабатывают только для пода testapp-b6cb5
root@k8s-worker2:~# curl 10.109.131.36
You've hit testapp-b6cb5
root@k8s-worker2:~# curl 10.109.131.36
curl: (7) Failed to connect to 10.109.131.36 port 80: No route to host
root@k8s-worker2:~# curl 10.109.131.36
curl: (7) Failed to connect to 10.109.131.36 port 80: No route to host
Там, чуть выше, @scruffпишет про CNI, возможно в этом дело?
Решил проблему, добавьте пожалуйста в мануал
kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
Поднимаем Kubernetes с нуля