CI/CD to automatyzacja drogi kodu od commita na serwer: ciągła integracja (*continuous integration*) automatycznie buduje i testuje kod po każdej zmianie, a ciągłe dostarczanie lub wdrażanie (*continuous delivery / deployment*) przygotowuje go do wydania albo wdraża na produkcję. Różnica między dwoma ostatnimi sprowadza się do ręcznego zatwierdzenia. Dzięki temu nie wysyłasz plików ręcznie i szybciej wykrywasz błędy.
W artykule o DevOpsie CI/CD jest jedną z umiejętności z listy, a w tekście o wysyłaniu plików przez FTP i SFTP pojawia się jako sposób, który zastępuje ręczne wysyłanie plików. Ten artykuł wyjaśnia, czym jest CI/CD, czym różnią się jego składniki, jak wygląda przykładowy pipeline w GitHub Actions i jak bezpiecznie obchodzić się z hasłami i kluczami. Dla jasności: przykład pliku konfiguracyjnego sprawdziłem lokalnie linterem, ale nie uruchamiałem go na prawdziwym GitHubie.
Czym jest CI/CD?
CI/CD to skrót od continuous integration / continuous delivery (lub deployment), czyli ciągłej integracji i ciągłego dostarczania (wdrażania). To zestaw praktyk i narzędzi, które po każdej zmianie w kodzie automatycznie budują aplikację, uruchamiają testy i, jeśli wszystko jest w porządku, przygotowują ją do wydania albo wdrażają. Zamiast ręcznie wysyłać pliki na serwer i pamiętać o każdym kroku, opisujesz ten proces raz w pliku, a narzędzie wykonuje go za Ciebie.
Ogólne wprowadzenie do tematu usłyszysz w rozmowie z Jerzym Wickowskim:
Czym różni się ciągła integracja od ciągłego dostarczania i wdrażania?
Trzy pojęcia często się mieszają. Oto ich różnice według dokumentacji GitHub i AWS:
| Pojęcie | Co oznacza | Czy człowiek zatwierdza wydanie? |
|---|---|---|
| Ciągła integracja (continuous integration, CI) | częste wrzucanie kodu do wspólnego repozytorium, przy którym automatycznie budujesz kod i uruchamiasz testy | nie dotyczy |
| Ciągłe dostarczanie (continuous delivery) | każda zmiana jest automatycznie przygotowana do wydania na produkcję | tak, wdrożenie wymaga ręcznej akceptacji |
| Ciągłe wdrażanie (continuous deployment) | każda zmiana, która przejdzie testy, trafia na produkcję | nie, wdrożenie jest w pełni automatyczne |
Dokumentacja AWS ujmuje różnicę wprost: różnica między ciągłym dostarczaniem a ciągłym wdrażaniem to obecność ręcznego zatwierdzenia przed aktualizacją produkcji. Dokumentacja GitHub definiuje samo CI jako praktykę częstego wysyłania kodu do wspólnego repozytorium, dzięki której błędy wykrywa się szybciej, a zmiany członków zespołu łatwiej się scala.
Po co komu CI/CD? Główne korzyści
- Szybciej wykryjesz błędy. Testy uruchamiają się po każdej zmianie, a wyniki widzisz w pull requeście, zanim kod trafi do głównej gałęzi.
- Wdrożenie przestaje zależeć od pamięci. Nie wysyłasz ręcznie plików ani nie zapominasz o jednym z nich.
- Każde wdrożenie wygląda tak samo. Proces jest opisany w pliku, więc jest powtarzalny, a nie zależy od tego, kto go wykonuje.
- Praca w zespole jest łatwiejsza. Wszyscy widzą wynik testów w tym samym miejscu. O samej pracy z gałęziami i pull requestami piszemy w artykule o pracy zespołowej w Gicie.
Według AWS korzyści to m.in. automatyzacja wydań, większa produktywność programistów, szybsze wykrywanie i naprawianie błędów oraz szybsze dostarczanie aktualizacji.
Z czego składa się pipeline CI/CD?
Pipeline (potok) to ciąg kroków, które wykonują się automatycznie po zdarzeniu, np. po wypchnięciu kodu. Nazwy elementów różnią się między narzędziami, ale idea jest ta sama. Według dokumentacji GitHub Actions są to:
| Element | Co oznacza |
|---|---|
| Event (zdarzenie) | konkretna czynność w repozytorium, która uruchamia workflow, np. push lub pull request |
| Workflow | skonfigurowany, zautomatyzowany proces złożony z jednego lub więcej jobów |
| Job (zadanie) | zestaw kroków wykonywanych na tym samym runnerze; domyślnie joby działają równolegle |
| Step (krok) | pojedyncza czynność: skrypt powłoki albo gotowa akcja |
| Action | gotowy, wielokrotnego użytku fragment, np. pobranie repozytorium |
| Runner | serwer, na którym wykonują się joby (Linux, Windows lub macOS od GitHub albo własny) |
W GitLabie ten sam pomysł nazywa się trochę inaczej: pipeline składa się z etapów (stages, np. build, test, deploy) i zadań (jobs), a konfiguracja leży w pliku .gitlab-ci.yml w katalogu głównym projektu. Znanym narzędziem jest też Jenkins, któremu poświęciliśmy osobny artykuł: czym jest Jenkins i jak go używać. Poniżej opisuję GitHub Actions, bo jest najłatwiejszy na start, jeśli i tak trzymasz kod na GitHubie.
Jak wygląda prosty pipeline w GitHub Actions?
Workflow to plik YAML w katalogu .github/workflows repozytorium. Poniżej przykład z dwoma jobami: test uruchamia testy przy każdym pushu i pull requeście, a deploy wdraża aplikację tylko po udanych testach i tylko z gałęzi main.
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Pobierz kod repozytorium
uses: actions/checkout@v6
- name: Zainstaluj zależności
run: python3 -m pip install -r requirements.txt
- name: Uruchom testy
run: python3 -m pytest
deploy:
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- name: Pobierz kod repozytorium
uses: actions/checkout@v6
- name: Wdróż na serwer
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: ./scripts/deploy.sh
Co robi ten plik:
onwskazuje zdarzenia, które uruchamiają workflow: push domaini każdy pull request.runs-on: ubuntu-latestoznacza, że joby działają na maszynie z Ubuntu hostowanej przez GitHub.needs: testsprawia, żedeployczeka na zakończenietest. Jeśli testy zawiodą, wdrożenie się nie uruchomi.ifogranicza wdrożenie do pushy na gałąźmain, więc pull requesty tylko testują kod.environment: productionpowiązuje job ze środowiskiem, na którym można ustawić reguły ochrony.secrets.DEPLOY_SSH_KEYto sekret, czyli wartość przechowywana poza kodem (więcej niżej).
Sprawdziłem ten plik linterem actionlint 1.7.12 i nie zgłosił błędów. Dla porównania celowo zepsuty plik z literówką w zdarzeniu (on: pusz), niedomkniętym wyrażeniem ${{ secrets.KLUCZ } i zależnością od nieistniejącego joba (needs: testy) dostał cztery komunikaty o błędach, m.in. „unknown Webhook event "pusz"” i „job "deploy" needs job "testy" which does not exist in this workflow”. Lint wyłapuje pomyłki w składni, ale nie uruchamia pipeline'u i nie dowodzi, że wdrożenie zadziała na prawdziwym serwerze. Tego nie testowałem.
Wyniki uruchomień zobaczysz w repozytorium na GitHubie w zakładce Actions: wybierasz workflow, uruchomienie, a potem job, w którym możesz rozwinąć logi każdego kroku.
Jak zadbać o ręczne zatwierdzenie wdrożenia?
Jeśli chcesz ciągłego dostarczania, czyli wdrożenia po ręcznej akceptacji, GitHub oferuje środowiska (environments) z regułami ochrony. Według dokumentacji możesz wskazać osoby lub zespoły, które muszą zatwierdzić job używający danego środowiska, a wystarczy akceptacja jednej z nich. Jest też opcja zablokowania zatwierdzania własnych uruchomień. W przykładzie powyżej job deploy jest powiązany ze środowiskiem production, więc po włączeniu takiej reguły wdrożenie zatrzyma się do czasu akceptacji. Jeśli reguły nie ustawisz, wdrożenie po testach pójdzie automatycznie, czyli będzie to ciągłe wdrażanie.
Jak bezpiecznie przechowywać hasła i klucze w CI/CD?
Pipeline często potrzebuje dostępu do serwera, np. przez klucz SSH. Nigdy nie wpisuj go w plik workflow ani do repozytorium. Zamiast tego użyj sekretów (secrets). Według dokumentacji GitHub to zmienne tworzone na potrzeby workflow na poziomie organizacji, repozytorium lub środowiska. Co warto wiedzieć:
- Workflow widzi tylko te sekrety, które mu wskażesz. Dokumentacja mówi wprost, że GitHub Actions może odczytać sekret tylko wtedy, gdy jawnie uwzględnisz go w workflow.
- Sekrety środowiska są dostępne tylko jobom, które z tego środowiska korzystają, i dopiero po spełnieniu reguł ochrony, np. akceptacji.
- Zasłanianie sekretów w logach nie jest gwarancją. Według dokumentacji GitHub automatycznie ukrywa wartości sekretów, ale istnieje wiele sposobów ich przekształcenia, więc nie ma pewności, że ukrycie zadziała zawsze. Nie wypisuj sekretów w logach.
- Przyznawaj minimalne uprawnienia. Dokumentacja zaleca m.in. klucze wdrożeniowe lub konta serwisowe zamiast osobistych tokenów.
Jeśli wdrażasz przez SSH, klucz dla pipeline'u powinien być osobnym kluczem z ograniczonymi uprawnieniami, a nie Twoim prywatnym kluczem. Jak działają klucze, opisaliśmy w artykule o SSH.
Jakie błędy zdarzają się przy CI/CD najczęściej?
| Problem | Co zwykle znaczy | Co zrobić |
|---|---|---|
| Workflow się nie uruchamia | plik nie leży w .github/workflows albo ma złe rozszerzenie | umieść plik w tym katalogu z rozszerzeniem .yml lub .yaml |
| Błąd składni YAML | złe wcięcia, literówka w nazwie zdarzenia lub joba | sprawdź plik linterem, np. actionlint |
| Testy przechodzą u Ciebie, a w pipeline nie | inne środowisko, brakujące zależności | zainstaluj zależności w pipeline i uruchom testy w czystym środowisku |
| Wdrożenie nie rusza | needs wskazuje job, który zawiódł, albo if nie jest spełnione | sprawdź logi jobów w zakładce Actions |
| Sekret jest pusty | zła nazwa sekretu lub brak dostępu do środowiska | sprawdź nazwę, poziom (repozytorium, środowisko) i reguły |
| Wyciek klucza w logu | wypisanie sekretu w kroku | nie wypisuj sekretów, a wyciekły klucz wymień |
Uwaga mentora: zacznij od najprostszego pipeline'u: przy każdym pushu uruchom testy. Wdrożenie automatyczne dodawaj dopiero wtedy, gdy ufasz swoim testom, bo zautomatyzowany pipeline powiela też błędy.
Od czego zacząć z CI/CD?
- Najpierw testy. Zacznij od prostego pipeline'u, który przy każdym pushu uruchamia testy. To CI w najprostszej formie.
- Dopiero potem wdrożenie. Automatyczne wdrożenie dodawaj, gdy ufasz swoim testom. Zautomatyzowany pipeline powiela też błędy, więc jakość testów decyduje o bezpieczeństwie wdrożeń.
- Ustaw ręczne zatwierdzenie dla produkcji na początku, a pełną automatyzację rozważ później.
- Trzymaj hasła i klucze w sekretach, nie w kodzie.
- Naucz się czytać logi. Większość problemów z CI/CD wyjaśnia wynik jednego z kroków.
Cały proces wdrożenia aplikacji na prawdziwym serwerze, razem z kontenerami i automatycznym HTTPS, ćwiczysz w module wdrożenie produkcyjne w chmurze w kursie AI Engineer. Jeśli wdrażasz na własny serwer, zobacz też artykuł o serwerze VPS.
Podsumowanie
- CI/CD to automatyzacja drogi kodu od commita do wdrożenia: ciągła integracja buduje i testuje kod, a ciągłe dostarczanie lub wdrażanie przygotowuje go do wydania albo wdraża.
- Delivery a deployment różnią się ręcznym zatwierdzeniem: w dostarczaniu człowiek akceptuje wydanie, we wdrażaniu wszystko dzieje się automatycznie.
- Pipeline składa się z zdarzeń, jobów i kroków. W GitHub Actions opisujesz go w pliku YAML w
.github/workflows. - Sekretów nie wpisuje się w kod. Zasłanianie ich w logach nie jest gwarancją, więc nie wypisuj ich w krokach.
- Przykładowy plik workflow sprawdziłem linterem, ale nie uruchamiałem go na prawdziwym GitHubie ani nie testowałem wdrożenia na serwerze.


