Jak Dark wdraża kod w 50 ms

Jak Dark wdraża kod w 50 ms

Im szybszy proces rozwoju, tym szybciej rozwija się firma technologiczna.

Niestety, współczesne aplikacje działają przeciwko nam – nasze systemy muszą być aktualizowane w czasie rzeczywistym, nie zakłócając przy tym pracy i nie prowadząc do przestojów. Wdrażanie w takich systemach staje się trudnym zadaniem i wymaga skomplikowanych pipeline'ów ciągłej dostawy, nawet w małych zespołach.

Te pipeline'y mają zwykle wąskie zastosowanie, działają wolno i nie są niezawodne. Deweloperzy muszą je najpierw ręcznie stworzyć, a potem nimi zarządzać, a firmy często zatrudniają do tego całe zespoły DevOps.

Szybkość tych pipeline'ów wpływa na szybkość rozwoju. U najlepszych zespołów wdrożenie zajmuje 5–10 minut, ale zazwyczaj wszystko trwa znacznie dłużej, a jedno wdrożenie wymaga kilku godzin.

W Dark zajmuje to 50 ms. Pięćdziesiąt. Milisekund.. Dark — to kompleksowe rozwiązanie z językiem programowania, edytorem i infrastrukturą, zaprojektowane specjalnie do ciągłej dostawy, a wszystkie aspekty Dark, w tym sam język, są stworzone z myślą o bezpiecznym i błyskawicznym wdrażaniu.

Dlaczego pipeline'y ciągłej dostawy są takie wolne?

Załóżmy, że mamy aplikację internetową w Pythonie i stworzyliśmy już znakomity i nowoczesny pipeline ciągłej dostawy. Dla dewelopera, który codziennie zajmuje się tym projektem, wdrożenie jednej drobnej zmiany będzie wyglądać mniej więcej tak:

Wprowadzenie zmian

  • Utworzenie nowej gałęzi w git
  • Wprowadzenie zmian za pomocą przełącznika funkcji
  • Testy modułowe w celu sprawdzenia zmian z przełącznikiem funkcji i bez

Pull request

  • Zatwierdzenie zmian
  • Wysłanie zmian do zdalnego repozytorium na githubie
  • Pull request
  • Budowanie CI odbywa się automatycznie w tle
  • Przegląd kodu
  • Jeszcze kilka przeglądów, jeśli to konieczne
  • Scalanie zmian z główną gałęzią w git.

CI wykonuje się na głównej gałęzi

  • Instalacja zależności frontendowych przez npm
  • Budowanie i optymalizacja zasobów HTML+CSS+JS
  • Przeprowadzanie modułowych i funkcjonalnych testów na frontendzie
  • Instalacja zależności Pythona z PyPI
  • Przeprowadzanie modułowych i funkcjonalnych testów na backendzie
  • Testowanie integracji na obu końcach
  • Wysłanie zasobów frontendowych do CDN
  • Budowa kontenera dla programu Python
  • Wysłanie kontenera do rejestru
  • Aktualizacja manifestu Kubernetes

Zamiana starego kodu na nowy

  • Kubernetes uruchamia wiele instancji nowego kontenera
  • Kubernetes czeka, aż instancje staną się funkcjonalne
  • Kubernetes dodaje instancje do balansu obciążenia HTTP
  • Kubernetes czeka, aż stare instancje przestaną być używane
  • Kubernetes zatrzymuje stare instancje
  • Kubernetes powtarza te operacje, aż nowe instancje zastąpią wszystkie stare

Włączenie nowego przełącznika funkcji

  • Nowy kod włączany jest tylko dla siebie, aby upewnić się, że wszystko działa poprawnie
  • Nowy kod włączany jest dla 10% użytkowników, monitorowane są metryki operacyjne i biznesowe
  • Nowy kod włączany jest dla 50% użytkowników, monitorowane są metryki operacyjne i biznesowe
  • Nowy kod włączany jest dla 100% użytkowników, monitorowane są metryki operacyjne i biznesowe
  • Na koniec powtarzasz całą procedurę, aby usunąć stary kod i przełącznik

Proces zależy od narzędzi, języka i architektur zorientowanych na usługi, ale w ogólnym zarysie wygląda tak. Nie wspomniałem o wdrożeniach z migracją baz danych, ponieważ jest to wymagające dokładnego planowania, ale poniżej opowiem, jak z tym poradzić sobie w Dark.

Występuje wiele komponentów, a wiele z nich może łatwo spowolnić, zawieść, powodować chwilową konkurencję lub całkowicie zburzyć działający system.

