
Cieszymy się, że firma „Flant” zwiększa swój wkład w narzędzia Open Source dla Kubernetes, wydając (Container Storage Interface) dla Yandex.Cloud.
Ale zanim przejdziemy do szczegółów implementacji, odpowiedzmy na pytanie, dlaczego to w ogóle jest potrzebne, gdy Yandex ma już usługę .
Wprowadzenie
Po co to?
W naszej firmie, od samego początku eksploatacji Kubernetes w środowisku produkcyjnym (tj. od kilku lat), rozwijamy własne narzędzie (deckhouse), które zresztą również planujemy wkrótce udostępnić jako projekt Open Source. Dzięki niemu jednolicie konfigurujemy i ustawiamy wszystkie nasze klastry, a obecnie jest ich już ponad 100, przy czym na bardzo różnych konfiguracjach sprzętowych i we wszystkich dostępnych usługach chmurowych.
Klastry wykorzystujące deckhouse mają wszystkie niezbędne komponenty do pracy: load balancery, monitoring z wygodnymi wykresami, metrykami i alertami, autoryzację użytkowników przez zewnętrznych dostawców do dostępu do wszystkich dashboardów itd. Taki „ulepszony” klaster nie ma sensu w rozwiązaniach zarządzanych, ponieważ często jest to niemożliwe lub prowadzi do konieczności wyłączenia połowy komponentów.
NB: To nasze doświadczenie, które jest dość specyficzne. Nie twierdzimy w żadnym wypadku, że każdy powinien samodzielnie zajmować się uruchamianiem klastrów Kubernetes zamiast korzystać z gotowych rozwiązań. Co więcej, nie mamy rzeczywistego doświadczenia w korzystaniu z Kubernetes oferowanego przez Yandex i nie zamierzamy oceniać tej usługi w tym artykule.
Czym to jest i dla kogo?
Zatem, już opowiadaliśmy o nowoczesnym podejściu do przechowywania w Kubernetes: i do takiego podejścia.
Obecnie wielu dużych dostawców usług chmurowych opracowało sterowniki do używania swoich „chmurowych” dysków jako Persistent Volume w Kubernetes. Jeżeli jednak dostawca nie ma takiego sterownika, ale wszystkie niezbędne funkcje są dostępne przez API, nic nie stoi na przeszkodzie, by zrealizować sterownik samodzielnie. Tak właśnie zrobiliśmy z Yandex.Cloud.
Jako bazę do rozwoju wzięliśmy i kilka pomysłów z , ponieważ interakcja z API tych chmur (Google i Yandex) ma wiele podobieństw. W szczególności API zarówno , jak i zwracają obiekt Operacja do śledzenia statusu długotrwałych operacji (np. tworzenia nowego dysku). Aby komunikować się z API Yandex.Cloud, używa się .
Wynik wykonanej pracy i może być przydatny dla tych, którzy z jakiegoś powodu używają własnej instalacji Kubernetes na maszynach wirtualnych Yandex.Cloud (ale nie gotowego zarządzanego klastra) i chcieliby korzystać z (zamawiać) dysków przez CSI.
Realizacja
Główne możliwości
W tej chwili sterownik wspiera następujące funkcje:
- Zamawianie dysków we wszystkich strefach klastra zgodnie z topologią dostępnych w klastrze węzłów;
- Usuwanie wcześniej zamówionych dysków;
- Offline resize dla dysków (Yandex.Cloud powiększanie dysków, które są zamontowane na maszynie wirtualnej). O tym, jak musiałem przerabiać sterownik, aby jak najmniej boleśnie przeprowadzać resize, patrz poniżej.
W przyszłości planowane jest wprowadzenie wsparcia dla tworzenia i usuwania migawek dysków.
Główna trudność i jej pokonanie
Brak w API Yandex.Cloud możliwości zwiększania dysków w czasie rzeczywistym — ograniczenie, które utrudnia operację resize'u dla PV (Persistent Volume): w takim przypadku konieczne jest, aby pod aplikacji, który używa dysku, był zatrzymany, co może spowodować przestój aplikacji.
Zgodnie z , jeśli kontroler CSI informuje, że potrafi wykonywać resize dysków tylko „w offline” (VolumeExpansion.OFFLINE), to proces zwiększania dysku musi przebiegać w ten sposób:
Jeśli wtyczka ma tylko
VolumeExpansion.OFFLINEzdolność rozszerzenia i wolumen jest obecnie opublikowany lub dostępny na węźle, toControllerExpandVolumeMUSI być wywołany TYLKO po tym, jak:
- Wtyczka ma kontroler
PUBLISH_UNPUBLISH_VOLUMEzdolność iControllerUnpublishVolumezostał pomyślnie wywołany.LUB
- Wtyczka NIE ma zdolności kontrolera
PUBLISH_UNPUBLISH_VOLUME, wtyczka ma węzełSTAGE_UNSTAGE_VOLUMEzdolność iNodeUnstageVolumezostał pomyślnie zakończony.LUB
- Wtyczka NIE ma zdolności kontrolera
PUBLISH_UNPUBLISH_VOLUMEzdolność, ani węzełSTAGE_UNSTAGE_VOLUMEzdolność iNodeUnpublishVolumenie został pomyślnie zakończony.
W zasadzie oznacza to konieczność odłączenia dysku od maszyny wirtualnej przed jego zwiększeniem.
Niestety, realizacja specyfikacje CSI poprzez sidecary nie spełniają tych wymagań:
- W kontenerze sidecar
csi-attacher, który ma odpowiadać za zapewnienie odpowiedniej przerwy pomiędzy zamontowaniami, przy offline-resize po prostu nie zrealizowano tej funkcji. Dyskusję na ten temat zainicjowano . - Czym właściwie jest kontener sidecar w tym kontekście? Sam wtyczka CSI nie obsługuje interakcji z API Kubernetes, a jedynie reaguje na wywołania gRPC, które wysyłają mu kontenery sidecar. Ostatnie społeczność Kubernetes.
W naszym przypadku (wtyczka CSI) operacja zwiększenia dysku wygląda następująco:
- Otrzymujemy wywołanie gRPC
ControllerExpandVolume; - Próbujemy zwiększyć dysk w API, ale otrzymujemy błąd o niemożności wykonania operacji, ponieważ dysk jest zamontowany;
- Zapisujemy identyfikator dysku w mapie, która zawiera dyski, dla których należy wykonać operację zwiększenia. Dalej dla skrótu będziemy nazywać tę mapę
volumeResizeRequired; - Ręcznie usuwamy pod, który korzysta z dysku. Kubernetes w tym czasie go zrestartuje. Aby dysk nie zdążył się zamontować (
ControllerPublishVolume) przed zakończeniem operacji zwiększenia podczas próby montowania, sprawdzamy, że dany dysk wciąż znajduje się wvolumeResizeRequiredi zwracamy błąd; - Sterownik CSI próbuje ponownie wykonać operację resize. Jeśli operacja zakończyła się sukcesem, usuwamy dysk z
volumeResizeRequired; - Ponieważ identyfikator dysku nie występuje w
volumeResizeRequired,ControllerPublishVolumeoperacja przebiega pomyślnie, dysk jest montowany, pod zostaje uruchomiony.
Wszystko wygląda dość prosto, ale jak zawsze są pewne pułapki. Zwiększeniem dysków zajmuje się , który w przypadku błędu podczas wykonywania operacji z wykładniczym zwiększeniem czasu oczekiwania do 1000 sekund:
func DefaultControllerRateLimiter() RateLimiter {
return NewMaxOfRateLimiter(
NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
// 10 qps, 100 wielkość wiadra. To tylko dla prędkości powtórzeń i to tylko ogólny czynnik (nie dla każdego elementu)
&BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
)
}Może to okresowo powodować, że operacja zwiększenia dysku rozciąga się na ponad 15 minut, a tym samym dysk staje się niedostępny.
Jedyną opcją, która wystarczająco łatwo i bez bólu pozwoliła nam zredukować potencjalny czas przestoju, było użycie własnej wersji external-resizer z maksymalnym ograniczeniem czasu oczekiwania :
workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)Nie uznaliśmy za konieczne pilnie podejmować dyskusji i łatkać external-resizer, ponieważ offline resize dysków to relikt, który wkrótce wyginie u wszystkich dostawców chmurowych.
Jak zacząć korzystać?
Sterownik jest wspierany w wersji Kubernetes 1.15 i nowszych. Aby sterownik działał, muszą być spełnione następujące wymagania:
- Flaga
--allow-privilegedustawione na wartośćtruedla API serwera i kubelet; - Włączone
--feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truedla API serwera i kubelet; - Rozprzestrzenienie montowania () musi być włączone w klastrze. Przy użyciu Dockera demon musi być skonfigurowany tak, aby umożliwiał współdzielone obiekty montowania (shared mounts).
Wszystkie niezbędne kroki dotyczące samej instalacji . Instalacja polega na tworzeniu obiektów w Kubernetes z manifestów.
Aby używać sterownika, będziesz potrzebować następujących:
- Określ w manifeście identyfikator katalogu (
folder-id) Yandex.Cloud (); - Do interakcji z API Yandex.Cloud w sterowniku CSI używane jest konto serwisowe. W manifeście Secret należy przekazać z konta serwisowego. W dokumentacji , jak utworzyć konto serwisowe i uzyskać klucze.
Ogólnie — , a będziemy wdzięczni za wszelkie opinie i , jeśli napotkasz jakieś trudności!
Dalsze wsparcie
Na zakończenie chcielibyśmy zaznaczyć, że ten sterownik CSI realizowaliśmy nie z powodu chęci zabawy w pisanie aplikacji w Go, ale z pilnej potrzeby wewnątrz firmy. Nie uważamy, że utrzymywanie własnej realizacji ma sens, dlatego, jeśli Yandex wykaże zainteresowanie i zdecyduje się na dalsze wsparcie sterownika, z przyjemnością przekażemy repozytorium do ich dyspozycji.
Ponadto, być może Yandex ma własną realizację sterownika CSI w zarządzanym klastrze Kubernetes, którą można wydać jako Open Source. Taki rozwój dla nas również wydaje się korzystny — społeczność mogłaby korzystać z sprawdzonego sterownika od dostawcy usług, a nie od zewnętrznej firmy.
P.S.
Przeczytaj także na naszym blogu:
- «»;
- «»;
- «»;
- «».
Źródło: habr.com
