18. 项目部署与维护

18.项目部署与维护

部署流程

部署 Phalcon 项目不像普通 PHP 项目那样简单地将文件上传到服务器即可,需要进行一系列的环境配置和优化才能确保应用稳定运行。作为一个用 C 扩展实现的框架,Phalcon 对服务器环境有一些特殊要求,这也是很多开发者在部署时容易踩坑的地方。

部署前准备

在开始部署之前,我们需要准备好以下几项:

  1. 代码版本控制:确保代码已经提交到 Git 仓库,并且所有开发环境的修改都已同步。建议使用标签(tag)标记发布版本,例如:
# 创建发布标签
git tag -a v1.0.0 -m "Production release v1.0.0"
# 推送标签到远程仓库
git push origin v1.0.0
  1. 环境检查清单:创建一个部署检查清单,确保服务器满足以下要求:

    • PHP 版本 >= 8.0
    • Phalcon 扩展 >= 5.0
    • 必要的 PHP 扩展(pdo, mbstring, json, openssl 等)
    • 数据库服务(MySQL/MariaDB 或其他支持的数据库)
    • Web 服务器(Nginx 或 Apache)
  2. 配置文件准备:为生产环境创建单独的配置文件,通常命名为 config.prod.php,包含数据库连接信息、缓存配置等敏感信息。这些信息不应提交到代码仓库,而应在部署时通过环境变量或配置服务器注入。

代码部署策略

对于 Phalcon 项目,我推荐使用以下两种部署策略之一:

1. 直接部署(小型项目)

对于规模较小的项目,可以采用简单直接的部署方式:

# 1. 登录服务器
ssh user@your-server.com

# 2. 进入网站根目录
cd /var/www/your-project

# 3. 拉取最新代码
git pull origin main

# 4. 安装依赖(如果使用 Composer)
composer install --no-dev --optimize-autoloader

# 5. 执行数据库迁移
php vendor/bin/phalcon-migrations run