Ponieważ te pipeline'y są niemal zawsze stworzone dla szczególnego przypadku, trudno na nich polegać. Wiele razy zdarza się, że kod nie może być wdrożony, ponieważ w Dockerfile są problemy, nastąpiła awaria jednego z dziesiątek serwisów lub potrzebny specjalista jest na urlopie.

Co gorsza, wiele z tych kroków w ogóle nie przynosi żadnej korzyści. Były potrzebne wcześniej, gdy wdrażaliśmy kod bezpośrednio dla użytkowników, ale teraz mamy przełączniki dla nowego kodu i te procesy się rozdzieliły. W rezultacie krok, na którym wdrażany jest kod (stary zastępowany nowym), stał się po prostu dodatkowym ryzykiem.

Oczywiście, to bardzo przemyślany pipeline. Zespół, który go stworzył, nie żałował czasu i pieniędzy na szybkie wdrożenie. Zazwyczaj pipeline'y wdrożeniowe są znacznie wolniejsze i mniej niezawodne.

Implementacja ciągłej dostawy w Dark

Ciągłe dostarczanie jest na tyle istotne dla Dark, że od samego początku dążyliśmy do czasu poniżej sekundy. Przeanalizowaliśmy wszystkie kroki w procesie, aby usunąć zbędne elementy, a resztę dopracowaliśmy. Oto, jak usuwaliśmy kroki.

Jessie Frazelle (Jessie Frazelle) wymyśliła nowe słowo deployless (nie wymagający wdrożenia) podczas konferencji Future of Software Development w Reykjaviku.

Zdecydowaliśmy od razu, że Dark będzie oparty na koncepcji "deployless" (dziękujemy Jessie Frazelle za neologizm). Deployless oznacza, że każdy kod jest błyskawicznie wdrażany i gotowy do użycia w produkcji. Oczywiście nie pomijamy błędnego lub niepełnego kodu (zasady bezpieczeństwa opiszę poniżej).

Na pokazie Dark często pytano nas, jak udało nam się tak przyspieszyć proces wdrożenia. Dziwne pytanie. Ludzie mogą myśleć, że wymyśliliśmy jakąś supertechnologię, która porównuje kod, kompiluje go, pakuje w kontener, uruchamia maszynę wirtualną, a następnie w zimnym uruchamia kontener i tym podobne — wszystko to w 50 ms. Mało prawdopodobne. Ale stworzyliśmy specjalny silnik wdrożeniowy, któremu to wszystko nie jest potrzebne.

Dark uruchamia interpretatory w chmurze. Załóżmy, że piszesz kod w funkcji lub obhandlerze HTTP czy zdarzeń. Wysyłamy różnice do abstrakcyjnego drzewa składniowego (implementacji kodu, którą wewnętrznie wykorzystuje nasz edytor i serwery) na nasze serwery, a następnie uruchamiamy ten kod w odpowiedzi na zapytania. Więc wdrożenie wygląda po prostu jak skromny wpis w bazie danych — momentalny i prosty. Wdrożenie odbywa się tak szybko, ponieważ obejmuje absolutne minimum.

W przyszłości planujemy uczynić z Dark kompilator infrastruktury, który będzie tworzył i uruchamiał idealną infrastrukturę dla wysokiej wydajności i niezawodności aplikacji. Momentalne wdrożenie, oczywiście, nie zniknie.

Bezpieczne wdrożenie

Strukturalny edytor

Kod w Dark pisany jest w edytorze Dark. Strukturalny edytor nie dopuszcza do błędów składniowych. Tak naprawdę w Dark nie ma nawet analizatora. Gdy wprowadzasz tekst, bezpośrednio pracujemy z abstrakcyjnym drzewem składniowym (AST), jak Paredit, Sketch-n-Sketch, Tofu, Prune i MPS.

Każdy niedokończony kod w Dark ma dopuszczalną semantykę wykonalności, mniej więcej tak jak typed holes w HazelNa przykład, jeśli zmieniasz wywołanie funkcji, zachowujemy starą funkcję, dopóki nowa nie stanie się gotowa.

Każdy program w Dark ma swój sens, więc niekompletny kod nie przeszkadza w działaniu ukończonego.

Tryby edycji

Piszesz kod w Dark w dwóch przypadkach. Po pierwsze: piszesz nowy kod i jesteś jedynym użytkownikiem. Na przykład, działa on w REPL, a inni użytkownicy nigdy nie będą mieli do niego dostępu, lub to nowa trasa HTTP, do której nigdzie nie linkujesz. Można tu pracować bez żadnych zabezpieczeń, i teraz mniej więcej tak działasz w środowisku deweloperskim.

