Zwykły deployment w Kubernetes zapewnia nam 2 strategie wdrażania, które możemy określić w polu .spec.strategy.type – RollingUpdate (opcja domyślna) i Recreate. I jest to zasadniczo wszystko, czego możemy użyć domyślnie w Kubernetes. Takie opcje mogą wystarczyć w niektórych przypadkach, zwłaszcza jeśli chcemy postawić działającą aplikacje tak szybko, jak to możliwe.
Ale co, jeśli potrzebujemy znacznie bardziej wyrafinowanej metody wdrażania? Istnieje niezliczona ilość strategii wdrażania:
- Blue-Green,
- Canary,
- Big Bang,
- Feature Toggle itd.
Oczywiście możemy skorzystać z hybryd tych metod, co daje nam jeszcze większe pole do odkrycia, niż domyślnie zapewniono w K8s. Ale jak możemy zaimplementować te strategie wdrażania bez konieczności pisania złożonych skryptów Bash, bez złożonej konfiguracji Load Balancera i wielu środowisk (lub klastrów K8s) w naszej chmurze i wreszcie bez potrzeby bardzo skomplikowanej konfiguracji routingu naszego K8s Ingressa?
Istnieje znacznie prostsze rozwiązanie tego problemu, które jest przyjazne dla Kubernetesa i umożliwi nam korzystanie z różnych dojrzałych mechanizmów wdrażania przy użyciu nawet najprostszej, jaką możesz sobie wyobrazić, konfiguracji K8s+chmura. To narzędzie nazywa się Argo Rollouts!
Najpierw przypomnijmy podstawy
Zanim wyjaśnimy sobie, czym jest Argo Rollouts i co może nam dać dzięki wykorzystaniu strategii Canary, najpierw przypomnijmy sobie, jak zachowuje się zwykły Kubernetes Deployment (z domyślną strategią RollingUpdate) podczas aktualizacji.
Weźmy poniższą definicję Deploymentu jako przykład:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 10
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: my-image:v1
ports:
- containerPort: 80
strategy: # Field added for better clarity
type: RollingUpdate
rollingUpdate:
maxSurge: 10%
maxUnavailable: 10%
Ten Deployment używa wszystkich domyślnych opcji konfiguracji strategii wdrażania, ale dla większej przejrzystości jawnie zdefiniowałem wartości w polu .spec.strategy.
Proces
Gdy go tworzymy, a następnie aktualizujemy jego Docker obraz do nowej wersji, jednocześnie rozpoczyna on uruchamianie nowych podów (replik) i usuwanie podów ze starszą wersją obrazu w równomiernych sekwencjach, a cały proces będzie wyglądał następująco:
- Początkowo mamy 10 replik, wszystkie z obrazem w wersji v1.
- Aktualizujemy tag obrazu do v2, więc Rolling Update wykonuje się zgodnie ze zdefiniowanym maxSurge i maxUnavailable.
- Tworzony jest nowy ReplicaSet, który będzie uruchamiał repliki z obrazem w wersji v2.
- Jednocześnie – nowy ReplicaSet tworzy 2 repliki z obrazem v2, a stary ReplicaSet usuwa swoją 1 starą replikę. Nowy ReplicaSet może utworzyć tylko 2 repliki w tym momencie, ponieważ maxSurge jest ustawiony na 10% (z liczby .spec.replicas), więc będziemy mieć łącznie 11 replik (9 starych replik w stanie Running i 2 nowe repliki w stanie ContainerCreating). Stary ReplicaSet (na razie) może usunąć tylko jedną replikę, ponieważ maxUnavailable jest ustawione na 10% (co najmniej 9 replik musi być w stanie Running).
- Zaraz po tym, jak repliki z nowego ReplicaSet przejdą ze stanu ContainerCreating do Running, stary ReplicaSet usunie 2 ze swoich replik, a jednocześnie nowy ReplicaSet utworzy kolejne 2 repliki), więc będziemy mieć łącznie 11 replik (7 starych replik w stanie Running, 2 nowe repliki w stanie Running i 2 nowe repliki ze stanem ContainerCreating).
- Następnie wszystkie kolejne operacje są podobne do kroku 5, aż osiągniemy 100% replik w Deploymencie w pożądanej wersji v2 (nowej) i 0% replik z poprzedniej wersji v1 (starej).
- Po wykonaniu ostatniej poprawki stary ReplicaSet jest zachowywany lub usuwany w zależności od pola .spec.revisionHistoryLimit (przy domyślnej konfiguracji pozostanie, chociaż nie będzie miał żadnych replik).
Stopniowa aktualizacja
Jest to bardzo przydatna funkcjonalność, szczególnie w porównaniu do przestarzałych metod wdrażania sprzed ery Kubernetes. Dzięki Rolling Update nie mamy przestojów w działaniu aplikacji, zamiast tego mamy stopniowe aktualizacje, w których stale coraz większy procent naszych replik jest zastępowany nowszą wersją. Możemy nawet ustawić maxUnavailable na 0, aby nie stracić żadnej pojemności (podczas wdrażania nowej wersji, zawsze będziemy mieć co najmniej taką samą liczbę uruchomionych replik, jak przed rozpoczęciem procesu aktualizacji).
To świetnie, ale co, jeśli potrzebujemy znacznie bardziej wyrafinowanej strategii wdrażania, która umożliwiłaby nam znacznie inteligentniejszą logikę w procesie wdrażania?
Teraz możemy w końcu przejść do Argo Rollouts!
Argo Rollouts oraz Canary Deployment
Argo Rollout to narzędzie open source, które zapewnia kontroler Kubernetes i zestaw CRD (np. Rollout) dla zaawansowanych strategii wdrażania. Podobnie jak Argo CD, pochodzi z projektu Argo. W tym artykule skupiam się tylko na najbardziej standardowym wykorzystaniu strategii Canary, ale możesz wykorzystać Blue-Green Deployment i wiele innych funkcji Canary Deployment, więc polecam zapoznać się z oficjalną dokumentacją po/podczas czytania tego wpisu na blogu.
W przypadku Canary Deployment masz o wiele większą kontrolę nad procesem wdrażania nowej wersji w porównaniu ze zwykłym Rolling Update. W przypadku Rolling Update proces wdrażania jest prosty, ciągły oraz równomiernie stopniowy – po prostu stopniowo zastępujemy stare repliki nowymi w tym samym tempie. W przypadku Canary Deployment tak nie jest.
Canary Deployment i górnicze kanarki
Nazwa „Canary Deployment” pochodzi od górników, którzy w przeszłości stosowali kanarki jako wczesny system ostrzegania przed szkodliwymi gazami, takimi jak tlenek węgla (CO) i metan (CH4). Kanarki ostrzegały górników o niebezpieczeństwie, zanim oni je rozpoznali. Podobnie jak górnicy węgla, inżynierowie oprogramowania chcą mieć pewność, że nowy obszar (wersja aplikacji) jest bezpieczny i może być używany na większą skalę.
Zamiast po prostu wdrażać nową wersję bez żadnej kontroli podczas procesu wdrażania, możemy wykorzystać Canary Deployment, aby początkowo uruchomić tylko kilka kontenerów w nowej wersji, tak aby tylko niektórzy użytkownicy korzystali z nowej wersji, a następnie, jeśli wszystko przebiegnie pomyślnie (testy nie wykryły błędów, a użytkownicy są zadowoleni ze zmiany), możemy przeprowadzić pełną aktualizację do nowej wersji (i ewentualnie wdrożyć kilka dodatkowych przydatnych kroków podczas procesu aktualizacji).
Możesz np. początkowo zastąpić 10% swoich replik w nowej wersji i przekierować 10% ruchu produkcyjnego do tej nowej wersji. Następnie możesz ustawić czas oczekiwania lub manualną bramkę (czekanie na ręczne potwierdzenie), a w międzyczasie uruchomić zautomatyzowane testy, które będą szukać problemu w nowej wersją. Następnie, jeśli testy zakończą się powodzeniem, minie odpowiednia ilość czasu lub zostanie zatwierdzona ręczna bramka, skalujemy np. do 30% replik (i skierowanego ruchu) w nowej wersji i 70% ze starej wersji, następnie odczekaj jakiś czas, a następnie przeskaluj do połowy replik w nowej wersji, a na koniec przeskaluj do 100% replik w nowej wersji.
To tylko jedna z nieskończonej liczby możliwych konfiguracji, które możesz skonfigurować za pomocą Canary Deployment i Argo Rollouts. Argo Rollout oferuje ogromną liczbę funkcji, które zaspokoją potrzeby procesu wdrażania. Możesz np. manipulować ilością ruchu przy użyciu 2 serwisów K8s i kontrolera K8s Ingress dla lepszej izolacji wersji i niezależności od liczby replik oraz kierowanego do nich ruchu (np. 10% replik w nowej wersji, ale tylko 5% ruchu kierowanego do tych replik).
Co wybrać?
Jak widać, Canary Deployment jest o wiele bardziej wszechstronną strategią wdrażania w porównaniu z Rolling Update. Nie mówię, że jest ona lepsza lub gorsza. Rzadko coś w inżynierii jest po prostu lepsze lub gorsze. Jeśli jedna z twoich aplikacji działających w K8s nie wymaga wdrożenia Canary, ponieważ np. jest stosunkowo prosta, ma bardzo częste i drobne aktualizacje oraz nie wymaga kompleksowej walidacji przy każdej aktualizacji do nowej wersji, wdrożenie Canary byłoby bez wątpienia przerostem formy ponad treścią i powinieneś pozostać przy domyślnym Rolling Update.
Jednak jeśli Twoja aplikacja może skorzystać z podejścia Canary Deployment, zdecydowanie powinieneś rozważyć jego wdrożenie, szczególnie przy użyciu Argo Rollouts.
Jeśli jesteś inżynierem DevOps lub kimś powiązanym z nowoczesnym cloud-native oraz konteneryzacją, to jest duże prawdopodobieństwo, że już słyszałeś o Argo CD. Jeśli tak, to dobrze, ponieważ pomoże ci to zrozumieć, czym jest Argo Rollouts. Oba te narzędzia mają zupełnie inny cel, ale pod względem sposobu fundamentalnego działania są bardzo podobne – oba są open-source kodem Golang, który możemy zainstalować (wraz z dedykowanym narzędziem CLI), aby wykorzystać nowy kontroler Kubernetes i zbiór CRDs do celów związanych z wdrażaniem w naszym klastrze K8s.
Najważniejszy koncept w Argo Rollouts – Rollout
Najważniejszym konceptem w Argo Rollout jest CRD zwany „Rollout”. Ten „nowy” obiekt nie jest tak nowy, jak mogłoby się wydawać, ponieważ Rollout to w zasadzie zwykły K8s Deployment z wieloma przydatnymi funkcjonalnościami wdrażania, które są w niego wbudowane.
Zobaczmy przykładową definicję obiektu Rollout:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: nginx-rollout
labels:
app: nginx
spec:
replicas: 10
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: my-image:v1
ports:
- containerPort: 80
strategy:
canary:
maxSurge: '10%'
maxUnavailable: '10%'
steps:
- setWeight: 30
- pause:
duration: 30m
- setWeight: 40
- pause:
duration: 1h
- pause: {}
# We don't need to explicitly specify below line because it's the default behavior
# - setWeight: 100
Rollout a Deployment
Jak widać, definicja Rolloutu jest prawie taka sama jak definicja Deploymentu, z trzema różnicami:
- .apiVersion: – musimy użyć argoproj.io/v1alpha1 zamiast apps/v1,
- .kind: – musimy użyć Rollout zamiast Deployment,
- .spec.strategy: – zamiast określać strategię wdrożenia w polu .spec.strategy.type i ewentualnie skonfigurowanie opcji Rolling Update w polu .spec.strategy.rollingUpdate, mamy możliwość wyboru między opcjami canary i blueGreen oraz określenia opcji konfiguracji w tych nowych polach.
Zasadniczo, wszystko jest takie samo jak w Deployment – z jedyną poważną różnicą w konfiguracji strategii wdrożenia. To świetna wiadomość dla wszystkich, którzy nie mają czasu na walkę z pisaniem jakiegoś customowego manifestu CRD od zera, zwłaszcza jeśli chcesz użyć tego niestandardowego zasobu jako zamiennika dla Deploymentu, który jest bezsprzecznie jednym z najważniejszych obiektów w klastrach K8s.
Dzięki Argo Rollouts możesz po prostu zainstalować Argo Rollouts (zajmiemy się tym za chwilę), zmienić .apiVersion, .kind i dodać np. pole .spec.strategy.canary z {} jako wartością, i to wszystko! Jeśli nawet nie musisz niczego określać w polu .spec.strategy.canary, ponieważ jeśli nic nie określisz w tym polu, twój Rollout będzie zachowywać się dokładnie tak jak zwykły Deployment.
Ale oczywiście na pewno chcesz wykorzystać funkcje, które zapewnia Rollout, jeśli zdecydowałeś się zainstalować Argo Rollouts, więc nie zostawiaj tego pola pustego 😉
Pole .spec.strategy
Teraz wyjaśnijmy, co dzieje się w polu .spec.strategy w przykładzie, który tutaj pokazałem:
...
strategy:
canary:
maxSurge: '10%'
maxUnavailable: '10%'
steps:
- setWeight: 30
- pause:
duration: 30m
- setWeight: 40
- pause:
duration: 1h
- pause: {}
Najpierw określamy, że chcemy użyć strategii wdrożenia Canary, a następnie opcjonalnie określamy parametry maxSurge i maxUnavailable, które działają dokładnie tak samo, jak w przypadku zwykłego Deploymentu. W tym przypadku maxSurge zapewnia, że w stanie Running lub ContainerCreating nie będzie nigdy więcej niż 11 replik (łącznie), a maxUnavailable zapewnia, że zawsze będzie uruchomionych co najmniej 9 replik.
Następnie określamy nasze kroki wdrażania, które definiują zachowanie Rollout podczas aktualizacji do nowej wersji.
Aktualizacja poda do nowej wersji
Oto wyjaśnienie krok po kroku, co się stanie, gdy zaktualizujemy poda do nowej wersji:
- Początkowo mamy 10 replik w pojedynczym ReplicaSet z obrazem w wersji v1.
- Aktualizujemy wersję obrazu do v2
- Pierwszy krok jest wykonywany – 1 replika jest usuwana ze starego ReplicaSet (z rewizją:1) i jednocześnie tworzony jest nowy ReplicaSet (z rewizją:2) z 2 replikami w stanie ContainerCreating, więc będziemy mieć 9 działających replik (wszystkie ze starego ReplicaSet) i 11 replik w stanie Running lub ContainerCreating (łącznie). To jest dokładnie to, czego oczekujemy od naszej konfiguracji pól i maxUnavailable i maxSurge.
- Zaraz po tym, jak jedna z replik z nowego ReplicaSet przejdzie ze stanu ContainerCreating do Running, tworzona jest nowa replika w nowym ReplicaSet, a jednocześnie inna replika ze starego ReplicaSet zostaje usunięta, więc będziemy mieć 9 działających replik (1 z nowego ReplicaSet i 8 ze starego ReplicaSet) i 11 replik w stanie Running lub ContainerCreating (łącznie).
- Zaraz po tym, jak inna replika z nowego ReplicaSet przejdzie ze stanu ContainerCreating do Running, inna replika ze starego ReplicaSet zostanie usunięta, więc będziemy mieć 9 działających replik (2 z nowego ReplicaSet i 7 ze starego ReplicaSet) i 11 replik w stanie Running lub ContainerCreating (łącznie).
- Zaraz po tym, jak kolejna replika z nowego ReplicaSet przejdzie ze stanu ContainerCreating do Running, kolejna replika ze starego ReplicaSet zostaje zakończona, więc będziemy mieć 10 działających replik (3 z nowego ReplicaSet i 7 ze starego ReplicaSet) i 10 replik w stanie Running, więc pierwszy krok został zakończony – mamy 30% działających replik z nowego ReplicaSet i 30% ruchu jest kierowane do tych nowych replik.
- Drugi krok jest wykonywany – Rollout czeka 30 minut (brak zmian w liczbie replik).
- Trzeci krok jest wykonywany – 1 replika jest usunięta ze starego ReplicaSet i w tym samym czasie 1 replika jest tworzona w nowym ReplicaSet (i jest w stanie ContainerCreating).
- Gdy replika z nowego ReplicaSet przechodzi ze stanu ContainerCreating do Running, trzeci krok się kończy, ponieważ mamy 40% działających replik z nowego ReplicaSet i 40% ruchu jest kierowane do tych nowych replik.
- Czwarty krok jest wykonywany – Rollout czeka 1 godzinę (brak zmian w liczbie replik).
- Piąty krok jest wykonywany – Rollouty czeka na manualą promocję. Jest to ważny krok, który implementuje ręczną bramę do naszego procesu wdrażania. Ten krok jest ostatnim zdefiniowanym w tym manifeście, więc jest ostatnim krokiem przed aktualizacją naszego Rollout do 100% nowych replik. Teraz powinniśmy przejść do interfejsu naszej aplikacji, prawdopodobnie wykonać kilka testów i upewnić się, że naprawdę chcemy zaktualizować do nowej wersji. Jeśli wszystko wygląda dobrze, możemy promować Rollout, np. używając polecenia kubectl argo rollouts promote nginx-rollout (za chwilę pokażę, jak zainstalować to polecenie).
- Na koniec wykonywany jest ostatni krok – aktualizacja do 100% replik z nowego ReplicaSet i usunięcie wszystkich replik ze starego ReplicaSet (oczywiście w zgodzie z polami maxSurge i maxUnavailable). Ten krok zostanie wykonany niezależnie od tego, czy go określimy, czy nie.
Instalacja
To był prosty przykład użycia Rollout. Teraz przejdźmy przez proces instalacji, abyś mógł przetestować ten przykład na własnym klastrze!
Najpierw uruchom te 2 polecenia, aby zainstalować Argo Rollouts Controller i CRD:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
Teraz możesz już wdrożyć swoją pierwszą instancję Rollout, ale zdecydowanie dobrym pomysłem będzie najpierw zainstalowanie kilku dodatkowych rzeczy.
Po pierwsze, polecam żebyś zainstalował Argo Rollouts plugin for kubectl, która umożliwia promowanie wdrożeń, wizualizację procesu aktualizacji wdrożeń, przeglądanie Argo Rollouts Dashboard, i ogólnie pozwala pracować wydajniej z obiektami Rollout. Ponadto, możesz chcieć zainstalować shell auto-completion for Argo Rollouts.
Po zainstalowaniu całego potrzebnego oprogramowania, prawdopodobnie powinieneś sam pobawić się Argo Rollouts. Możesz użyć przykładu, który już tutaj pokazałem, lub przykładu, który pokażę za chwilę, albo poszukać innych dostępnych w Internecie (oficjalne przykłady z GitHub mogą być dobrym punktem wyjścia).
Zalecam otwieranie co najmniej dwóch okien terminala jednocześnie – jednego, w którym będziesz wykonywał polecenia takie jak np. kubectl apply, i drugiego, w którym będziesz uruchamiał polecenie kubectl argo rollouts get rollout nginx-rollout –watch. Dzięki temu będziesz na bieżąco ze wszystkim, co dzieje się podczas wdrażania (jak przebiega proces).
Zautomatyzowane testy skonfigurowane w procesie wdrażania
Teraz przejdźmy do znacznie ciekawszego przykładu, który pokaże ci jedną z najważniejszych zalet Argo Rollouts – automatyczne testy, które są uruchamiane podczas procesu wdrażania. Ręczne bramki, przestoje czasowe i elastyczność ustawiania ilości aktualizowanych replik na każdym etapie wdrożenia to bardzo przydatne funkcjonalności, ale nie tak przełomowe jak funkcjonalność Argo Rollouts, którą omówimy teraz.
Argo Rollouts pozwala nam definiować naprawdę kompleksowe testy, które będą oparte np. na metrykach z twojego rozwiązania monitorującego (np. Prometheus), które przetestują nową wersję (rewizję) twojego Rollout i na podstawie wyników testów zdecydują, czy kontynuować proces wdrażania, czy powrócić do poprzedniej wersji – wszystko w pełni zautomatyzowany sposób!
Dwa manifesty
Zobaczmy przykład z 2 manifestami. Jeden z Rollout, a drugi z nowym zasobem – AnalysisTemplate. AnalysisTemplate definiuje sposób wykonywania analizy kanarkowej, takiej jak metryki, które powinna wykonać, jej częstotliwość i wartości, które są uważane za udane lub nieudane.
rollout.yml (z polem .spec uproszczonym dla lepszej czytelności):
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: guestbook
spec:
# ...
strategy:
canary:
analysis:
templates:
- templateName: success-rate
startingStep: 2 # Delay starting analysis run until setWeight: 40%
args:
- name: service-name
value: guestbook-svc.default.svc.cluster.local
steps:
- setWeight: 20
- pause: {duration: 10m}
- setWeight: 40
- pause: {duration: 10m}
- setWeight: 60
- pause: {duration: 10m}
- setWeight: 80
- pause: {duration: 10m}
analysis-template.yml:
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
args:
- name: service-name
metrics:
- name: success-rate
interval: 5m
# NOTE: Prometheus queries return results in the form of a vector.
# So it is common to access the index 0 of the returned array to obtain the value
successCondition: result[0] >= 0.95
failureLimit: 3
provider:
prometheus:
address: http://prometheus.example.com:9090
query: |
sum(irate(
istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
)) /
sum(irate(
istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
))
W definicji Rollout możemy zobaczyć, że określamy AnalysisTemplate, który zostanie użyty do naszego Rollout. Ponadto wyraźnie określamy nazwę usługi FQDN i to wszystko, co jest nowe, ale definicja AnalysisTemplate jest czymś zupełnie nowym. W pliku analysis-template.yml określamy konfigurację AnalysisTemplate, taką jak:
- interwał,
- warunek powodzenia,
- limit niepowodzeń,
- konfiguracja dostawcy.
Należy pamiętać, że aby użyć tego przykładu, musisz już mieć działającego Prometheusa.
Nasz AnalysisTemplate rozpocznie testowanie od drugiego kroku i będzie wykonywał zapytanie Prometheusa (wyrażenie PromQL) co 5 minut, aby sprawdzić, czy współczynnik powodzenia wynosi co najmniej 95%, a jeśli warunek nie zostanie spełniony 3 razy (wystąpią 3 lub więcej niepowodzeń), nowa wersja (ReplicaSet) zostanie wycofana (zeskalowana do 0%), a poprzednia wersja zostanie ponownie zeskalowana do 100%, zaś całe Rollout pozostanie w stanie Degraded (do momentu ponownej aktualizacji Rollout).
To świetna funkcjonalność – absolutnie zero ręcznych operacji, nasze wdrożenie jest wykonywane automatycznie z ciągłymi testami, a jeśli coś jest nie tak, po prostu wrócimy do poprzedniej (i prawie na pewno działającej) wersji! Wyobraź sobie, ile możesz zrobić dzięki tym testom.
Możesz bazować na:
- dowolnych metrykach (opóźnienie, wskaźnik sukcesu, itp.),
- dowolnych logach,
- rezultatach z aplikacji.
Możliwości są praktycznie nieograniczone.
Same metryki Prometheusa dostarczą Ci bardzo przydatnych informacji o potencjalnych problemach z nową wersją twojej aplikacji, ale nie jesteś ograniczony do Prometheusa – możesz używać Datadog, NewRelic, AWS CloudWatch, a nawet skonfigurować K8s Jobs lub skonfigurować żądanie HTTP, które będzie szukać określonych pomiarów!
AnalysisTemplate to prawdziwa moc Argo Rollouts i jestem bliski stwierdzenia, że jest to najbardziej przydatna funkcja tego narzędzia, więc jeśli już zdecydowałeś, że chcesz wdrożyć Argo Rollouts ze względu na jakąś inną jego funkcjonalność, to gorąco polecam wgłębić się w Analysis in Argo Rollouts.
Argo Rollouts wraz z Argo CD
Pozostała jedna rzecz, o której zdecydowanie warto wspomnieć – jak Argo Rollouts i Argo CD współpracują ze sobą, gdy są używane na tych samych K8s workloads?
Oba te narzędzia pochodzą z tego samego projektu Argo, więc jak można się spodziewać, mają świetną integrację. Oba mogą być używane bez używania drugiego (jako samodzielne narzędzia), ale w większości nowoczesnych konfiguracji K8s będziesz chciał zaimplementować Argo CD, oraz w zależności od pożądanej strategii wdrażania, możesz również zaimplementować Argo Rollout.
Oczywiście wszystko wydaje się jasne w przypadku pomyślnego wdrożenia – mamy aktualizacje obrazu w zdalnym repozytorium -> Argo CD to zauważa i rozpoczyna synchronizację -> Argo Rollout wykonuje aktualizację (która jest pomyślna) -> mamy nową wersję działającą w klastrze.
Czy grozi nam nieskończona pętla?
A co z sytuacją, gdy AnalysisTemplate zawiedzie, a proces wdrażania zostanie przerwany przez Rollout, ponieważ nowa wersja obrazu ma błąd? Czy wpadniemy w nieskończoną pętlę, w której Argo CD nieustannie próbuje zsynchronizować stan ze zdalnego repozytorium, a jednocześnie Argo Rollout raz po raz zawodzi? Na szczęście tak się nie stanie. Argo CD jest świadome stanu Degraded naszego Rollout i nie podejmie żadnych dalszych działań, jeśli ten stan wystąpi, więc zamiast wykonać nadpisanie, po prostu wyświetli status Out of Sync.
To świetnie, ale co powinniśmy zrobić w przypadku takiej sytuacji? Jest co najmniej kilka sposobów, aby sobie z tym poradzić.
Uważam, że jeśli już używasz podejścia GitOps w swoim SDLC, powinieneś trzymać się wartości tej filozofii i użyć polecenia git revert, aby cofnąć commit, który spowodował problem w najnowszej wersji, tak aby po wykonaniu pusha, twoje repozytorium git odzwierciedliło pożądany stan. Argo CD zauważy tę szansę i automatycznie zaktualizuje klaster, więc skończysz z repozytorium i klastrem K8s, które są ponownie zsynchronizowane, a Rollout jest stabilny i zdrowy (choć z poprzednią wersją).
Ostatecznie możesz po prostu pushnąć nową zmianę z poprawką buga, zamiast używać git revert, ale ta akcja oczywiście zakłada, że wiesz, jak naprawić problem, już go naprawiłeś i masz nowy kontener Docker gotowy do użycia. Często, gdy Rollout „wywali się” podczas procesu wdrażania, najpierw chcesz przywrócić poprzednią wersję (używając git revert), aby jak najszybciej zminimalizować zakłócenia w aplikacji, a następnie spróbować faktycznie naprawić problem i spróbować wdrożyć ponownie.