# 6. 清除缓存
rm -rf app/cache/*

# 7. 设置文件权限
chmod -R 775 app/cache
chmod -R 775 public/uploads

这种方法简单直接,但缺点是在拉取代码和更新过程中,可能会导致短暂的服务不可用。

2. 蓝绿部署(中大型项目)

对于对可用性要求较高的项目,蓝绿部署是更好的选择。这种方式需要在服务器上维护两个相同的环境:

  • 蓝环境:当前正在运行的生产环境
  • 绿环境:准备部署的新版本环境

部署流程如下:

# 1. 登录服务器
ssh user@your-server.com

# 2. 进入备用目录
cd /var/www/your-project-green

# 3. 拉取最新代码
git pull origin main

# 4. 安装依赖
composer install --no-dev --optimize-autoloader

# 5. 执行数据库迁移
php vendor/bin/phalcon-migrations run

# 6. 清除缓存
rm -rf app/cache/*

# 7. 设置文件权限
chmod -R 775 app/cache
chmod -R 775 public/uploads

# 8. 切换符号链接
ln -sfn /var/www/your-project-green /var/www/your-project

# 9. 重启 PHP-FPM
systemctl restart php-fpm

通过这种方式,新版本的部署可以瞬间完成,几乎不会导致服务中断。

环境配置

Phalcon 项目的环境配置涉及多个层面,包括 PHP 配置、Web 服务器配置和应用配置。

PHP 配置优化

生产环境的 PHP 配置需要进行一些优化以提高性能和安全性。以下是 php.ini 中一些关键配置项的建议值:

# 性能优化
memory_limit = 256M
max_execution_time = 30
opcache.enable = On
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 60

# 安全设置
expose_php = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
allow_url_fopen = Off

特别是 OPCache 的配置对 Phalcon 应用的性能影响很大。由于 Phalcon 本身是 C 扩展,不需要像其他 PHP 框架那样缓存 PHP 文件,但应用中的业务代码仍然可以通过 OPCache 获得性能提升。

Web 服务器配置

Phalcon 支持 Nginx 和 Apache 作为 Web 服务器,其中 Nginx 由于其高性能和低资源消耗,成为大多数生产环境的首选。

Nginx 配置

以下是一个针对 Phalcon 应用优化的 Nginx 配置示例:

server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$host$request_uri; # 强制 HTTPS
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /path/to/ssl/certificate.crt;
    ssl_certificate_key /path/to/ssl/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    root /var/www/your-project/public;
    index index.php index.html;

    charset utf-8;
    client_max_body_size 100M;
    fastcgi_read_timeout 1800;

    # 日志配置
    access_log /var/log/nginx/your-project-access.log;
    error_log /var/log/nginx/your-project-error.log;

    location / {
        try_files $uri $uri/ /index.php?_url=$uri&$args;
    }

    location ~ [^/]\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
        fastcgi_index /index.php;
        include fastcgi_params;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # 静态文件缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 30d;
        add_header Cache-Control "public, max-age=2592000";
        log_not_found off;
    }
}

这个配置包含了几个重要部分:

  1. 强制 HTTPS 访问
  2. SSL 安全配置
  3. 正确的 PHP-FPM 连接设置
  4. 静态文件缓存策略
  5. 适当的日志配置

Apache 配置

如果必须使用 Apache,可以使用以下配置:

<VirtualHost *:80>
    ServerName your-domain.com
    Redirect permanent / https://your-domain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName your-domain.com
    DocumentRoot "/var/www/your-project/public"

    SSLEngine on
    SSLCertificateFile "/path/to/ssl/certificate.crt"
    SSLCertificateKeyFile "/path/to/ssl/private.key"

    <Directory "/var/www/your-project/public">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog "logs/your-project-error.log"
    CustomLog "logs/your-project-access.log" common
</VirtualHost>

同时,需要在项目根目录创建 .htaccess 文件:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

应用配置管理

Phalcon 应用的配置管理是部署过程中的关键环节。一个好的配置策略应该满足以下要求:

  1. 环境隔离:开发、测试、生产环境使用不同配置
  2. 安全存储:敏感信息(如数据库密码)不应明文存储
  3. 易于维护:配置变更不需要修改代码

推荐使用环境变量 + 配置文件的方式管理配置:

// app/config/config.php
return new \Phalcon\Config\Config([
    'database' => [
        'adapter'  => getenv('DB_ADAPTER') ?: 'Mysql',
        'host'     => getenv('DB_HOST') ?: 'localhost',
        'username' => getenv('DB_USERNAME') ?: 'root',
        'password' => getenv('DB_PASSWORD') ?: '',
        'dbname'   => getenv('DB_NAME') ?: 'phalcon_app',
        'charset'  => 'utf8mb4',
    ],
    'application' => [
        'appDir'         => APP_PATH . '/app/',
        'controllersDir' => APP_PATH . '/app/controllers/',
        'modelsDir'      => APP_PATH . '/app/models/',
        'viewsDir'       => APP_PATH . '/app/views/',
        'cacheDir'       => APP_PATH . '/app/cache/',
        'baseUri'        => getenv('APP_BASE_URI') ?: '/',
        'debug'          => getenv('APP_DEBUG') === 'true',
    ],
]);

然后在服务器上设置环境变量,可以通过修改 /etc/environment 文件或 PHP-FPM 配置文件实现:

# /etc/php/8.0/fpm/pool.d/www.conf
env[DB_HOST] = localhost
env[DB_USERNAME] = prod_user
env[DB_PASSWORD] = secure_password_here
env[DB_NAME] = phalcon_production
env[APP_DEBUG] = false

监控与日志

应用部署到生产环境后,监控和日志就成了了解应用运行状态的重要手段。Phalcon 提供了灵活的日志组件,可以帮助我们记录应用运行过程中的关键信息。

日志系统配置

Phalcon 的日志组件支持多种适配器,包括文件流、系统日志等。在生产环境中,建议将日志分为不同级别和类型进行管理:

// app/config/services.php
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;

$di->setShared('logger', function () {
    $logger = new Logger('app-logger');

    // 错误日志
    $errorAdapter = new Stream(APP_PATH . '/logs/error.log');
    $errorAdapter->setLogLevel(Logger::ERROR | Logger::CRITICAL | Logger::EMERGENCY);
    $logger->addAdapter('error', $errorAdapter);

    // 访问日志
    $accessAdapter = new Stream(APP_PATH . '/logs/access.log');
    $accessAdapter->setLogLevel(Logger::INFO);
    $logger->addAdapter('access', $accessAdapter);

    // 调试日志(仅在开发环境启用)
    if (getenv('APP_DEBUG') === 'true') {
        $debugAdapter = new Stream(APP_PATH . '/logs/debug.log');
        $debugAdapter->setLogLevel(Logger::DEBUG);
        $logger->addAdapter('debug', $debugAdapter);
    }

    return $logger;
});

在控制器或模型中使用日志组件:

// 记录访问信息
$this->logger->info(
    'User login',
    [
        'user_id' => $user->id,
        'ip' => $this->request->getClientAddress(),
        'timestamp' => time(),
    ]
);

// 记录错误信息
try {
    // 一些可能抛出异常的操作
} catch (Exception $e) {
    $this->logger->error(
        'Database error',
        [
            'message' => $e->getMessage(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTraceAsString(),
        ]
    );
}

日志轮转

随着时间推移,日志文件会变得越来越大,不仅占用磁盘空间,也会影响日志查看效率。因此,日志轮转是必不可少的。在 Linux 系统中,可以使用 logrotate 工具来管理日志轮转:

创建日志轮转配置文件 /etc/logrotate.d/phalcon-app:

/var/www/your-project/logs/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload nginx > /dev/null
    endscript
}

这个配置的含义是:

  • 每天轮转一次日志
  • 保留 14 天的日志
  • 压缩旧日志
  • 轮转后重新加载 Nginx

性能监控

除了日志,性能监控也是生产环境中不可或缺的一环。以下是一些常用的性能监控工具和方法:

1. XDebug + Webgrind

XDebug 是 PHP 的调试扩展,可以用来分析代码性能。结合 Webgrind 可以直观地查看函数执行时间和调用次数:

# php.ini 配置
[xdebug]
zend_extension=xdebug.so
xdebug.mode=profile
xdebug.profiler_output_dir=/tmp/xdebug
xdebug.profiler_output_name=cachegrind.out.%p

注意:XDebug 会对性能产生较大影响,生产环境中建议仅在需要分析性能问题时临时启用。

2. XHProf

XHProf 是 Facebook 开发的 PHP 性能分析工具,相比 XDebug,它对性能的影响较小,更适合在生产环境中使用:

// 在入口文件 index.php 开头添加
if (getenv('ENABLE_PROFILING') === 'true') {
    xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
    register_shutdown_function(function () {
        $xhprof_data = xhprof_disable();
        $XHPROF_ROOT = '/var/www/xhprof';
        include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_lib.php';
        include_once $XHPROF_ROOT . '/xhprof_lib/utils/xhprof_runs.php';
        $xhprof_runs = new XHProfRuns_Default();
        $run_id = $xhprof_runs->save_run($xhprof_data, 'phalcon_app');
        error_log("XHProf run id: \$run_id");
    });
}

3. 数据库慢查询日志

数据库往往是性能瓶颈的来源,启用慢查询日志可以帮助我们找到执行效率低下的 SQL 语句:

# MySQL 配置
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

备份策略

数据是应用的核心资产,一个完善的备份策略可以在发生意外时最大限度地减少损失。备份策略应该包括数据库备份、代码备份和配置备份。

数据库备份

数据库备份有多种方式,选择合适的备份策略取决于数据量和业务需求。

1. 逻辑备份(mysqldump)

mysqldump 是 MySQL 自带的逻辑备份工具,可以生成 SQL 语句形式的备份文件:

# 备份整个数据库
date=\$(date +%Y%m%d_%H%M%S)
mysqldump -u username -p'password' --databases phalcon_production > /backup/db/phalcon_prod_\$date.sql

# 压缩备份文件
gzip /backup/db/phalcon_prod_\$date.sql

# 保留最近30天的备份
find /backup/db -name "phalcon_prod_*.sql.gz" -mtime +30 -delete

可以将以上命令添加到 crontab,实现定时备份:

# 每天凌晨3点执行备份
0 3 * * * /path/to/backup_script.sh

2. 物理备份

对于数据量较大的数据库,物理备份比逻辑备份更高效。可以直接复制数据库文件:

# 停止数据库服务
systemctl stop mysql

# 复制数据库文件
tar -czf /backup/db/physical_backup_\$(date +%Y%m%d).tar.gz /var/lib/mysql

# 启动数据库服务
systemctl start mysql

物理备份的优点是速度快,恢复也快,但需要停止数据库服务,可能会影响业务。

文件备份

除了数据库,应用的上传文件、配置文件等也需要定期备份:

# 备份上传文件
tar -czf /backup/files/uploads_\$(date +%Y%m%d).tar.gz /var/www/your-project/public/uploads

# 备份配置文件
tar -czf /backup/config/config_\$(date +%Y%m%d).tar.gz /var/www/your-project/app/config

备份验证与恢复演练

备份不是一劳永逸的,定期验证备份的可用性至关重要。建议每月进行一次恢复演练,确保备份文件可以正常恢复:

# 验证数据库备份
gunzip -c /backup/db/phalcon_prod_20230101_030000.sql.gz | mysql -u test -p'test_password' test_db

# 检查恢复的数据
mysql -u test -p'test_password' -e "SELECT COUNT(*) FROM users" test_db

版本更新

应用部署后,还需要进行持续的维护和更新。版本更新是其中最重要的环节,需要谨慎处理。

版本更新流程

  1. 准备阶段

    • 在测试环境验证新版本功能
    • 进行性能测试和兼容性测试
    • 制定回滚计划
  2. 更新阶段

    • 执行数据库备份
    • 部署新版本代码
    • 执行数据库迁移
    • 清除缓存
  3. 验证阶段

    • 检查应用是否正常运行
    • 监控错误日志
    • 进行基本功能测试

Phalcon 版本升级

当需要升级 Phalcon 扩展本身时,需要特别注意:

# 使用 PECL 升级 Phalcon
pecl upgrade phalcon

# 重启 PHP-FPM
systemctl restart php-fpm

# 验证版本
php -m | grep phalcon
php -r "echo Phalcon\Version::get() . '\n';"

升级前一定要仔细阅读官方的升级指南,注意版本之间的兼容性变化。特别是主版本升级(如从 4.x 升级到 5.x)通常会有不兼容的 API 变更。

自动化部署

对于频繁更新的项目,手动部署不仅效率低,还容易出错。可以使用自动化部署工具来提高效率:

1. 使用 Deployer

Deployer 是一个用 PHP 开发的部署工具,支持多种 PHP 框架,包括 Phalcon:

// deploy.php
<?php
namespace Deployer;

require 'recipe/phalcon.php';

// 项目配置
set('application', 'your-project');
set('repository', 'git@github.com:yourusername/your-project.git');
set('deploy_path', '/var/www/your-project');

// 服务器配置
host('your-server.com')
    ->user('deploy')
    ->set('deploy_path', '/var/www/your-project');

// 任务
task('build', function () {
    run('cd {{release_path}} && composer install --no-dev');
});

// 钩子
after('deploy:update_code', 'build');
after('deploy', 'success');

使用方法:

# 部署
dep deploy production

# 回滚
dep rollback production

2. 使用 CI/CD 管道

对于更复杂的项目,可以使用 CI/CD 管道(如 GitHub Actions、GitLab CI 等)实现全自动部署:

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/your-project
            git pull origin main
            composer install --no-dev
            php vendor/bin/phalcon-migrations run
            rm -rf app/cache/*
            chmod -R 775 app/cache

这种方式可以实现代码提交后自动部署,大大提高开发效率。

总结

项目部署和维护是一个持续优化的过程,没有一劳永逸的解决方案。作为开发者,我们需要不断学习和实践,结合项目特点制定合适的部署策略。

本章介绍的部署流程、环境配置、监控日志、备份策略和版本更新等内容,希望能为你提供一个全面的指导。记住,一个稳定可靠的生产环境,是应用成功的关键保障。