當你把程式碼從 GitHub 自動部署到自己的伺服器時,可以節省時間並避免出錯。部署自動化能夠帶來更快的回饋,也有助於團隊更高效地協作。藉助 GitHub Actions、Webhook 和部署腳本等工具,你可以減少人為失誤,讓整個流程更加穩定可靠。即使你只掌握了 GitHub 和伺服器管理的基礎知識,也能建立這套工作流程,並很快看到改善效果。

重點整理

  • 將程式碼部署自動化可以節省時間並減少錯誤。使用 GitHub Actions 和 Webhook 等工具,可以讓流程更加順暢。
  • 準備好必要的工具和帳戶,包括 GitHub 儲存庫、雲端伺服器以及部署腳本。這些基礎設定是成功實現自動化的關鍵。
  • 透過 SSH 金鑰實現免密碼存取,保障伺服器安全。這能確保只有受信任的系統可以連線到你的伺服器。
  • 在正式上線前,先在預備伺服器上測試部署流程。這樣可以及早發現問題,保護正式環境。
  • 使用 GitHub Secrets 安全儲存敏感資訊。這可以讓密碼和金鑰不會暴露在工作流程檔案中。

自動部署的前置條件

所需工具與帳戶

在開始設定自動部署之前,你需要準備一些必要的工具和帳戶。它們將幫助你把 GitHub 上的程式碼連接到伺服器,並讓整個流程更加順暢。

  1. 線上遠端儲存庫:你需要一個 GitHub 帳戶,並擁有一個存放專案程式碼的儲存庫。
  2. 本機 Git 儲存庫:在你的電腦上設定一個本機 Git 儲存庫,用於管理程式碼變更。
  3. 雲端伺服器:選擇一個雲端伺服器供應商,例如 Amazon EC2 或 Rackspace。你的網站或應用程式將執行於此。
  4. 部署腳本:撰寫一個部署腳本,例如 deploy.php,用來拉取 GitHub 上的最新程式碼。
  5. 在伺服器上安裝 Git:請確認你的伺服器已安裝 Git,且版本為最新。
  6. SSH 金鑰設定:在伺服器上產生 SSH 金鑰,以實現與 GitHub 的安全免密碼通訊。
  7. 將 SSH 公鑰加入 GitHub:把伺服器的 SSH 公鑰加入你的 GitHub 帳戶中,以便伺服器能夠存取儲存庫。
  8. 設定 Post-Receive Hook:在 GitHub 中設定 post-receive hook,用來觸發你的部署腳本。

提示:請妥善保管你的 SSH 金鑰。絕不要將私鑰分享給任何人。

準備你的伺服器

你必須先準備好伺服器,以便接收來自 GitHub 的程式碼更新。這樣的設定可以確保每次自動部署都能順利執行。

  • 將你的 GitHub 儲存庫複製到伺服器上的某個目錄。你可以為正式環境和預備環境分別建立不同的目錄。
  • 撰寫 Bash 部署腳本,並賦予這些腳本執行權限,以便它們能夠取得最新程式碼並執行。
  • 訂閱 GitHub 的 Webhook API。這樣你的伺服器就能監聽事件,並在需要時自動開始部署流程。

下面是一個簡單的儲存庫複製命令:

git clone git@github.com:yourusername/your-repo.git

完成這些步驟後,你的伺服器就可以進行自動部署了。每次部署新程式碼時,你都能節省時間並減少錯誤。

使用 GitHub Actions 自動部署程式碼

你可以藉助 GitHub Actions 將程式碼自動部署到伺服器。這個工具可以幫助你在每次推送變更時自動執行腳本並發佈程式碼。你不再需要手動登入伺服器或手動執行命令,整個過程會更加流暢且可重複。

建立工作流程檔案

要實現程式碼自動部署,你需要在儲存庫中建立一個工作流程檔案。這個檔案會告訴 GitHub Actions:當你推送新程式碼時,需要執行哪些操作。請將該檔案放在 .github/workflows/ 目錄中,並命名為類似 main.yml 的名稱。

