PHP CI/CD 管道怎么配

wen PHP项目 1

本文目录导读:

PHP CI/CD 管道怎么配

  1. 常用 CI/CD 工具选择
  2. GitHub Actions 配置示例
  3. GitLab CI 配置示例
  4. Jenkins Pipeline 示例
  5. 高级配置技巧
  6. 部署脚本示例
  7. 最佳实践建议
  8. 完整生产级配置
  9. 关键要点

我来详细介绍 PHP 项目的 CI/CD 管道配置,包括常见的工具和实践方案。

常用 CI/CD 工具选择

# 常用工具组合
1. GitHub Actions / GitLab CI / Jenkins
2. PHPUnit + PHP CS Fixer + PHPStan
3. Composer 依赖管理
4. Docker 容器化部署
5. 部署工具:Deployer, Capistrano

GitHub Actions 配置示例

基础配置 .github/workflows/php.yml

name: PHP CI/CD
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php-versions: ['8.0', '8.1', '8.2']
    steps:
    - uses: actions/checkout@v3
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: ${{ matrix.php-versions }}
        extensions: mbstring, intl, pdo_mysql
        coverage: xdebug
    - name: Install Dependencies
      run: |
        composer install --no-progress --prefer-dist --optimize-autoloader
        cp .env.example .env
        php artisan key:generate
    - name: Run Tests
      run: |
        php artisan migrate --force
        vendor/bin/phpunit
      env:
        DB_CONNECTION: sqlite
        DB_DATABASE: :memory:
    - name: Run Code Style
      run: |
        vendor/bin/php-cs-fixer fix --dry-run --diff
        vendor/bin/phpstan analyse --memory-limit=512M
    - name: Run Security Check
      run: composer audit
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
    - uses: actions/checkout@v3
    - name: Setup SSH
      uses: webfactory/ssh-agent@v0.7.0
      with:
        ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
    - name: Deploy to Production
      run: |
        ssh deployer@server 'cd /var/www/app && git pull && composer install --no-dev && php artisan migrate --force && php artisan config:cache'
      env:
        DB_PASSWORD: ${{ secrets.DB_PASSWORD }}

GitLab CI 配置示例

.gitlab-ci.yml

image: php:8.2
variables:
  MYSQL_DATABASE: test_db
  MYSQL_ROOT_PASSWORD: root
  DB_HOST: mysql
  DB_USERNAME: root
  DB_PASSWORD: root
services:
  - mysql:8.0
stages:
  - test
  - quality
  - build
  - deploy
cache:
  key: "$CI_COMMIT_REF_SLUG"
  paths:
    - vendor/
before_script:
  - apt-get update -qq
  - apt-get install -y -qq git zip unzip libxml2-dev libpq-dev
  - docker-php-ext-install pdo pdo_mysql pdo_pgsql
  - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
test:
  stage: test
  script:
    - composer install --no-progress --prefer-dist
    - cp .env.testing .env
    - php artisan migrate --force
    - vendor/bin/phpunit --coverage-text --colors=never
  artifacts:
    reports:
      cobertura: build/coverage.xml
code_quality:
  stage: quality
  script:
    - vendor/bin/phpstan analyse --memory-limit=512M
    - vendor/bin/php-cs-fixer fix --dry-run --diff
    - vendor/bin/phpcs --standard=PSR2 app/ tests/
build:
  stage: build
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main
deploy_production:
  stage: deploy
  script:
    - apt-get install -y -qq sshpass
    - sshpass -p $PRODUCTION_PASSWORD ssh deployer@server "
        cd /var/www/project &&
        git pull origin main &&
        composer install --no-dev --optimize-autoloader &&
        php artisan migrate --force &&
        php artisan cache:clear &&
        php artisan config:cache &&
        php artisan route:cache &&
        php artisan view:cache
      "
  only:
    - main
  environment:
    name: production
  when: manual

Jenkins Pipeline 示例

Jenkinsfile

