本文目录导读:

为PHP项目编写部署脚本需要考虑环境一致性、安全性和可重复性,下面提供一个从基础到进阶的部署方案,涵盖Shell脚本、Ansible和Docker三种主流方式。
基础Shell部署脚本
一个完整的deploy.sh示例:
#!/bin/bash
set -e # 任何命令失败立即退出
set -u # 使用未定义变量时报错
# ============ 配置区域 ============
PROJECT_NAME="my-php-app"
REPO_URL="https://github.com/your/repo.git"
DEPLOY_DIR="/var/www/${PROJECT_NAME}"
BACKUP_DIR="/var/backups/${PROJECT_NAME}"
BRANCH="main"
PHP_VERSION="8.1"
COMPOSER_PATH="/usr/local/bin/composer"
# ================================
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始部署 ${PROJECT_NAME}..."
# 1. 创建目录结构
mkdir -p "${DEPLOY_DIR}" "${BACKUP_DIR}"
# 2. 备份当前版本(如果存在)
if [ -d "${DEPLOY_DIR}/current" ]; then
echo "备份当前版本..."
TIMESTAMP=$(date +'%Y%m%d_%H%M%S')
cp -r "${DEPLOY_DIR}/current" "${BACKUP_DIR}/backup_${TIMESTAMP}"
# 只保留最近5个备份
ls -t "${BACKUP_DIR}" | tail -n +6 | xargs -I {} rm -rf "${BACKUP_DIR}/{}" 2>/dev/null
fi
# 3. 克隆/拉取代码
if [ -d "${DEPLOY_DIR}/current" ]; then
echo "拉取最新代码..."
cd "${DEPLOY_DIR}/current"
git fetch origin
git reset --hard "origin/${BRANCH}"
else
echo "首次克隆代码..."
git clone --depth=1 -b "${BRANCH}" "${REPO_URL}" "${DEPLOY_DIR}/current"
fi
# 4. 设置文件权限
echo "设置文件权限..."
find "${DEPLOY_DIR}/current" -type f -exec chmod 644 {} \;
find "${DEPLOY_DIR}/current" -type d -exec chmod 755 {} \;
# Web服务器用户(如www-data)可写目录
chmod -R 775 "${DEPLOY_DIR}/current/storage"
chmod -R 775 "${DEPLOY_DIR}/current/bootstrap/cache"
chown -R www-data:www-data "${DEPLOY_DIR}/current"
# 5. 安装Composer依赖
echo "安装PHP依赖..."
cd "${DEPLOY_DIR}/current"
${COMPOSER_PATH} install --no-dev --optimize-autoloader --no-interaction
# 6. 环境配置
echo "配置环境..."
if [ ! -f ".env" ]; then
cp .env.example .env
# 生成APP_KEY(适用于Laravel等框架)
php artisan key:generate --force
fi
# 7. 数据库迁移(需要数据库连接)
# php artisan migrate --force
# 8. 清理缓存(Laravel示例)
echo "优化缓存..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 9. 创建符号链接(部署版本管理)
ln -sfn "${DEPLOY_DIR}/current" "${DEPLOY_DIR}/latest"
# 10. 重启PHP-FPM(如果使用)
echo "重启PHP-FPM..."
sudo systemctl reload php${PHP_VERSION}-fpm
echo "[$(date +'%Y-%m-%d %H:%M:%S')] 部署完成!"
使用方法:
chmod +x deploy.sh ./deploy.sh
零停机部署脚本(使用符号链接)
#!/bin/bash
set -e
DEPLOY_DIR="/var/www/my-app"
RELEASE_DIR="${DEPLOY_DIR}/releases/$(date +'%Y%m%d%H%M%S')"
SHARED_DIR="${DEPLOY_DIR}/shared"
echo "创建新版本目录..."
mkdir -p "${RELEASE_DIR}"
echo "克隆指定版本代码..."
git clone --depth=1 -b main https://github.com/your/repo.git "${RELEASE_DIR}"
echo "共享资源链接..."
ln -nfs "${SHARED_DIR}/.env" "${RELEASE_DIR}/.env"
ln -nfs "${SHARED_DIR}/storage" "${RELEASE_DIR}/storage"
echo "安装依赖..."
cd "${RELEASE_DIR}"
composer install --no-dev --optimize-autoloader
echo "切换符号链接(零停机)..."
ln -nfs "${RELEASE_DIR}" "${DEPLOY_DIR}/current"
echo "重启服务..."
sudo systemctl reload nginx
sudo systemctl reload php8.1-fpm
echo "清理旧版本(保留最近3个)..."
cd "${DEPLOY_DIR}/releases"
ls -t | tail -n +4 | xargs -r rm -rf
目录结构:
/var/www/my-app/
├── current -> releases/20231001_120000/
├── releases/
│ ├── 20231001_110000/
│ ├── 20231001_120000/
│ └── 20231002_090000/
└── shared/
├── .env
└── storage/
Docker部署脚本
1 Dockerfile
FROM php:8.1-fpm-alpine
# 安装系统依赖
RUN apk add --no-cache \
git \
unzip \
libpng-dev \
libzip-dev \
oniguruma-dev \
&& docker-php-ext-install pdo_mysql mbstring zip gd
# 安装Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 设置工作目录
WORKDIR /var/www/html
# 复制项目文件
COPY . .
# 安装PHP依赖
RUN composer install --no-dev --optimize-autoloader --no-interaction
# 权限设置
RUN chown -R www-data:www-data storage bootstrap/cache
2 docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: php-app
restart: unless-stopped
volumes:
- ./storage:/var/www/html/storage
environment:
- DB_HOST=mysql
- DB_DATABASE=app
- DB_USERNAME=app
- DB_PASSWORD=secret
depends_on:
- mysql
- redis
networks:
- app-network
web:
image: nginx:alpine
container_name: nginx-web
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- .:/var/www/html
depends_on:
- app
networks:
- app-network
mysql:
image: mysql:8.0
container_name: mysql-db
restart: unless-stopped
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- mysql_data:/var/lib/mysql
networks:
- app-network
redis:
image: redis:alpine
container_name: redis-cache
restart: unless-stopped
networks:
- app-network
volumes:
mysql_data:
networks:
app-network:
driver: bridge
3 deploy-docker.sh
#!/bin/bash set -e echo "===== Docker部署开始 =====" # 1. 拉取最新代码 git pull origin main # 2. 构建新镜像 docker-compose build --no-cache app # 3. 执行数据库迁移(如果有) docker-compose run --rm app php artisan migrate --force # 4. 启动服务(零停机滚动更新) docker-compose up -d --scale app=3 --no-recreate web # 5. 等待健康检查 sleep 10 docker-compose ps echo "===== 部署完成 ====="
Ansible自动化部署
deploy-php.yml:
---
- name: 部署PHP应用
hosts: webservers
become: yes
vars:
project_name: "my-php-app"
repo_url: "https://github.com/your/repo.git"
deploy_dir: "/var/www/{{ project_name }}"
branch: "main"
tasks:
- name: 安装必要系统包
apt:
name:
- git
- nginx
- php8.1-fpm
- php8.1-mysql
- php8.1-xml
- php8.1-mbstring
- composer
state: present
update_cache: yes
- name: 创建部署目录
file:
path: "{{ deploy_dir }}"
state: directory
owner: www-data
group: www-data
mode: 0755
- name: 克隆代码
git:
repo: "{{ repo_url }}"
dest: "{{ deploy_dir }}/current"
version: "{{ branch }}"
force: yes
- name: 设置文件权限
file:
path: "{{ deploy_dir }}/current"
state: directory
recurse: yes
owner: www-data
group: www-data
- name: 配置.env
copy:
src: "{{ playbook_dir }}/files/.env.production"
dest: "{{ deploy_dir }}/current/.env"
owner: www-data
group: www-data
mode: 0600
- name: 安装Composer依赖
composer:
command: install
working_dir: "{{ deploy_dir }}/current"
no_dev: yes
optimize_autoloader: yes
- name: 执行数据库迁移
command:
cmd: php artisan migrate --force
chdir: "{{ deploy_dir }}/current"
- name: 优化缓存
command:
cmd: "{{ item }}"
chdir: "{{ deploy_dir }}/current"
loop:
- php artisan config:cache
- php artisan route:cache
- php artisan view:cache
- name: 配置Nginx
template:
src: "nginx.conf.j2"
dest: "/etc/nginx/sites-available/{{ project_name }}"
notify: reload nginx
- name: 启用站点
file:
src: "/etc/nginx/sites-available/{{ project_name }}"
dest: "/etc/nginx/sites-enabled/{{ project_name }}"
state: link
- name: 确保PHP-FPM运行
systemd:
name: php8.1-fpm
state: started
enabled: yes
handlers:
- name: reload nginx
systemd:
name: nginx
state: reloaded
运行Ansible:
ansible-playbook -i inventory.ini deploy-php.yml
CI/CD集成示例(GitHub Actions)
.github/workflows/deploy.yml:
name: Deploy PHP Application
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: mbstring, xml, gd, zip
tools: composer
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Run tests
run: vendor/bin/phpunit
- name: Deploy to server
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/my-app
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
sudo systemctl reload php8.1-fpm
安全注意事项
- 不要在脚本中硬编码数据库密码,使用环境变量或密钥管理工具
- 限制部署用户权限(尽量不用root)
- 备份前的版本,确保可以快速回滚
性能优化
- 使用
--optimize-autoloader生成优化的类映射 - 预编译模板和配置文件
- 使用OPcache
监控告警
- 部署后在脚本中添加健康检查
- 监控核心页面响应时间
- 设置回滚触发条件
选择哪种方式取决于你的项目复杂度:
- 简单项目:使用Shell脚本即可
- 微服务架构:推荐Docker
- 多服务器环境:使用Ansible等配置管理工具
- 持续集成:结合CI/CD工具
建议先在测试环境验证脚本,确保回滚机制正常工作后再用于生产环境。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播