Ugrás a fő tartalomhoz

Deployer - PHP Deployment Eszköz

A Deployer egy PHP alapú deployment automatizálási eszköz. Zero-downtime deployment-et biztosít, támogatja a rollback-et, és speciális WordPress receptekkel rendelkezik.

Miért Deployer?

  • Zero-downtime - Nincs leállás deployment közben
  • Atomic deploy - Sikertelen deploy nem töri el a site-ot
  • Rollback - Egyszerű visszaállás korábbi verzióra
  • Parallel - Több szerverre párhuzamos deploy
  • WordPress recept - Előre konfigurált WordPress támogatás
  • PHP alapú - Könnyű testreszabás

Telepítés

Composer (ajánlott)

# Projekt szintű
composer require deployer/deployer --dev

# Globális
composer global require deployer/deployer

Phar

curl -LO https://deployer.org/deployer.phar
chmod +x deployer.phar
sudo mv deployer.phar /usr/local/bin/dep

Alapkonfiguráció

Inicializálás

dep init

deploy.php (WordPress)

<?php

namespace Deployer;

require 'recipe/wordpress.php';

// Projekt konfiguráció
set('application', 'my-wordpress-site');
set('repository', '[email protected]:user/repo.git');

// Megosztott fájlok és mappák (deploy-ok között megmaradnak)
add('shared_files', [
'wp-config.php',
'.htaccess',
]);

add('shared_dirs', [
'wp-content/uploads',
'wp-content/cache',
]);

// Írható mappák
add('writable_dirs', [
'wp-content/uploads',
'wp-content/cache',
]);

// Host konfiguráció
host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/html')
->set('branch', 'main');

host('staging')
->set('hostname', 'staging.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/staging')
->set('branch', 'develop');

// Egyedi feladatok
task('deploy:wp-cli', function () {
run('cd {{release_path}} && wp cache flush');
run('cd {{release_path}} && wp rewrite flush');
});

// Deploy után WP-CLI parancsok
after('deploy:symlink', 'deploy:wp-cli');

Deployment folyamat

Mappa struktúra

/var/www/html/
├── current -> releases/5 # Symlink az aktuális release-re
├── releases/
│ ├── 1/
│ ├── 2/
│ ├── 3/
│ ├── 4/
│ └── 5/ # Legújabb release
└── shared/
├── wp-config.php
├── .htaccess
└── wp-content/
└── uploads/

Deploy parancsok

# Deploy production-re
dep deploy production

# Deploy staging-re
dep deploy staging

# Deploy verbose kimenettel
dep deploy production -vvv

# Dry run
dep deploy production --dry-run

Rollback

# Visszaállás előző verzióra
dep rollback production

# Adott számú lépés visszaállítása
dep rollback production --revision=3

WordPress specifikus beállítások

Composer alapú WordPress

<?php

namespace Deployer;

require 'recipe/common.php';

set('application', 'my-wordpress-site');
set('repository', '[email protected]:user/repo.git');

// Composer alapú WP struktúra
set('shared_files', [
'.env',
'web/.htaccess',
]);

set('shared_dirs', [
'web/app/uploads',
]);

set('writable_dirs', [
'web/app/uploads',
]);

// Composer telepítés
task('deploy:vendors', function () {
run('cd {{release_path}} && composer install --no-dev --optimize-autoloader');
});

// Asset build
task('deploy:build', function () {
run('cd {{release_path}} && npm ci && npm run build');
});

// WP-CLI cache flush
task('deploy:cache', function () {
run('cd {{release_path}}/web && wp cache flush');
});

task('deploy', [
'deploy:prepare',
'deploy:vendors',
'deploy:build',
'deploy:publish',
'deploy:cache',
]);

host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/html');

Bedrock WordPress

<?php

namespace Deployer;

require 'recipe/common.php';

set('application', 'bedrock-site');
set('repository', '[email protected]:user/bedrock-site.git');

// Bedrock struktúra
set('shared_files', [
'.env',
]);

set('shared_dirs', [
'web/app/uploads',
]);

set('writable_dirs', [
'web/app/uploads',
]);

// Bedrock deploy
task('deploy:vendors', function () {
run('cd {{release_path}} && composer install --no-dev --prefer-dist --optimize-autoloader');
});

task('deploy', [
'deploy:prepare',
'deploy:vendors',
'deploy:publish',
]);

after('deploy:failed', 'deploy:unlock');

host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/bedrock');

Téma és plugin fejlesztés

Csak téma deployment

<?php

namespace Deployer;

require 'recipe/common.php';

set('application', 'my-theme');
set('repository', '[email protected]:user/my-theme.git');

// Téma deployment
set('theme_path', '/var/www/html/wp-content/themes/my-theme');

task('deploy:theme', function () {
$source = get('release_path');
$target = get('theme_path');

run("rsync -avz --delete {$source}/ {$target}/");
});

task('deploy:build', function () {
run('cd {{release_path}} && npm ci && npm run build');
});

task('deploy:cache', function () {
run('cd /var/www/html && wp cache flush');
});

task('deploy', [
'deploy:prepare',
'deploy:build',
'deploy:theme',
'deploy:cache',
'deploy:cleanup',
]);

host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/home/deploy/theme-releases');

Plugin deployment

<?php

namespace Deployer;

require 'recipe/common.php';

set('application', 'my-plugin');
set('repository', '[email protected]:user/my-plugin.git');

set('plugin_path', '/var/www/html/wp-content/plugins/my-plugin');

