PHP项目持续部署CD如何实现自动上线

wen PHP项目 24

本文目录导读:

PHP项目持续部署CD如何实现自动上线

  1. 核心流程概览
  2. 方案一:使用成熟的CI/CD平台(推荐)
  3. 方案二:自建 Shell 脚本 + Git Hooks / Webhook
  4. 方案三:基于容器化部署(Docker)
  5. PHP 特定注意事项
  6. 总结与最佳实践

针对 PHP 项目的持续部署(CD),实现“自动上线”的核心思路是:代码提交到指定分支(如 mainrelease)后,触发自动化流程,将代码部署到生产环境并生效。

下面我将介绍几种从简单到复杂的实现方案,你可以根据项目规模、团队构成和资源情况进行选择。

核心流程概览

无论哪种方案,通常都包含以下步骤:

  1. 代码推送:开发者将代码 Push 到远程仓库(如 GitHub, GitLab, Gitee)。
  2. 触发流程:仓库的 Webhook 通知 CI/CD 系统有新的提交。
  3. CI阶段(可选但推荐):自动运行测试(单元测试、lint检查)、代码安全检查、构建产物(如编译Sass/JS、清理缓存)。
  4. CD阶段:将代码部署到目标服务器(生产环境)。
  5. 生效:重启 PHP-FPM(如果是 CLI 模式常驻进程)或等待下次请求加载(传统模式)。

使用成熟的CI/CD平台(推荐)

这是目前最主流、最稳定的方式,常用的平台有:

  • GitHub Actions (GitHub 项目首选)
  • GitLab CI/CD (GitLab 项目首选)
  • Jenkins (老牌、自托管、高度自定义)
  • Drone CI (轻量级、容器化)
  • 阿里云/腾讯云 CodePipeline (云厂商集成)

示例:使用 GitHub Actions 部署到 VPS(传统FPM模式)

场景:代码托管在 GitHub,生产环境是 Ubuntu VPS Web 服务器(Nginx + PHP-FPM)。

在服务器上配置 SSH 免密登录

  • 在 GitHub 仓库的 Settings -> Secrets and variables -> Actions 中添加:
    • SERVER_IP:服务器 IP
    • SERVER_USER:SSH 用户名(如 deploy
    • SSH_PRIVATE_KEY服务器的部署专用私钥(不要用主账号的!)

在仓库根目录创建 .github/workflows/deploy.yml 文件

name: Deploy to Production
# 1. 触发条件:推送到 main 分支时
on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      # 2. 检出代码
      - name: Checkout code
        uses: actions/checkout@v4
      # 3. (可选)设置 PHP 环境并运行测试
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - name: Install dependencies
        run: composer install --no-dev --optimize-autoloader
      - name: Run tests
        run: php artisan test  # 或其他测试命令
      # 4. 部署到服务器
      - name: Deploy to VPS
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          # 注意:这里使用 -o StrictHostKeyChecking=no 仅用于演示,生产环境请配置known_hosts
          # script 中可执行 rsync 同步,或 git pull
          script: |
            cd /var/www/your-project
            git pull origin main
            composer install --no-dev --optimize-autoloader
            php artisan migrate --force  # 数据库迁移,需谨慎
            php artisan config:cache
            php artisan route:cache
            php artisan view:cache
            sudo systemctl reload php8.2-fpm  # 重启FPM以清除OPcache

这个 YAML 文件做了什么?

  1. main 分支有新的 Push 时,自动启动 Job。
  2. 在 GitHub 的虚拟机中检出代码,安装依赖,运行测试。
  3. 通过 SSH 连接到你的生产服务器。
  4. 在服务器上执行 git pull 拉取最新代码,执行 Laravel 的优化命令,最后重启 PHP-FPM。

自建 Shell 脚本 + Git Hooks / Webhook

适用于小型项目、内网环境或高度自定义的场景。

工具rsyncgit pull + systemctl

场景:你有一台部署服务器(或与Web服务器同机),一个私有的 Git 仓库(如 Gitea)。

编写部署脚本 deploy.sh

这个脚本放在你的服务器上。

#!/bin/bash
# deploy.sh
PROJECT_DIR="/var/www/my-php-app"
BRANCH="main"
PHP_FPM_SERVICE="php8.2-fpm"
echo "=== Starting Deployment ==="
cd $PROJECT_DIR
# 1. 拉取最新代码
git fetch origin
git reset --hard origin/$BRANCH
# 2. 更新依赖
composer install --no-dev --optimize-autoloader
# 3. 运行数据库迁移 (谨慎!)
php artisan migrate --force
# 4. 优化框架
php artisan optimize
# 5. 重启 PHP-FPM 以清除 OPcache
sudo systemctl reload $PHP_FPM_SERVICE
echo "=== Deployment Complete ==="

设置 Git Server-Side Hook

在你的 Git 服务器上,找到仓库的 hooks 目录,编辑 post-receive 文件(如果没有则创建)。

#!/bin/bash
# post-receive
while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    # 仅当 main 分支被推送时触发
    if [ "$branch" == "main" ]; then
        echo "Branch $branch received. Triggering deployment..."
        # 调用远程服务器上的部署脚本
        ssh deploy-user@your-server-ip "/var/www/my-php-app/deploy.sh"
    fi
done

配置 SSH 互信

需要在 Git 服务器与 Web 服务器之间配置 SSH 无密码登录,让 post-receive hook 可以远程执行命令。

优点:完全可控,无第三方依赖。 缺点:需要自行维护脚本和异常处理,回滚等机制需要自己实现。


基于容器化部署(Docker)

如果项目已经容器化,CD会变得非常简单和标准化。

流程:提交代码 -> 构建 Docker Image -> 推送镜像到仓库 -> 在生产环境拉取并重启容器。

准备 Dockerfile

FROM php:8.2-fpm-alpine
RUN docker-php-ext-install pdo_mysql opcache
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
EXPOSE 9000
CMD ["php-fpm"]

使用 GitHub Actions 构建和部署

# 省略了测试步骤...
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker Image
        run: docker build -t my-registry/my-php-app:latest .
      - name: Push to Registry
        run: |
          docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PAT }} my-registry.com
          docker push my-registry/my-php-app:latest
      - name: Deploy on Server
        uses: appleboy/ssh-action@v1.0.3
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull my-registry/my-php-app:latest
            docker stop my-php-container || true
            docker rm my-php-container || true
            docker run -d --name my-php-container -p 9000:9000 my-registry/my-php-app:latest
            # 重新加载 Nginx 或反向代理配置