Druga sytuacja: kod jest już używany. Jeśli przez kod przechodzi ruch (funkcje, operatory zdarzeń, bazy danych itd.), należy zachować ostrożność. W tym celu blokujemy cały używany kod i wymagamy korzystania z bardziej zorganizowanych narzędzi do jego edytowania. O narzędziach strukturalnych opowiem poniżej: przełącznikach funkcji dla handlerów HTTP i zdarzeń, potężnej platformie migracji dla baz danych i nowej metodzie zarządzania wersjami dla funkcji i typów.

Przełączniki funkcji

Jednym ze sposobów usunięcia zbędnej złożoności w Dark jest rozwiązanie kilku problemów jednym podejściem. Przełączniki funkcji wykonują wiele różnych zadań: zastępują lokalne środowisko deweloperskie, gałęzie git, wdrażanie kodu i, oczywiście, tradycyjne, wolne i kontrolowane wprowadzanie nowego kodu.

Utworzenie i wdrożenie przełącznika funkcji odbywa się w naszym edytorze w jednym kroku. Tworzy on pustą przestrzeń dla nowego kodu i zapewnia elementy sterujące dostępem do starego i nowego kodu oraz przyciski i polecenia do stopniowego przejścia na nowy kod lub jego wykluczenia.

Przełączniki funkcji są wbudowane w język Dark, a nawet niekompletne przełączniki pełnią swoją rolę — jeśli warunek w przełączniku nie jest spełniony, wykonany zostanie stary zablokowany kod.

Środowisko deweloperskie

Przełączniki funkcji zastępują lokalne środowisko deweloperskie. Dziś zespoły mają trudności z zapewnieniem, że wszyscy używają tych samych wersji narzędzi i bibliotek (narzędzia do formatowania kodu, linters, menedżery pakietów, kompilatory, preprocessory, narzędzia testowe itd.). Dzięki Dark nie trzeba lokalnie instalować zależności, zarządzać lokalną instalacją Dockera ani podejmować innych działań, aby zapewnić choćby namiastkę równości między środowiskiem deweloperskim a produkcją. Biorąc pod uwagę, że taka równość i tak jest niemożliwa, nawet nie będziemy udawać, że dążymy do niej.

Zamiast tworzyć sklonowane lokalne środowisko, przełączniki w Dark tworzą nową piaskownicę na produkcji, która zastępuje środowisko deweloperskie. W przyszłości planujemy także tworzyć piaskownice dla innych części aplikacji (np. natychmiastowe klony baz danych), chociaż obecnie nie wydaje się to zbyt istotne.

Gałęzie i wdrożenia

Obecnie istnieje kilka sposobów wprowadzania nowego kodu do systemów: gałęzie git, etapy wdrożenia i przełączniki funkcji. Rozwiązują one jeden problem w różnych częściach procesu roboczego: git — na etapach przed wdrożeniem, wdrożenie — w momencie przejścia ze starego kodu na nowy, a przełączniki funkcji — do kontrolowanego wydania nowego kodu.

Najskuteczniejszym sposobem są przełączniki funkcji (co jest jednocześnie najprostszym do zrozumienia i używania). Dzięki nim można całkowicie zrezygnować z pozostałych dwóch metod. Szczególnie przydatne jest usunięcie etapu wdrożenia — jeśli mimo wszystko używamy przełączników funkcji do włączania kodu, to etap przełączania serwerów na nowy kod tylko stwarza zbędne ryzyko.

Git jest trudny w użyciu, zwłaszcza dla nowicjuszy, co ogranicza jego zastosowanie, ale ma wygodne gałęzie. Wyeliminowaliśmy wiele wad gita. Dark edytuje w czasie rzeczywistym i zapewnia możliwość współpracy w stylu Google Docs, dzięki czemu nie trzeba wysyłać kodu i rzadziej wykonuje się rebase i merge.

Przełączniki funkcji są kluczowe dla bezpiecznego wdrażania. Wraz z natychmiastowym wdrażaniem umożliwiają szybkie testowanie koncepcji w małych fragmentach o niskim ryzyku, zamiast wprowadzać jedną dużą zmianę, która może zrujnować system.

Wersjonowanie

Do zmiany funkcji i typów używamy wersjonowania. Jeśli chcesz zmienić funkcję, Dark tworzy nową wersję tej funkcji. Następnie możesz wywołać tę wersję za pomocą przełącznika w obsłudze HTTP lub zdarzeń. (Jeśli ta funkcja jest głęboko w grafie wywołań, nowa wersja każdej funkcji jest tworzona po drodze. Może się to wydawać zbyt skomplikowane, ale funkcje nie przeszkadzają, jeśli ich nie używasz, więc nawet tego nie zauważysz.)

