Usuwanie przestarzałej gałęzi funkcji w klastrze Kubernetes
Hi! Oddział funkcji (inaczej wdrażanie podglądu, przeglądanie aplikacji) — wtedy wdrażana jest nie tylko gałąź główna, ale także każde żądanie ściągnięcia pod unikalny adres URL. Możesz sprawdzić, czy kod działa w środowisku produkcyjnym, funkcjonalność można pokazać innym programistom lub specjalistom ds. produktu. Podczas pracy z żądaniem ściągnięcia każde nowe wdrożenie zatwierdzenia starego kodu jest usuwane i wdrażane jest nowe wdrożenie nowego kodu. Pytania mogą pojawić się, gdy połączysz żądanie ściągnięcia z gałęzią główną. Nie potrzebujesz już gałęzi funkcji, ale zasoby Kubernetes nadal znajdują się w klastrze.
Więcej o gałęziach funkcji
Jednym ze sposobów tworzenia gałęzi funkcji w Kubernetesie jest użycie przestrzeni nazw. W skrócie konfiguracja produkcyjna wygląda następująco:
W przypadku gałęzi funkcji tworzona jest przestrzeń nazw z jej identyfikatorem (na przykład numerem żądania ściągnięcia) i pewnym rodzajem przedrostka/postfiksu (na przykład -pr-):
Generalnie napisałem Operator Kubernetesa (aplikacja mająca dostęp do zasobów klastra), link do projektu na Githubie. Usuwa przestrzenie nazw należące do starych gałęzi funkcji. W Kubernetes, jeśli usuniesz przestrzeń nazw, inne zasoby w tej przestrzeni nazw również zostaną automatycznie usunięte.
$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7h
Możesz przeczytać o tym, jak wdrożyć gałęzie funkcji w klastrze tutaj и tutaj.
Motywacja
Przyjrzyjmy się typowemu cyklowi życia żądania ściągnięcia z ciągłą integracją (continuous integration):
Wrzucamy nowe zatwierdzenie do gałęzi.
Podczas kompilacji uruchamiane są lintery i/lub testy.
Konfiguracje Kubernetes pull request są generowane na bieżąco (np. ich numer wstawiany jest do gotowego szablonu).
Za pomocą kubectl Apply konfiguracje są dodawane do klastra (wdrażane).
Żądanie ściągnięcia jest scalane z gałęzią główną.
Podczas pracy z żądaniem ściągnięcia każde nowe wdrożenie zatwierdzenia starego kodu jest usuwane i wdrażane jest nowe wdrożenie nowego kodu. Kiedy jednak żądanie ściągnięcia zostanie scalone z gałęzią główną, zbudowana zostanie tylko gałąź główna. W efekcie okazuje się, że o pull requestie już zapomnieliśmy, a jego zasoby Kubernetesa nadal znajdują się w klastrze.
Jak korzystać
Zainstaluj projekt za pomocą poniższego polecenia:
Parametr przestrzeń nazwPodciąg potrzebne do filtrowania przestrzeni nazw dla żądań ściągnięcia z innych przestrzeni nazw. Na przykład, jeśli klaster ma następujące przestrzenie nazw: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, wówczas będą kandydaci do usunięcia habr-back-end-pr-17, habr-back-end-pr-33.
Parametr poDaysBez wdrożenia potrzebne do usunięcia starych przestrzeni nazw. Na przykład, jeśli utworzono przestrzeń nazw 3 дня 1 час z powrotem, a parametr wskazuje 3 дня, ta przestrzeń nazw zostanie usunięta. Działa to również w odwrotnym kierunku, jeśli utworzona jest przestrzeń nazw 2 дня 23 часа z powrotem, a parametr wskazuje 3 дня, ta przestrzeń nazw nie zostanie usunięta.
Jest jeszcze jeden parametr, który odpowiada za częstotliwość skanowania wszystkich przestrzeni nazw i sprawdzania dni bez wdrożenia - sprawdźCoMinuty. Domyślnie jest równa 30 минутам.
kubectl — interfejs wiersza poleceń do zarządzania klastrem.
Lokalnie podnosimy klaster Kubernetes:
$ minikube start --vm-driver=docker
minikube v1.11.0 on Darwin 10.15.5
Using the docker driver based on existing profile.
Starting control plane node minikube in cluster minikube.
Ponieważ konfiguracje produkcyjne są skonfigurowane do sprawdzania starych przestrzeni nazw, a nasz nowo utworzony klaster ich nie posiada, zastąpimy zmienną środowiskową IS_DEBUG na true. Przy tej wartości parametr afterDaysWithoutDeploy nie jest brany pod uwagę, a przestrzenie nazw nie są sprawdzane przez dni bez wdrożenia, tylko pod kątem wystąpienia podciągu (-pr-).
Jeśli jesteś włączony Linux:
$ sed -i 's|false|true|g' stale-feature-branch-production-configs.yml
Jeśli jesteś włączony macOS:
$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.yml
$ kubectl get pods --namespace stale-feature-branch-operator
NAME ... STATUS ... AGE
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38s
Jeśli spojrzysz na jego logi, jest on gotowy do przetwarzania zasobów StaleFeatureBranch:
Operator odpowiedział i jest gotowy do sprawdzenia przestrzeni nazw:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch is being processing.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}
zainstalować fixtures, zawierający dwie przestrzenie nazw (project-pr-1, project-pr-2) i oni deployments, services, ingress, i tak dalej:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/first-feature-branch.yml -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/second-feature-branch.yml
...
namespace/project-pr-1 created
deployment.apps/project-pr-1 created
service/project-pr-1 created
horizontalpodautoscaler.autoscaling/project-pr-1 created
secret/project-pr-1 created
configmap/project-pr-1 created
ingress.extensions/project-pr-1 created
namespace/project-pr-2 created
deployment.apps/project-pr-2 created
service/project-pr-2 created
horizontalpodautoscaler.autoscaling/project-pr-2 created
secret/project-pr-2 created
configmap/project-pr-2 created
ingress.extensions/project-pr-2 created
Sprawdzamy, czy wszystkie powyższe zasoby zostały pomyślnie utworzone:
$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
NAME ... READY ... STATUS ... AGE
pod/project-pr-1-848d5fdff6-rpmzw ... 1/1 ... Running ... 67s
NAME ... READY ... AVAILABLE ... AGE
deployment.apps/project-pr-1 ... 1/1 ... 1 ... 67s
...
Ponieważ uwzględniliśmy debug, przestrzenie nazw project-pr-1 и project-pr-2, dlatego wszystkie inne zasoby będą musiały zostać natychmiast usunięte bez uwzględnienia parametru afterDaysWithoutDeploy. Można to zobaczyć w logach operatora:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-1"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-1"}
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-2"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-2"}
Jeśli sprawdzisz dostępność zasobów, będą one miały status Terminating (proces usuwania) lub już usunięty (wyjście polecenia jest puste).
$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
Możesz powtórzyć proces tworzenia fixtures kilka razy i upewnij się, że zostaną usunięte w ciągu minuty.
Alternatywy
Co można zrobić zamiast operatora pracującego w klastrze? Podejść jest kilka, wszystkie są niedoskonałe (a ich wady są subiektywne) i każdy sam decyduje, co jest najlepsze dla konkretnego projektu:
Usuń gałąź funkcji podczas kompilacji ciągłej integracji gałęzi głównej.
Aby to zrobić, musisz wiedzieć, które żądanie ściągnięcia odnosi się do budowanego zatwierdzenia. Ponieważ przestrzeń nazw gałęzi funkcji zawiera identyfikator żądania ściągnięcia - jego numer lub nazwę gałęzi, identyfikator zawsze będzie musiał zostać określony w zatwierdzeniu.
Kompilacje gałęzi głównych kończą się niepowodzeniem. Na przykład masz następujące etapy: pobranie projektu, uruchomienie testów, zbudowanie projektu, wydanie wydania, wysłanie powiadomień, wyczyszczenie gałęzi funkcji z ostatniego żądania ściągnięcia. Jeśli kompilacja nie powiedzie się podczas wysyłania powiadomienia, konieczne będzie ręczne usunięcie wszystkich zasobów w klastrze.
Bez odpowiedniego kontekstu usunięcie gałęzi funkcji w kompilacji głównej nie jest oczywiste.
To może nie być Twoje podejście. Na przykład w Jenkins, tylko jeden typ potoku obsługuje możliwość zapisywania jego konfiguracji w kodzie źródłowym. Korzystając z webhooków, musisz napisać własny skrypt, aby je przetworzyć. Skrypt ten będzie musiał zostać umieszczony w interfejsie Jenkinsa, który jest trudny w utrzymaniu.