Wyobraź sobie dwa zespoły programistyczne.
Pierwszy przygotowuje nową wersję aplikacji.
Programista kończy zadanie. Ktoś sprawdza kod. Potem trzeba uruchomić testy. Ktoś przygotowuje paczkę. Ktoś inny loguje się na serwer. Następnie trzeba wykonać kilka ręcznych czynności, sprawdzić konfigurację i obserwować system po wdrożeniu. Jeżeli wszystko pójdzie dobrze, nowa wersja jest dostępna.
Drugi zespół pracuje inaczej.
Kod trafia do repozytorium. Automatycznie uruchamiają się testy, analiza jakości i kontrole bezpieczeństwa. System buduje wersję aplikacji, wdraża ją na środowisko testowe, wykonuje kolejne sprawdzenia, a po spełnieniu określonych warunków może wdrożyć ją produkcyjnie. Jeżeli coś pójdzie nie tak, wdrożenie zostaje zatrzymane albo system może wrócić do poprzedniej wersji.
Oba zespoły tworzą oprogramowanie.
Ale tylko jeden z nich zbudował powtarzalny proces dostarczania oprogramowania.
I właśnie o to chodzi w CI/CD.
"Działa na produkcji" to nie jest jeszcze dojrzały proces
Wiele firm mierzy sukces bardzo prostą miarą: aplikacja działa.
To oczywiście podstawowy warunek.
Ale wraz z rozwojem systemu pojawiają się kolejne pytania:
- Jak szybko możemy wdrożyć poprawkę?
- Jak często możemy publikować nowe funkcje?
- Ile ręcznych czynności wykonujemy przy każdym wdrożeniu?
- Czy każdy programista może uruchomić proces wdrożenia według tych samych zasad?
- Czy wiemy, która wersja aktualnie działa?
- Czy potrafimy wrócić do poprzedniej wersji?
- Czy po wdrożeniu automatycznie sprawdzamy, czy system działa prawidłowo?
- Czy mamy monitoring?
- Czy wiemy, że wdrożenie spowodowało problem, zanim zgłosi go klient?
To są pytania dotyczące software delivery, a nie tylko samego programowania.
CI i CD - dwa elementy jednego procesu
CI, czyli Continuous Integration, oznacza ciągłą integrację zmian.
W praktyce chodzi o to, aby zmiany trafiały do wspólnego repozytorium często i były automatycznie sprawdzane.
Typowy pipeline może uruchomić między innymi:
-
kompilację lub budowanie aplikacji,
-
testy jednostkowe,
-
testy integracyjne,
-
linting,
-
analizę statyczną kodu,
-
skanowanie zależności,
-
kontrole bezpieczeństwa,
-
budowanie artefaktów wdrożeniowych.
Dzięki temu problem może zostać wykryty zanim kod trafi na produkcję.
CD, czyli Continuous Delivery lub Continuous Deployment, dotyczy kolejnego etapu - dostarczania zmian.
W zależności od przyjętego modelu system może przygotować gotową wersję do wdrożenia albo automatycznie wdrożyć ją po przejściu określonych kontroli.
To ważne rozróżnienie.
Continuous Delivery nie musi oznaczać automatycznego wdrażania każdej zmiany na produkcję.
Może oznaczać po prostu, że każda wersja jest w sposób powtarzalny przygotowana do wdrożenia.
Dlaczego ręczne wdrożenia stają się problemem?
Ręczne wdrożenie nie musi być złe.
W małym projekcie może być całkowicie wystarczające.
Problem zaczyna się wtedy, gdy proces rośnie wraz z aplikacją.
Najpierw mamy jedną osobę, która wie, jak wdrożyć system. Potem dochodzi drugi serwer. Później środowisko testowe. Następnie baza danych, cache, kolejki, storage, kilka usług i zewnętrzne API. Do tego dochodzą różne konfiguracje dla developmentu, testów i produkcji.
Po kilku latach proces może wyglądać mniej więcej tak:
"Najpierw uruchom X, potem zmień parametr Y, później zrestartuj usługę Z, ale przedtem zrób kopię bazy. A jeśli pojawi się błąd, zadzwoń do osoby, która wdrażała to ostatnim razem."
To nie jest już proces. To wiedza ukryta w głowie człowieka. I właśnie wtedy ryzyko rośnie.
Automatyzacja nie służy tylko wygodzie programistów
Często CI/CD przedstawia się jako narzędzie zwiększające komfort developerów. To prawda, ale jest to tylko część obrazu.
Automatyzacja delivery przede wszystkim zwiększa powtarzalność procesu.
Jeżeli wdrożenie wykonuje człowiek, istnieje możliwość, że za każdym razem zrobi coś trochę inaczej.
Jeżeli robi to pipeline, można zdefiniować dokładną sekwencję kroków.
Ta sama wersja.
Te same testy.
Te same kontrole.
Te same zasady.
To szczególnie istotne w projektach, które są rozwijane przez kilka osób lub kilka zespołów.
Testy przed wdrożeniem są ważniejsze niż szybkość wdrożenia
Automatyzacja bez testów może jedynie sprawić, że błędy będą pojawiały się szybciej.
Dlatego dobrze zaprojektowany pipeline nie powinien być tylko mechanizmem: "kod → produkcja".
Powinien być systemem kontroli jakości.
W zależności od projektu mogą znaleźć się w nim:
- Testy jednostkowe - sprawdzające pojedyncze elementy logiki.
- Testy integracyjne - sprawdzające współpracę komponentów.
- Testy end-to-end - symulujące rzeczywiste scenariusze użytkownika.
- Testy bezpieczeństwa - sprawdzające między innymi zależności i znane podatności.
- Testy wydajnościowe - potrzebne tam, gdzie istotna jest obsługa określonego obciążenia.
Nie każda aplikacja potrzebuje wszystkich tych warstw w takim samym zakresie.
I to jest ważne.
CI/CD nie polega na wrzuceniu jak największej liczby narzędzi do pipeline'u.
Chodzi o dobranie kontroli do ryzyka konkretnego systemu.
Co się dzieje, kiedy test nie przejdzie?
To jedno z najważniejszych pytań w całym procesie.
Dojrzały pipeline powinien mieć jasno określone zasady.
Jeżeli krytyczny test nie przechodzi, wersja nie powinna być traktowana jako gotowa do wdrożenia.
Jeżeli skan bezpieczeństwa wykrywa określony poziom ryzyka, pipeline może zatrzymać proces.
Jeżeli build się nie wykonuje, nie ma czego wdrażać.
To brzmi banalnie. Ale właśnie takie automatyczne "bramki" powodują, że jakość nie zależy wyłącznie od pamięci i dokładności człowieka.
A jeśli wdrożenie jednak się nie powiedzie?
Nawet najlepszy proces nie eliminuje wszystkich błędów. Dlatego drugi element dojrzałego delivery to możliwość kontrolowanego wycofania zmiany.
Rollback może oznaczać powrót do poprzedniego artefaktu, obrazu kontenera albo wersji aplikacji. Ale tutaj pojawia się ważny problem. Rollback kodu nie zawsze oznacza rollback danych.
Jeżeli nowa wersja zmieniła strukturę bazy danych, sytuacja staje się bardziej skomplikowana.
Dlatego migracje baz danych powinny być projektowane tak, aby cały proces był możliwie bezpieczny i odwracalny albo przynajmniej kompatybilny z poprzednią wersją aplikacji.
To jeden z przykładów pokazujących, że profesjonalne CI/CD jest problemem architektonicznym, a nie tylko konfiguracją narzędzia.
Blue-green, canary i inne strategie wdrażania
W bardziej wymagających systemach nie trzeba od razu przełączać wszystkich użytkowników na nową wersję. Można zastosować różne strategie deploymentu.
Blue-green deployment
Działają dwie wersje środowiska.
Jedna obsługuje ruch, druga jest przygotowywana do przejęcia ruchu.
Po pozytywnej weryfikacji następuje przełączenie.
Zaletą jest możliwość szybkiego powrotu do poprzedniego środowiska.
Wadą może być większe zużycie infrastruktury.
Canary deployment
Nowa wersja trafia najpierw do niewielkiej części użytkowników lub ruchu.
Jeżeli monitoring nie wykazuje problemów, zakres wdrożenia może być stopniowo zwiększany.
To ogranicza potencjalny zasięg błędu.
Wymaga jednak odpowiedniej infrastruktury, monitoringu i sposobu zarządzania ruchem.
Feature flags
Funkcja może być wdrożona do systemu, ale pozostawać wyłączona dla użytkowników.
Dzięki temu wdrożenie kodu i uruchomienie funkcjonalności stają się dwoma osobnymi procesami.
To daje większą kontrolę, szczególnie przy dużych zmianach.
Nie oznacza jednak, że feature flags są rozwiązaniem dla każdego projektu. Ich nadmiar również może zwiększyć złożoność systemu.
Monitoring po wdrożeniu
Można przeprowadzić wszystkie testy. Można mieć świetny pipeline. Można wdrożyć nową wersję bez żadnego błędu. A kilka minut później aplikacja może zacząć zachowywać się inaczej pod rzeczywistym obciążeniem.
Dlatego proces nie powinien kończyć się na deploymencie. Potrzebna jest observability, czyli możliwość zrozumienia, co dzieje się wewnątrz działającego systemu.
W zależności od architektury obejmuje ona między innymi:
-
logi,
-
metryki,
-
tracing,
-
monitoring infrastruktury,
-
monitoring aplikacji,
-
alerty,
-
informacje o błędach,
-
wskaźniki biznesowe.
Nie chodzi o zbieranie wszystkiego. Chodzi o to, żeby na ważne pytania można było odpowiedzieć na podstawie danych.
Czy aplikacja działa?
Czy działa wolniej niż wcześniej?
Czy wzrosła liczba błędów?
Która usługa generuje problem?
Czy problem dotyczy wszystkich użytkowników czy tylko części?
100 wdrożeń dziennie nie zawsze jest celem
Tytuł tego artykułu mówi o 100 wdrożeniach dziennie, ale nie chodzi o ustanowienie takiej liczby jako celu.
W systemie wewnętrznym aktualizowanym raz w miesiącu nie ma sensu sztucznie dążyć do setek deploymentów. W systemie rozwijanym bardzo intensywnie taka częstotliwość może natomiast być technicznie możliwa.
Kluczowa jest zdolność do bezpiecznego dostarczania zmian, a nie sama liczba wdrożeń. To fundamentalna różnica.
Dojrzałość procesu mierzy się nie tym, jak często wdrażamy, tylko tym, jak przewidywalnie i bezpiecznie potrafimy to robić.
Kiedy CI/CD może być przerostem formy nad treścią?
Nie każda aplikacja potrzebuje skomplikowanej infrastruktury deploymentowej.
Jeżeli mamy małą aplikację, niewielki zespół i kilka wdrożeń rocznie, rozbudowany pipeline może kosztować więcej niż problemy, które rozwiązuje.
Podobnie w przypadku bardzo specyficznych systemów, gdzie wdrożenie wymaga ręcznej kontroli z powodów bezpieczeństwa, regulacji albo charakteru infrastruktury.
Dlatego architektura delivery powinna wynikać z potrzeb systemu. Nie z mody.
Kiedy automatyzacja wdrożeń daje szczególnie dużo?
Warto ją rozważyć szczególnie wtedy, gdy:
-
system jest rozwijany regularnie,
-
nad kodem pracuje kilka osób,
-
istnieje więcej niż jedno środowisko,
-
wdrożenia są częste,
-
ręczne wdrożenia generują błędy,
-
system ma krytyczne znaczenie biznesowe,
-
potrzebujemy szybkiego rollbacku,
-
aplikacja posiada wiele komponentów,
-
wymagane są audyty lub ślad zmian,
-
czas dostarczenia funkcji ma znaczenie biznesowe.
W takich przypadkach dobrze zaprojektowany pipeline może być jednym z najważniejszych elementów procesu wytwarzania oprogramowania.
CI/CD nie naprawi złej architektury
To również warto podkreślić.
Można stworzyć świetny pipeline dla złej aplikacji.
Automatycznie testować zły kod.
Automatycznie wdrażać złą architekturę.
Automatycznie skalować źle zaprojektowany system.
Automatyzacja nie zastępuje więc architektury, testów ani kompetencji zespołu.
Ona wzmacnia istniejący proces.
Jeżeli proces jest dobry, pomaga go skalować.
Jeżeli proces jest zły, może po prostu szybciej wykonywać złe rzeczy.
Jak wygląda dojrzały proces?
Nie istnieje jeden uniwersalny pipeline.
Ale dojrzały proces powinien mieć kilka podstawowych właściwości.
Powtarzalność - wdrożenie wykonuje się według zdefiniowanych kroków.
Automatyzację - maszyny wykonują możliwie dużą część powtarzalnej pracy.
Testowalność - zmiany są automatycznie weryfikowane.
Bezpieczeństwo - proces obejmuje odpowiednie kontrole bezpieczeństwa.
Obserwowalność - po wdrożeniu wiadomo, co dzieje się z systemem.
Odwracalność - istnieje zaplanowany sposób reagowania na nieudaną zmianę.
Śledzenie zmian - wiadomo, jaka wersja została wdrożona i z czego powstała.
Kontrolę dostępu - nie każdy może dowolnie wdrożyć wszystko na produkcję.
To właśnie z takich elementów powstaje profesjonalny proces software delivery.
Najważniejsza zmiana zaczyna się od innego pytania
Firmy często pytają: "Jak szybko możemy stworzyć tę funkcję?"
Warto dodać drugie pytanie: "Jak szybko i bezpiecznie będziemy mogli dostarczać kolejne 50 funkcji?"
Bo pojedyncze wdrożenie można wykonać ręcznie. Można nawet ręcznie wdrażać aplikację przez kilka lat. Ale wraz ze wzrostem produktu, zespołu, liczby użytkowników i liczby zmian rośnie również cena takiego podejścia.
Dlatego CI/CD, automatyczne testy, monitoring i kontrolowane deploymenty nie są tylko rozwiązaniami dla dużych korporacji.
To elementy infrastruktury procesu, który pozwala rozwijać oprogramowanie bez dokładania niepotrzebnego ryzyka do każdej kolejnej zmiany.
A ostatecznie właśnie o to chodzi.
Nie o 100 wdrożeń dziennie.
Nie o modne narzędzia.
Nie o najbardziej skomplikowany pipeline.
Tylko o możliwość powiedzenia:
"Mamy zmianę. Sprawdziliśmy ją. Wiemy, co wdrażamy. Wiemy, jak ją obserwować. I wiemy, co zrobimy, jeśli coś pójdzie nie tak."



