Deployment PHP aplikací pomocí Deployeru a Gitlab CI

Jednoduchý návod na snadný deployment PHP/Symfony aplikací z Gitlabu i z lokálního počítače.

Nasazení nové verze aplikace bývá rutinní sled mnoha kroků a nebývá dobré na některý z nich zapomenout. To může být trochu složitější v situacích, kdy se třeba mění vlastnosti u dat neverzovaných v repozitářích - např. práva zápisu nebo struktura u dat aplikace. 

Ideální řešení je tedy celý proces co nejvíce zautomatizovat, zakomponovat jej do vývojového procesu a učinit jej v něm snadno a rychle dostupný. Pokud provozujete vaší aplikaci v nějakém container enginu, tak pro její deployment pravděpodobně využíváte některý z nástrojů pro orchestraci kontejnerů. Pokud ale provozujete aplikaci klasickým způsobem, můžete automatizovaného deploymentu  snadno dosáhnout např. jednoduchým Bash skriptem a nastavením možností jeho vzdáleného spouštění. Nám se ale pro tento způsob nasazování nových verzí Symfony aplikací asi nejvíce osvědčil nástroj Deployer

Následující návod přidá možnost ručního spuštění deploymentu z Gitlabu pomocí CI a z lokálního počítače s naklonovaným repozitářem.

Deployer

Jako první krok přidáme do repozitáře phar soubory deployeru a composeru. Byť na stránkách deployer.org zkracují název souboru na prosté dep, doporučuji jej ponechat s koncovkou .phar. V PhpStormu pak bude možné rozkliknout jeho obsah a jednoduše sprojít a prozkoumat všechny různé 'recepty' pro různé frameworky a situace.

$ curl -LO https://deployer.org/deployer.phar

Poté již stačí vytvořit jednoduchý skript deploy.php s popisem jednotlivých kroků pro spuštění aplikace a v jakém pořadí se mají spustit. Pro pořádek uvedu, že v rámci předpřipravených receptů není k dispozici konkrétní recept pro aktuální Symfony5. Nasazování aplikací se ale nijak neliší od Symfony4 a proto lze jednoduše vyžít recept pro tuto verzi. Níže uvedený recept je nutné v konkrétních detailech (repo url, sdílené soubory a adresáře, zapisovatelné adresáře atd.) upravit dle konkrétních potřeb.

<?php

namespace Deployer;

require 'recipe/symfony4.php';

set('application', 'iD-SIGN Website');
set('repository', 'ssh://git@gitlab.url/your/repo'); 
set('shared_dirs', ['var/log', 'var/sessions', 'public/media', 'data']);
set('shared_files', ['.env.local', 'public/robots.txt']);
set('writable_dirs', ['public/media', 'data', 'var/cache']);
set('bin/composer', '{{release_path}}/composer.phar');
set('keep_releases', 3);

// Hosts
host('production')
    ->hostname('yourserver.com')
    ->user('user')
    ->set('deploy_path', '/var/www/id-sign.com/www')
    ->set('http_user', 'www-data')
    ->become('id-sign');

// Tasks
task('deploy:build_assets', static function () {
    run('cd {{release_path}} && yarn install && yarn encore production');
});

// Migrate database before symlink new release.
before('deploy:symlink', 'database:migrate');
before('database:migrate', 'deploy:build_assets');

// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');

Samotný skript je asi samovysvětlující. Pro rychlejší pochopení bez nutnosti studování kódu ještě připojím seznam úkolů, které definuje a spouští recept pro Symfony4 v rámci úkolu 'deploy'.

desc('Deploy project');
task('deploy', [
    'deploy:info',
    'deploy:prepare',
    'deploy:lock',
    'deploy:release',
    'deploy:update_code',
    'deploy:shared',
    'deploy:vendors',
    'deploy:writable',
    'deploy:cache:clear',
    'deploy:cache:warmup',
    'deploy:symlink',
    'deploy:unlock',
    'cleanup',
]);

Jak to celé funguje? Deployer se skrze ssh spojení připojí na hostname() server jako user(). Pokud je potřeba se následně přepnout na jiného uživatele, nastaví se tento pomocí metody become() a k přepnutí se defaultně využívá sudo. Je potřeba tedy mít tuto možnost přepnutí user() -> become() povolenou.

Nastavení sudo je jednoduché, stačí přidat konfigurační soubor do /etc/sudoers.d - např. /etc/sudoers.d/projectname a do něj uvést jednoduchý zápis a reloadnout sudo. Ukázka nastavení pro umožnění uživateli newman přepnutí se bez hesla na uživatele id-sign a tomu pak možnost přepnutí se na uživatele www-data.

newman ALL=(id-sign) NOPASSWD:ALL
id-sign ALL=(www-data) NOPASSWD:ALL

Že vše funguje ověříte velmi snadno např. pomocí:

newman@server$ sudo -u id-sign bash

Před prvním testovacím spuštěním uvedu, že deployer si na serveru vytváří vlastní adresářovou strukturu pro jednotlivé vydání. Pokud  tedy již aplikaci máte nainstalovanou na serveru, bude velmi pravděpodobně nutné upravit její umístění a rovněž tak nastavení web serveru.

