webhook 설정 오류 수정
- deployer 배포 webhook 오류 설정 수정
This commit is contained in:
@@ -1,5 +1,16 @@
|
|||||||
FROM python:3.12-slim
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git rsync ca-certificates curl \
|
||||||
|
docker.io \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN pip install --no-cache-dir fastapi uvicorn
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
COPY app.py /app/app.py
|
COPY app.py /app/app.py
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
EXPOSE 9000
|
||||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "9000"]
|
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "9000"]
|
||||||
|
|||||||
@@ -5,25 +5,33 @@ app = FastAPI()
|
|||||||
SECRET = os.getenv("WEBHOOK_SECRET", "")
|
SECRET = os.getenv("WEBHOOK_SECRET", "")
|
||||||
|
|
||||||
def verify(sig: str, body: bytes) -> bool:
|
def verify(sig: str, body: bytes) -> bool:
|
||||||
# Gitea: X-Gitea-Signature = sha256=...
|
if not SECRET or not sig:
|
||||||
if not SECRET:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
mac = hmac.new(SECRET.encode(), msg=body, digestmod=hashlib.sha256).hexdigest()
|
mac = hmac.new(SECRET.encode(), msg=body, digestmod=hashlib.sha256).hexdigest()
|
||||||
expected = f"sha256={mac}"
|
|
||||||
return hmac.compare_digest(expected, sig)
|
# Gitea가 보내는 포맷이 케이스별로 달라서 둘 다 허용
|
||||||
|
candidates = {mac, f"sha256={mac}"}
|
||||||
|
return any(hmac.compare_digest(sig, c) for c in candidates)
|
||||||
|
|
||||||
@app.post("/webhook")
|
@app.post("/webhook")
|
||||||
async def webhook(req: Request):
|
async def webhook(req: Request):
|
||||||
body = await req.body()
|
body = await req.body()
|
||||||
sig = req.headers.get("X-Gitea-Signature", "")
|
|
||||||
|
# ✅ 여기(함수 안)에서 헤더 읽기
|
||||||
|
sig = (
|
||||||
|
req.headers.get("X-Gitea-Signature")
|
||||||
|
or req.headers.get("X-Hub-Signature-256")
|
||||||
|
or ""
|
||||||
|
)
|
||||||
|
|
||||||
if not verify(sig, body):
|
if not verify(sig, body):
|
||||||
raise HTTPException(401, "bad signature")
|
raise HTTPException(401, "bad signature")
|
||||||
|
|
||||||
# 배포 스크립트 실행
|
# 배포 스크립트 실행
|
||||||
# (컨테이너에 /scripts 가 마운트되어 있어야 함)
|
|
||||||
p = subprocess.run(["/scripts/deploy.sh"], capture_output=True, text=True)
|
p = subprocess.run(["/scripts/deploy.sh"], capture_output=True, text=True)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise HTTPException(500, f"deploy failed:\n{p.stdout}\n{p.stderr}")
|
raise HTTPException(500, f"deploy failed:\n{p.stdout}\n{p.stderr}")
|
||||||
|
|
||||||
return {"ok": True, "out": p.stdout}
|
return {"ok": True, "out": p.stdout}
|
||||||
|
|
||||||
|
|||||||
2
deployer/requirements.txt
Normal file
2
deployer/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
@@ -56,8 +56,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "19010:9000" # 외부 노출 필요 없으면 내부만 (리버스프록시로 /webhook만 노출 추천)
|
- "19010:9000" # 외부 노출 필요 없으면 내부만 (리버스프록시로 /webhook만 노출 추천)
|
||||||
environment:
|
environment:
|
||||||
- WEBHOOK_SECRET=여기에_긴_랜덤값
|
- WEBHOOK_SECRET=webpage_deploy_7f3A9cE2KpLwQ8N5VxRZbD4mH6TYeJ
|
||||||
volumes:
|
volumes:
|
||||||
- /volume1/workspace/web-page-backend:/repo:rw
|
- /volume1/workspace/web-page-backend:/repo:rw
|
||||||
- /volume1/docker/webpage:/runtime:rw
|
- /volume1/docker/webpage:/runtime:rw
|
||||||
- /volume1/docker/webpage/scripts:/scripts:ro
|
- /volume1/docker/webpage/scripts:/scripts:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|||||||
@@ -66,6 +66,27 @@ server {
|
|||||||
proxy_pass http://backend:8000;
|
proxy_pass http://backend:8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# webhook receiver (handle both /webhook and /webhook/)
|
||||||
|
location = /webhook {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_pass http://deployer:9000/webhook;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webhook/ {
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
proxy_pass http://deployer:9000/webhook;
|
||||||
|
}
|
||||||
|
|
||||||
# SPA 라우팅 (마지막에 두는 게 안전)
|
# SPA 라우팅 (마지막에 두는 게 안전)
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="/volume1/docker/webpage"
|
SRC="/repo"
|
||||||
|
DST="/runtime" # (= /volume1/docker/webpage 가 마운트된 곳)
|
||||||
|
|
||||||
cd "$ROOT"
|
cd "$SRC"
|
||||||
|
|
||||||
echo "[1/5] git fetch + pull"
|
# 레포에서 운영으로 반영할 항목들만 복사/동기화 (필요한 것만 적기)
|
||||||
git fetch --all --prune
|
# backend, travel-proxy, deployer, nginx, scripts, docker-compose.yml, .env 등
|
||||||
git pull --ff-only
|
rsync -a --delete \
|
||||||
|
--exclude ".git" \
|
||||||
|
--exclude ".releases" \
|
||||||
|
"$SRC/backend/" "$DST/backend/"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude ".git" \
|
||||||
|
"$SRC/travel-proxy/" "$DST/travel-proxy/"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude ".git" \
|
||||||
|
"$SRC/deployer/" "$DST/deployer/"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude ".git" \
|
||||||
|
"$SRC/nginx/" "$DST/nginx/"
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude ".git" \
|
||||||
|
"$SRC/scripts/" "$DST/scripts/"
|
||||||
|
|
||||||
echo "[2/5] docker compose build"
|
# compose 파일 / env 파일
|
||||||
docker compose build --pull
|
rsync -a "$SRC/docker-compose.yml" "$DST/docker-compose.yml"
|
||||||
|
if [ -f "$SRC/.env" ]; then
|
||||||
|
rsync -a "$SRC/.env" "$DST/.env"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[3/5] docker compose up"
|
echo "SYNC_OK"
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
echo "[4/5] status"
|
|
||||||
docker compose ps
|
|
||||||
|
|
||||||
echo "[5/5] done"
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ set -euo pipefail
|
|||||||
SRC="/repo"
|
SRC="/repo"
|
||||||
DST="/runtime"
|
DST="/runtime"
|
||||||
|
|
||||||
|
git config --global --add safe.directory "$SRC"
|
||||||
|
|
||||||
cd "$SRC"
|
cd "$SRC"
|
||||||
git fetch --all --prune
|
git fetch --all --prune
|
||||||
git pull --ff-only
|
git pull --ff-only
|
||||||
@@ -20,5 +22,5 @@ rsync -a --delete \
|
|||||||
bash "$SRC/scripts/deploy-nas.sh"
|
bash "$SRC/scripts/deploy-nas.sh"
|
||||||
|
|
||||||
cd "$DST"
|
cd "$DST"
|
||||||
docker compose up -d --build backend travel-proxy frontend
|
docker-compose up -d --build backend travel-proxy frontend
|
||||||
echo "DEPLOY_OK $TAG"
|
echo "DEPLOY_OK $TAG"
|
||||||
|
|||||||
Reference in New Issue
Block a user