innocenzi/deployer-recipe-forge

使用 Deployer 在 Forge 上实现无缝零停机部署

0.3.4 2024-06-27 13:03 UTC

This package is auto-updated.

Last update: 2024-08-27 13:21:04 UTC


README

release version

使用 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_BRANCHREPOSITORY_NAME 变量对于食谱的工作是必需的,因为它们用于将您的站点和分支与您的站点 Forge 匹配。

注意

为了方便,如果您正在使用付费的 GitHub 计划,您可以将您的 Forge API 令牌和 Slack webhook 设置为 组织范围的密钥

 

设置 Forge

创建新站点

以下步骤解释了如何在 Forge 上设置新站点以在 GitHub Actions 上使用此食谱。

  1. 创建一个 隔离 站点。

    目前,此食谱仅适用于隔离 Forge 站点。您必须然后创建一个隔离站点。

  2. 使用 GitHub 集成 安装仓库。

    您可以取消选中“安装 composer 依赖项”,以加快安装速度,因为站点目录将被删除。
    如果您还没有将服务器的部署密钥与您的GitHub仓库关联,请确保您已经这样做,或者为该站点创建一个部署密钥

  3. 如有必要,请将服务器的公钥(~/.ssh/id_rsa.pub)添加到仓库的部署密钥

    这将允许Deployer从服务器上的SSH会话克隆仓库。

  4. 通过SSH连接到服务器,复制其公钥(~/.ssh/id_rsa.pub),并将其添加到Forge上的授权密钥

    这是允许Deployer操作通过SSH连接到服务器的第一步。
    密钥应与正确的隔离站点用户名关联。

  5. 最后,复制服务器的私钥(~/.ssh/id_rsa),并将其添加到仓库的秘密

    这是允许Deployer操作通过SSH连接到服务器的最后一步。
    我们建议根据目标环境命名秘密。例如,如果您正在创建一个测试站点,它可能被称为STAGING_SSH_KEY

  6. 然后您可以触发部署工作流程。

 

添加到现有站点

首先,请确保网站是隔离的。它必须位于服务器上的/home/<isolated-username>/<site-name>。否则,您必须创建一个新的隔离站点

您必须首先备份您的.env文件和storage目录,因为Deployer将删除站点的目录以替换为符号链接。

备份后,您可以按照步骤3到6进行操作。部署完成后,您可以在/home/<isolated-username>/deployer/<site-name>/shared中恢复您的.envstorage

 

警告

请谨慎操作。确保将站点设置为维护状态,并考虑在迁移过程中可能发生的潜在副作用。

 

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.ymlstyle.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_NAMEREPOSITORY_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内部使用,我们不愿意为此提供支持或添加许多功能。对于修复和小型添加的拉取请求可能受欢迎。