fix: route auth errors to login page (#45) #21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy | |
| # 정책 (Week 3~): | |
| # - N100 에는 prod 단일 환경만 운영. | |
| # - dev push → staging-* GHCR image build/push 까지만. "컨테이너 빌드가 깨지지 않는가" 안전망용. | |
| # N100 에는 절대 SSH 안 함. | |
| # - main push → prod-* GHCR image build/push + N100 SSH 배포. | |
| # - workflow_dispatch 로 임의 ref 에 대해 prod target 수동 배포 가능. | |
| # | |
| # Staging 컨테이너를 N100 에서 안 돌리기로 결정한 배경은 회고-Week2 + 회고-Week3 참조. | |
| on: | |
| push: | |
| branches: [dev, main] | |
| workflow_dispatch: | |
| inputs: | |
| target: | |
| description: "수동 배포 대상 (prod 만 지원)" | |
| required: true | |
| default: "prod" | |
| type: choice | |
| options: [prod] | |
| # 동시 배포 금지. 같은 ref 에 새 push 가 오면 in-progress 취소. | |
| concurrency: | |
| group: deploy-${{ github.ref_name }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| packages: write # ghcr.io push 권한 | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE: ${{ github.repository }} | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # 1) build image → ghcr.io 푸시 (dev=staging tag, main=prod tag, dispatch=prod tag) | |
| # --------------------------------------------------------------------------- | |
| build: | |
| name: Build & push image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| outputs: | |
| image_tag: ${{ steps.meta.outputs.image_tag }} | |
| target: ${{ steps.meta.outputs.target }} | |
| deploy_to_n100: ${{ steps.meta.outputs.deploy_to_n100 }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Resolve target + tag | |
| id: meta | |
| run: | | |
| # 우선순위: workflow_dispatch.inputs.target → branch | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| target="${{ inputs.target }}" | |
| deploy_to_n100="true" | |
| elif [ "${{ github.ref_name }}" = "main" ]; then | |
| target="prod" | |
| deploy_to_n100="true" | |
| else | |
| # dev push (또는 그 외 브랜치) — image 만 빌드하고 N100 SSH 는 안 함. | |
| target="staging" | |
| deploy_to_n100="false" | |
| fi | |
| sha_short="$(echo "${{ github.sha }}" | cut -c1-7)" | |
| image_tag="${target}-${sha_short}" | |
| echo "target=$target" >> "$GITHUB_OUTPUT" | |
| echo "image_tag=$image_tag" >> "$GITHUB_OUTPUT" | |
| echo "deploy_to_n100=$deploy_to_n100" >> "$GITHUB_OUTPUT" | |
| echo "image_ref=${REGISTRY}/${IMAGE}:${image_tag}" >> "$GITHUB_OUTPUT" | |
| echo "image_ref_target=${REGISTRY}/${IMAGE}:${target}" >> "$GITHUB_OUTPUT" | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build & push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: deploy/Dockerfile | |
| push: true | |
| tags: | | |
| ${{ steps.meta.outputs.image_ref }} | |
| ${{ steps.meta.outputs.image_ref_target }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # --------------------------------------------------------------------------- | |
| # 2) N100 SSH secrets 준비 여부 확인. 미등록이면 build 까지만 하고 deploy 는 skip. | |
| # --------------------------------------------------------------------------- | |
| deploy-preflight: | |
| name: Check deploy secrets | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 3 | |
| needs: build | |
| if: needs.build.outputs.deploy_to_n100 == 'true' | |
| outputs: | |
| deploy_ready: ${{ steps.secrets.outputs.deploy_ready }} | |
| steps: | |
| - name: Check N100 secrets | |
| id: secrets | |
| run: | | |
| if [ -n "$N100_HOST" ] && [ -n "$N100_USER" ] && [ -n "$N100_SSH_KEY" ]; then | |
| echo "deploy_ready=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "deploy_ready=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::N100 deploy secrets are not configured yet. Image build/push completed; SSH deploy is skipped." | |
| fi | |
| env: | |
| N100_HOST: ${{ secrets.N100_HOST }} | |
| N100_USER: ${{ secrets.N100_USER }} | |
| N100_SSH_KEY: ${{ secrets.N100_SSH_KEY }} | |
| # --------------------------------------------------------------------------- | |
| # 3) main / dispatch 한정. SSH 로 N100 접속 → docker compose pull && up -d | |
| # --------------------------------------------------------------------------- | |
| deploy: | |
| name: Deploy to ${{ needs.build.outputs.target }} | |
| needs: [build, deploy-preflight] | |
| if: needs.build.outputs.deploy_to_n100 == 'true' && needs.deploy-preflight.outputs.deploy_ready == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| # prod environment 에 Required reviewers 를 걸면 수동 승인 게이트가 된다. | |
| environment: | |
| name: ${{ needs.build.outputs.target }} | |
| steps: | |
| - name: Pull & restart on N100 | |
| uses: appleboy/ssh-action@v1.0.3 | |
| with: | |
| host: ${{ secrets.N100_HOST }} | |
| username: ${{ secrets.N100_USER }} | |
| key: ${{ secrets.N100_SSH_KEY }} | |
| # 호스트의 deploy/ 디렉터리에서 git sync → image pull → compose up. | |
| # IMAGE_TAG 는 GHCR 이미지 태그, MURUN_ENV_FILE 은 .env.prod 고정 (N100=prod only). | |
| script: | | |
| set -e | |
| cd ${MURUN_DEPLOY_DIR:-~/murun-peterabcd/deploy} | |
| git -C .. fetch --depth=1 origin "${{ github.ref_name }}" | |
| git -C .. checkout -B "${{ github.ref_name }}" FETCH_HEAD | |
| export IMAGE_TAG="${{ needs.build.outputs.image_tag }}" | |
| export MURUN_ENV_FILE=".env.${{ needs.build.outputs.target }}" | |
| on_error() { | |
| echo "::group::docker compose ps" | |
| docker compose -p murun-${{ needs.build.outputs.target }} --env-file "$MURUN_ENV_FILE" ps || true | |
| echo "::endgroup::" | |
| echo "::group::app logs" | |
| docker compose -p murun-${{ needs.build.outputs.target }} --env-file "$MURUN_ENV_FILE" logs --tail=160 app || true | |
| echo "::endgroup::" | |
| echo "::group::caddy logs" | |
| docker compose -p murun-${{ needs.build.outputs.target }} --env-file "$MURUN_ENV_FILE" logs --tail=80 caddy || true | |
| echo "::endgroup::" | |
| } | |
| trap on_error ERR | |
| docker compose -p murun-${{ needs.build.outputs.target }} --env-file "$MURUN_ENV_FILE" pull | |
| docker compose -p murun-${{ needs.build.outputs.target }} --env-file "$MURUN_ENV_FILE" up -d --remove-orphans | |
| docker image prune -f |