Podsumowanie
Argo Rollouts może być świetnym rozwiązaniem, jeśli potrzebujesz implementacji bardziej zaawansowanej strategii wdrażania (takiej jak Canary), zamiast polegać na domyślnej aktualizacji Rolling Update w Kubernetes Deployment. Ponadto pamiętaj, że prawdopodobnie najważniejszymi zaletami Argo Rollouts są automatyczne testy i wycofania aktualizacji (automatyczny powrót do poprzedniej wersji), więc nie zapomnij o mocy tych funkcjonalności.
Zwróć również uwagę, że wdrożenie tego nowego narzędzia do twojego klastra nie powinno być zbyt skomplikowane, ponieważ dokumentacja jest przejrzysta, zawiera kilka dobrych przykładów, a społeczność DevOps stworzyła już wiele świetnych przewodników na z Argo CD w roli głównej. Nie powinieneś również mieć problemu ze znalezieniem odpowiedniego problemu na GitHubie lub pytania na Stack Overflow, jeśli napotkasz jakiś problem podczas pracy z Argo Rollouts.
Na koniec, naprawdę ważna kwestia – zawsze pamiętaj, aby przeanalizować i upewnić się, że faktycznie potrzebujesz takiego narzędzia. Nie próbuj wdrażać czegoś, co nie jest ci potrzebne. Nadmierna inżynieria (overengineering) to jedna z największych pułapek dla każdego inżyniera (nie tylko inżynierów DevOps), więc zawsze staraj się kwestionować swoje wymagania, zamiast tworzyć lub akceptować pracę, która nie przynosi rzeczywistej wartości (wartości biznesowej lub innego rodzaju).
Niemniej, jeśli widzisz prawdziwe korzyści we Canary Deployment w przypadku twojej aplikacji, to Argo Rollouts czeka na Ciebie!
***
Jeśli interesują Cię narzędzia stosowane w IT, zajrzyj koniecznie również do innych artykułów naszych ekspertów 🙂
Zostaw komentarz