innocenzi / deployer-recipe-forge
使用 Deployer 在 Forge 上实现无缝零停机部署
Requires
- php: ^8.2|^8.3
- deployer/deployer: ^7.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.59.3
README
使用 Deployer 在 Forge 上实现无缝零停机部署
composer require --dev innocenzi/deployer-recipe-forge
关于
deployer-recipe-forge
是一个针对 Deployer 的食谱,它可以帮助在 Laravel Forge 上实现零停机。
它使用 Forge 的 API 获取站点的凭证,例如其 IP 地址和远程用户名,因此您无需在您的 deploy.php
中硬编码它们。它自动使用您的仓库名称找到正确的 Forge 网站,因此您只需在 Forge 上进行配置。
此外,它还能够通过 Deployer 的集成(需要您设置 webhook)或通过ping Forge 的部署 URL 来在 Slack 上发送通知。
安装
将包安装为开发依赖
composer require --dev innocenzi/deployer-recipe-forge
然后,在您的项目根目录下创建一个 deploy.php
文件。 导入自动加载器,并调用 \Deployer\Forge::make()->configure();
。您可以使用 Deployer 修改您的部署脚本。
namespace Deployer; // This is required require __DIR__ . '/vendor/autoload.php'; \Deployer\Forge::make()->configure(); // This is your custom deployment script task('deploy:build', function () { // build assets here runLocally('bun i'); runLocally('bun run build'); });
使用
设置仓库
本食谱旨在与 GitHub 工作流程一起使用,使用由 Deployer 提供的 操作。
设置它至少需要两个 仓库密钥
- 您的服务器的 私有 SSH 密钥,将用于
deployphp/action
通过 SSH 连接 - 您的 Forge API 令牌,将用于食谱获取您的站点和服务器凭证
然后,这些仓库密钥必须作为环境变量转发到操作中,或者对于 SSH 密钥,作为 private-key
参数
- uses: deployphp/action@v1 with: private-key: ${{ secrets.PRIVATE_SSH_KEY }} dep: deploy env: FORGE_API_KEY: ${{ secrets.FORGE_API_KEY }} REPOSITORY_BRANCH: ${{ github.ref_name }} REPOSITORY_NAME: ${{ github.repository }}
警告
请注意,REPOSITORY_BRANCH
和 REPOSITORY_NAME
变量对于食谱的工作是必需的,因为它们用于将您的站点和分支与您的站点 Forge 匹配。
注意
为了方便,如果您正在使用付费的 GitHub 计划,您可以将您的 Forge API 令牌和 Slack webhook 设置为 组织范围的密钥。
设置 Forge
创建新站点
以下步骤解释了如何在 Forge 上设置新站点以在 GitHub Actions 上使用此食谱。
-
创建一个 隔离 站点。
目前,此食谱仅适用于隔离 Forge 站点。您必须然后创建一个隔离站点。
-
使用 GitHub 集成 安装仓库。
您可以取消选中“安装 composer 依赖项”,以加快安装速度,因为站点目录将被删除。
如果您还没有将服务器的部署密钥与您的GitHub仓库关联,请确保您已经这样做,或者为该站点创建一个部署密钥。 -
如有必要,请将服务器的公钥(
~/.ssh/id_rsa.pub
)添加到仓库的部署密钥。这将允许Deployer从服务器上的SSH会话克隆仓库。
-
通过SSH连接到服务器,复制其公钥(
~/.ssh/id_rsa.pub
),并将其添加到Forge上的授权密钥。这是允许Deployer操作通过SSH连接到服务器的第一步。
密钥应与正确的隔离站点用户名关联。 -
最后,复制服务器的私钥(
~/.ssh/id_rsa
),并将其添加到仓库的秘密。这是允许Deployer操作通过SSH连接到服务器的最后一步。
我们建议根据目标环境命名秘密。例如,如果您正在创建一个测试站点,它可能被称为STAGING_SSH_KEY
。 -
然后您可以触发部署工作流程。
添加到现有站点
首先,请确保网站是隔离的。它必须位于服务器上的/home/<isolated-username>/<site-name>
。否则,您必须创建一个新的隔离站点。
您必须首先备份您的.env
文件和storage
目录,因为Deployer将删除站点的目录以替换为符号链接。
备份后,您可以按照步骤3到6进行操作。部署完成后,您可以在/home/<isolated-username>/deployer/<site-name>/shared
中恢复您的.env
和storage
。
警告
请谨慎操作。确保将站点设置为维护状态,并考虑在迁移过程中可能发生的潜在副作用。
Slack通知
使用Deployer
此食谱支持使用webhook发送Slack通知。要创建它,您可以遵循Slack有关此主题的文档。然后,您必须将webhook作为仓库或组织秘密添加,并将其作为环境变量转发到操作中。
- uses: deployphp/action@v1 with: private-key: ${{ secrets.PRIVATE_SSH_KEY }} dep: deploy env: # ... # Add these two SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} RUNNER_ID: ${{ github.run_id }}
注意
请注意,需要RUNNER_ID
,因为Slack通知链接到相关的GitHub工作流程。
使用Forge
或者,您可以在Forge上设置Slack通知,并在Forge上触发部署。这样,您还可以使用Forge的部署历史记录。
要触发Forge上的部署,只需调用triggerDeploymentsOnForge
。
\Deployer\Forge::make() ->triggerDeploymentsOnForge() ->configure();
警告
当使用此策略时,请确保清空Forge配置的默认部署脚本。
多个环境
此食谱支持部署到多个环境,如测试或生产,无需任何特定配置,只需将不同的私有SSH密钥添加到您的仓库秘密中即可。
它是通过将仓库分支与Forge站点上定义的分支关联来工作的。例如,您可以将main
分支与example.com
关联,将develop
分支与staging.example.com
关联。
对于两个环境
私有SSH密钥必须提供给private-key
参数,例如使用条件,如下所示
- uses: deployphp/action@v1 with: private-key: ${{ github.ref_name == 'develop' && secrets.STAGING_SSH_KEY || secrets.PRODUCTION_SSH_KEY }} dep: deploy env: # ...
对于更多环境
如果您有超过两个环境,您只需复制操作并使用if
语句确保它们为正确的分支运行
steps: - name: Deploy (staging) if: github.ref_name == 'develop' uses: deployphp/action@v1 with: private-key: ${{ secrets.STAGING_SSH_KEY }} dep: deploy # ... - name: Deploy (production) if: github.ref_name == 'main' uses: deployphp/action@v1 with: private-key: ${{ secrets.PRODUCTION_SSH_KEY }} dep: deploy # ...
在CI或服务器上构建
默认情况下,食谱将在CI上构建资源,并在之后上传到服务器。要在服务器上构建,请调用buildOnServer
\Deployer\Forge::make() ->buildOnServer() ->configure();
注意,默认情况下不提供deploy:build
任务,您应该自己编写。例如,您可以使用Bun来构建资源。
\Deployer\Forge::make()->configure(); task('deploy:build', function () { runLocally('bun i'); runLocally('bun run build'); });
显然,在使用此示例之前,请确保Bun已经安装在CI上。
示例工作流程
此工作流程在运行test.yml
和style.yml
工作流程后,根据推送的分支在生产或预发布环境中部署。如果提交体包含[skip deploy]
,则将跳过部署,并将部署通知到Slack。
此外,您可以手动调度工作流程。
name: Deploy on: workflow_dispatch: push: branches: [main, develop] concurrency: group: ${{ github.ref }} jobs: test: uses: ./.github/workflows/test.yml style: uses: ./.github/workflows/style.yml deploy: needs: [test, style] if: ${{ !contains(github.event.head_commit.message, '[skip deploy]') }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: shivammathur/setup-php@v2 with: php-version: 8.2 - uses: oven-sh/setup-bun@v1 with: bun-version: latest - name: Install dependencies run: composer install --no-interaction --prefer-dist - uses: deployphp/action@v1 with: private-key: ${{ github.ref_name == 'develop' && secrets.STAGING_SSH_KEY || secrets.PRODUCTION_SSH_KEY }} dep: deploy env: FORGE_API_KEY: ${{ secrets.FORGE_API_KEY }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} REPOSITORY_BRANCH: ${{ github.ref_name }} REPOSITORY_NAME: ${{ github.repository }} RUNNER_ID: ${{ github.run_id }}
在本地使用dep
由于食谱依赖于多个环境变量,您不能轻易地在本地上调用vendor/bin/dep
。
您可以通过将FORGE_API_KEY
添加到您的.env
文件,以及REPOSITORY_NAME
和REPOSITORY_BRANCH
来解决这个问题。
FORGE_API_KEY="abc...123" REPOSITORY_NAME="yourorg/repo" REPOSITORY_BRANCH="develop"
然后,您可以将以下脚本添加到composer.json
中,并运行composer dep
而不是vendor/bin/dep
。
"dep": "set -o allexport && source ./.env && set +o allexport && vendor/bin/dep"
警告
在本地使用dep
将创建一个.deployer_cache
文件,您应该将其添加到.gitignore
中。
注意
如果您被拒绝SSH访问,请确保在服务器上添加您的公钥并将其与您的站点的用户关联。
问答
为什么不使用Envoyer?
Envoyer与Forge的集成移除了在Forge内直接管理一切便捷性,迫使我们需要在两个不同的用户界面之间切换。我们的开发体验使用Deployer和这个食谱会更好。
为什么问题会被关闭?
此食谱主要在Jetfly内部使用,我们不愿意为此提供支持或添加许多功能。对于修复和小型添加的拉取请求可能受欢迎。