Deploy #2
Workflow file for this run
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 | |
| on: | |
| push: | |
| branches: [dev, main] | |
| workflow_dispatch: | |
| inputs: | |
| target: | |
| description: "배포 대상 (staging | prod)" | |
| required: true | |
| default: "staging" | |
| type: choice | |
| options: [staging, prod] | |
| # 동시 배포 금지. 같은 대상에 새 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 푸시 | |
| # --------------------------------------------------------------------------- | |
| 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 }} | |
| 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 }}" | |
| elif [ "${{ github.ref_name }}" = "main" ]; then | |
| target="prod" | |
| else | |
| target="staging" | |
| 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 "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) SSH 로 N100 접속 → docker compose pull && up -d | |
| # --------------------------------------------------------------------------- | |
| deploy: | |
| name: Deploy to ${{ needs.build.outputs.target }} | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| # prod 는 환경(environment) 보호로 수동 승인 가능 | |
| environment: | |
| name: ${{ needs.build.outputs.target }} | |
| steps: | |
| - name: Sanity check secrets | |
| run: | | |
| missing="" | |
| for v in N100_HOST N100_USER N100_SSH_KEY; do | |
| eval val="\$$v" | |
| if [ -z "$val" ]; then missing="$missing $v"; fi | |
| done | |
| if [ -n "$missing" ]; then | |
| echo "::error::Missing required secrets:$missing" | |
| echo "GitHub repo Settings → Secrets and variables → Actions 에서 등록하세요." | |
| exit 1 | |
| fi | |
| env: | |
| N100_HOST: ${{ secrets.N100_HOST }} | |
| N100_USER: ${{ secrets.N100_USER }} | |
| N100_SSH_KEY: ${{ secrets.N100_SSH_KEY }} | |
| - 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/ 디렉터리에서 pull → up. | |
| # IMAGE_TAG selects the pushed GHCR image; MURUN_ENV_FILE selects .env.staging/.env.prod. | |
| script: | | |
| set -e | |
| cd ${MURUN_DEPLOY_DIR:-~/murun-peterabcd/deploy} | |
| export IMAGE_TAG="${{ needs.build.outputs.image_tag }}" | |
| export MURUN_ENV_FILE=".env.${{ needs.build.outputs.target }}" | |
| 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 |