Z tych samych powodów wersjonujemy typy. O naszym systemie typów szczegółowo pisaliśmy w poprzednim poście.

Dzięki wersjonowaniu funkcji i typów możesz wprowadzać zmiany w aplikacji stopniowo. Można sprawdzić, że każdy oddzielny obsługiwacz działa z nową wersją, nie trzeba od razu wprowadzać wszystkich zmian w aplikacjach (ale mamy narzędzia, aby szybko to zrobić, jeśli zajdzie taka potrzeba).

To znacznie bezpieczniejsze niż pełne wdrażanie wszystkiego jednocześnie, jak ma to miejsce obecnie.

Nowe wersje pakietów i standardowa biblioteka

Kiedy aktualizujesz pakiet w Dark, nie zastępujemy od razu użycia każdej funkcji lub typu w całej bazie kodu. To nie jest bezpieczne. Kod nadal używa tej samej wersji, którą używał, a ty aktualizujesz użycie funkcji i typów do nowej wersji dla każdego indywidualnego przypadku za pomocą przełączników.

Jak Dark wdraża kod w 50 ms
Zrzut ekranu części automatycznego procesu w Dark, pokazujący dwie wersje funkcji Dict::get. Dict::get_v0 zwracał typ Any (którego się pozbywamy), a Dict::get_v1 zwraca typ Option.

Często dostarczamy nową funkcję standardowej biblioteki i wykluczamy stare wersje. Użytkownicy ze starymi wersjami w kodzie zachowają do nich dostęp, ale nowi użytkownicy nie będą mogli ich uzyskać. Planujemy dostarczyć narzędzia, aby przenieść użytkowników ze starych wersji na nowe za jednym krokiem, znowu za pomocą przełączników funkcji.

Dark oferuje również unikalną możliwość: ponieważ uruchamiamy Twój kod roboczy, możemy testować nowe wersje, porównując wyniki dla nowych i starych zapytań, aby poinformować Cię o zmianach. Ostatecznie aktualizacja pakietów, która często jest przeprowadzana na ślepo (lub wymaga dokładnego testowania w celach bezpieczeństwa), staje się znacznie mniej ryzykowna i może odbywać się automatycznie.

Nowe wersje Dark

Migracja z Pythona 2 do Pythona 3 trwała dekadę i wciąż jest problematyczna. Ponieważ tworzymy Dark do ciągłego dostarczania, musimy uwzględnić te zmiany językowe.

Kiedy wprowadzamy niewielkie zmiany w języku, tworzymy nową wersję Dark. Stary kod pozostaje w starej wersji Dark, a nowy kod jest używany w nowej wersji. Przy przejściu na nową wersję Dark można używać przełączników lub wersji funkcji.

Jest to szczególnie przydatne, biorąc pod uwagę, że Dark pojawił się całkiem niedawno. Wiele zmian w języku lub bibliotece może okazać się nieudanych. Stopniowe wersjonowanie języka pozwala nam na wprowadzanie niewielkich aktualizacji, co oznacza, że nie musimy się spieszyć i możemy odłożyć wiele decyzji dotyczących języka, aż będziemy mieli więcej użytkowników, a zatem więcej informacji.

Migracje baz danych

Dla bezpiecznej migracji bazy danych istnieje standardowa formuła:

  • Przepisać kod na potrzeby wsparcia nowych i starych formatów
  • Przekształcić wszystkie dane do nowego formatu
  • Usunąć stary dostęp do danych

W rezultacie migracja bazy danych wydłuża się i wymaga wielu zasobów. Gromadzą się u nas przestarzałe schematy, ponieważ nawet proste zadania, takie jak poprawa nazwy tabeli czy kolumny, nie są warte poniesionych wysiłków.

Dark ma efektywną platformę migracji baz danych, która (mamy nadzieję) tak uprości proces, że przestaniesz się go bać. Wszystkie zbiory danych w Dark (zbiory par „klucz-wartość” lub trwałe tablice haszujące) mają typ. Aby przenieść zbiór danych, po prostu przypisujesz mu nowy typ oraz funkcję wycofania i zastosowania do przekształcania wartości między dwoma typami.