task('deploy:composer', function () {
run('cd {{release_path}} && composer install --no-dev --optimize-autoloader');
});

task('deploy:build', function () {
run('cd {{release_path}} && npm ci && npm run build');
});

task('deploy:plugin', function () {
$source = get('release_path');
$target = get('plugin_path');

// Dist fájlok másolása
run("rsync -avz --delete \
--exclude='.git' \
--exclude='node_modules' \
--exclude='tests' \
--exclude='src' \
{$source}/ {$target}/");
});

task('deploy:activate', function () {
run('cd /var/www/html && wp plugin activate my-plugin');
});

task('deploy', [
'deploy:prepare',
'deploy:composer',
'deploy:build',
'deploy:plugin',
'deploy:activate',
'deploy:cleanup',
]);

host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/home/deploy/plugin-releases');

Egyedi task-ok

Adatbázis backup

task('db:backup', function () {
$date = date('Y-m-d_H-i-s');
run("cd {{deploy_path}}/current && wp db export ~/backups/db_{$date}.sql");
})->desc('Backup database');

// Deploy előtt automatikus backup
before('deploy:symlink', 'db:backup');

Maintenance mode

task('maintenance:enable', function () {
run('cd {{deploy_path}}/current && wp maintenance-mode activate');
})->desc('Enable maintenance mode');

task('maintenance:disable', function () {
run('cd {{deploy_path}}/current && wp maintenance-mode deactivate');
})->desc('Disable maintenance mode');

// Deploy közben maintenance mode
before('deploy:symlink', 'maintenance:enable');
after('deploy:symlink', 'maintenance:disable');

Cache törés

task('cache:clear', function () {
run('cd {{deploy_path}}/current && wp cache flush');
run('cd {{deploy_path}}/current && wp transient delete --all');
run('cd {{deploy_path}}/current && wp rewrite flush');
})->desc('Clear all caches');

after('deploy:symlink', 'cache:clear');

Opcache reset

task('opcache:reset', function () {
run('cd {{deploy_path}}/current && wp eval "opcache_reset();"');
})->desc('Reset OPcache');

after('deploy:symlink', 'opcache:reset');

Több környezet

Host konfigurációk

// Production
host('production')
->set('hostname', 'prod.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/html')
->set('branch', 'main')
->set('http_user', 'www-data')
->set('keep_releases', 5);

// Staging
host('staging')
->set('hostname', 'staging.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/staging')
->set('branch', 'develop')
->set('http_user', 'www-data')
->set('keep_releases', 3);

// Development
host('dev')
->set('hostname', 'dev.example.com')
->set('remote_user', 'deploy')
->set('deploy_path', '/var/www/dev')
->set('branch', 'develop')
->set('keep_releases', 2);

Környezet specifikus beállítások

// Production specifikus
host('production')
->set('hostname', 'prod.example.com')
->set('deploy_path', '/var/www/html')
->set('env', [
'APP_ENV' => 'production',
'WP_ENV' => 'production',
]);

// Staging
host('staging')
->set('hostname', 'staging.example.com')
->set('deploy_path', '/var/www/staging')
->set('env', [
'APP_ENV' => 'staging',
'WP_ENV' => 'staging',
]);

SSH konfiguráció

SSH kulcs

host('production')
->set('hostname', 'server.example.com')
->set('remote_user', 'deploy')
->set('identity_file', '~/.ssh/deploy_key')
->set('deploy_path', '/var/www/html');

SSH proxy/jump host

host('production')
->set('hostname', 'internal-server.local')
->set('remote_user', 'deploy')
->set('proxy_host', 'jumpbox.example.com')
->set('proxy_user', 'proxy-user')
->set('deploy_path', '/var/www/html');

CI/CD integráció

GitHub Actions

.github/workflows/deploy.yml:

name: Deploy

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'

- name: Install dependencies
run: composer install --no-dev --optimize-autoloader

- name: Setup SSH
uses: webfactory/ssh-[email protected]
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

- name: Deploy to production
run: vendor/bin/dep deploy production

GitLab CI

.gitlab-ci.yml:

stages:
- deploy

deploy_production:
stage: deploy
image: php:8.2-cli
before_script:
- apt-get update && apt-get install -y git openssh-client
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
- mkdir -p ~/.ssh
- echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
- composer install --no-dev
script:
- vendor/bin/dep deploy production
only:
- main

Hibaelhárítás

Deploy unlock

# Ha a deploy elakad
dep deploy:unlock production

Részletes output

dep deploy production -vvv

SSH teszt

dep ssh production

Task lista

dep list

Best Practices

1. Mindig készíts backup-ot

before('deploy:symlink', 'db:backup');

2. Használj .env fájlt

set('shared_files', ['.env']);

3. Tartsd meg több release-t

set('keep_releases', 5);

4. Logold a deploy-okat

task('deploy:log', function () {
$date = date('Y-m-d H:i:s');
$user = run('whoami');
$branch = get('branch');
run("echo '{$date} - {$user} deployed {$branch}' >> {{deploy_path}}/deploy.log");
});

after('deploy:symlink', 'deploy:log');

5. Értesítések

task('notify:slack', function () {
$webhook = 'https://hooks.slack.com/services/xxx';
$message = json_encode([
'text' => '🚀 ' . get('application') . ' deployed to ' . get('hostname'),
]);
run("curl -X POST -H 'Content-type: application/json' --data '{$message}' {$webhook}");
});

after('deploy:success', 'notify:slack');

Források