Your cart is currently empty!
部署流程自動化 GitHub CD w/ Flask & Deploy Keys
每次寫完程式碼 Push 上 GitHub 後,就要手動部署一次(我是部署在 GCP),所以今天來處理 CD (Continuous Deployment) 的部分,使用 GitHub Webhhok 到我的 Server,使用 Flask 接收並執行 Bash Script。
Reference: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#set-up-deploy-keys
簡單說明達成 CD 的邏輯
這篇適合已經熟悉 Nginx 或 Apache 反向代理以及 Systemd,知道一點 Python 和 SSH 的人類。
最基礎(暴力)的 Deploy 就是 SSH Server 然後 git clone 之後運行他,因為我也不是很 Senior,這個應該非常適合我,這個方法會遇到的唯一困難就是遇到自己的 private repo 要設定 SSH Key,讓你的 Server 在 git clone 時不會遇到權限問題,稍微整理一下總共有以下幾個步驟:
- 製作 SSH Key 放上 GitHub(僅適用 private repository) & 試試看 git clone
- 寫 Flask 接收 GitHub Webhook
- 寫部署的 Bash Script
製作 SSH Key 放上 GitHub(僅適用 private repository)& 試試看 git clone
可以參考這個 GitHub 頁面:Generating a new SSH key。使用你的 GitHub Email,然後他會詢問 passphrase,你要使用空白或是自己設定都可以。完成之後他會存在 ~/.ssh 資料夾裡面。
ssh-keygen -t ed25519 -C "[email protected]"
cat ~/.ssh/id_ed25519.pub 把你的「public key」顯示出來之後複製貼上到你的 repository >> Settings >> Deploy keys
好酷!直接使用 SSH clone,之前都是使用 https 的方法複製的。
git clone [email protected]:GITHUB_USER/YOUR_REPO.git
好的我確定他有 clone 到我的 server,下一步驟就是寫 Flask 聆聽 GitHub Webhook。
寫 Flask 接收 GitHub Webhook
請出 ChatGPT 然後修修修修修,確認程式沒有問題,然後用原本就有的 Nginx 或 Apache 網頁伺服器反向代理到設定的 port 5055。
# Python Flask @~/cd.py
import subprocess
import hmac
import hashlib
import os
from flask import Flask, request, abort
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
secret = os.getenv('GITHUB_WEBHOOK_SECRET')
if not secret:
raise RuntimeError("GITHUB_WEBHOOK_SECRET not found")
@app.route('/', methods=['POST'])
def webhook():
signature_sha256 = request.headers.get('X-Hub-Signature-256')
data = request.data
mac = hmac.new(secret.encode(), msg=data, digestmod=hashlib.sha256)
valid = hmac.compare_digest('sha256=' + mac.hexdigest(), signature_sha256)
if signature_sha256 is None or not valid:
print(f"Invalid signature: {signature_sha256}")
abort(403)
try:
result = subprocess.run(['/home/my_user/app/cd.sh'], check=True, text=True, capture_output=True)
return result.stdout, 200
except subprocess.CalledProcessError as e:
print("Error:", e.stderr)
return f"Error: {e.stderr}", 500
except Exception as e:
error_message = f"Failed to execute script: {str(e)}"
return error_message, 500
if __name__ == '__main__':
app.run(port=5055)
寫部署的 Bash Script
這邊就是寫你 push 完會在 server 執行的一些東西,例如 git pull、restart systemd。
#!/usr/bin/bash
cd /home/user/app
git pull origin main
pip install -r requirements.txt
sudo systemctl restart app
完成後記得要讓使用者有權限使用,透過 python 開啟時才不會遇到 Failed to execute script: [Errno 13] Permission denied: /path/to/sh。
chmod +x /home/my_user/app/cd.sh
這邊很蠢的跟你們說,我一開始在 Bash Script 裡面寫了 systemctl 重新開啟我的 CD 程式,所以 GitHub 在傳送 Webhook 時還沒接收到我的 Python return 就會被我的 Script 重開,造成 502 網頁伺服器錯誤(因為重開 Apache 就無法回傳反向代理的 Python 的回傳)害我搞了 3 個小時…,不知道在笨幾點嗚。
同場加應 GitHub 回傳狀態 & Tools Config
沒啦我也要記錄一下我東西怎麼設定的,不然這種太少碰到會忘 ><。