První pokusy doporučuji provádět mimo produkční verzi :-)

Testovací spuštění můžeme provést z lokálního počítače z adresáře s naklonovaným projektem. Pro plný komfort je vhodné mít nastaveno přihlašování na server pomocí ssh klíče. Pokud to nemáte, lze to velmi jednoduše napravit. 

Vygenerování ssh klíče:

$ ssh-keygen

Instalace klíče na server (server uživatele a hostname serveru si upravte dle vaší situace):

$ ssh-copy-id user@your-server.com

Nyní již můžeme zkusit váš první deploy, který může vypadat takto:

$ php deployer.phar deploy production
✈︎ Deploying master on production
✔ Executing task deploy:prepare
✔ Executing task deploy:lock
✔ Executing task deploy:release
✔ Executing task deploy:update_code
✔ Executing task deploy:shared
✔ Executing task deploy:vendors
✔ Executing task deploy:writable
✔ Executing task deploy:cache:clear
✔ Executing task deploy:cache:warmup
✔ Executing task deploy:build_assets
✔ Executing task database:migrate
✔ Executing task deploy:symlink
✔ Executing task deploy:unlock
✔ Executing task cleanup
Successfully deployed!

Pokud by během procesu deploymentu nastala chyba, bude vás Deployer poměrně srozumitelně informovat. Pokud vše proběhlo v pořádku, tak byste měli mít na serveru v adresáři pro aplikaci vytvořenou novou strukturu adresářů:

$ ls -l
celkem 8
lrwxrwxrwx 1 id-sign id-sign   10 čec  9 13:15 current -> releases/1
drwxr-xr-x 8 id-sign id-sign 4096 čec  9 13:17 releases
drwxr-xr-x 5 id-sign id-sign 4096 lis 18  2020 shared

Nastavení webového serveru upravíte tak, aby document root ukazoval do public adresáře v adresáři current. Pokud by něco z výše uvedeného nebylo jasné, nebo vás zajímaly všechny možnosti nastavení, doporučuji si projít deployer dokumentaci

Gitlab CI

Pro deployment můžeme využít i Gitlab tak, abychom mohli nasadit nové verze přímo z jeho webového rozhraní. Oceníte to, pokud je součástí vaší práce třeba kontrola slučování různých vývojových větví do main větve a její následný release. Vše lze samozřejmě nastavit automaticky po úspěšném běhu testů, lintu atd. V této ukázce bude ale pro jednoduchost konfigurován manuální release. Ten si lze pak snadno upravit dle potřeb.

Jako první krok přidáme do repozitáře soubor .gitlab-ci.yml s tímto obsahem (server hostname a php verzi upravímr dle potřeby):

stages:
    - deploy

deploy:
    image: chialab/php:8.0
    stage: deploy

    script:
        - eval "$(ssh-agent -s)"
        - ssh-add <(echo "$DEPLOY_KEY" | openssl base64 -A -d)
        - mkdir ~/.ssh && ssh-keyscan -H your.server.com >> ~/.ssh/known_hosts
        - php ./deployer.phar deploy production --branch $CI_COMMIT_REF_NAME -vv

    when: manual

Dále v Gitlabu v nastavení repozitáře Settings -> CI/CD vytvoříme maskovanou proměnnou DEPLOY_KEY do které si uložíme base64 string ssh privátního klíče, kterým se budeme přihlašovat na server. Z bezpečnostních důvodů nechceme, aby byl privátní klíč pro přihlášení na server součástí repozitáře. Base64 string získáme snadno buďto v nějaké online službě, nebo v linuxu příkazem base64. Abychom mohli proměnnou v Gitlabu maskovat, musí být její hodnota jednořádková - parametrem -w 0 vypneme zalamování generovaného textu:

$ base64 -w 0 private.key > private64

Obsah vzniklého souboru zkopírujeme a uložíme jej do výše zmíněné proměnné DEPLOY_KEY.

A to je v podstatě vše. Nyní by se vám v rámci Gitlabu měla zobrazovat možnost pro spuštění CI deploy jobu a pokud máte k repozitáři i dostupné CI pipeline, mělo by vše bez problémů proběhnout a vy tak získáte možnost pustit deploy třeba ihned po sloučení změn z různých větví do hlavní větve, aniž byste museli pouštět příkazovou řádku a přihlašovat se na server.

Mohlo by vás také zajímat

Sentry Performance, PHP a GraphQL

Jak využít Sentry Performance pro monitoring výkonu PHP aplikace včetně výkonu GraphQL API.

Číst více

PHP8.1, Enum třídy a Doctrine

Jednou z novinek PHP8.1 je i podpora Enum tříd. Tento zápisek vznikl jako stručné intro k tomu, jak lze tuto novinku používat ve spojení s Doctrine.

Číst více

Symfony, lokální server a důvěryhodný SSL certifikát v Chrome

Nastavte si důvěryhodný certifikát v Chrome i pro vývoj Symfony aplikací

Číst více

nám. Republiky 28
301 00 Plzeň
Česká republika
IČ: 28006402
DIČ: CZ28006402

© 2002 - 2024 iD-SIGN BRANDS MENTIONED ABOVE ARE PROPERTY OF THEIR RESPECTIVE OWNER.