Czym jest CI/CD i dlaczego każdy zespół go potrzebuje
O CI/CD mówi się jak o jednym modnym haśle, ale to tak naprawdę dwie odrębne idee sklejone w jedną: ciągła integracja i ciągłe dostarczanie (lub ciągłe wdrażanie). Kiedy rozpatrzy się je osobno, całość staje się znacznie mniej abstrakcyjna.
Ciągła integracja polega na częstym scalaniu kodu – kilka razy dziennie, a nie raz w tygodniu – i uruchamianiu automatycznego budowania oraz zestawu testów za każdym razem, gdy ktoś wypchnie zmianę. Nie chodzi o częstotliwość dla samej częstotliwości. Chodzi o to, że małe, częste scalenia łatwo ogarnąć, a ogromna gałąź, która od trzech tygodni rozjeżdża się z mainem, to konflikt przy scalaniu, który tylko czeka, żeby wybuchnąć. CI wyłapuje konflikt, zepsuty test czy przypadkową literówkę w ciągu kilku minut od ich pojawienia się, a nie dwa tygodnie później, gdy nikt już nie pamięta, po co była ta linijka.
Ciągłe dostarczanie idzie o krok dalej: gdy kod przejdzie CI, jest automatycznie pakowany i przygotowywany do wydania – czasem w środowisku stagingowym, czasem aż na produkcji. Ciągłe wdrażanie to bardziej radykalna wersja, w której przejście wszystkich automatycznych kontroli oznacza, że kod trafia na produkcję bez klikania przycisku przez człowieka. Większość zespołów ląduje gdzieś pośrodku: automatycznie aż do stagingu, ręczne zatwierdzenie przed produkcją.
Co właściwie robi prawdziwy pipeline
Pipeline CI/CD to po prostu sekwencja automatycznych kroków uruchamianych przy każdej zmianie kodu. Typowy wygląda mniej więcej tak:
- Pobranie nowego kodu i instalacja zależności
- Uruchomienie linterów i analizy statycznej, by szybko wyłapać oczywiste błędy
- Uruchomienie automatycznego zestawu testów – najpierw testów jednostkowych, bo są tanie, potem wolniejszych testów integracyjnych
- Zbudowanie artefaktu do wdrożenia – obrazu Dockera, skompilowanego pliku binarnego, paczki ze stroną statyczną
- Wdrożenie go w środowisku stagingowym lub produkcyjnym
- Uruchomienie testu dymnego (smoke test) na działającym wdrożeniu, by potwierdzić, że wszystko faktycznie poprawnie wystartowało
Każdy błąd na dowolnym etapie zatrzymuje pipeline i powiadamia osobę, która wypchnęła zmianę. Na tym polega cały trik: zamiast polegać na tym, że człowiek za każdym razem pamięta, by poprawnie i w odpowiedniej kolejności uruchomić testy, zbudować i wdrożyć aplikację, robi to maszyna – za każdym razem identycznie.
Dlaczego ma to większe znaczenie, niż się wydaje
Bez CI/CD wdrożenia stają się wydarzeniami. Ktoś wyznacza „dzień wdrożenia”, wszyscy są trochę zdenerwowani, a jeśli coś się zepsuje, ustalanie, która z dwudziestu zmian od ostatniego wdrożenia jest winna, to droga przez mękę. Z CI/CD każda zmiana jest mała, testowana w izolacji i wdrażana osobno – więc gdy coś się zepsuje, wiadomo dokładnie, która pięciolinijkowa zmiana to spowodowała, bo tylko ona trafiła na produkcję.
Eliminuje to też konkretny rodzaj ludzkiego błędu: wdrożenie, które działa na laptopie jednego inżyniera, ale nie na produkcji z powodu jakiejś subtelnej różnicy w środowisku, albo wydanie, przy którym ktoś zapomniał najpierw uruchomić migracje. Pipeline za każdym razem wykonuje te same kroki w tej samej kolejności, więc „u mnie działało, jak robiłem to ręcznie” przestaje być wytłumaczeniem, dlaczego produkcja stoi w ogniu.
Gdzie zespoły popełniają błędy
Najczęstszym błędem nie jest całkowita rezygnacja z CI/CD – większość zespołów ma już jakiś pipeline. Jest nim pipeline z doczepionym cienkim, zawodnym zestawem testów, przez co „testy przeszły” niewiele właściwie znaczy. Zielony pipeline, który nie wyłapuje prawdziwych błędów, jest gorszy niż brak pipeline'u, bo daje fałszywe poczucie bezpieczeństwa. Drugim częstym błędem jest pipeline, który działa czterdzieści minut – to po cichu skłania inżynierów do grupowania zmian i rzadszego scalania, co niweczy cały sens ciągłej integracji.
Dobre CI/CD zależy nie tyle od wybranego narzędzia – GitHub Actions, GitLab CI, Jenkins, CircleCI, każde z nich da radę – ile od realnej inwestycji w szybkie, wiarygodne testy i utrzymania samego pipeline'u na tyle prostym, by ludzie mu ufali, zamiast go obchodzić.
To kluczowa część prac infrastrukturalnych, które wykonujemy w Burncode: konfigurujemy pipeline'y CI/CD na tyle szybkie, że inżynierowie naprawdę na nich polegają, wraz z monitoringiem, który wyłapuje awarie, jakich sam pipeline nie wykrywa.