サーバーへのデプロイ
現状
GithubへPush -> サーバー側でPull -> 自動リコンパイル
の流れで開発中のアプリケーションを実行していましたが、毎回毎回サーバーに繋いでPull
するのはめんどくさいです。
目標
GithubへPush -> サーバー側で自動Pull -> 自動リコンパイル
の流れにし、手動の作業はGithubへのPush
だけにしたいと思います。
使うもの
Github
プロキシサーバーの443に向けてGithubからWebhookを送信するように設定し、プロキシサーバーからデプロイサーバーに向けてリバースプロキシでWebhookを転送します。
プロキシサーバー
Nginx
いつものごとく、Githubからhttps://webhook.example.com
に飛んでくるWebhookをhttp://192.168.1.x:5000
にプロキシします。
デプロイサーバー
Flask
Nginxから飛んできたWebhookでイベントを発火させ、サブプロセスでgit pull
をするのに使います。
設定
Github
リポジトリ -> Settings -> WebhooksのAdd Webhook
でトリガーを作成します。
Payload URL
にプロキシサーバーのアドレスを設定し、イベントトリガーをJust the push event
にします。
Nginx (リバースプロキシ)
デプロイサーバーへのプロキシ設定と、GithubのIPアドレスからのアクセスのみ受け付ける設定をします。
#~~~~~~~~~~~~~~~~~~~~~~
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name webhook.example.com;
add_header Strict-Transport-Security 'max-age=15552000';
ssl_certificate /etc/letsencrypt/live/webhook.example.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/webhook.example.com/privkey.pem;
include /etc/nginx/allowed-address.conf;
deny all;
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect http:// $scheme://;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://YOUR_DEPLOY_SERVER:5000/;
}
}
#~~~~~~~~~~~~~~~~~~~~~~
/etc/nginx/allowed-address.conf
にGithubのアドレスを追加します。
GithubからのWebhookで使用されるIPアドレスは、Github APIの/metaエンドポイントのhooks
にあります。
allow 192.30.252.0/22;
allow 185.199.108.0/22;
allow 140.82.112.0/20;
allow 143.55.64.0/20;
allow 2a0a:a440::/29;
allow 2606:50c0::/32;
Flask (デプロイサーバー)
Webhookを受け取ったら、subprocess
でgit pull
を実行するだけのスクリプトです。
from flask import Flask, request, abort
import subprocess
app = Flask(__name__)
@app.route("/", methods=["POST"])
def webhook():
if request.method == "POST":
subprocess.run("git pull", shell=True, cwd=r"EXECUTION_DIR")
print("ok")
return "success",200
else:
abort(400)
if __name__ == "__main__":
app.run(host="0.0.0.0")