Предположим, вам необходимо мигрировать ваш кластер k8s в другой vlan или просто сменить ip адреса. Насколько это необходимо каждый решает сам. Будем считать, что перенос нагрузки ямлами на другой кластер затруднён или у кластера специфические настройки.
В качестве начальных условий: кластер on prem с root доступом на узлы, установлен через kubeadm или kubespray, calico как cni. В нашем случае под ногами ubuntu на узлах кластера. Балансировщик kube api отсутствует. Если у вас кластер установлен the hard way , то статья вам не нужна, вы сами всё умеете.
Перемещать лучше начинать с третьей мастер ноды, т.к. бывает, что все ноды смотрят именно на первую в качестве api сервера. Последовательно перемещаем control plane ноды, далее перемещаем по одной рабочей ноде.
Перенос control plane ноды
Очищаем мастер ноду, которая будет переноситься (выполнять с любой мастер ноды или хоста с kubectl доступом до кластера):
sudo kubectl drain mycluster-m3.domain.ru --ignore-daemonsets=true --delete-emptydir-data=trueНа переносимой ноде бакапим конфиги и etcd (etcd не обязательно):
sudo cp -r /etc/kubernetes{,.back}
sudo cp -r /var/lib/etcd{,.back}Очищаем ноду от кубера (на переносимой ноде):
sudo kubeadm resetДальше тушим ноду, меняем адреса на гипервизоре или железке, поднимаем, проверяем наличие сетевой связности нод.
Убиваем ноду из кластера. Не обязательно, тогда при передобавлении ноды с тем же именем сохранятся метки на ноде и время создания ноды.
sudo kubectl delete node mycluster-m3.domain.ruПравим /etc/hosts на перемещаемом хосте и остальных нодах, обновляем адрес перемещаемой ноды (kubespray любит прописывать статиком адреса нод в /etc/hosts). Тут можно использовать bash/ansible по желанию.
Если используется nginx proxy на worker нодах (вместо внешнего балансировщика kube api), то нужно поправить адреса control plane в конфиге nginx.conf, обычно живёт в /etc/nginx/nginx.conf. Аналогично bash/ansible в помощь.
Если менялся nginx.conf, рекомендуется перечитать настройки:
for pod in $(sudo kubectl get pods -n kube-system -l k8s-app=kube-nginx --no-headers -o jsonpath='{.items[*].metadata.name}');do sudo kubectl exec -n kube-system $pod -- nginx -s reload;doneДалее чиним пере��есённую мастер ноду.
Нужно поправить адрес в /etc/kubernetes/kubelet.env на перемещаемом хосте (прописать адрес ноды).
Поправить kubeadm-config в кластере. Обратить внимание на ip адрес новой ноды в разделе certSANs и адрес в controlPlaneEndpoint (тут указать адрес любой рабочей мастер ноды или адрес балансировщика kube api).
sudo kubectl -n kube-system edit cm kubeadm-configМеняем адрес api сервера в конфигмапе cluster-info, из него kubelet получает адрес сервера для присоединения и создания конфига. Ставим адрес любой рабочей мастер ноды или адрес балансировщика.
sudo kubectl edit cm -n kube-public cluster-infoМеняем адрес (на перемещаемой ноде) api сервера в конфиге /etc/kubernetes/admin.conf, или проверяем его корректность, т.к. kubeadm использует этот конфиг для авторизации в кластере. Адрес ставим на любую рабочую мастер ноду.
Создаём токен присоединения и получаем команду присоединения (на мастер ноде):
sudo kubeadm token create --print-join-commandСоздаём секрет в kube-system с сертификатами кластера:
sudo kubeadm init phase upload-certs --upload-certsПрисоединяем старую ноду как новую. Используем полученное значение из команды создания секрета, указываем в разделе --certificate-key
в --apiserver-advertise-address указываем ip адрес ноды
в --node-name имя хоста
токен получили из команды создания токена
В качестве адреса присоединения используем любой адрес рабочей мастер ноды или балансировщик.
Пример команды:
sudo kubeadm join 10.10.10.10:6443 /
--token k7or1a.1yozzaqnqylq7h5z /
--discovery-token-ca-cert-hash sha256:17eb90f281daeea2f47057216dd72182edd43c2fcd1188d64cc819239f728b0f /
--control-plane /
--certificate-key fda49053d60170092bc149624b56c977cf51263ac02d18fbe812ef7bc0833879 /
--apiserver-advertise-address 10.10.10.11 /
--node-name mycluster-m3.domain.ruЕсли использовался адрес одного из мастеров, то он прописался в конфиг kubelet. Лучше его заменить на localhost.
Нужно поправить конфиг /etc/kubernetes/kubelet.conf в разделе server поставить https://localhost:6443 и перезапустить kubelet:
sudo systemctl restart kubelet.serviceОсталось поправить манифесты.
Правим манифест на перемещаемом хосте /etc/kubernetes/manifests/etcd.yaml:
в разделе --initial-cluster оставляем только адрес перемещённой ноды (можно взять за образец строку из манифеста в /etc/kubernetes.back), убираем раздел --initial-cluster-state=existing
Под с etcd перезапустится, контролируем корректность запуска.
Правим манифест на перемещаемом хосте /etc/kubernetes/manifests/kube-apiserver.yaml если были расхождения с бакапом в /etc/kubernetes.back (например дополнительные опции запуска).
Перенос k8s из одной control plane ноды
Если у вас кубер состоит из одного узла, то проблем чуть больше.
Останавливаем kubelet и бакапим манифесты и etcd:
sudo systemctl disable kubelet.service --now
sudo cp -r /etc/kubernetes{,.back}
sudo cp -r /var/lib/etcd{,.back}Меняем адреса у хоста на гипервизоре или железке, правим /etc/hosts на перемещаемом хосте при необходимости.
Правим адрес в конфиге kubelet и манифестах кубера (apiserver и etcd).
Файлы:
/etc/kubernetes/kubelet.env
/etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/etcd.yaml
Смотрим прошлый сертификат у apiserver, обратить внимание на раздел X509v3 Subject Alternative Name и Subject:
sudo openssl x509 -in /etc/kubernetes/pki/apiserver.crt -textУдаляем старый сертификат от apiserver (файл /etc/kubernetes/ssl/apiserver.*) и создаём новый сертификат. Учитываем cidr у сервисов (можно посмотреть в манифесте apiserver, настройка service-cidr) и extra sans (берём из старого сертификата, но убираем "DNS:" и "IP Address:", просто список через запятую). В качестве ip адреса прописываем новый адрес ноды, старый убираем.
Пример:
sudo kubeadm init phase certs apiserver /
--service-cidr "10.233.0.0/16" /
--apiserver-cert-extra-sans "kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster.local,lb-apiserver.kubernetes.local,localhost,mycluster,mycluster.domain.ru,10.233.0.1,10.10.10.10,127.0.0.1"Всё, осталось стартовать kubelet:
sudo systemctl enable kubelet.service --nowЕсли надумаете позже присоединять ещё ноды, то стоит поправить конфиги cluster-info и kubeadm-config в кластере. Смотреть в предыдущем разделе.
В качестве бонуса или в случае отсутствия kubeadm. Возможно создать новые сертификаты вручную через openssl:
sudo openssl req /
-x509 /
-newkey rsa:2048 /
-keyout /etc/kubernetes/pki/apiserver.key /
-sha256 /
-out /etc/kubernetes/pki/apiserver.crt /
-days 1500 /
-noenc /
-CA /etc/kubernetes/pki/ca.crt /
-CAkey /etc/kubernetes/pki/ca.key /
-subj "/CN=kube-apiserver" /
-addext "basicConstraints=critical,CA:FALSE" /
-addext "keyUsage=critical,digitalSignature,keyEncipherment" /
-addext "extendedKeyUsage=serverAuth" /
-addext "subjectAltName=DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:lb-apiserver.kubernetes.local, DNS:localhost, DNS:mycluster, DNS:mycluster.domain.ru, IP:10.233.0.1, IP:10.10.10.10, IP:127.0.0.1"Перенос worker ноды
Кордоним и очищаем ноду, смотрим что нагрузка переместилась на другие ноды:
sudo kubectl drain mycluster-n1.domain.ru --ignore-daemonsets=true --delete-emptydir-data=trueБакапим конфиги:
sudo cp -r /etc/kubernetes{,.back}Очищаем ноду от кубера (на переносимой ноде):
sudo kubeadm resetУбираем ноду из списка нод:
sudo kubectl delete node mycluster-n1.domain.ruМеняем адреса у хоста на гипервизоре или железке, правим /etc/hosts на всех нодах, если там прописаны адреса статикой.
Правим /etc/kubernetes/kubelet.env на перемещаемом хосте, меняем адрес ноды.
Возвращаем на место манифест nginx proxy из папки /etc/kubernetes.back/manifests если используется nginx proxy. Команда kubeadm reset очищает папку с манифестами.
На мастер ноде создаём токен присоединения. Если несколько нод перемещаем одновременно, то можно использовать один токен, время жизни токена два часа.
sudo kubeadm token create --print-join-commandПрисоединяем старую ноду как новую, пример команды (получена из предыдущего шага, нужно поменять ip адрес на адрес мастер ноды или балансировщика):
sudo kubeadm join 10.10.10.10:6443 /
--token 40j37s.bupenjhou2bx5ydv /
--discovery-token-ca-cert-hash sha256:17eb90f281daeea2f47057216dd72182edd43c2fcd1188d64cc819239f728b0fЕсли использвался адрес одного из мастеров, то он прописался в конфиг kubelet. Лучше его заменить на localhost если используется nginx-proxy для kube api. Правим /etc/kubernetes/kubelet.conf и рестартим kubelet:
sudo systemctl restart kubelet.serviceЗаключение
В целом переезд кластера происходит без простоя и незаметен для пользователей (при наличии нескольких подов на сервис). Если у вас используется deckhouse kubernetes platform, то там переезд осуществляется проще. При наличии пожеланий, позже можно расширить статью на этот случай.
В целом статья написана больше для обучения и лучшего понимания устройства кластера для желающих посмотреть под капот. Если есть методы проще и удобнее, прошу поделиться в комментариях.
