PHP持续集成与自动化部署流程
持续集成和自动化部署是现代软件开发的标准实践。每次代码提交后自动运行测试、代码检查、构建和部署。今天说说PHP项目的CI/CD流程搭建。
一个完整的CI/CD流程包括代码检查、测试、构建和部署几个阶段。用GitHub Actions可以轻松实现。
```yaml
# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, pdo_mysql, redis, gd
tools: composer, phpstan, phpcs
- run: composer install --prefer-dist --no-progress
- name: 代码规范检查
run: phpcs src --standard=PSR12 --extensions=php
- name: 静态分析
run: phpstan analyse src --level=8 --no-progress
- name: 单元测试
run: vendor/bin/phpunit --coverage-clover=coverage.xml
- name: 上传覆盖率
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
build:
needs: quality
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 构建Docker镜像
run: |
docker build -t app:latest .
docker tag app:latest registry.example.com/app:${{ github.sha }}
- name: 推送到镜像仓库
run: |
docker push registry.example.com/app:${{ github.sha }}
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: SSH部署
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd /var/www/app
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
sudo supervisorctl restart all
echo "部署完成"
```
PHP代码中的部署状态检查:
```php
class DeploymentStatus
{
private string $deployDir;
public function __construct(string $deployDir = __DIR__)
{
$this->deployDir = rtrim($deployDir, '/');
}
public function getCurrentRelease(): string
{
$releaseFile = $this->deployDir . '/RELEASE_VERSION';
if (file_exists($releaseFile)) {
return trim(file_get_contents($releaseFile));
}
return 'unknown';
}
public function getDeployTime(): string
{
$deployFile = $this->deployDir . '/DEPLOY_TIME';
if (file_exists($deployFile)) {
return trim(file_get_contents($deployFile));
}
return 'unknown';
}
public function getGitCommit(): string
{
$gitDir = $this->deployDir . '/.git';
if (is_dir($gitDir)) {
$headFile = $gitDir . '/HEAD';
if (file_exists($headFile)) {
$head = trim(file_get_contents($headFile));
if (str_starts_with($head, 'ref: ')) {
$refPath = $gitDir . '/' . substr($head, 5);
if (file_exists($refPath)) {
return trim(file_get_contents($refPath));
}
}
}
}
return 'unknown';
}
public function getDeployLog(): array
{
$logFile = $this->deployDir . '/storage/logs/deploy.log';
if (!file_exists($logFile)) return [];
$lines = file($logFile);
$entries = [];
foreach (array_slice($lines, -50) as $line) {
$entry = json_decode(trim($line), true);
if ($entry) {
$entries[] = $entry;
}
}
return $entries;
}
public function healthCheck(): array
{
$checks = [
'app_version' => $this->getCurrentRelease(),
'git_commit' => $this->getGitCommit(),
'deploy_time' => $this->getDeployTime(),
'php_version' => PHP_VERSION,
'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB',
'disk_free' => round(disk_free_space('/') / 1024 / 1024 / 1024, 2) . 'GB',
];
return $checks;
}
}
class DeployLogger
{
public static function log(string $stage, string $status, string $message): void
{
$entry = [
'time' => date('Y-m-d H:i:s'),
'stage' => $stage,
'status' => $status,
'message' => $message,
'user' => get_current_user(),
];
$logDir = __DIR__ . '/storage/logs';
if (!is_dir($logDir)) mkdir($logDir, 0755, true);
file_put_contents(
$logDir . '/deploy.log',
json_encode($entry, JSON_UNESCAPED_UNICODE) . "\n",
FILE_APPEND | LOCK_EX
);
}
}
$status = new DeploymentStatus();
print_r($status->healthCheck());
?>
```
零停机部署的实现。常见的方式有蓝绿部署和金丝雀部署。PHP应用由于是无状态的(PHP-FPM模式),实现平滑部署相对简单。只需先启动新版本实例,再切换流量,最后关闭旧版本即可。
自动化部署脚本示例:
```bash
#!/bin/bash
# deploy.sh
set -e
echo "开始部署..."
DEPLOY_DIR="/var/www/app"
RELEASE_DIR="/var/www/releases/$(date +%Y%m%d%H%M%S)"
# 拉取代码
echo "拉取代码..."
git clone -b main git@github.com:org/app.git $RELEASE_DIR
# 安装依赖
echo "安装依赖..."
cd $RELEASE_DIR
composer install --no-dev --optimize-autoloader
# 创建存储链接
ln -nfs $DEPLOY_DIR/storage $RELEASE_DIR/storage
ln -nfs $DEPLOY_DIR/.env $RELEASE_DIR/.env
# 设置权限
chmod -R 775 $RELEASE_DIR/storage
chmod -R 775 $RELEASE_DIR/bootstrap/cache
# 运行迁移
php artisan migrate --force
# 切换版本
ln -nfs $RELEASE_DIR $DEPLOY_DIR/current
# 重启PHP-FPM
sudo service php8.2-fpm reload
# 清理旧版本
ls -t /var/www/releases | tail -n +6 | xargs -I {} rm -rf /var/www/releases/{}
echo "部署完成"
```
CI/CD流程让代码从提交到上线变得自动化、标准化。每次部署都可追溯,出了问题也能快速回滚。虽然搭建CI/CD需要一些前期投入,但长期来看能极大提升团队的交付效率和代码质量。
PHP持续集成与自动化部署流程
张小明
前端开发工程师
大卷积核的‘通用感知’魔法:深入解读UniRepLKNet中的Dilated Reparam Block设计精髓
UniRepLKNet中的Dilated Reparam Block:大卷积核的轻量化革命在计算机视觉领域,卷积神经网络(CNN)的设计一直围绕着如何高效提取特征展开。近年来,随着Transformer架构的兴起,大感受野操作的重要性被重新认识。UniRepLKNet提出的D…
早期初创公司如何选择AI营销助手:从需求分析到选型落地指南
1. 项目概述:为什么早期初创公司需要AI营销助手?在早期创业阶段,你和我一样,每天都在和时间、预算、人力这三座大山搏斗。营销,这个听起来就“烧钱”的活儿,往往是创始人最头疼但又绕不开的环节。没钱请一个…
OpenCASCADE 7.8.0编译踩坑实录:CMake配置项详解与第三方库避坑指南
OpenCASCADE 7.8.0编译实战:CMake关键配置解析与疑难解决方案在三维建模与CAD开发领域,OpenCASCADE(简称OCCT)作为开源的几何内核引擎,其强大的B-rep建模和可视化能力吸引了大量工程师。然而,当7.8.0版本取…
告别混乱!用STM32CubeIDE的‘虚拟文件夹’和‘链接文件’高效管理多模块工程
告别混乱!用STM32CubeIDE的‘虚拟文件夹’和‘链接文件’高效管理多模块工程在嵌入式开发中,随着项目规模的增长,代码管理往往成为工程师面临的一大挑战。想象一下,当你需要在一个STM32项目中集成数十个外设驱动、算法模块和中间件…
Agent 一接级联调用就开始全链路雪崩:从 Timeout Budget 到 Circuit Breaker 的工程实战
一、痛点引入💥 某电商平台订单 Agent 在促销期大面积超时。根源只是一个库存接口从 50ms 涨到 3s。Agent 顺序调用库存校验、优惠计算、物流预估、库存锁定四个服务,每步都设独立 5s 超时,首节点阻塞吃光预算,下游还没开始就被取…
眼科医生的‘新手术刀’:达芬奇FEMTO LDV Z8飞秒激光在角膜移植与白内障手术中的实战应用与参数设置心得
眼科医生的‘新手术刀’:达芬奇FEMTO LDV Z8飞秒激光在角膜移植与白内障手术中的实战应用与参数设置心得作为一名在屈光手术领域深耕十余年的眼科医生,第一次接触达芬奇FEMTO LDV Z8飞秒激光系统时的震撼感至今难忘。这台被誉为"眼科手术革命性工具…