优点:环境完全一致,回滚只需重新部署旧版本的 Image。 缺点:需要学习 Docker,增加了一点基础设施复杂度。


PHP 特定注意事项

  1. OPcache 问题:这是 PHP 最大的坑,PHP-FPM 模式下,OPcache 会缓存 PHP 文件的字节码。一定要在部署后重启 PHP-FPMsystemctl reload php-fpm),否则用户访问到的还是旧代码。

    • 替代方案:设置 opcache.revalidate_freq = 0 并利用 opcache_reset() 函数,但重启 FPM 是最安全的方式。
  2. 数据库迁移

    • 向前迁移php artisan migrate --force(Laravel)或 phinx migrate
    • 向后回滚:必须有对应的回滚脚本,并集成到你的 CD 流程中,手动回滚数据库是非常危险的。
  3. .env 配置文件

    • 绝对不要.env 文件纳入版本控制。
    • 可以维护一个 .env.example,并通过 CI/CD 系统在部署时动态生成 .env 文件(使用仓库的 Secrets 或环境的变量工具)。
    • 更好的做法:将配置文件放在服务器上的 /etc/your-app/ 目录,部署时通过符号链接引用。
  4. 文件权限

    • CI/CD 执行用户通常不是 www-data,部署后可能需要重置 storage/uploads/ 目录的权限。
    • 方案:使用 ACL 或设置 umask,或在部署脚本最后执行 chown -R www-data:www-data storage/ bootstrap/cache/
  5. 静态资源

    • 如果使用了 Vite 或 Webpack,建议在 CI 系统中构建静态资源(npm run build),避免在生产服务器上安装 Node.js 构建。

总结与最佳实践

场景 推荐方案 关键点
小团队,单一VPS GitHub Actions + SSH 简单、门槛低,注意 .env 和 OPcache,务必使用 Secrets 管理敏感信息
多服务器,高并发 Docker + K8s / Docker Swarm 标准化、弹性伸缩、滚动更新,构建镜像时包含依赖,部署只拉取镜像。
内网环境,安全要求高 GitLab CI/CD 一套工具管理代码和部署,安全审计功能完善。
快速原型,不想折腾 Deployer (PHP 部署工具) Deployer 是一个专为 PHP 设计的部署工具,可以用 dep deploy 一条命令完成复杂流程,支持 Laravel、Symfony 等,它内部使用 rsyncgit

落地建议:

  1. 先确定触发方式:是 Push 到 main 就自动上线,还是手动点击按钮上线?对于生产环境,强烈推荐手动点击按钮或 Pull Request 合并时触发,避免未测试的代码直接上线。
  2. 小步快跑,逐步完善:不要试图一步到位,先从最简单的 SSH + git pull 开始,然后再加上测试、告警、回滚等功能。
  3. 配置回滚方案:CD最重要的不仅仅是“上去”,更是“下来”,确保部署脚本支持回滚。
    • 简单回滚:在服务器上保留最近几个版本的目录(如 /releases/v1, /releases/v2),通过符号链接 current 指向最新版本。
    • 回滚脚本rm current && ln -s releases/v1 current && systemctl reload php-fpm
  4. 监控与告警:部署完成后,自动运行健康检查(curl http://your-site.com/health),如果不通过,自动触发回滚并通知团队。

从你的问题来看,如果项目不大、团队不大,直接使用 GitHub Actions + SSH 是目前比较实用的切入点,上手快,问题也解决得比较彻底。

抱歉,评论功能暂时关闭!