Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,13 @@ jobs:
- name: Health check and switch
id: health
uses: appleboy/ssh-action@v1
env:
DOMAIN: ${{ needs.resolve.outputs.domain }}
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
envs: DOMAIN
script: |
# 슬롯 재판정 - 배포 스텝과 같은 공용 블록·같은 값으로 읽는다 (상태 파일이 source of truth)
DECIDED=$(bash /tmp/piki-deploy/slot_decide.sh --state-file /etc/nginx/team3-upstream.conf \
Expand All @@ -590,8 +593,14 @@ jobs:
# 실패 시 이전 upstream 원복까지 블록의 원복 경계 안에서 돈다. 종전 인라인(tee + reload)에는
# 원복이 없어 전환 실패 시 상태 파일과 실제 서빙이 어긋난 채 남았고, 그 괴리는 다음 배포가
# 서빙 중인 슬롯을 비활성으로 오판·제거하게 만들었다 (infra#37 에서 실사고로 실증된 결함의 해소).
# verify-cmd: 전환 직후 소비자 경로(프론트 443 → nginx → 새 슬롯)를 통째로 검증한다 - 앱만
# 살아있고 배달 경로가 끊긴 부류(extractor 이행 배포의 Host/444 사고가 그 실례)를 원복 경계
# 안에서 잡는다. /health 는 conf 가 127.0.0.1 에만 열어 둔 내부 검증 전용 경로이고, 검증 배선
# (폴링·재시도·TLS 우회 -k·Host 헤더)은 extractor 와 같은 공용 블록(healthcheck.sh)이 진다 -
# 값(URL·간격·도메인)만 여기서 준다. 짧은 재시도(2s x 5)는 reload 직후 워커 교체 흔들림 흡수.
if ! bash /tmp/piki-deploy/slot_switch.sh \
--state-file /etc/nginx/team3-upstream.conf --server "localhost:$INACTIVE_PORT"; then
--state-file /etc/nginx/team3-upstream.conf --server "localhost:$INACTIVE_PORT" \
--verify-cmd "bash /tmp/piki-deploy/healthcheck.sh --url https://127.0.0.1/health --interval 2 --attempts 5 --insecure --host-header $DOMAIN"; then
echo "슬롯 전환 실패(이전 upstream 원복됨) - 새 슬롯 정리 후 중단"
timeout 40 docker stop -t 30 "piki-core-$INACTIVE" 2>/dev/null || true
timeout 30 docker rm -f "piki-core-$INACTIVE" 2>/dev/null || true
Expand Down
10 changes: 8 additions & 2 deletions infra/nginx/api.piki.day.conf
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,14 @@ server {
proxy_pass http://team3;
}

# /health 는 화이트리스트에 없다(#833) - 배포 헬스체크는 localhost 직결이라 nginx 를 안 타고,
# 외부 호출 실적은 봇 스캔뿐이었다(7일 실측). 외부 uptime 모니터를 도입하면 그때 재개방한다.
# /health 는 박스 자신(127.0.0.1)에게만 연다 - 배포(slot_switch)가 전환 직후 "프론트 → nginx → 새 슬롯"
# 경로를 검증하는 용도다. 외부는 종전(#833)대로 봇 스캔에 상태코드조차 안 주는 444 를 유지한다
# ("외부 uptime 모니터 도입 시 재개방" 조건과 별개 - 이건 외부 개방이 아니다).
# if+return 은 rewrite phase 라 limit_req 를 안 타지만, 내부 1회성 검증이라 레이트리밋이 불필요하다.
location = /health {
if ($remote_addr != "127.0.0.1") { return 444; }
proxy_pass http://team3;
}

# 어드민 페이지가 참조하는 유일한 정적 리소스.
location = /favicon.ico {
Expand Down
10 changes: 8 additions & 2 deletions infra/nginx/dev.api.piki.day.conf
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,14 @@ server {
proxy_pass http://team3;
}

# /health 는 화이트리스트에 없다(#833) - 배포 헬스체크는 localhost 직결이라 nginx 를 안 타고,
# 외부 호출 실적은 봇 스캔뿐이었다(7일 실측). 외부 uptime 모니터를 도입하면 그때 재개방한다.
# /health 는 박스 자신(127.0.0.1)에게만 연다 - 배포(slot_switch)가 전환 직후 "프론트 → nginx → 새 슬롯"
# 경로를 검증하는 용도다. 외부는 종전(#833)대로 봇 스캔에 상태코드조차 안 주는 444 를 유지한다
# ("외부 uptime 모니터 도입 시 재개방" 조건과 별개 - 이건 외부 개방이 아니다).
# if+return 은 rewrite phase 라 limit_req 를 안 타지만, 내부 1회성 검증이라 레이트리밋이 불필요하다.
location = /health {
if ($remote_addr != "127.0.0.1") { return 444; }
proxy_pass http://team3;
}

# 어드민 페이지가 참조하는 유일한 정적 리소스.
location = /favicon.ico {
Expand Down
Loading