下面是一個工作流程檔案範例:它會在每次推送標籤時觸發,並執行部署工作:

name: Deploy on Tag

on:
  push:
    tags:
      - '*'

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout Repository
      uses: actions/checkout@v3

    - name: Deploy to Test Server
      env:
        REMOTE_PATH: [your remote path location]
      if: startsWith(github.ref, 'refs/tags/') && contains(github.ref, 'rc')
      run: |
        mkdir -p ~/.ssh
        echo "${{ secrets.TEST_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
        cd ~/.ssh
        chmod 600 id_rsa
        ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa ${{ secrets.TEST_SSH_USERNAME }}@${{ secrets.TEST_SERVER }} 'echo "${{secrets.REPO_DEPLOY_KEY}}" > ~/.ssh/gh_key && chmod 600 ~/.ssh/gh_key && eval `ssh-agent -s` && ssh-add ~/.ssh/gh_key && cd ${{ env.REMOTE_PATH }} && git fetch --tags && git checkout ${{ github.ref }} && /usr/bin/docker compose run --rm backend php yii migrate --interactive=0 && /usr/bin/docker compose run --rm backend php yii cache/flush-all && rm -f ~/.ssh/gh_key'

這個工作流程會先簽出你的程式碼,然後連線到伺服器,並執行命令來更新專案。你可以根據自己的需求調整這些步驟。

在建立工作流程檔案時,你可能會遇到一些常見問題:

  • 工作流程沒有觸發。請確認檔案位於 .github/workflows/main.yml
  • YAML 語法錯誤。請確保每一級縮排使用兩個空格。
  • 找不到命令。請檢查 GitHub runner 上是否安裝了所有所需工具。

你可以透過反覆檢查檔案位置和語法來避免這些問題。

設定環境與 Secrets

在自動部署程式碼時,你必須確保伺服器安全。絕不要把密碼或私鑰直接寫進工作流程檔案。相反地,你應該使用 GitHub Secrets 來儲存敏感資訊。

進入你的儲存庫設定頁面,找到「Secrets」部分。新增 SSH 私鑰、伺服器使用者名稱以及其他敏感資訊。在工作流程檔案中,你可以使用 ${{ secrets.YOUR_SECRET_NAME }} 的形式來引用這些 Secrets。這樣可以確保你的資料安全且不會外洩。

你也可以為測試環境和正式環境分別設定不同的 Environment。這樣一來,你可以先把程式碼自動部署到測試伺服器;如果一切正常,再部署到正式伺服器。藉助 GitHub Actions,你可以精確控制程式碼在何時、部署到哪裡。

按照這些步驟操作後,每次你推送變更時,程式碼都會自動部署。你將節省時間、減少錯誤,並讓整個部署流程更加穩固、安全。

使用 Webhook 實現自動部署

Webhook 是實現部署自動化的一種非常有力的方式。設定完成後,你的伺服器可以監聽來自 GitHub 的事件,並在收到通知後自動更新程式碼。如果你希望在自己的伺服器上掌控整個部署流程,這種方法會非常適合。

撰寫 Webhook 監聽腳本

首先,你需要一個用於監聽 Webhook 請求的腳本。你可以使用 PHP、Node.js,或其他能夠處理 HTTP POST 請求的語言。這個腳本會在你向儲存庫推送變更時接收來自 GitHub 的通知。

下面是一套典型的 Webhook 監聽器設定流程:

  1. 將你的 Git 儲存庫分別複製到正式環境和預備環境對應的目錄中。
  2. 為每個環境建立 Bash 腳本,並賦予這些腳本執行權限,以便自動執行。
  3. 撰寫處理 Webhook 事件的程式碼。許多開發者會在 Node.js 中使用 github-webhook-handler 套件,但你也可以使用 PHP 或 Python。
  4. 在 GitHub 儲存庫設定中配置 Webhook URL。選擇用來觸發 Webhook 的事件,例如 push 或 pull request。
  5. 測試並驗證你的設定。你可以使用 PM2 這類行程管理工具來監控腳本,並透過日誌排查錯誤。

