Kubernetes ma kilka opcji aktualizacji zasobów: zastosuj, edytuj, łataj i zastępuj. Istnieje zamieszanie co do tego, co każdy z nich robi i kiedy ich używać. Rozwiążmy to.
jeśli kubectl patch
, co nie obejmuje porównania apply
и patch
. W tym artykule przyjrzymy się różnym opcjom, a także właściwemu wykorzystaniu każdej z nich.
Podczas cyklu życia zasobu Kubernetes (usługa, wdrożenie, ruch przychodzący itp.) czasami trzeba zmienić, dodać lub usunąć niektóre właściwości tego zasobu. Na przykład dodaj notatkę, zwiększ lub zmniejsz liczbę replik.
Interfejs wiersza polecenia Kubernetesa
Jeśli już pracujesz z klastrami Kubernetes za pośrednictwem interfejsu CLI, jest to już Ci znane apply
и edit
. Zespół apply
odczytuje specyfikację zasobu z pliku i dokonuje „upsert” do klastra Kubernetes, czyli tzw. tworzy zasób, jeśli nie istnieje i aktualizuje go, jeśli istnieje. Zespół edit
odczytuje zasób poprzez API, następnie zapisuje specyfikację zasobu do pliku lokalnego, który następnie jest otwierany w edytorze tekstu. Po edycji i zapisaniu pliku, kubectl
wyśle wprowadzone zmiany z powrotem przez API, które ostrożnie zastosuje te zmiany do zasobu.
Nie każdy zna polecenia patch
и replace
. Zespół patch
umożliwia zmianę części specyfikacji zasobu, udostępniając w wierszu poleceń tylko zmienioną część. Zespół replace
działa tak samo jak edit
, ale wszystko trzeba zrobić ręcznie: trzeba pobrać aktualną wersję specyfikacji zasobu, na przykład za pomocą kubectl get -o yaml
, edytuj go, a następnie użyj replace
zaktualizować zasób zgodnie ze zmienioną specyfikacją. Zespół replace
nie będzie działać, jeśli między odczytaniem a zastąpieniem zasobu nastąpiły jakiekolwiek zmiany.
API Kubernetesa
Prawdopodobnie znasz te metody CoreV1().Pods().Update()
, replaceNamespacedService
lub patch_namespaced_deployment
, jeśli pracujesz z klastrami za pośrednictwem PUT
и PATCH
... W którym update
и replace
posługiwać się PUT
I patch
, bez względu na to, jak trywialne może to być, używa PATCH
.
Należy zauważyć, że kubectl
współpracuje również z klastrami poprzez API. Innymi słowy, kubectl
to opakowanie na bibliotekę klienta dla języka Go, które w dużej mierze zapewnia możliwość dostarczania podpoleceń w bardziej zwartej i czytelnej formie, oprócz standardowych możliwości API. Na przykład, jak być może już zauważyłeś, metoda apply
nie zostało wspomniane powyżej w poprzednim akapicie. Obecnie (maj 2020, około. tłumacz) cała logika kubectl apply
, tj. tworzenie nieistniejących zasobów i aktualizacja istniejących, działa całkowicie po stronie kodu kubectl
. Podejmowane są wysiłki apply
po stronie API, ale nadal jest w fazie beta. Poniżej napiszę szerzej.
Domyślnie łatka
Najlepiej używany patch
, jeśli chcesz zaktualizować zasób. W ten sposób obie biblioteki klienckie działają na interfejsie Kubernetes API i kubectl
(nic dziwnego, ponieważ jest to opakowanie biblioteki klienta, około. tłumacz).
Pracuj strategicznie
Wszystkie drużyny kubectl
apply
, edit
и patch
użyj metody PATCH
w żądaniach HTTP w celu aktualizacji istniejącego zasobu. Jeśli bardziej szczegółowo zagłębisz się w implementację poleceń, wszystkie z nich zastosują to podejście patch
może zastosować inne podejścia (więcej na ten temat poniżej). Podejście polegające na łataniu strategicznego łączenia ma na celu „zrobienie tego dobrze” poprzez połączenie dostarczonej specyfikacji z istniejącą specyfikacją. Mówiąc dokładniej, próbuje połączyć zarówno obiekty, jak i tablice, co oznacza, że zmiany mają charakter addytywny. Na przykład uruchomienie polecenia patch
z nową zmienną środowiskową w specyfikacji kontenera pod, powoduje, że ta zmienna środowiskowa zostanie dodana do istniejących zmiennych środowiskowych, zamiast je zastępować. Aby usunąć przy użyciu tego podejścia, należy wymusić wartość parametru na null w podanej specyfikacji. Która z drużyn kubectl
Czy najlepiej używać go do aktualizacji?
Jeśli tworzysz i zarządzasz swoimi zasobami za pomocą kubectl apply
, podczas aktualizacji lepiej zawsze używać kubectl apply
Do kubectl
może zarządzać konfiguracją i właściwie śledzić żądane zmiany w poszczególnych aplikacjach. Zaleta zawsze używana apply
polega na tym, że śledzi wcześniej zastosowaną specyfikację, dzięki czemu wie, kiedy właściwości specyfikacji i elementy tablicy są jawnie usuwane. Dzięki temu możesz korzystać apply
aby usunąć właściwości i elementy tablicy, podczas gdy normalne scalanie strategiczne nie będzie działać. Zespoły edit
и patch
nie aktualizuj tego kubectl apply
używa do śledzenia swoich zmian, więc wszelkie zmiany, które są śledzone i wprowadzane za pośrednictwem interfejsu API Kubernetes, ale wprowadzane za pomocą poleceń edit
и patch
, niewidoczny dla kolejnych poleceń apply
Oznacza to, że apply
nie usuwa ich, nawet jeśli nie pojawiają się w specyfikacji wejściowej dla apply
(Dokumentacja tak mówi edit
и patch
dokonaj aktualizacji używanych notatek apply
, ale w praktyce - nie).
Jeśli nie użyjesz polecenia apply
, może być używany jako edit
I patch
, wybierając polecenie, które najlepiej pasuje do wprowadzanej zmiany. Podczas dodawania i zmiany właściwości BOM oba podejścia są mniej więcej takie same. Podczas usuwania właściwości specyfikacji lub elementów tablicy edit
zachowuje się jak jednorazowe uruchomienie apply
, w tym śledzenie, jak wyglądała specyfikacja przed i po edycji, dzięki czemu można jawnie usuwać właściwości i elementy tablicy z zasobu. Należy jawnie ustawić wartość właściwości na null w specyfikacji patch
aby usunąć go z zasobu. Usuwanie elementu tablicy za pomocą łatki polegającej na łączeniu strategicznym jest bardziej złożone, ponieważ wymaga użycia dyrektyw scalających. Zobacz inne metody aktualizacji poniżej, aby uzyskać bardziej opłacalne alternatywy.
Aby zaimplementować metody aktualizacji w bibliotece klienta, które zachowują się podobnie do powyższych poleceń kubectl
, należy ustawić w żądaniach content-type
в application/strategic-merge-patch+json
. Jeśli chcesz usunąć właściwości w specyfikacji, musisz jawnie ustawić ich wartości na null w podobny sposób kubectl patch
. Jeśli chcesz usunąć elementy tablicy, powinieneś uwzględnić dyrektywy scalające w specyfikacji aktualizacji lub zastosować inne podejście do aktualizacji.
Inne podejścia do aktualizacji
Kubernetes obsługuje dwa inne podejścia do aktualizacji: kubectl patch --type=merge
. Pracując z API Kubernetes warto skorzystać z metody request PATCH
i instalacja content-type
в application/merge-patch+json
.
Metoda łatek JSON zamiast dostarczać częściową specyfikację zasobu, wykorzystuje dostarczanie zmian, które chcesz wprowadzić w zasobie, w postaci tablicy, w której każdy element tablicy reprezentuje opis zmiany wprowadzanej w zasobie. Takie podejście jest bardziej elastycznym i wydajnym sposobem wyrażania wprowadzanych zmian, ale kosztem wyszczególnienia wprowadzanych zmian w osobnym formacie innym niż Kubernetes, zamiast wysyłania częściowej specyfikacji zasobów. W kubectl
możesz wybrać łatkę JSON za pomocą kubectl patch --type=json
. W przypadku korzystania z interfejsu API Kubernetes to podejście działa przy użyciu metody żądania PATCH
i instalacja content-type
в application/json-patch+json
.
Potrzebujemy zaufania - użyj zamiany
W niektórych przypadkach należy się upewnić, że między odczytaniem zasobu a jego aktualizacją nie wprowadzono żadnych zmian w zasobie. Innymi słowy, powinieneś upewnić się, że wszystkie zmiany zostaną atomowy. W takim przypadku do aktualizacji zasobów należy użyć replace
. Na przykład, jeśli masz ConfigMap z licznikiem aktualizowanym przez wiele źródeł, powinieneś upewnić się, że dwa źródła nie aktualizują licznika w tym samym czasie, co spowoduje utratę aktualizacji. Aby to zademonstrować, wyobraź sobie sekwencję zdarzeń, stosując to podejście patch
:
- A i B pobierają bieżący stan zasobu z interfejsu API
- Każdy z nich lokalnie aktualizuje specyfikację, zwiększając licznik o jeden, a także dodając odpowiednio „A” lub „B” do notatki „zaktualizowany przez”
- I aktualizuje zasób nieco szybciej
- B aktualizuje zasób
W rezultacie aktualizacja A zostanie utracona. Ostatnia operacja patch
wygrywa, licznik jest zwiększany o jeden zamiast o dwa, a wartość notatki „zaktualizowany przez” kończy się na „B” i nie zawiera „A”. Porównajmy powyższe z tym, co dzieje się, gdy aktualizacje są wykonywane przy użyciu tego podejścia replace
:
- A i B pobierają bieżący stan zasobu z interfejsu API
- Każdy z nich lokalnie aktualizuje specyfikację, zwiększając licznik o jeden, a także dodając odpowiednio „A” lub „B” do notatki „zaktualizowany przez”
- I aktualizuje zasób nieco szybciej
- B próbuje zaktualizować zasób, ale aktualizacja zostaje odrzucona przez API, ponieważ wersja zasobu jest podana w specyfikacji
replace
nie pasuje do bieżącej wersji zasobu w Kubernetesie, ponieważ wersja zasobu została zwiększona w wyniku operacji zamiany A.
W powyższym przypadku B będzie musiał ponownie pobrać zasób, wprowadzić zmiany w nowym stanie i spróbować ponownie replace
. Spowoduje to zwiększenie licznika o dwa i notatkę „zaktualizowany przez” zawierającą „AB” na końcu.
Powyższy przykład sugeruje, że podczas wykonywania replace
Cały zasób zostaje całkowicie zastąpiony. Specyfikacja używana do replace
, nie może być częściowe lub w częściach jak w apply
, ale kompletne, łącznie z dodatkiem resourceVersion
w metadanych specyfikacji. Jeśli nie włączyłeś resourceVersion
lub podana przez Ciebie wersja jest nieaktualna, zamiennik zostanie odrzucony. Najlepszym podejściem jest więc użycie replace
– przeczytaj zasób, zaktualizuj go i natychmiast zastąp. Za pomocą kubectl
, może to wyglądać tak:
$ kubectl get deployment my-deployment -o json
| jq '.spec.template.spec.containers[0].env[1].value = "new value"'
| kubectl replace -f -
Warto zauważyć, że następujące dwa polecenia, wykonane sekwencyjnie, zostaną wykonane pomyślnie, ponieważ deployment.yaml
nie zawiera własności .metadata.resourceVersion
$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml
Wydawałoby się to sprzeczne z tym, co zostało powiedziane powyżej, tj. „dodawanie resourceVersion
w metadane specyfikacji.” Czy to niewłaściwe stwierdzenie? Nie, nie jest, ponieważ if kubectl
uwagi, których nie określiłeś resourceVersion
, odczyta go z zasobu i doda do określonej specyfikacji, a dopiero potem wykona replace
. Ponieważ jest to potencjalnie niebezpieczne, jeśli polegasz na atomowości, magia działa całkowicie na boku kubectl
, nie należy na nim polegać podczas korzystania z bibliotek klienckich współpracujących z interfejsem API. W takim przypadku będziesz musiał przeczytać aktualną specyfikację zasobu, zaktualizować ją, a następnie wykonać PUT
żądanie.
Nie możesz zrobić łatki – my dokonujemy wymiany
Czasami trzeba wprowadzić pewne zmiany, których API nie może obsłużyć. W takich przypadkach można wymusić wymianę zasobu, usuwając go i tworząc ponownie. Odbywa się to za pomocą kubectl replace --force
. Uruchomienie polecenia natychmiast usuwa zasoby, a następnie odtwarza je na podstawie dostarczonej specyfikacji. W API nie ma procedury obsługi „wymuszonej zamiany” i aby to zrobić poprzez API, należy wykonać dwie operacje. Najpierw musisz usunąć zasób, ustawiając go gracePeriodSeconds
do zera (0) i propagationPolicy
w „Tło”, a następnie utwórz ponownie ten zasób z żądaną specyfikacją.
Ostrzeżenie: takie podejście jest potencjalnie niebezpieczne i może prowadzić do nieokreślonego stanu.
Zastosuj po stronie serwera
Jak wspomniano powyżej, programiści Kubernetes pracują nad wdrożeniem logiki apply
z kubectl
w API Kubernetesa. Logika apply
dostępne w Kubernetes 1.18 poprzez kubectl apply --server-side
lub poprzez API przy użyciu metody PATCH
с content-type
application/apply-patch+YAML
.
Uwaga: JSON jest również prawidłowym YAML, więc możesz wysłać specyfikację jako JSON, nawet jeśli
content-type
wolaapplication/apply-patch+yaml
.
Poza tą logiką kubectl
staje się dostępny dla każdego poprzez API, apply
po stronie serwera śledzi, kto jest odpowiedzialny za pola w specyfikacji, umożliwiając w ten sposób bezpieczny wielokrotny dostęp w celu bezkonfliktowej edycji. Innymi słowy, jeśli apply
po stronie serwera staną się bardziej powszechne, pojawi się uniwersalny, bezpieczny interfejs do zarządzania zasobami dla różnych klientów, na przykład kubectl, Pulumi czy Terraform, GitOps, a także samodzielnie napisane skrypty korzystające z bibliotek klienckich.
Wyniki
Mam nadzieję, że ten krótki przegląd różnych sposobów aktualizacji zasobów w klastrach był dla Ciebie pomocny. Warto wiedzieć, że nie chodzi tylko o zastosowanie i zamianę, ale także o aktualizację zasobu poprzez zastosowanie, edycję, łatanie lub zamianę. Przecież w zasadzie każde podejście ma swój własny obszar zastosowania. W przypadku zmian atomowych preferowana jest zamiana; w przeciwnym razie powinieneś użyć łatki scalającej strategicznie poprzez zastosowanie. Przynajmniej oczekuję, że zrozumiesz, że nie możesz ufać Google ani StackOerflow, gdy szukasz „kubernetes zastosuj vs zamień”. Przynajmniej do czasu, gdy ten artykuł zastąpi obecną odpowiedź.
Źródło: www.habr.com