pipeline {
    agent any
    environment {
        MYSQL_DATABASE = 'test_db'
        MYSQL_USER = 'test_user'
        MYSQL_PASSWORD = 'test_password'
        MYSQL_HOST = 'localhost'
    }
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Setup') {
            steps {
                sh '''
                    apt-get update -qq
                    apt-get install -y -qq php php-cli php-mysql php-xml php-mbstring composer
                    composer install --no-progress --prefer-dist
                    cp .env.jenkins .env
                    php artisan key:generate
                '''
            }
        }
        stage('Test') {
            parallel {
                stage('PHPUnit') {
                    steps {
                        sh 'vendor/bin/phpunit --coverage-text'
                    }
                }
                stage('Static Analysis') {
                    steps {
                        sh 'vendor/bin/phpstan analyse --memory-limit=512M'
                    }
                }
                stage('Code Style') {
                    steps {
                        sh 'vendor/bin/php-cs-fixer fix --dry-run --diff'
                    }
                }
            }
        }
        stage('Security') {
            steps {
                sh 'composer audit --format=json > security_report.json'
            }
        }
        stage('Build') {
            steps {
                sh '''
                    if [ "$GIT_BRANCH" = "origin/main" ]; then
                        docker build -t app:${GIT_COMMIT} .
                        docker push registry.example.com/app:${GIT_COMMIT}
                    fi
                '''
            }
        }
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                script {
                    sh '''
                        ansible-playbook deploy.yml \
                            -e HOST=production \
                            -e VERSION=${GIT_COMMIT} \
                            --extra-vars "vault_password_file=~/.vault_pass"
                    '''
                }
            }
        }
    }
    post {
        always {
            junit 'build/reports/phpunit/*.xml'
            cleanWs()
        }
        failure {
            slackSend(
                color: 'danger',
                message: "Job '${env.JOB_NAME}' (${env.BUILD_NUMBER}) failed: ${env.BUILD_URL}"
            )
        }
        success {
            slackSend(
                color: 'good',
                message: "Job '${env.JOB_NAME}' (${env.BUILD_NUMBER}) succeeded"
            )
        }
    }
}

高级配置技巧

Docker 多阶段构建 Dockerfile

# 开发环境
FROM php:8.2-fpm-alpine AS dev
WORKDIR /var/www
# 生产环境
FROM node:16-alpine AS frontend-build
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
FROM php:8.2-fpm-alpine AS prod
WORKDIR /var/www
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
COPY --from=frontend-build /app/dist /var/www/public/dist
RUN docker-php-ext-install pdo_mysql opcache
COPY . .
COPY --from=dev /var/www/vendor /var/www/vendor
RUN chown -R www-data:www-data /var/www \
    && chmod -R 755 /var/www
USER www-data
CMD ["php-fpm"]

部署脚本示例

Deployer 配置 deploy.php

<?php
namespace Deployer;
require 'recipe/laravel.php';
set('application', 'My PHP Application');
set('repository', 'git@github.com:username/repo.git');
set('php_version', '8.2');
host('production')
    ->set('hostname', '203.0.113.10')
    ->set('user', 'deployer')
    ->set('deploy_path', '/var/www/app')
    ->set('branch', 'main')
    ->set('keep_releases', 5);
set('shared_files', [
    '.env',
    'storage/oauth-private.key',
    'storage/oauth-public.key',
]);
task('deploy:quality', function () {
    run('cd {{release_path}} && vendor/bin/phpstan analyse');
    run('cd {{release_path}} && vendor/bin/php-cs-fixer fix --dry-run');
});
task('deploy:security', function () {
    run('cd {{release_path}} && composer audit --no-dev');
});
task('deploy:healthcheck', function () {
    run('curl -f http://localhost/health-check');
});
before('deploy', 'deploy:quality');
before('deploy', 'deploy:security');
after('deploy:success', 'deploy:healthcheck');

最佳实践建议

环境变量管理

# 使用 GitHub Secrets
secrets:
  DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
  APP_KEY: ${{ secrets.APP_KEY }}
  PGP_KEY: ${{ secrets.PGP_KEY }}

数据库迁移策略

# CI 中使用内存数据库
DB_CONNECTION: sqlite
DB_DATABASE: :memory:
# 生产环境使用手动审批
deploy_production:
  stage: deploy
  when: manual
  script:
    - php artisan migrate --force --path=database/migrations

安全扫描

security_scan:
  stage: test
  script:
    - composer audit --format=json
    - vendor/bin/php-security-checker
    - nmap -sV --script vulners target_server

完整生产级配置

创建 .env.ci 文件:

APP_ENV=testing
APP_DEBUG=false
APP_URL=http://ci.example.com
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=test_db
DB_USERNAME=test_user
DB_PASSWORD=test_password
CACHE_DRIVER=array
SESSION_DRIVER=array
QUEUE_CONNECTION=sync

关键要点

  1. 多环境支撑:开发、测试、生产环境配置分离
  2. 自动化测试:单元测试、集成测试、E2E 测试
  3. 质量检查:代码规范、静态分析、安全扫描
  4. 部署策略:蓝绿部署、滚动更新、灰度发布
  5. 监控反馈:部署后自动检查健康状态

这个配置涵盖了 PHP 项目 CI/CD 的完整流程,可以根据项目需求进行适当调整。

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