Laravel 12 部署最佳实践:从容器化到监控
摘要
本文详解 Laravel 12 的部署最佳实践,包括环境配置、容器化部署、CI/CD 集成、负载均衡和监控系统。提供完整的部署方案,从开发环境到生产环境,帮助开发者构建高可用、高性能的 Laravel 应用。
1. 部署环境准备
1.1 服务器要求
| 组件 | 版本要求 | 推荐版本 |
|---|
| PHP | >= 8.1 | 8.2+ |
| Composer | >= 2.0 | 2.2+ |
| Web 服务器 | Nginx/Apache | Nginx 1.20+ |
| 数据库 | MySQL/PostgreSQL/SQLite | MySQL 8.0+ |
| 缓存 | Redis/Memcached | Redis 7.0+ |
| 队列 | Redis/Beanstalkd/SQS | Redis 7.0+ |
1.2 环境配置
生产环境配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| # .env.production APP_NAME=Laravel APP_ENV=production APP_KEY=base64:your-app-key APP_DEBUG=false APP_URL=https://your-domain.com
LOG_CHANNEL=stack LOG_LEVEL=error
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laravel DB_PASSWORD=your-db-password
REDIS_HOST=redis REDIS_PASSWORD=null REDIS_PORT=6379
CACHE_DRIVER=redis QUEUE_CONNECTION=redis SESSION_DRIVER=redis SESSION_LIFETIME=120
MAIL_MAILER=smtp MAIL_HOST=smtp.mailgun.org MAIL_PORT=587 MAIL_USERNAME=postmaster@your-domain.com MAIL_PASSWORD=your-mailgun-password MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS=no-reply@your-domain.com MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET=
PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
性能优化配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| return [ 'enabled' => env('OPCACHE_ENABLED', true), 'validate_timestamps' => env('OPCACHE_VALIDATE_TIMESTAMPS', false), 'max_accelerated_files' => env('OPCACHE_MAX_ACCELERATED_FILES', 10000), 'memory_consumption' => env('OPCACHE_MEMORY_CONSUMPTION', 128), 'interned_strings_buffer' => env('OPCACHE_INTERNED_STRINGS_BUFFER', 16), ];
return [ 'connections' => [ 'mysql' => [ 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_STRINGIFY_FETCHES => false, ]) : [], ], ], ];
|
2. 容器化部署
2.1 Docker 配置
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| FROM php:8.2-fpm-alpine
RUN apk add --no-cache \ libpng-dev \ libjpeg-turbo-dev \ freetype-dev \ libzip-dev \ zlib-dev \ curl \ git \ unzip \ nginx \ supervisor \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd pdo_mysql zip opcache \ && pecl install redis \ && docker-php-ext-enable redis \ && rm -rf /var/cache/apk/*
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY . .
RUN composer install --optimize-autoloader --no-dev
RUN php artisan key:generate
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
COPY docker/nginx.conf /etc/nginx/nginx.conf COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
EXPOSE 80
CMD ["/usr/bin/supervisord", "-n"]
|
Docker Compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| version: '3.8'
services: app: build: . ports: - "8000:80" volumes: - .:/var/www/html - ./docker/php.ini:/usr/local/etc/php/conf.d/php.ini environment: - APP_ENV=production - DB_HOST=db - REDIS_HOST=redis depends_on: - db - redis
db: image: mysql:8.0 ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql - ./docker/mysql.cnf:/etc/mysql/conf.d/mysql.cnf environment: - MYSQL_ROOT_PASSWORD=root - MYSQL_DATABASE=laravel - MYSQL_USER=laravel - MYSQL_PASSWORD=laravel
redis: image: redis:7.0-alpine ports: - "6379:6379" volumes: - redis-data:/data
volumes: mysql-data: redis-data:
|
配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| events { worker_connections 1024; }
http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log error; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; gzip on; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; server { listen 80; server_name localhost; root /var/www/html/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass unix:/var/run/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [supervisord] nodaemon=true
[program:php-fpm] command=/usr/local/sbin/php-fpm autostart=true autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
[program:nginx] command=/usr/sbin/nginx -g 'daemon off;' autostart=true autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
|
2.2 部署流程
1. 构建镜像
2. 启动服务
3. 运行迁移
1
| docker-compose exec app php artisan migrate --force
|
4. 缓存配置
1 2 3
| docker-compose exec app php artisan config:cache docker-compose exec app php artisan route:cache docker-compose exec app php artisan view:cache
|
5. 优化自动加载
1
| docker-compose exec app composer dump-autoload --optimize
|
3. CI/CD 集成
3.1 GitHub Actions
基本配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| name: Deploy
on: push: branches: - main
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.2' extensions: mbstring, dom, curl, sqlite3, pdo_mysql, zip, gd, redis - name: Install dependencies run: composer install --prefer-dist --no-progress - name: Run tests run: vendor/bin/pest
deploy: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@v4 with: context: . push: true tags: yourusername/laravel-app:latest - name: Deploy to server uses: appleboy/ssh-action@v0.1.4 with: host: ${{ secrets.SERVER_HOST }} username: ${{ secrets.SERVER_USERNAME }} password: ${{ secrets.SERVER_PASSWORD }} script: | cd /var/www/laravel-app docker-compose pull docker-compose up -d docker-compose exec app php artisan migrate --force docker-compose exec app php artisan config:cache docker-compose exec app php artisan route:cache docker-compose exec app php artisan view:cache
|
3.2 GitLab CI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| stages: - test - build - deploy
test: stage: test image: php:8.2 script: - apt-get update && apt-get install -y git unzip - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - composer install --prefer-dist --no-progress - vendor/bin/pest
build: stage: build image: docker:latest services: - docker:dind script: - docker build -t registry.gitlab.com/yourusername/laravel-app:latest . - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker push registry.gitlab.com/yourusername/laravel-app:latest
deploy: stage: deploy image: alpine:latest script: - apk add --no-cache openssh-client - ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts - ssh $SERVER_USERNAME@$SERVER_HOST "cd /var/www/laravel-app && docker-compose pull && docker-compose up -d && docker-compose exec app php artisan migrate --force && docker-compose exec app php artisan config:cache && docker-compose exec app php artisan route:cache && docker-compose exec app php artisan view:cache" environment: name: production only: - main
|
4. 负载均衡与高可用
4.1 Nginx 负载均衡
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| upstream laravel_app { server app1:8000; server app2:8000; server app3:8000; least_conn; }
server { listen 80; server_name your-domain.com; location / { proxy_pass http://laravel_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; ssl_prefer_server_ciphers off; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; }
|
4.2 数据库高可用
MySQL 主从复制
1 2 3 4 5 6 7 8 9 10 11 12 13
|
[mysqld] server-id = 1 log-bin = mysql-bin binlog-format = ROW
[mysqld] server-id = 2 relay-log = relay-bin read-only = 1
|
Redis 集群
1 2 3 4 5 6 7
| docker run -d --name redis-1 -p 7001:6379 redis:7.0-alpine redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes docker run -d --name redis-2 -p 7002:6379 redis:7.0-alpine redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes docker run -d --name redis-3 -p 7003:6379 redis:7.0-alpine redis-server --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes
docker exec -it redis-1 redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 --cluster-replicas 0
|
5. 监控系统
5.1 应用监控
Laravel Telescope
1 2 3
| composer require laravel/telescope --dev php artisan telescope:install php artisan migrate
|
Laravel Horizon
1 2 3
| composer require laravel/horizon php artisan horizon:install php artisan migrate
|
5.2 服务器监控
Prometheus + Grafana
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| version: '3.8'
services: prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus
grafana: image: grafana/grafana:latest ports: - "3000:3000" volumes: - grafana-data:/var/lib/grafana environment: - GF_SECURITY_ADMIN_USER=admin - GF_SECURITY_ADMIN_PASSWORD=admin
node_exporter: image: prom/node-exporter:latest ports: - "9100:9100"
redis_exporter: image: oliver006/redis_exporter:latest ports: - "9121:9121" environment: - REDIS_ADDR=redis:6379
volumes: prometheus-data: grafana-data:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| global: scrape_interval: 15s
scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['localhost:9090']
- job_name: 'node' static_configs: - targets: ['node_exporter:9100']
- job_name: 'redis' static_configs: - targets: ['redis_exporter:9121']
- job_name: 'laravel' static_configs: - targets: ['app:8000'] metrics_path: '/metrics'
|
5.3 日志管理
ELK Stack
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| version: '3.8'
services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.8.0 ports: - "9200:9200" volumes: - es-data:/usr/share/elasticsearch/data environment: - discovery.type=single-node - ES_JAVA_OPTS=-Xms1g -Xmx1g
logstash: image: docker.elastic.co/logstash/logstash:8.8.0 ports: - "5044:5044" volumes: - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf depends_on: - elasticsearch
kibana: image: docker.elastic.co/kibana/kibana:8.8.0 ports: - "5601:5601" depends_on: - elasticsearch
filebeat: image: docker.elastic.co/beats/filebeat:8.8.0 volumes: - ./filebeat.yml:/usr/share/filebeat/filebeat.yml - /var/log/nginx:/var/log/nginx - /var/www/html/storage/logs:/var/www/html/storage/logs depends_on: - logstash
volumes: es-data:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| # logstash.conf input { beats { port => 5044 } }
filter { if [fileset][module] == "nginx" { if [fileset][name] == "access" { grok { match => { "message" => "%{NGINXACCESS}" } } date { match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ] target => "@timestamp" } } } if [source] == "/var/www/html/storage/logs/laravel.log" { grok { match => { "message" => "\[%{TIMESTAMP_ISO8601:timestamp}\] %{DATA:environment}\.%{LOGLEVEL:level}: %{GREEDYDATA:message}" } } date { match => [ "timestamp", "yyyy-MM-dd HH:mm:ss" ] target => "@timestamp" } } }
output { elasticsearch { hosts => ["elasticsearch:9200"] index => "logs-%{+YYYY.MM.dd}" } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| filebeat.inputs: - type: log enabled: true paths: - /var/log/nginx/access.log - /var/log/nginx/error.log fields: fileset.module: nginx
- type: log enabled: true paths: - /var/www/html/storage/logs/laravel.log fields: fileset.module: laravel
output.logstash: hosts: ["logstash:5044"]
|
6. 自动化运维
6.1 定时任务
Laravel Scheduler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| protected function schedule(Schedule $schedule) { $schedule->command('log:clean')->daily(); $schedule->command('db:optimize')->weekly(); $schedule->command('backup:run')->dailyAt('02:00'); $schedule->command('cache:clear')->daily(); $schedule->command('report:send')->weeklyOn(1, '09:00'); }
|
Supervisor 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/html/artisan queue:work --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true user=www-data numprocs=8 redirect_stderr=true stdout_logfile=/var/www/html/storage/logs/worker.log stopwaitsecs=3600
[program:laravel-scheduler] process_name=%(program_name)s command=php /var/www/html/artisan schedule:run --sleep=60 autostart=true autorestart=true user=www-data numprocs=1 redirect_stderr=true stdout_logfile=/var/www/html/storage/logs/scheduler.log
|
6.2 自动化备份
Laravel Backup
1 2
| composer require spatie/laravel-backup php artisan vendor:publish --provider="Spatie\Backup\BackupServiceProvider"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| return [ 'backup' => [ 'destination' => [ 'disks' => ['local', 's3'], ], 'monitorBackups' => [ 'enabled' => true, 'targets' => [ [ 'name' => env('APP_NAME'), 'disk' => 'local', 'newestBackupsShouldNotBeOlderThanDays' => 1, 'storageUsedMayNotBeHigherThanMegabytes' => 5000, ], ], ], ], ];
|
备份命令
1 2 3 4 5 6 7 8 9 10 11
| php artisan backup:run
php artisan backup:list
php artisan backup:clean
php artisan backup:monitor
|
7. 安全加固
7.1 服务器安全
SSH 配置
1 2 3 4 5 6
| Port 2222 PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AllowUsers deploy
|
防火墙配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apt install ufw
ufw default deny incoming ufw default allow outgoing ufw allow 2222/tcp ufw allow 80/tcp ufw allow 443/tcp ufw allow 3306/tcp ufw allow 6379/tcp ufw enable
ufw status
|
7.2 应用安全
HTTPS 配置
1 2 3 4 5 6 7 8
| apt install certbot python3-certbot-nginx
certbot --nginx -d your-domain.com -d www.your-domain.com
certbot renew --dry-run
|
安全头
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| server { add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https://*.googleusercontent.com; font-src 'self' https://fonts.gstatic.com" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always; }
|
速率限制
1 2 3 4 5 6 7 8 9 10 11 12
| protected $middlewareGroups = [ 'api' => [ \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api', ], ];
Route::middleware('throttle:60,1')->group(function () { Route::get('/api/users', [UserController::class, 'index']); });
|
8. 性能优化
8.1 应用级优化
代码优化
- 使用类型声明:添加函数参数和返回类型
- 避免 N+1 查询:使用 eager loading
- 使用缓存:缓存频繁访问的数据
- 优化路由:使用路由缓存
- 优化视图:使用视图缓存
- 优化配置:使用配置缓存
数据库优化
- 添加索引:为频繁查询的列添加索引
- 使用查询构建器:避免原始 SQL
- 批量操作:使用批量插入和更新
- 分页优化:使用游标分页
- 连接池:配置数据库连接池
8.2 服务器级优化
PHP 优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.validate_timestamps=0 opcache.revalidate_freq=0 opcache.save_comments=1 opcache.fast_shutdown=1
zend_extension=opcache zend_extension=redis
memory_limit=512M max_execution_time=30 max_input_time=60 post_max_size=100M upload_max_filesize=100M
|
Nginx 优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| worker_processes auto; worker_connections 1024; events { use epoll; multi_accept on; }
http { sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; keepalive_requests 100; gzip on; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; open_file_cache max=10000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on; }
|
9. 实战案例:完整部署方案
9.1 项目背景
- 规模:中型电商应用
- 流量:1000-5000 QPS
- 架构:微服务架构
- 技术栈:Laravel 12、Vue 3、Redis、MySQL、Docker
- 要求:高可用、高性能、安全
9.2 部署架构
1. 基础设施
- 云服务:AWS EC2 + RDS + ElastiCache
- 容器编排:Kubernetes
- 负载均衡:AWS ALB
- CDN:CloudFront
- 监控:CloudWatch + Prometheus + Grafana
2. 服务架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 客户端 │ → → │ CloudFront │ → → │ ALB │ └─────────────┘ └─────────────┘ └─────────────┘ ↑ ↑ │ │ ↓ ↓ ┌─────────────┬─────────────┐ ↓ ↓ ↓ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 前端服务 │ │ API 服务 │ │ 后台服务 │ └─────────────┘ └─────────────┘ └─────────────┘ ↑ ↑ ↑ │ │ │ ↓ ↓ ↓ ┌─────────────┬─────────────┐ ↓ ↓ ↓ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Redis │ │ MySQL │ │ S3 │ └─────────────┘ └─────────────┘ └─────────────┘
|
3. CI/CD 流程
- 代码提交:开发者提交代码到 GitHub
- 自动化测试:GitHub Actions 运行测试
- 构建镜像:构建 Docker 镜像并推送到 ECR
- 部署应用:Kubernetes 部署新版本
- 健康检查:检查应用健康状态
- 回滚机制:失败时自动回滚
9.3 实施效果
| 指标 | 实施前 | 实施后 | 提升 |
|---|
| 响应时间 | 500ms | 100ms | 80% |
| QPS | 1000 | 5000 | 400% |
| 可用性 | 99.5% | 99.99% | 显著 |
| 部署时间 | 30分钟 | 5分钟 | 83% |
| 维护成本 | 高 | 低 | 60% |
10. 部署最佳实践总结
10.1 环境配置
- 使用环境变量:避免硬编码配置
- 分离环境:开发、测试、生产环境分离
- 版本控制:配置文件纳入版本控制
- 自动化配置:使用配置管理工具
10.2 容器化部署
- 使用 Docker:容器化应用
- 使用 Docker Compose:本地开发环境
- 使用 Kubernetes:生产环境编排
- 多阶段构建:减小镜像大小
- 镜像分层:优化镜像构建
10.3 CI/CD 集成
- 自动化测试:每次提交运行测试
- 自动化构建:构建镜像并推送
- 自动化部署:部署到生产环境
- 自动化回滚:失败时自动回滚
- 自动化监控:监控部署状态
10.4 高可用设计
- 负载均衡:分发流量到多个实例
- 数据库复制:主从复制保证数据安全
- Redis 集群:提高缓存可用性
- 自动缩放:根据流量自动缩放
- 多可用区:跨可用区部署
10.5 监控与告警
- 应用监控:监控应用状态和性能
- 服务器监控:监控服务器资源使用
- 数据库监控:监控数据库性能
- 缓存监控:监控缓存命中率
- 日志管理:集中管理和分析日志
- 告警机制:异常时及时告警
10.6 安全加固
- HTTPS:启用 HTTPS 加密
- 防火墙:配置防火墙规则
- SSH 加固:禁用密码登录
- 速率限制:防止暴力攻击
- 安全头:添加安全 HTTP 头
- 定期扫描:扫描安全漏洞
10.7 性能优化
- 代码优化:优化代码结构和算法
- 数据库优化:添加索引和优化查询
- 缓存策略:合理使用缓存
- 服务器优化:优化服务器配置
- CDN:使用 CDN 加速静态资源
11. 总结
Laravel 12 的部署是一个系统工程,涉及环境配置、容器化、CI/CD、负载均衡、监控和安全等多个方面。通过本文的介绍,开发者可以掌握 Laravel 12 部署的最佳实践,构建高可用、高性能、安全的 Laravel 应用。
在实际项目中,开发者应该根据项目的规模和需求,选择合适的部署方案。对于小型项目,可以使用简单的 Nginx + PHP-FPM 部署;对于中型项目,可以使用 Docker Compose 部署;对于大型项目,应该使用 Kubernetes 等容器编排工具。
同时,开发者应该注重自动化运维,通过 CI/CD 流程自动化测试、构建和部署,减少人工操作的错误。此外,应该建立完善的监控系统,及时发现和解决问题,保证应用的稳定运行。
随着云计算和容器技术的不断发展,Laravel 的部署方案也在不断演进。开发者应该保持学习的态度,关注最新的部署技术和工具,为构建更好的 Laravel 应用而努力。
Laravel 12 的部署最佳实践不仅是一套技术方案,更是一种工程化的思维方式:通过标准化的流程和工具,提高开发效率,保证代码质量,确保系统稳定。这种思维方式已经被越来越多的开发者所接受,成为现代 PHP 开发的主流选择。
在未来,随着 Laravel 生态系统的不断完善和云服务的不断发展,Laravel 的部署将会变得更加简单、高效和可靠。让我们一起期待 Laravel 的未来,为 PHP 生态系统的繁荣做出贡献。