下面是一個簡單的 PHP Webhook 監聽腳本範例:

<?php
$secret = 'your_webhook_secret';
$payload = file_get_contents('php://input');
$signature = 'sha1=' . hash_hmac('sha1', $payload, $secret);

if (hash_equals($signature, $_SERVER['HTTP_X_HUB_SIGNATURE'])) {
    // Run your deployment script
    shell_exec('/path/to/deploy.sh');
    http_response_code(200);
    echo "Deployment triggered.";
} else {
    http_response_code(403);
    echo "Invalid signature.";
}
?>

提示:一定要使用 GitHub 提供的範例 payload 測試你的 Webhook 監聽器。這樣可以幫助你在影響線上網站之前發現錯誤。

設定 GitHub Webhook

建立好監聽腳本之後,你還需要在 GitHub 儲存庫中設定 Webhook。這一步會把你的儲存庫和伺服器連接起來,並告訴 GitHub 應該把通知送到哪裡。

按照以下步驟設定你的 Webhook:

  1. 撰寫處理 Webhook 事件的程式碼,並確保你的伺服器擁有一個 GitHub 可以存取的公開 URL。
  2. 如果你想簡化事件處理流程,可以使用像 github-webhook-handler 這樣的套件。
  3. 執行你的服務程式,讓它開始監聽傳入的 Webhook 請求。
  4. 進入 GitHub 儲存庫設定頁面,新增一個 Webhook,並填寫監聽腳本的 URL。
  5. 選擇應該觸發 Webhook 的事件,例如 push 事件或 pull request。

在使用 Webhook 時,安全性非常重要。你需要確保只有 GitHub 才能觸發伺服器上的部署。以下是一些關鍵的安全注意事項:

安全注意事項說明
使用密鑰進行驗證為你的 Webhook 新增一個密鑰,以幫助確認請求確實來自 GitHub。
Webhook URL 的可存取性請妥善保護你的 Webhook URL,不要隨意公開,以防止未經授權的存取。
使用 HTTPS設定 HTTPS,以加密 GitHub 與伺服器之間的通訊。

注意:如果你使用了密鑰,請同步更新監聽腳本,以驗證傳入請求的簽章。這會增加一層額外的安全保護。

完成這些步驟後,每次你向儲存庫推送程式碼,伺服器都會自動部署最新版本。這樣的設定可以節省時間,並減少手動操作帶來的風險。

安全的伺服器存取與 SSH 金鑰

設定安全存取機制,是任何自動化部署流程中都非常關鍵的一部分。你需要確保只有受信任的使用者和系統能夠連線到伺服器。使用 SSH 金鑰可以幫助你實現安全、免密碼的連線。

產生 SSH 金鑰

你可以透過產生 SSH 金鑰,讓部署流程安全地連線到伺服器。請依照以下步驟為部署使用者設定 SSH 金鑰:

  1. 在本機上產生一對新的 SSH 金鑰:
    ssh-keygen -t ed25519 -f ~/.ssh/blog_deployer
  2. 在伺服器上建立一個專門用於部署的使用者:
    useradd blog-deployer
  3. 鎖定該使用者的密碼,防止其透過密碼登入:
    passwd -l blog-deployer
  4. 為新使用者建立一個 .ssh 目錄:
    mkdir -p /home/blog-deployer/.ssh
  5. 將公鑰加入 authorized_keys 檔案中:
    nano /home/blog-deployer/.ssh/authorized_keys
  6. 變更主目錄的擁有權:
    chown -R blog-deployer:blog-deployer /home/blog-deployer

這樣設定之後,就只有你的部署系統才能連線到伺服器並將專案部署到伺服器上。

設定權限

