|
1 | | -name: Deploy Next.js to ECS |
| 1 | +name: Deploy frontend to S3 and CloudFront |
2 | 2 |
|
3 | 3 | on: |
4 | 4 | push: |
5 | | - branches: |
6 | | - - main |
7 | | - - develop |
| 5 | + branches: [main, develop] |
| 6 | + workflow_dispatch: |
| 7 | + |
| 8 | +concurrency: |
| 9 | + group: growit-frontend-${{ github.ref }} |
| 10 | + cancel-in-progress: true |
8 | 11 |
|
9 | 12 | env: |
10 | 13 | AWS_REGION: ap-northeast-2 |
11 | | - ECR_REPOSITORY: growit-fe |
| 14 | + S3_BUCKET: ${{ github.ref_name == 'main' && vars.PROD_S3_BUCKET || vars.DEV_S3_BUCKET }} |
| 15 | + CLOUDFRONT_DISTRIBUTION_ID: ${{ github.ref_name == 'main' && vars.PROD_CLOUDFRONT_DISTRIBUTION_ID || vars.DEV_CLOUDFRONT_DISTRIBUTION_ID }} |
| 16 | + DEPLOY_API_URL: ${{ github.ref_name == 'main' && vars.PROD_API_URL || vars.DEV_API_URL }} |
| 17 | + DEPLOY_REDIRECT_URL: ${{ github.ref_name == 'main' && vars.PROD_REDIRECT_URL || vars.DEV_REDIRECT_URL }} |
| 18 | + DEPLOY_FRONTEND_URL: ${{ github.ref_name == 'main' && vars.PROD_FRONTEND_URL || vars.DEV_FRONTEND_URL }} |
12 | 19 |
|
13 | 20 | jobs: |
14 | | - # 1. 환경 결정 |
15 | | - setup: |
16 | | - name: Determine Environment |
| 21 | + build-and-deploy: |
17 | 22 | runs-on: ubuntu-latest |
18 | | - outputs: |
19 | | - environment: ${{ steps.set-env.outputs.environment }} |
20 | | - image_tag: ${{ steps.set-env.outputs.image_tag }} |
21 | | - steps: |
22 | | - - name: Set environment based on branch |
23 | | - id: set-env |
24 | | - run: | |
25 | | - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then |
26 | | - echo "environment=production" >> $GITHUB_OUTPUT |
27 | | - echo "image_tag=prod-${{ github.sha }}" >> $GITHUB_OUTPUT |
28 | | - else |
29 | | - echo "environment=development" >> $GITHUB_OUTPUT |
30 | | - echo "image_tag=dev-${{ github.sha }}" >> $GITHUB_OUTPUT |
31 | | - fi |
32 | | -
|
33 | | - # 2. Docker 이미지 빌드 및 ECR 푸시 |
34 | | - build-and-push: |
35 | | - name: Build and Push Docker Image |
36 | | - runs-on: ubuntu-latest |
37 | | - needs: setup |
38 | | - environment: ${{ needs.setup.outputs.environment }} |
39 | | - outputs: |
40 | | - image: ${{ steps.build-image.outputs.image }} |
| 23 | + permissions: |
| 24 | + contents: read |
| 25 | + id-token: write |
41 | 26 | steps: |
42 | 27 | - name: Checkout |
43 | 28 | uses: actions/checkout@v4 |
| 29 | + - name: Setup Node.js |
| 30 | + uses: actions/setup-node@v4 |
44 | 31 | with: |
45 | | - ref: ${{ github.ref }} |
46 | | - |
47 | | - - name: Configure AWS credentials |
48 | | - uses: aws-actions/configure-aws-credentials@v4 |
49 | | - with: |
50 | | - aws-region: ${{ env.AWS_REGION }} |
51 | | - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} |
52 | | - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} |
53 | | - |
54 | | - - name: Login to Amazon ECR |
55 | | - id: login-ecr |
56 | | - uses: aws-actions/amazon-ecr-login@v2 |
57 | | - |
58 | | - - name: Create .env file |
59 | | - run: | |
60 | | - cat <<EOF > .env |
61 | | - NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }} |
62 | | - NEXT_PUBLIC_REDIRECT_URL=${{ vars.NEXT_PUBLIC_REDIRECT_URL }} |
63 | | - NEXT_PUBLIC_CLOUDFRONT_VIDEO_URL=${{ vars.NEXT_PUBLIC_CLOUDFRONT_VIDEO_URL }} |
64 | | - EOF |
65 | | -
|
66 | | - - name: Build, tag, and push image |
67 | | - id: build-image |
| 32 | + node-version: '20' |
| 33 | + cache: yarn |
| 34 | + - name: Install dependencies |
| 35 | + run: yarn install --frozen-lockfile |
| 36 | + - name: Build static site |
68 | 37 | env: |
69 | | - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} |
70 | | - IMAGE_TAG: ${{ needs.setup.outputs.image_tag }} |
71 | | - run: | |
72 | | - IMAGE="$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$IMAGE_TAG" |
73 | | - echo "Building $IMAGE for ${{ needs.setup.outputs.environment }}" |
74 | | - docker build -t "$IMAGE" . |
75 | | - docker push "$IMAGE" |
76 | | - echo "image=$IMAGE" >> $GITHUB_OUTPUT |
77 | | -
|
78 | | - # 3. ECS 배포 |
79 | | - deploy: |
80 | | - name: Deploy to ECS (${{ needs.setup.outputs.environment }}) |
81 | | - runs-on: ubuntu-latest |
82 | | - needs: [setup, build-and-push] |
83 | | - environment: ${{ needs.setup.outputs.environment }} |
84 | | - steps: |
85 | | - - name: Checkout |
86 | | - uses: actions/checkout@v4 |
87 | | - with: |
88 | | - ref: ${{ github.ref }} |
89 | | - |
| 38 | + NEXT_PUBLIC_API_URL: ${{ env.DEPLOY_API_URL }} |
| 39 | + NEXT_PUBLIC_REDIRECT_URL: ${{ env.DEPLOY_REDIRECT_URL }} |
| 40 | + NEXT_PUBLIC_CLOUDFRONT_VIDEO_URL: ${{ vars.NEXT_PUBLIC_CLOUDFRONT_VIDEO_URL }} |
| 41 | + run: yarn build |
90 | 42 | - name: Configure AWS credentials |
91 | 43 | uses: aws-actions/configure-aws-credentials@v4 |
92 | 44 | with: |
| 45 | + role-to-assume: arn:aws:iam::009075573241:role/growit-github-frontend-deploy |
93 | 46 | aws-region: ${{ env.AWS_REGION }} |
94 | | - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} |
95 | | - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} |
96 | | - |
97 | | - - name: Download task definition |
| 47 | + - name: Upload immutable assets |
98 | 48 | run: | |
99 | | - aws ecs describe-task-definition \ |
100 | | - --task-definition "${{ vars.ECS_TASK_DEFINITION }}" \ |
101 | | - --query taskDefinition > task-definition.json |
102 | | -
|
103 | | - - name: Render task definition |
104 | | - id: task-def |
105 | | - uses: aws-actions/amazon-ecs-render-task-definition@v1 |
106 | | - with: |
107 | | - task-definition: task-definition.json |
108 | | - container-name: ${{ vars.ECS_CONTAINER_NAME }} |
109 | | - image: ${{ needs.build-and-push.outputs.image }} |
110 | | - |
111 | | - - name: Deploy to ECS |
112 | | - uses: aws-actions/amazon-ecs-deploy-task-definition@v2 |
113 | | - with: |
114 | | - task-definition: ${{ steps.task-def.outputs.task-definition }} |
115 | | - service: ${{ vars.ECS_SERVICE }} |
116 | | - cluster: growit-fe-cluster |
117 | | - wait-for-service-stability: false |
118 | | - |
119 | | - - name: Deployment Summary |
| 49 | + aws s3 sync out/_next/ "s3://$S3_BUCKET/_next/" --delete \ |
| 50 | + --cache-control "public,max-age=31536000,immutable" |
| 51 | + - name: Upload pages |
120 | 52 | run: | |
121 | | - echo "## 🚀 배포 완료" >> $GITHUB_STEP_SUMMARY |
122 | | - echo "" >> $GITHUB_STEP_SUMMARY |
123 | | - echo "| 항목 | 값 |" >> $GITHUB_STEP_SUMMARY |
124 | | - echo "|------|-----|" >> $GITHUB_STEP_SUMMARY |
125 | | - echo "| **환경** | ${{ needs.setup.outputs.environment }} |" >> $GITHUB_STEP_SUMMARY |
126 | | - echo "| **브랜치** | ${{ github.ref_name }} |" >> $GITHUB_STEP_SUMMARY |
127 | | - echo "| **커밋** | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY |
128 | | - echo "| **이미지** | ${{ needs.build-and-push.outputs.image }} |" >> $GITHUB_STEP_SUMMARY |
| 53 | + aws s3 sync out/ "s3://$S3_BUCKET/" --delete --exclude "_next/*" \ |
| 54 | + --cache-control "public,max-age=0,must-revalidate" |
| 55 | + - name: Invalidate CloudFront |
| 56 | + run: aws cloudfront create-invalidation --distribution-id "$CLOUDFRONT_DISTRIBUTION_ID" --paths "/*" |
| 57 | + - name: Verify frontend |
| 58 | + run: curl --fail --retry 5 --retry-delay 10 "$DEPLOY_FRONTEND_URL/login/" |
0 commit comments