本文目录导读:

我来为您详细介绍PHP代码自动部署的几种方案:
简单方案
Git Webhook + 简单脚本
// deploy.php (放在服务器上)
<?php
$secret = 'your-secret-key';
$headers = getallheaders();
$signature = $headers['X-Hub-Signature'] ?? '';
// 验证GitHub/GitLab签名
$payload = file_get_contents('php://input');
$hash = 'sha1=' . hash_hmac('sha1', $payload, $secret);
if ($hash !== $signature) {
http_response_code(403);
exit('Invalid signature');
}
// 执行部署命令
$commands = [
'cd /var/www/project && git pull origin main',
'composer install --no-dev --optimize-autoloader',
'php artisan migrate --force', // 如果有Laravel
'chown -R www-data:www-data /var/www/project',
];
foreach ($commands as $command) {
$output = shell_exec($command . ' 2>&1');
file_put_contents('/var/log/deploy.log', $output, FILE_APPEND);
}
echo 'Deploy completed';
简单Shell脚本
#!/bin/bash
# deploy.sh
set -e
PROJECT_ROOT="/var/www/project"
cd $PROJECT_ROOT
# 备份当前版本
cp -r $PROJECT_ROOT /backup/project_$(date +%Y%m%d_%H%M%S)
# 拉取最新代码
git pull origin main
# 更新依赖
if [ -f composer.json ]; then
composer install --no-dev --prefer-dist --optimize-autoloader
fi
# 执行数据库迁移
if [ -f artisan ]; then
php artisan migrate --force
fi
# 清理缓存
php artisan cache:clear
php artisan config:clear
# 设置权限
chown -R www-data:www-data $PROJECT_ROOT
chmod -R 755 storage bootstrap/cache
使用部署工具
Deployer (推荐)
// deploy.php
<?php
namespace Deployer;
require 'recipe/common.php';
// 项目配置
set('application', 'my_project');
set('repository', 'git@github.com:username/project.git');
set('git_tty', false);
set('keep_releases', 5);
// 服务器配置
host('production')
->hostname('your-server.com')
->user('deployer')
->set('deploy_path', '/var/www/project')
->set('branch', 'main');
// 上传配置
set('shared_files', ['.env']);
set('shared_dirs', ['storage', 'uploads']);
set('writable_dirs', ['storage', 'bootstrap/cache']);
// 任务定义
task('build', function () {
run('cd {{release_path}} && composer install --no-dev --prefer-dist --optimize-autoloader');
run('cd {{release_path}} && php artisan migrate --force');
run('cd {{release_path}} && php artisan optimize');
});
task('deploy', [
'deploy:info',
'deploy:prepare',
'deploy:lock',
'deploy:release',
'deploy:update_code',
'deploy:shared',
'deploy:writable',
'build',
'deploy:symlink',
'deploy:unlock',
'cleanup',
]);
after('deploy:failed', 'deploy:unlock');
Capistrano
# Capfile
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/composer'
require 'capistrano/file-permissions'
# config/deploy.rb
set :application, 'project'
set :repo_url, 'git@github.com:username/project.git'
set :deploy_to, '/var/www/project'
set :branch, `git rev-parse --abbrev-ref HEAD`.chomp
set :keep_releases, 5
# 服务器配置
server 'your-server.com', user: 'deployer', roles: %w{app web}
namespace :deploy do
after :updated, :composer_install do
on roles(:app) do
within release_path do
execute :composer, 'install --no-dev --prefer-dist --optimize-autoloader'
end
end
end
after :finished, :finalize do
on roles(:app) do
within release_path do
execute :php, 'artisan migrate --force'
execute :php, 'artisan cache:clear'
end
end
end
end
CI/CD 方案
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Install dependencies
run: composer install --no-interaction
- name: Run tests
run: php artisan test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/project
git pull origin main
composer install --no-dev --prefer-dist
php artisan migrate --force
php artisan optimize
GitLab CI
# .gitlab-ci.yml
stages:
- test
- deploy
test:
stage: test
script:
- composer install --no-interaction
- php artisan test
deploy_production:
stage: deploy
script:
- apt-get update -y
- apt-get install -y sshpass
- sshpass -p $SERVER_PASSWORD ssh $SERVER_USER@$SERVER_HOST "
cd /var/www/project &&
git pull origin main &&
composer install --no-dev --prefer-dist -o &&
php artisan migrate --force &&
php artisan optimize
"
only:
- main
Docker 容器化部署
# Dockerfile
FROM php:8.1-fpm
# 安装扩展
RUN docker-php-ext-install pdo_mysql bcmath
# 安装Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 设置工作目录
WORKDIR /var/www/html
# 复制源码
COPY . .
# 安装依赖
RUN composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction
# 设置权限
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 storage bootstrap/cache
# 启动命令
CMD ["php-fpm"]
# docker-compose.yml
version: '3.8'
services:
php:
build: .
container_name: project-php
restart: unless-stopped
working_dir: /var/www/html
volumes:
- ./:/var/www/html
environment:
- APP_ENV=production
- DB_HOST=mysql
depends_on:
- mysql
nginx:
image: nginx:alpine
container_name: project-nginx
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
mysql:
image: mysql:8.0
container_name: project-mysql
restart: unless-stopped
environment:
- MYSQL_DATABASE=project
- MYSQL_USER=user
- MYSQL_PASSWORD=password
- MYSQL_ROOT_PASSWORD=rootpassword
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
推荐方案对比
| 方案 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| Webhook+脚本 | 简单、轻量 | 有限错误处理 | 小型项目 |
| Deployer | 功能强大、支持回滚 | 学习成本 | 中大型项目 |
| CI/CD | 自动化程度高、可测试 | 配置复杂 | 团队协作项目 |
| Docker | 环境一致、可扩展 | 资源消耗 | 微服务架构 |
最佳实践建议
安全措施
// 部署前安全检查
function preDeployCheck() {
// 检查仓库状态
$status = shell_exec('cd /var/www/project && git status --porcelain');
if ($status) {
throw new Exception('工作目录不干净,请先提交或回滚');
}
// 检查PHP语法
$files = shell_exec('find /var/www/project -name "*.php" -not -path "*/vendor/*"');
foreach (explode("\n", $files) as $file) {
if ($file) {
$result = shell_exec("php -l $file 2>&1");
if (strpos($result, 'No syntax errors') === false) {
throw new Exception("语法错误: $file");
}
}
}
}
回滚策略
// 回滚到上一版本
function rollback($targetRelease = null) {
$releaseDir = '/var/www/releases';
if (!$targetRelease) {
// 获取上一个版本
$releases = glob("$releaseDir/*", GLOB_ONLYDIR);
sort($releases);
$targetRelease = $releases[count($releases) - 2];
}
// 创建软链接
shell_exec("ln -sfn $targetRelease /var/www/current");
// 清理缓存
shell_exec("cd /var/www/current && php artisan optimize:clear");
// 记录日志
file_put_contents('/var/log/deploy.log',
"Rollback to $targetRelease at " . date('Y-m-d H:i:s') . "\n");
}
零停机部署
#!/bin/bash
# zero-downtime-deploy.sh
FRESH_DIR="/var/www/releases/$(date +%Y%m%d%H%M%S)"
CURRENT_DIR="/var/www/current"
# 克隆新版本
git clone -b main --depth=1 /var/www/repo $FRESH_DIR
# 安装依赖
cd $FRESH_DIR
composer install --no-dev --prefer-dist --no-interaction
# 复制环境文件
cp /var/www/shared/.env $FRESH_DIR/.env
# 创建共享目录链接
ln -s /var/www/shared/storage $FRESH_DIR/storage
ln -s /var/www/shared/uploads $FRESH_DIR/uploads
# 切换软链接
ln -sfn $FRESH_DIR $CURRENT_DIR
# 清理过期版本
find /var/www/releases -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
监控和日志
// 部署日志记录
class DeployLogger {
private $logFile = '/var/log/deploy.log';
public function log($message, $type = 'INFO') {
$timestamp = date('Y-m-d H:i:s');
$entry = "[$timestamp] [$type] $message\n";
file_put_contents($this->logFile, $entry, FILE_APPEND);
// 发送通知
$this->notify($message, $type);
}
private function notify($message, $type) {
// 发送到Slack
$slackUrl = getenv('SLACK_WEBHOOK_URL');
if ($slackUrl) {
// curl请求发送通知
}
// 发送邮件
if (in_array($type, ['ERROR', 'ROLLBACK'])) {
// 邮件通知管理员
}
}
}
总结建议
- 小型项目:使用 Git Webhook + 简单脚本
- 中型项目:使用 Deployer + 手动触发备份
- 大型项目:使用 GitLab CI/CD + Docker 容器化
- 关键应用:实现零停机部署 + 自动化回滚机制
选择方案时需要考虑:
- 团队技术栈
- 服务器环境
- 部署频率
- 失败容忍度
- 是否需要自动化测试
无论选择哪种方案,都要确保有完善的备份和回滚机制。