你必須設定正確的權限,才能確保部署過程的安全。如果權限設定不當,攻擊者可能會取得存取權限,甚至竊取資料。以下是一些最佳實務:

  • 限制部署使用者的 SSH 登入能力。你可以使用如下命令:
    restrict,pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding,command="/usr/local/bin/rrsync -wo /var/www/blog"
    
  • 限制部署使用者可執行的操作,只允許執行部署所需的最小權限操作。
  • 將 Secrets 和金鑰保存在安全的保管庫中,並確保其在靜態儲存和傳輸過程中都經過加密。
  • 定期稽核並監控伺服器存取情況。
  • 定期輪替 SSH 金鑰和各類敏感憑證。

提示:務必檢查 SSH 金鑰和部署腳本的權限設定。權限設定錯誤可能會導致未經授權的存取、資料外洩或遭受攻擊。

遵循這些步驟後,你就能更好地保護部署流程,並確保伺服器安全。

測試並部署你的網站

執行一次測試部署

在將網站部署到正式環境之前,你應當始終先進行測試。測試部署可以幫助你及早發現問題,並確保整個流程符合預期。請依照以下步驟,從 GitHub 向你的私有伺服器執行一次測試部署:

  1. 準備你的伺服器。使用一個乾淨的 Linux 系統,例如 Ubuntu 22.04 或更新版本。確保伺服器至少具備 4GB 記憶體和 2 個 CPU 核心,並確認它可以連上網際網路。
  2. 從 GitHub 複製你的部署儲存庫。使用正確的 SSH 金鑰或 HTTPS 方式來確保存取安全。
  3. 選擇你的安裝方式。如果你想快速安裝,可執行:
    ./scripts/install-fast.sh

    如果你需要自訂安裝,請先準備好設定檔,然後使用 Helm 安裝命令。

  4. 觸發部署。向儲存庫推送一次變更,或手動觸發工作流程或 Webhook。
  5. 查看伺服器日誌,確認部署腳本已經執行並成功更新檔案。

提示:在將網站部署到正式環境之前,請務必先在預備伺服器上測試。這能夠保護你的線上網站安全。

排解常見問題

在部署過程中,你可能會遇到一些常見問題。下表列出了常見錯誤、成因以及預防措施:

問題錯誤訊息原因預防措施
映射中發現重複鍵duplicate key found in mappingYAML 解析器更新在範本中使用唯一且描述清楚的命名
找不到 SecretSecret not found or variable is empty語法錯誤在範本中展示正確的上下文語法
矩陣策略錯誤Matrix not expanded, tests skipped無效的矩陣設定在範本中提供一個可正常運作的矩陣範例
上下文語法錯誤Variable not interpolated, value is empty忘記使用 ${{ }} 包裹在範本中展示所有上下文模式
範本過於複雜Contributor ignores template, issue incomplete包含 20 個以上欄位保持技能類範本精簡(最多 5-8 個欄位)
缺少必填欄位Issue incomplete, missing key informationMarkdown 範本缺少驗證使用帶有 required: true 的 YAML 範本
工作流程重複Wasted CI time, high maintenance overhead為 CI / CodeQL / dependency review 分別設定了獨立工作流程在範本中提供整合方案

如果你遇到錯誤,請檢查 YAML 檔案中是否存在問題。確認所有 Secrets 和變數都已正確設定。查看部署日誌通常可以幫助你快速定位原因。及早修正這些小問題,會讓你的部署流程更加順暢可靠。

你應該經常測試部署流程,並保持部署腳本的安全性。你也可以嘗試一些更進階的工具,例如 AWS Code Deploy、Heroku、Zeit Now、Netlify、Travis CI、CircleCI、AWS ECS、Docker Swarm 和 Kubernetes。對於行動端專案,也可以使用 Bitrise 和 Firebase。為你的 GitHub 整合加入通知系統,可以幫助你更好地監控部署狀態。這些工具能夠幫助你管理 Git 工作流程,並讓你的雲端伺服器保持最新。自動化檢查、監控工具和視覺化儀表板,會為你帶來更強的掌控力與安全性。