Czym jest webhook?

Webhook to metoda komunikacji dwóch aplikacji poprzez ich interfejsy API w czasie rzeczywistym. Przyjmijmy, że aplikacja A do poprawnej pracy lub uruchomienia zaprogramowanego w niej scenariusza potrzebuje danych z aplikacji B. Wykonanie akcji może być uzależnione od zmiany wartości udostępnianego przez aplikację B licznika lub wystąpienia zaprogramowanego w niej zdarzenia. W typowych rozwiązaniach aplikacja A musi nieprzerwanie odpytywać aplikację B o interesujące ją informacje. W ten sposób na bieżąco aktualizuje posiadane dane, lecz obciąża to zasoby obu z nich. W informatyce nie ma nic za darmo i nieustanne odpytywanie aplikacji B przez aplikację A obciąża procesor obu maszyn oraz łącze pomiędzy nimi. Nawet jeżeli pojedyncza informacja nie wymaga dużej ilości wspomnianych zasobów, to pamiętajmy o efekcie skali. Stosując webhooki, to aplikacja B przesyła w czasie rzeczywistym dane do aplikacji A, informując ją tym samym o każdej zmianie jej stanu. Zatem nie ma potrzeby ciągłego odpytywania o stan i przesyłania danych, które się nie zmieniły od ostatniego zapytania.

Idea webhook-ów powstała jako jeden z elementów całej koncepcji API (Application Programming Interface), czyli interfejsu pozwalającego na programowanie aplikacji. W obecnych sieciach, a w szczególności w Internecie zarówno interfejsy API, jak i sam mechanizm webhook-ów, w swoim działaniu wykorzystują protokół HTTP. Obowiązkowo teraz rozszerzony o bezpieczną komunikację zgodną najlepiej ze standardem TLS1.2 lub wyższym. Operacje implementowane są za pomocą znanych akcji takich jak GET czy POST. Same dane są przesyłane w postaci obiektu typu JSON, rzadziej XML.

Przykład integracji za pomocą Webhook

W poprzednich artykułach pokazałem Wam dwa produkty – GitLab i Jenkins, oraz jak uruchomić je w kontenerach Dockera. Te produkty w prosty sposób możemy połączyć ze sobą w modelu CI/CD za pomocą właśnie mechanizmu webhook. Każda zmiana w repozytorium GitLab wyzwalać będzie wykonanie projektu w Jenkins.

Aby zintegrować Jenkins z GitLab musimy w tym pierwszym dodać nowy plugin o nazwie Gitlab oraz AnsiColor. W tym celu wchodzimy w Manage Jenkins -> Manage Plugins i w zakładce Available znajdujemy nasze pluginy i je instalujemy. Następnie tworzymy nowy projekt typu Pipeline i nadajemy mu wybraną przez nas nazwę. Nasz projekt jedyne co będzie robił, to wypisywał w konsoli prosty tekst. W polu pipeline umieszczamy następujący skrypt:

node {
    ansiColor(’xterm’) {
        stage „To jest nazwa kroku”
    }
}

Zapisujemy teraz projekt przyciskiem Save i przetestujemy czy od działa. Aby go ręcznie uruchomić w głównym oknie projektu wciskamy przycisk Build Now. Powinniśmy zobaczyć w historii wykonania projektu jego wykonanie oznaczone identyfikatorem #1, zaś w polu Stage View informacje o wykonanych krokach

Budowa projektu

Jeżeli klikniemy teraz w identyfikator wykonania projektu, a następnie Console Output na ekranie wyświetlą się kolejne kroki wykonania projektu, w tym właśnie informacja o nazwie kroku, którą wypisaliśmy na wyjściu konsoli (na załączonym zrzucie podświetliłem ją).

Output konsoli

Dodajemy teraz integrację z GitLabem. W pierwszej kolejności aktywujemy odpowiedni interfejs po stronie projektu. Wracamy zatem do jego konfiguracji i zaznaczamy w sekcji Build Triggers opcję Build when a change is pushed to GitLab. Znajdziemy tam też URL, który będziemy wywoływać z GitLaba, aby uaktywnić webhook.

Tworzenie wyzwalaczy

Jeżeli kontenery z Gitlab i Jenkins działają na tej samej maszynie, musimy najpierw połączyć je wewnętrzną siecią między kontenerami. Ja poleceniem docker network create Lab utworzyłem sieć o nazwie Lab. Znane z poprzednich artykułów, ale zaktualizowane pliki konfiguracyjne docker-compose.yml do uruchamiania Jenkins i Gitlab ze wspólną siecią znajdują się w moim repozytorium. Nazwę kontenera z Jenkins odczytamy z wyniku polecenia docker ps.

Nazwa kontenera Jenkins

W moim przypadku URL webhooka będzie miał postać http://jenkins_jenkins_1:8080/project/WriteOutput (WriteOutput to nazwa utworzonego w Jenkins projektu).

Konfiguracja po stronie Gitlab

Przystępujemy teraz do konfiguracji GitLaba. Na początek musimy umożliwić wysyłanie żądań typu webhook w sieci lokalnej. W tym celu przechodzimy na koncie z uprawnieniami administratora do Admin -> Settings -> Network -> Outbound Requests i zaznaczamy obie opcje.

Ustawianie żądań

Następnie tworzymy nowy pusty projekt i przechodzimy do jego ustawień Settings -> Webhooks. To sekcja konfiguracji odpowiadająca za integrację właśnie za pomocą webhooków. W polu URL wpisujemy adres, który uzyskaliśmy konfigurując Jenkinsa. Jako wyzwalacz wybieramy Push events oraz odznaczamy pole Enable SSL verification. W naszym przykładzie nie używamy połączeń szyfrowanych.

Ustawienia webhooków

Każdy poprawnie zdefiniowany webhook wyświetli nam się na liście. Aby go ręcznie wyzwolić wystarczy, że rozwiniemy menu Test i wybierzemy akcję Push events.

Webhooki

Webhook się uruchomi, ale nie wykona poprawnie. Na ekranie zobaczymy komunikat błędu zwrócony przez Jenkinsa

Błąd Jenkinsa

Autentykacja za pomocą tokena

Osobą uprawnioną do wykonania webhooka możemy autoryzować przekazując login i hasło albo specjalny token. Ja preferuję tą drugą metodę, gdyż token generujemy do wskazanego projektu jedynie. Wracamy więc do Jenkinsa i konfiguracji utworzonego projektu. W sekcji Build Triggers odnajdujemy stworzoną wcześniej konfigurację webhooka i wciskamy przycisk Advanced. Na samym końcu właściwości webhooka znajdue się pole Secret token. Wypełniamy je przyciskiem Generate i zapisujemy konfigurację projektu.

W Gitlab w ustawieniach projektu odnajdujemy nasz webhook i klikamy Edit. Następnie w polu Secret Token wprowadzamy wartość klucza wygenerowaną wcześniej w Jenkins. Zapisujemy konfigurację i powtarzamy test. Tym razem zamiast błędu zobaczymy komunikat HTTP 200 oznaczający poprawne wywołanie webhooka.

Wracamy ponownie do Jenkinsa i panelu głównego naszego projektu. W historii powinno nam pojawić się wykonanie projektu z identyfikatorem #2 oraz dodatkową informacją, że zostało ono zainicjowane przez Gitlab.

Historia tworzenia projektu

Wykonajmy teraz zmianę w kodzie w repozytorium naszego projektu. Ja dodałem po prostu nowy plik.

Repozytorium projektu

Gdy wcisnę przycisk Commit changes do repozytorium zostanie dodany plik o nazwie LICENSE. Jednocześnie uruchomiony zostanie webhook zdefiniowany w parametrach projektu. Wracamy zatem do okna projektu w Jenkins i w historii znajdziemy trzecie jego wykonanie.

Historia tworzenia projektu 2