ProHoster > Blog > administracja > Nasze doświadczenie z danymi w klastrze etcd Kubernetes bezpośrednio (bez API K8s)
Nasze doświadczenie z danymi w klastrze etcd Kubernetes bezpośrednio (bez API K8s)
Coraz częściej klienci proszą nas o udostępnienie klastra Kubernetes, aby móc uzyskać dostęp do usług w ramach klastra: aby móc bezpośrednio połączyć się z jakąś bazą danych lub usługą, aby połączyć aplikację lokalną z aplikacjami w ramach klastra...
Na przykład istnieje potrzeba połączenia się z komputera lokalnego z usługą memcached.staging.svc.cluster.local. Zapewniamy tę możliwość za pomocą VPN w klastrze, z którym łączy się klient. W tym celu ogłaszamy podsieci podów, usług i przekazujemy klientowi klaster DNS. Tak więc, gdy klient próbuje połączyć się z usługą memcached.staging.svc.cluster.local, żądanie trafia do DNS klastra i w odpowiedzi otrzymuje adres tej usługi z sieci usług klastrowych lub adres poda.
Klastry K8s konfigurujemy za pomocą kubeadm, gdzie znajduje się domyślna podsieć usługi 192.168.0.0/16, a sieć kapsuł jest 10.244.0.0/16. Zwykle wszystko działa dobrze, ale jest kilka punktów:
Podsieć 192.168.*.* często stosowane w sieciach biurowych klientów, a jeszcze częściej w sieciach domowych deweloperów. A potem dochodzą konflikty: routery domowe pracują w tej podsieci, a VPN wypycha te podsieci z klastra do klienta.
Mamy kilka klastrów (produkcyjny, etapowy i/lub kilka klastrów deweloperskich). Wtedy domyślnie wszystkie będą miały te same podsieci dla podów i usług, co stwarza duże trudności przy jednoczesnej pracy z usługami w kilku klastrach.
Już dawno przyjęliśmy praktykę wykorzystywania różnych podsieci dla usług i podów w ramach tego samego projektu – ogólnie rzecz biorąc, tak aby wszystkie klastry miały różne sieci. Istnieje jednak duża liczba działających klastrów, których nie chciałbym przenosić od zera, ponieważ obsługują wiele usług, aplikacji stanowych itp.
A potem zadaliśmy sobie pytanie: jak zmienić podsieć w istniejącym klastrze?
Wyszukiwanie decyzji
Najczęstszą praktyką jest odtwarzanie wszystko usługi z typem ClusterIP. Jako opcja, mogę doradzić i to:
W następującym procesie występuje problem: po skonfigurowaniu wszystkiego pody wyświetlają stary adres IP jako serwer nazw DNS w pliku /etc/resolv.conf.
Ponieważ nadal nie znalazłem rozwiązania, musiałem zresetować cały klaster za pomocą polecenia kubeadm reset i zainicjować go ponownie.
Ale to nie jest odpowiednie dla wszystkich... Oto bardziej szczegółowe wprowadzenie do naszego przypadku:
Używana jest flanela;
Klastry istnieją zarówno w chmurach, jak i na sprzęcie;
Chciałbym uniknąć ponownego wdrażania wszystkich usług w klastrze;
Ogólnie rzecz biorąc, należy zrobić wszystko przy minimalnej liczbie problemów;
Wersja Kubernetesa to 1.16.6 (jednak dalsze kroki będą podobne dla pozostałych wersji);
Głównym zadaniem jest zapewnienie, aby w klastrze wdrożonym przy użyciu kubeadm znajdowała się podsieć serwisowa 192.168.0.0/16, zamień go na 172.24.0.0/16.
I tak się złożyło, że od dawna byliśmy ciekawi, co i jak w Kubernetesie jest przechowywane w etcd, co można z tym zrobić… Pomyśleliśmy więc: „Dlaczego po prostu nie zaktualizować danych w etcd, zastępując stare adresy IP (podsieć) nowymi? "
Szukając gotowych narzędzi do pracy z danymi w etcd, nie znaleźliśmy niczego, co całkowicie rozwiązałoby problem. (Nawiasem mówiąc, jeśli znasz jakieś narzędzia do pracy z danymi bezpośrednio w etcd, będziemy wdzięczni za linki.) Jednak dobrym punktem wyjścia jest itp.pomocnik z OpenShift(dzięki jego autorom!).
To narzędzie może łączyć się z etcd przy użyciu certyfikatów i odczytywać stamtąd dane za pomocą poleceń ls, get, dump.
Dodaj etcdhelper
Następna myśl jest logiczna: „Co powstrzymuje Cię przed dodaniem tego narzędzia poprzez dodanie możliwości zapisu danych do etcd?”
Stało się zmodyfikowaną wersją etcdhelper z dwiema nowymi funkcjami changeServiceCIDR и changePodCIDR. na jej możesz zobaczyć kod tutaj.
Co dają nowe funkcje? Algorytm changeServiceCIDR:
utwórz deserializator;
skompiluj wyrażenie regularne, aby zastąpić CIDR;
przechodzimy przez wszystkie usługi o typie ClusterIP w klastrze:
dekodować wartość z etcd do obiektu Go;
za pomocą wyrażenia regularnego zastępujemy pierwsze dwa bajty adresu;
przypisać usłudze adres IP z nowej podsieci;
utwórz serializator, przekonwertuj obiekt Go na protobuf, zapisz nowe dane do itp.
Funkcja changePodCIDR zasadniczo podobne changeServiceCIDR - tylko zamiast edytować specyfikację usługi, robimy to dla węzła i zmieniamy .spec.PodCIDR do nowej podsieci.
Praktyka
Zmień usługę CIDR
Plan realizacji zadania jest bardzo prosty, jednak wiąże się z przestojem na czas ponownego utworzenia wszystkich podów w klastrze. Po opisaniu głównych kroków podzielimy się również przemyśleniami na temat tego, jak teoretycznie można zminimalizować ten przestój.
Kroki przygotowawcze:
instalowanie niezbędnego oprogramowania i instalowanie załatanego pliku etcdhelper;
kopia zapasowa itp. i /etc/kubernetes.
Krótki plan działania dotyczący zmiany usługiCIDR:
zmiana manifestów apiservera i menedżera kontrolerów;
ponowne wydanie certyfikatów;
zmiana usług ClusterIP w itp.;
uruchom ponownie wszystkie zasobniki w klastrze.
Poniżej znajduje się pełna sekwencja działań w szczegółach.
Oszczędzamy dla siebie etcdhelper.go, pobierz zależności, zbierz:
wget https://raw.githubusercontent.com/flant/examples/master/2020/04-etcdhelper/etcdhelper.go
go get go.etcd.io/etcd/clientv3 k8s.io/kubectl/pkg/scheme k8s.io/apimachinery/pkg/runtime
go build -o etcdhelper etcdhelper.go
4. Zmień podsieć usługi w manifestach płaszczyzny kontrolnej Kubernetes. W plikach /etc/kubernetes/manifests/kube-apiserver.yaml и /etc/kubernetes/manifests/kube-controller-manager.yaml zmienić parametr --service-cluster-ip-range do nowej podsieci: 172.24.0.0/16 zamiast 192.168.0.0/16.
5. Ponieważ zmieniamy podsieć usługi, do której kubeadm wystawia certyfikaty dla apiserver (w tym), należy je ponownie wystawić:
Zobaczmy dla jakich domen i adresów IP został wystawiony aktualny certyfikat:
openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
X509v3 Subject Alternative Name:
DNS:dev-1-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:apiserver, IP Address:192.168.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
Ostrzeżenie! W tym momencie rozpoznawanie domeny przestaje działać w klastrze, ponieważ w istniejących podach /etc/resolv.conf zarejestrowany jest stary adres CoreDNS (kube-dns), a kube-proxy zmienia reguły iptables ze starej podsieci na nową. W dalszej części artykułu napisano o możliwych opcjach minimalizacji przestojów.
Naprawmy ConfigMap w przestrzeni nazw kube-system:
kubectl -n kube-system edit cm kubelet-config-1.16
- zamień tutaj clusterDNS na nowy adres IP usługi kube-dns: kubectl -n kube-system get svc kube-dns.
kubectl -n kube-system edit cm kubeadm-config
- naprawimy to data.ClusterConfiguration.networking.serviceSubnet do nowej podsieci.
Ponieważ adres kube-dns uległ zmianie, konieczna jest aktualizacja konfiguracji kubelet na wszystkich węzłach:
6. Zrestartujmy jeden po drugim wszystkie węzły klastra.
7. Jeśli opuścisz przynajmniej jeden węzeł stary podCIDR, wówczas kube-controller-manager nie będzie mógł zostać uruchomiony, a pody w klastrze nie zostaną zaplanowane.
Tak naprawdę zmianę podCIDR można przeprowadzić jeszcze prościej (np. tak). Chcieliśmy jednak nauczyć się pracować bezpośrednio z etcd, ponieważ zdarzają się przypadki edycji obiektów Kubernetesa w etcd - pojedynczy możliwy wariant. (Na przykład nie można po prostu zmienić pola Usługa bez przestojów spec.clusterIP.)
Łączny
W artykule omówiono możliwość bezpośredniej pracy z danymi w etcd, tj. z pominięciem API Kubernetes. Czasami takie podejście pozwala na wykonanie „trudnych rzeczy”. Operacje podane w tekście przetestowaliśmy na prawdziwych klastrach K8s. Jednak ich stan gotowości do powszechnego stosowania jest PoC (weryfikacja koncepcji). Dlatego też, jeśli chcesz używać zmodyfikowanej wersji narzędzia etcdhelper w swoich klastrach, robisz to na własne ryzyko.