Dostęp do zbiorów danych w Dark odbywa się za pomocą wersjonowanych nazw zmiennych. Na przykład, zbiór danych Users początkowo będzie nosił nazwę Users-v0. Gdy tworzona jest nowa wersja o innym typie, nazwa zmienia się na Users-v1. Jeśli dane zostały zapisane za pomocą Users-v0, a uzyskujesz do nich dostęp przez Users-v1, stosowana jest funkcja przywracania. Jeśli dane zostały zapisane przez Users-v1, a uzyskujesz do nich dostęp przez Users-v0, stosowana jest funkcja cofania.

Jak Dark wdraża kod w 50 ms
Ekran migracji bazy danych z nazwami pól starej bazy danych, wyrażeniami przywracania i cofania oraz instrukcjami dotyczącymi włączenia migracji.

Użyj przełączników funkcji, aby kierować wywołania do Users-v0 w wersję Users-v1. Można to robić po jednym obsługiwaczu HTTP na raz, aby zminimalizować ryzyko, a przełączniki działają dla poszczególnych użytkowników, abyś mógł sprawdzić, że wszystko działa zgodnie z oczekiwaniami. Gdy użytkowników Users-v0 już nie będzie, Dark automatycznie przekształci wszystkie pozostałe dane w tle ze starego formatu na nowy. Nie zauważysz nawet, że to się dzieje.

Testowanie

Dark to funkcjonalny język programowania o statycznym typowaniu i niemutowalnych wartościach, dlatego powierzchnia testowania jest znacznie mniejsza w porównaniu do języków obiektowych z dynamicznym typowaniem. Ale nadal trzeba testować.
W Dark edytor automatycznie uruchamia testy jednostkowe w tle dla edytowanego kodu i domyślnie przeprowadza te testy dla wszystkich przełączników funkcji. W przyszłości chcemy automatycznie przeprowadzać fuzzing kodu za pomocą statycznych typów, aby znajdować błędy.

Ponadto, Dark wykonuje twoją infrastrukturę w produkcji, co otwiera nowe możliwości. Automatycznie zapisujemy zapytania HTTP w infrastrukturze Dark (na razie zapisujemy wszystkie zapytania, ale później chcemy przejść do próbkowania). Testujemy na ich podstawie nowy kod i przeprowadzamy testy jednostkowe, a jeśli chcesz, możesz łatwo przekształcić interesujące zapytania w testy jednostkowe.

Czego się pozbyliśmy

Skoro nie mamy wdrożeń, ale mamy przełączniki funkcji, około 60% procesu wdrożenia pozostaje na uboczu. Nie potrzebujemy gałęzi git ani pull requestów, budowania zasobów backendowych i kontenerów, wysyłania zasobów i kontenerów do rejestrów ani kroków wdrożeniowych w Kubernetes.

Jak Dark wdraża kod w 50 ms
Porównanie standardowego pipeline'u ciągłej dostawy (po lewej) oraz Dark Continuous Delivery (po prawej). W Dark dostawa składa się z 6 kroków i jednego cyklu, podczas gdy tradycyjna wersja obejmuje 35 kroków i 3 cykle.

W Dark wdrażanie wymaga tylko 6 kroków i 1 cyklu (kroki, które powtarzają się wielokrotnie), podczas gdy nowoczesny pipeline ciągłej dostawy składa się z 35 kroków i 3 cykli. W Dark testy uruchamiają się automatycznie, a Ty nawet tego nie zauważasz; zależności instalują się automatycznie; wszystko, co dotyczy git lub Github, nie jest już potrzebne; nie trzeba budować, testować i przesyłać kontenerów Docker; wdrażanie w Kubernetes jest zbędne.

Nawet pozostające kroki w Dark stały się prostsze. Dzięki zarządzaniu przełącznikami funkcji za pomocą jednego działania nie ma potrzeby ponownego przechodzenia przez cały pipeline wdrożeniowy, aby usunąć stary kod.

Uprościliśmy dostarczanie kodu, skracając czas i ryzyko związane z ciągłą dostawą. Dodatkowo znacznie uprościliśmy aktualizacje pakietów, migracje baz danych, testowanie, zarządzanie wersjami, instalację zależności, równość między środowiskiem deweloperskim a produkcyjnym oraz szybkie i bezpieczne aktualizacje wersji języka.

Odpowiadam na pytania dotyczące tego na HackerNews.

Aby dowiedzieć się więcej o urządzeniu Dark, przeczytaj artykuł o Dark, obserwuj nas na Twitterze (lub na mnie) lub zapisz się na wersję beta i otrzymuj powiadomienia o kolejnych postach. Jeśli wybierasz się na StrangeLoop we wrześniu, przyjdź na naszą premierę.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster