Wprowadzenie do GitLab CI/CD

25 września, 2023

Poznaj GitLab CI/CD od podstaw:

Automatyzacja wdrażania oprogramowania jest aktualnym i zdecydowanie właściwym trendem. Oprócz szybszego procesu dostarczania nowych wersji aplikacji i możliwości łatwego wycofania zmian w przypadku nieprawidłowości zwiększamy też bezpieczeństwo środowiska — osoba odpowiedzialna za wdrożenie (np. programista) zasadniczo nie potrzebuje w takim podejściu dostępu do serwera.

Jednym z głównych rozwiązań stosowanych w tym celu jest GitLab. To niezwykle rozbudowane środowisko wymagające pewnej wstępnej konfiguracji. Właśnie ta złożoność jest także pewną zaletą — nie potrzebujemy osobno konfigurować repozytorium Git, container registry dla obrazów kontenerów, środowiska CI/CD czy nawet narzędzia do zarządzania projektami. Wszystko otrzymujemy w postaci jednego rozwiązania.

Oznacza to również, że GitLab znajduje zastosowanie w różnych obszarach IT. Wystarczy przejrzeć dostępne na theprotocol.it oferty pracy, aby zauważyć, że w wielu specjalizacjach jest to jedna z wymaganych umiejętności.

GitLab możemy uruchomić we własnej infrastrukturze, jak i korzystać z opcji SaaS oferowanych przez wydawcę. Ze szczegółami można zapoznać się na dedykowanej stronie.

W tym artykule omówimy sposób instalacji GitLab w systemie Ubuntu, podstawową konfigurację, integrację z Active Directory, utworzenie container registry dostępnego pod dedykowaną domeną, konfigurację runner’a i oczywiście tworzenie procesów CI/CD (własne skrypty oraz wykorzystanie zewnętrznego narzędzia).


Instalacja GitLab

Podstawowe wymagania sprzętowe to 4 GB pamięci RAM oraz zalecane 4 rdzenie CPU. Potrzebna przestrzeń na dysku jest zależna od wielkości naszych projektów, natomiast sama paczka instalacyjna po wypakowaniu zajmie około 2.5 GB miejsca. Te informacje wraz z pełnym wyjaśnieniem są dostępne w dokumentacji.

GitLab powinien być wdrażany na czystym systemie, ponieważ sama jego architektura jest w pewnym stopniu skomplikowana i złożona z kilku usług. Pozostała kwestia to wydajność, nie możemy oczekiwać całkowicie płynnego działania w przypadku mocno obciążonego środowiska.

Polecam przeznaczyć osobny dysk na katalog /var/opt/gitlab (można utworzyć partycję i zamontować ją przed instalacją), ponieważ w tej lokalizacji zapisywanych jest wiele danych, jak repozytoria i przesłane obrazy Docker. Procedury instalacji w zależności od środowiska zostały przedstawione w tym miejscu. Zamierzamy użyć systemu Ubuntu, czyli wystarczy wykonać poniższe polecenia:

				
					sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates tzdata perl postfix
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo EXTERNAL_URL="http://gitlab.test.local" apt-get install gitlab-ce
				
			

Jako EXTERNAL_URL podajemy domenę, na której GitLab będzie dostępny. Jeśli od razu podamy ją z protokołem HTTPS, nastąpi próba wygenerowania certyfikatu Let’s Encrypt, co nie zadziała dla dostępnej lokalnie domeny. Tak samo jeśli posiadamy wcześniej zakupiony czy wygenerowany certyfikat i klucz — lepiej na początku podać ten adres z protokołem HTTP.

Po poprawnym zainstalowaniu pakietu gitlab-ce zobaczymy poniższy output.

Wynik poprawnej instalacji GitLab.

Wstępna konfiguracja

Część potrzebnych zmian możemy wdrożyć poprzez panel administratora, ale edytowanie plików z poziomu terminala i przeładowywanie konfiguracji poleceniem gitlab-ctl także będzie wymagane w wielu przypadkach. Na początek skonfigurujemy obsługę HTTPS, a także uruchomimy własne container registry pod domeną cr.test.local.

Głównym plikiem konfiguracyjnym jest /etc/gitlab/gitlab.rb i w nim modyfikujemy oraz dodajemy linie:

external_url 'https://gitlab.test.local'
letsencrypt['enable'] = false
nginx['redirect_http_to_https'] = true
registry_external_url 'https://cr.test.local'
registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/cr.test.local.crt"
registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/cr.test.local.key"

Ustawiliśmy adres z prefikem https, wyłączyliśmy opcję korzystania z certyfikatów Let’s Encrypt oraz wymusiliśmy przekierowanie ruchu HTTP na HTTPS. W celu uruchomienia container registry wskazaliśmy domenę, pod którą obrazy będą dostępne do pobrania i wysłania (docker pull, docker push) oraz podaliśmy lokalizacje pliku z certyfikatem i kluczem — musieliśmy jawnie zapisać te ścieżki, ponieważ domena jest inna.

Tworzymy następnie katalog /etc/gitlab/ssl i przenosimy do niego certyfikaty i powiązane klucze. Konfigurację możemy przeładować poleceniem sudo gitlab-ctl reconfigure.

W pliku /etc/gitlab/initial_root_password zapisane będzie hasło dla użytkownika root ważne przez 24 godziny. Korzystając z niego możemy zalogować się do GitLab.

Pierwsze logowanie do GitLab.

Nie ma obowiązku używania konta root do administracji GitLab. Możemy dodać własnego użytkownika z rolą Administrator. Przechodzimy do listy Your work i wybieramy Admin Area, a następnie Users. Tam z kolei klikamy przycisk New user, po czym zobaczmy formularz dodawania użytkownika. Uzupełniamy pola Name, Username, Email, a jako Access level wybieramy Administrator.

Na wskazany adres e-mail zostanie wysłany link do resetu hasła. Jeśli jednak z jakiegoś powodu musimy manualnie ustawić tymczasowe hasło (po pierwszym zalogowaniu konieczna będzie zmiana hasła), to klikamy przycisk Edit i dwukrotnie wpisujemy hasło.

Integracja z Active Directory — logowanie domenowe

Aby umożliwić użytkownikom logowanie kontem domenowym w pliku /etc/gitlab/gitlab.rb ustawiamy opcję gitlab_rails[’ldap_enabled’] na wartość true oraz uzupełniamy szczegóły konfiguracji Active Directory w opcji gitlab_rails[’ldap_servers’]. Komentarze proponują dodanie konfiguracji bezpośrednio w tym bloku, natomiast wydaje się, że czytelniej będzie umieścić wszystko w osobnym pliku:

				
					gitlab_rails['ldap_servers'] = YAML.load_file('/etc/gitlab/ad.yml')
				
			

Działająca konfiguracja wygląda zgodnie z poniższym przykładem:

				
					
main:
  label: 'AD'
  host: 'dc.test.local'
  port: 389
  uid: 'sAMAccountName'
  bind_dn: 'test\dev'
  password: 'zaq1@WSX'
  base: 'DC=test,DC=local'
  lowercase_usernames: true
  encryption: 'plain'
				
			

Wartości powinny być ogólnie zrozumiałe i są typowe dla podobnych integracji. label w tym przypadku oznacza nazwę karty do logowania.

Najlepiej wcześniej zadbać o niewygasanie hasła i brak możliwości jego zmiany dla użytkownika podanego w bind_dn. Jeśli zapomnimy zmienić hasło, a ono wygaśnie, pozostali użytkownicy domenowi nie będą mogli uzyskać dostępu do GitLab. Przy tworzeniu użytkownika w dsa.msc wystarczy odznaczyć pierwszą opcję, a zaznaczyć kolejnie dwie.

Dodawanie użytkownika do domeny Active Directory.

Zmiany wdrażamy poleceniem sudo gitlab-ctl reconfigure.

Zanim przetestujemy działanie logowania, sugeruję jeszcze przejście do ustawień (Admin Area -> Settings -> General) i w sekcji Account and limit dezaktywację opcji Allow new users to create top-level groups. Jeśli ilość naszych użytkowników będziemy liczyć w setkach i każdy z nich będzie mógł zakładać grupy w „głównej przestrzeni”, to bardzo szybko zostanie wprowadzony nieporządek.

Dodany wcześniej label jest widoczny oprócz domyślnego Standard służącego do logowania dla kont spoza domeny.

Logowanie domenowe w GitLab.

Można się domyślić, że rola administratora w GitLab nie jest równoznaczna przykładowo z członkostwem w grupie Domain Admins AD. Oznacza to, że jeśli którykolwiek z użytkowników pochodzących z domeny powinien mieć uprawnienia administratora, musimy je manualnie ustawić z poziomu innego konta administracyjnego po pierwszym zalogowaniu tego użytkownika.

Tworzenie grup i projektów

W grupach możemy tworzyć projekty w pewien logiczny sposób ze sobą powiązane, np. wszystkie pisane w tej samej technologii czy oparte na tym samym systemie CMS. Grupy tworzymy wybierając Create a group ; Create group. Wystarczy podać jej nazwę.

Tworzenie nowej grupy w GitLab.

Grupa może mieć członków, którzy po utworzeniu projektów w danej grupie będą do nich automatycznie dodawani. Aby przypisać członków do grupy, z poziomu jej widoku wybieramy Manage; Members; Invite members.

Tworzenie projektów również nie jest skomplikowane. Będąc w widoku grupy wybieramy zwyczajnie Create new project -> Create blank project. Jeśli projekt będziemy dodawać z innego miejsca, to proces jest analogiczny, jednak musimy wtedy określić docelową grupę z listy rozwijanej.

Tworzenie nowego projektu w GitLab.

GitLab Runner

Kluczowym elementem procesów CI/CD w GitLab są runner’y. To dedykowane hosty z zainstalowanym narzędziem gitlab-runner i przystosowane do obsługi pipelines. Instalacja runner’a jest wyjątkowo prosta, a instrukcje krok-po-kroku możemy zobaczyć wchodząc w Admin Area -> CI/CD -> Runners i wybierając z listy (ikona trzech pionowych kropek) Show runner installation and registration instructions.

Instrukcje instalacji GitLab Runner.

Najpierw warto jednak określić zastosowanie tego runner’a i wcześniej przygotować środowisko. Do dyspozycji mamy kilka rodzajów tzw. executors, np. ssh, shell, virtualbox, docker. Porównanie zostało przedstawione w dokumentacji dostępnej na tej stronie. Osobiście uważam, że wybranie Docker’a to dobra decyzja, bo zapewnia największą elastyczność. Zwykle sprawniej i łatwiej jest utworzyć obraz kontenera niż cały serwer czy maszynę wirtualną.

Samo tworzenie obrazów, które następnie będą przez nas używane w CI/CD pipelines, może okazać się wartościowym zajęciem. Obrazy powinny być minimalne i zawierać tylko potrzebne narzędzia, co nierzadko wymaga stosowania metody „prób i błędów” oraz szukania różnych rozwiązań na podstawie zdobytych doświadczeń. W IT kluczowy jest ciągły rozwój własnych kompetencji i zdobywanie nowej wiedzy, np. poprzez lekturę branżowych portali jak blog.theprotocol.it.

Jeśli zainstalowaliśmy Docker, możemy przystąpić do wykonywania poleceń widocznych w instrukcji.

Rejestracja runner w GitLab.

W domyślnej konfiguracji obrazy będą pobierane za każdym razem z container registry, nawet gdy są w pełni aktualne. Nie jest to może najbardziej odpowiednie rozwiązanie, dlatego powinniśmy zmienić właściwość pull_policy na wartość “if-not-present” w pliku /etc/gitlab-runner/config.toml (należy ją dodać w sekcji runners.docker).

Na koniec wykonujemy polecenie sudo gitlab-runner verify. Runner będzie już widoczny i dostępny do użycia w GitLab.

Dodane do GitLab runner'y.

Korzystanie z container registry

Utworzyliśmy wcześniej własne container registry pod domeną cr.test.local. Możemy teraz przesyłać do niego zbudowane przez nas obrazy. Taką dobrą praktyką jest dodanie dedykowanej grupy, a w niej projektów odpowiadających poszczególnym obrazom. Różne wersje obrazów możemy oznaczać tagami i przechowywać w tych samych projektach. Proces jest dość standardowy.

Lokalizacja obrazu w GitLab jest definiowana na podstawie jego nazwy. Jeśli obraz zamierzamy mieć pod adresem cr.test.local/docker/php-deploy:8.2, to lokalnie nazywamy go właśnie cr.test.local/docker/php-deploy:8.2. Obrazy mogą przesyłać członkowie grupy / projektu z rolą Maintainer. Z kolei jeśli inny członek chciałby użyć danego obrazu (w ramach CI/CD swojego projektu lub dany obraz pobrać) musi mieć jakąkolwiek rolę w projekcie z obrazem (nawet Guest).

Wysyłanie obrazu Docker.

Przesłane obrazy widoczne są po wejściu w Deploy -> Container Registry odpowiedniego projektu.

Obrazy Docker w GitLab.

Tworzenie CI/CD — własne skrypty

GitLab zapewnia wyjątkowo wygodny sposób tworzenia CI/CD pipelines. Właściwie zapoznanie się już z kilkoma przykładami pozwala zrozumieć ogólne koncepcje, a w konsekwencji umożliwia dodawanie coraz bardziej rozbudowanych przepływów.

Zaczniemy właśnie od podstawowego przeglądu tego procesu na przykładzie systemu CMS Made Simple. Do repozytorium przesłałem kod źródłowy zwykłej witryny dostępnej po zainstalowaniu tego systemu.

CMS Made Simple w repozytorium.

Na początku dodamy bardzo prosty stage, który zwyczajnie utworzy archiwum ZIP z zawartością repozytorium. W tym celu do pliku .gitlab-ci.yml (to nazwa głównego pliku konfiguracji CI/CD w GitLab) dodajemy poniższy kod:

				
					stages:
  - build

build:
  stage: build
  when: on_success
  only:
    - master
  image: alpine
  script: echo "Build"
  artifacts:
    paths:
       - .
    exclude:
      - .git
      - .git/**/*
      - .gitignore
      - .gitlab-ci.yml

				
			

Blok stages oznacza listę kolejnych etapów w przepływie CI/CD. Aktualnie jest tylko jeden, ponieważ nie wykonujemy żadnych złożonych kroków, a wyłącznie tworzymy archiwum z repozytorium. W kolejnym bloku określamy już podstawowe „założenia” zdefiniowanego wcześniej stage, czyli piszemy joba. Poszczególne opcje są następujące:

  • stage — określenie nazwy stage
  • when — tutaj on_success, czyli stage zostanie rozpoczęty automatycznie po każdym kolejnym przesłaniu kodu do repozytorium
  • only — zawiera nazwy gałęzi, dla których stage będzie wykonywany
  • image — nazwa wykorzystywanego obrazu Docker
  • script — polecenia wykonywane w ramach stage’u (tutaj tylko komunikat echo, bo chociaż nie potrzebujemy obecnie nic wykonywać, to script musi się znajdować w definicji joba)
  • artifacts — w paths podajemy ścieżkę względną do utworzenia archiwum, z kolei exclude zawiera ignorowanych listę plików i katalogów (.git/**/* oznacza całą zawartość katalogu .git)

Po przesłaniu pliku do repozytorium możemy przejść do Build -> Pipelines, aby zobaczyć historię wykonywanych jobów.

Historia jobów w GitLab.

Przechodząc do poszczególnych stage będziemy mogli sprawdzić cały przebieg ich wykonywania. Prawdopodobnie będziemy musieli trochę poczekać na rozpoczęcie wykonywania, ponieważ dopiero dodaliśmy runner i będą na niego pobierane potrzebne obrazy wykorzystywane przez GitLab.

Zapis wykonywania joba w GitLab.

Po prawej stronie w sekcji Job artifacts możemy przeglądać i pobierać utworzone archiwa.

Pokazany powyżej zapis pliku YML może z czasem przestać być czytelny, szczególnie gdy będziemy dodawać kolejne złożone etapy do przepływów. YAML posiada możliwość użycia anchors. W naszym przypadku modyfikacja będzie wyglądać w ten sposób:

				
					stages:
  - build

.build: &build
  image: alpine
  script: echo "Build"
  artifacts:
    paths:
      - .
    exclude:
      - .git
      - .git/**/*
      - .gitignore
      - .gitlab-ci.yml

build:
  stage: build
  when: on_success
  only:
    - master
  <<: *build
				
			

Wykonanie joba będzie miało dokładnie taki sam efekt.

Po praktycznym zapoznaniu ze strukturą YAML oraz konfiguracji CI/CD pipelines możemy utworzyć bardziej ambitny przykład, w którym na serwer prześlemy kod z repozytorium. Zmodyfikujemy stage build oraz dodamy nowy o nazwie deploy.

Definiujemy więc drugi stage:

				
					stages:
  - build
  - deploy
				
			

W przypadku build komunikat echo zastępujemy poleceniem tar, który utworzy nam paczkę sources.tgz z kodem, wykluczając jednak pewne wrażliwe pliki i katalogi:

				
					script:
  - tar --exclude=".git" --exclude=".gitignore" --exclude=".gitlab-ci.yml" -zcpf sources.tgz *
				
			

Znacznie modyfikujemy też opcję artifacts — zależy nam, aby w drugim etapie deploy była możliwość dostępu do utworzonej paczki.

				
					  artifacts:
    name: "$CI_JOB_NAME"
    paths:
      - sources.tgz
				
			

Dodajemy też całą konfigurację dla deploy:

				
					.deploy: &deploy
  image: alpine
  before_script:
    - apk --update add openssh-client
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$key")
    - mkdir ~/.ssh && echo -e "Host *\n\tStrictHostKeyChecking no" > ~/.ssh/config
  script:
    - ssh $connection "mkdir -p $path"
    - scp sources.tgz $connection:$path
    - ssh $connection "tar -C $path -zxf $path/sources.tgz && rm $path/sources.tgz"

deploy:
  stage: deploy
  when: manual
  dependencies:
    - build
  only:
    - master
  variables:
    connection: $connection
    path: $path
    key: $key
  <<: *deploy

				
			

W tym miejscu wymagane są wyjaśnienia poszczególnych opcji. Można zauważyć, że dodałem opcję before_script. Różnica pomiędzy tą opcją a script obejmuje nazwę — ich działanie jest analogiczne, wykonują się po kolei od góry do dołu. before_script ma znaczenie z punktu widzenia czytelności zapisu. W naszym przypadku w before_script zawarliśmy polecenia przygotowujące środowisko kontenera do przesłania paczki protokołem SSH. Instalujemy klienta tej usługi, inicjujemy agenta i przekazujemy do niego klucz prywatny. Dodatkowo dodajemy konfigurację do pliku ~/.ssh/config, która zapobiegnie standardowemu „pytaniu” przed pierwszym połączeniem z serwerem SSH — nie mamy możliwości bezpośredniej interakcji z kontenerem.

Natomiast w script wykonujemy już właściwe polecenia służące do przesłania i wypakowania archiwum na serwerze.

when w jobie deploy ustawiłem na manual, aby nie rozpocząć przypadkowego wdrożenia aplikacji. Da nam to również czas na dodanie widocznych zmiennych connection, path i key dla zdalnego serwera, na którym uruchomimy CMS Made Simple. Dzięki użyciu dependencies GitLab pobierze nam utworzony w poprzednim jobie artefakt sources.tgz.

W Build -> Pipelines zobaczymy, że job build został wykonany, a deploy czeka na manualne rozpoczęcie.

Job wymagający uruchomienia przez użytkownika.

Należy dodać zmienne connection, path i key po przejściu w Settings -> CI/CD i rozwinięciu karty Variables. Ich zawartości można się domyślić:

  • connection — nazwa i adres docelowego hosta, jak przy zwykłym połączeniu SSH (np. [email protected])
  • path — docelowa lokalizacja, najpewniej document root dla naszej witryny (np. /home/www/cmsms/public_html)
  • key — klucz prywatny powiązany z kluczem publicznym dodanym na docelowym serwerze

Dodane zmienne w GitLab.

Teraz możemy uruchomić job i zobaczyć efekty działania.

Zapis deploy w logach.

Dane aplikacji zostały przesłane na serwer. Wystarczy zaimportować bazę danych oraz dodać zawartość pliku config.php. tar przy wypakowywaniu nadpisuje jedynie pliki zawarte w archiwum (tutaj w repozytorium), więc wszelkie dane dodane przez nas pozostaną nienaruszone. CMS Made Simple został z powodzeniem wdrożony.

Panel administratora CMS Made Simple.

Plik .gitlab-ci.yml jest znacznie dłuższy niż na początku. Ilość linii będzie się zwiększać wraz z dodawaniem nowych stage’y. Polecam wyodrębnić wszystkie dodawane etapy do innych plików zawartych np. w katalogu .gitlab. Służy do tego opcja include. Czyli w .gitlab-ci.yml pozostawiamy wyłącznie:

				
					stages:
  - build
  - deploy

include:
  - /.gitlab/build.yml
  - /.gitlab/deploy.yml
				
			

Natomiast do plików .gitlab/build.yml i .gitlab/deploy.yml przenosimy definicję jobów odpowiednio dla build i deploy.

Nie ma potrzeby, aby wszystkie polecenia prowadzące do wdrożenia aplikacji zapisywać w opcji script. Świetnym rozwiązaniem jest napisanie własnego skryptu, ustawienie prawa do wykonywania (można to osiągnąć zarówno w opcji script, jak i bezpośrednio na pliku w lokalnym repozytorium) i jego uruchomienie. Zmiany dodamy na osobnym branchu, a następnie wykonamy merge do głównej gałęzi master.

W celu utworzenia brancha wybieramy przycisk + i New branch.

Tworzenie nowej gałęzi w GitLab.

Tworzymy plik deploy.sh ze skryptem do wdrożeń:

				
					#!/bin/bash


ssh $connection "mkdir -p $path"
scp sources.tgz $connection:$path
ssh $connection "tar -C $path -zxf $path/sources.tgz &amp;&amp; rm $path/sources.tgz"
				
			

W deploy.yml zastępujemy całą opcję script jednym uruchomieniem skryptu deploy.sh. Z kolei w build.yml dodajemy plik do –exclude polecenia tar. Po wysłaniu zmian na branch deploy możemy utworzyć merge request.

Oczekujące merge request’y można sprawdzić w odpowiedniej zakładce w projekcie. Po zaakceptowaniu zmiany zostaną dodane do głównej gałęzi.

Akceptacja merge request.

Tworzenie CI/CD — Deployer

Nie zawsze skrypty podobne do tego z powyższych przykładów będą wystarczające. Przy większych projektach zachodzi potrzeba użycia bardziej zaawansowanych rozwiązań. Bardzo dobrym wyborem będzie Deployer. Pomimo tego, że jest napisany w PHP, nic nas nie ogranicza przed użyciem Deployer do wdrożeń aplikacji napisanych w innych językach — jedynie kontener używany do deploy’a będzie musiał obsługiwać PHP i posiadać zainstalowany rsync.

Deployer zawiera szereg gotowych konfiguracji (nazwanych recipes) dla najpopularniejszych CMS czy frameworków. Możemy również napisać własne recipes, co nie jest zbyt skomplikowane, aczkolwiek przyda się podstawowa znajomość instrukcji PHP. Sam Deployer ma wbudowanych kilka poleceń. Zachęcam do ich przetestowania we własnym zakresie, natomiast pełna wiedza wszystkich funkcjonalnościach nie jest absolutnie wymagana do użycia Deployer z GitLab CI/CD.

Podczas wdrożenia z wykorzystaniem Deployer tworzona jest charakterystyczna struktura katalogów:

  • releases — zawiera dziesięć (domyślna wartość) ostatnio wdrożonych wersji aplikacji oznaczonych kolejnymi liczbami
  • shared — katalog na dane “przechodzące” pomiędzy kolejnymi wydaniami, np. pliki konfiguracyjne czy katalogi przeznaczone na przesłane grafiki
  • .dep — katalog pomocniczy Deployer zawierający historię wydań
  • release — tymczasowy link symboliczny do aktualnie wdrażanej wersji z katalogu releases
  • current — link symboliczny do aktualnej wersji z katalogu releases (w idealnych przypadkach to zawsze najnowsza wersja)

Powyższa struktura jest zakładana w katalogu zdefiniowanym jako deploy_path. Ma to znaczenie w kontekście ustawiania document root dla naszej witryny. Jeśli z jakiegoś powodu nie mamy możliwości zmiany tej lokalizacji, zawsze można utworzyć symlink do <deploy_path>/current.

Spróbujemy zautomatyzować wdrożenia systemu WordPress. Deployer w projekcie zainstalujemy poprzez Composer. Toteż tworzymy plik composer.json.

				
					{
    "require": {
        "deployer/deployer": "^7.3"
    }
}
				
			

Zawartość .gitlab-ci.yml będzie taka sama jak poprzednio:

				
					stages:
  - build
  - deploy

include:
  - /.gitlab/build.yml
  - /.gitlab/deploy.yml
				
			

W pliku build.yml jedyne zmiany to dodanie deploy.php do –exclude polecenia tar i (ewentualnie) zmiana paths artefaktu.

				
					.build: &build
  image: alpine
  script:
    - tar --exclude=".git" --exclude=".gitignore" --exclude=".gitlab-ci.yml" --exclude=".gitlab" --exclude="deploy.php" -zcpf code.tgz *
  artifacts:
    name: "$CI_JOB_NAME"
    paths:
      - code.tgz

				
			

GitLab posiada kilka wbudowanych zmiennych. $CI_JOB_NAME jest jedną z nich.

Zdecydowanie więcej modyfikacji wymaga deploy.yml.

				
					.deploy: &deploy
  image: cr.test.local/docker/php-deploy:8.2
  before_script:
    - eval $(ssh-agent -s)
    - ssh-add <(echo "$key")
    - mkdir ~/.ssh && echo -e "Host *\n\tStrictHostKeyChecking no" > ~/.ssh/config
    - composer install
  script:
    - sed -i "s/ci_host/$host/g" deploy.php
    - sed -i "s/ci_user/$user/g" deploy.php
    - sed -i "s|ci_path|$path|g" deploy.php
    - vendor/bin/dep deploy

deploy:
  stage: deploy
  when: manual
  only:
    - master
  variables:
   user: $user
   host: $host
   path: $path
   key: $key
  <<: *deploy

				
			

Mój obraz php-deploy:8.2 oparłem na oficjalnym obrazie php:8.2. Zainstalowałem pakiety git, unzip, libzip-dev i rsync, rozszerzenie php-zip (w Docker wystarczy użyć docker-php-ext-install zip) oraz Composer. To wystarczy do pobrania Deployer poprzez Composer i wykonania wdrożenia.

W script używamy sed do modyfikacji pliku deploy.php (kod widoczny poniżej). Nie powinniśmy zapisywać bezpośrednio w nim tych trzech wartości zmiennych.

				
					<?php
namespace Deployer;
require 'recipe/wordpress.php';
set('http_user', 'ci_user');
task('deploy:update_code', function () {
    upload('code.tgz', '{{release_path}}/code.tgz');
    run('tar -C {{release_path}} -zxf {{release_path}}/code.tgz');
    run('rm {{release_path}}/code.tgz {{release_path}}/composer.json');
});
host('ci_host')
    ->set('remote_user', 'ci_user')
    ->set('deploy_path', 'ci_path/wp');
after('deploy:failed', 'deploy:unlock');

				
			

Ustawienie http_user nie jest niezbędne, ponieważ Deployer na podstawie listy procesów będzie próbował sam ustalić nazwę użytkownika, na którego prawach działa proces serwera WWW. Jeśli jednak widoczność procesów została ograniczona, to sprawdzenie się nie powiedzie, dlatego w tym wypadku należało zapisać tę nazwę w deploy.php. Celem tego sprawdzenia jest ustawienie własności katalogów zdefiniowanych jako writable_dirs (w recipe); domyślnie używane jest do tego polecenie setfacl.

Domyślnie też Deployer zwyczajnie używa git archive w funkcji update_code. Nam jednak zależy na przesłaniu danych utworzonych przez GitLab opcją artefacts, dlatego konieczne było nadpisanie tej funkcji. upload stosuje rsync do przesłania archiwum code.tgz, następnie poleceniem tar wyodrębniamy zawartość, a na koniec usuwamy archiwum i plik composer.json ze zdalnego serwera.

Dodajemy variables do naszego projektu. Tym razem zmienną connection z poprzednich przykładów zastąpiliśmy osobnymi user i host — w PHP można co prawda użyć funkcji explode wyodrębnienia potrzebnych informacji z jednej zmiennej, ale przedstawiony sposób jest łatwiejszy. Proszę zwrócić uwagę na zmienną path — w deploy_path dodajemy do podanej w variables ścieżki /wp, więc path nie zawiera ostatecznej lokalizacji.

Zmienne używane we wdrożeniu z wykorzystaniem Deployer.

Job powinien zakończyć się sukcesem.

Udane wdrożenie.

Po uzupełnieniu pliku wp-config.php (z katalogu wp/shared) i zaimportowaniu bazy danych widzimy, że WordPress został poprawnie wdrożony.

Wdrożony WordPress.

Możemy też potwierdzić istnienie opisanej wcześniej struktury katalogów Deployer.

Struktura katalogów Deployer.

Podsumowanie

GitLab to świetne narzędzie, które spełnia swoją rolę. Umiejętność tworzenia CI/CD pipelines zawarta w naszym CV i potwierdzona w praktyce na pewno zostanie doceniona przez pracodawców, także z obszaru security.

Czy ten artykuł był pomocny?

Oceniono: 13 razy

Picture of Michał Giza

Michał Giza

Autor tekstów na portalu Fundacji AVLab dla Cyberbezpieczeństwa. Administrator systemów Linux i Windows Server.
Picture of Michał Giza

Michał Giza

Autor tekstów na portalu Fundacji AVLab dla Cyberbezpieczeństwa. Administrator systemów Linux i Windows Server.

PODZIEL SIĘ:

guest
0 komentarzy
Inline Feedbacks
View all comments

Wyrażam zgodę na przesłanie oferty drogą telefoniczną przez IT Partners security sp. z o.o. z siedzibą Katowicach ul.Padereskiego 35 na podany przeze mnie adres e-mail zgodnie z ustawą z dnia 10 maja 2018 roku o ochronie danych osobowych (Dz. Ustaw z 2018, poz. 1000) oraz zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych oraz uchylenia dyrektywy 95/46/WE (RODO).

Wyrażam zgodę na przesłanie oferty drogą mailową przez IT Partners security sp. z o.o. z siedzibą Katowicach ul.Padereskiego 35 na podany przeze mnie adres e-mail zgodnie z ustawą z dnia 10 maja 2018 roku o ochronie danych osobowych (Dz. Ustaw z 2018, poz. 1000) oraz zgodnie z Rozporządzeniem Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich danych oraz uchylenia dyrektywy 95/46/WE (RODO).

[ninja_tables id=”27481″]