기존 ec2
+ pm2
로 배포되있던Next.js
로 만든 프로젝트를 S3
+ CloudFront
로 변경하여 배포하는 작업을 맡았고 더불어 git-action
를 통한 CI/CD
까지 구축하게되었다.
Next.js
의 빌드는 React
의 빌드와 조금 다른면이 있어 S3
를 통한 정적 페이지 배포시에는 package.json
파일에 아래와 같이 추가해주었다. 또한 next.config.js
Image loader 부분에 이슈가 있어 아래와 같이 추가해주었다.
// package.json
"scripts": {
"deploy": "next build && next export"
}
// next.config.js
trailingSlash: true,
images: {
loader: 'akamai',
path: '/',
},
next build
의 경우 .next
라는 폴더에 애플리케이션에 빌드하지만 next export
의 경우 .out
폴더에 모든페이지를 정적 HTML 파일로 내보낸다 !
또한 next export
시 예를들어 /page/user/index.tsx
파일의 경우 /user.html
로 빌드되는데 위의 next.config.js
에 trailingSlash: true
를 설정하게 되면 /user/index.html
로 빌드되는 것을 볼 수 있다. (해당 설정 이유는 아래에서 다룰 예정)
아래의 설명에 AWS IAM 설정은 제외한다. (S3, Cloudfront, Route53, ACM 관련 정책 추가)
위와 같이 버킷 이름 입력 후, AWS 리전을 선택해 주고 버킷을 생성한다.
S3 버킷 선택 -> 속성에서 정적 웹 사이트 호스팅
관련 index.html
설정을 해준다.
또한 권한에서 퍼블릭 엑세스 차단
을 해제 후
아래와 같이 버킷 정책
을 설정해주어 S3 엑세스
를 퍼블릭
으로 설정해준다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::{{S3 버킷 이름}}/*"
}
]
}
CloudFront
배포 생성을 클릭 후 원본 도메인
은 위에서 생성한 S3 버킷
을 선택해준뒤 아래와 같이 설정해준다.
또한 Route 53
도메인 설정을 위하여 사용자 정의 SSL 인증서
를 선택해야하는데 인증서 요청
을 클릭 하여 ACM 인증서
를 요청하여 선택해줘야하는데, 인증서 요청 후 CloudFront
를 생성한 후
Route 53
에서 원하는 도메인에 대한 레코드
를 생성해준다. 이때, 별칭은 생성한 CloudFront
를 선택해 준다. (S3
, CloudFront
, Route 53
, ACM 인증서
이름은 모두 생성을 원하는 도메인명으로 !)
-> 생성 완료시 요청한 ACM 인증서가 적격
, 사용중
으로 변경됨. (시간은 걸릴 수 있음!)
이제 어느정도 배포 설정은 마무리 되었으니 git-actions 를 통한 CI/CD를 구축하여 원하는 git branch
에 push
혹은 merge
시에 자동으로 빌드
후 S3에 업데이트
하는 설정을 해볼려고한다.
먼저 .github/workflows
폴더를 생성 후 원하는 branch 이름
을 따서 main.yml
혹은 develop.yml
파일을 만들어 준다.
name: {{이름}}
on:
push:
branches: {{branch 이름}}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Git Checkout
uses: actions/checkout@v3
- name: Use Node.js version 14.x
uses: actions/setup-node@v3
with:
node-version: 14.x
cache: yarn
cache-dependency-path: yarn.lock
- name: yarn deploy
env:
NEXT_PUBLIC_API_URL: {{환경 변수 설정 부분}}
run: |
npm install -g yarn
yarn install --frozen-lockfile
yarn deploy
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy to S3
env:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
aws s3 rm s3://{{S3 버킷 이름}} --recursive
aws s3 cp --recursive --region ap-northeast-2 ./out s3://{{S3 버킷 이름}}
- name: Clear Cache to Cloudfront
env:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: aws cloudfront create-invalidation --distribution-id {{CloudFront ID}} --paths "/*"
secrets
관련 key
의 경우 git
레포지토리의 setting -> Security -> Secrets -> Actions
에서 미리 설정할 수 있다.
위의 yml파일
맨 아래의 name : Clear Cache to Cloudfront
의 경우 CloudFront
는 기본 캐시
설정 시간이 24시간으로 설정되어있어 배포시 즉시 적용이 되지 않으므로 캐시
를 무효화 해주는 부분의 작업이다.
이제 S3
, CloudFront
값 혹은 도메인 명
으로 접속시에 잘 배포된것을 확인할 수 있다.
하지만 하나의 문제점이 발견되었는데, 위에서 trailingSlash: true
을 설정해준덕에 /page/user/index.tsx
파일이 /user/index.html
로 잘 빌드되어 배포환경에서 /user
로 접속시 페이지가 잘 나타나는 것을 확인할 수 있다.
하지만 새로고침시에 /user/index.html
를 찾는것이 아닌 /user
를 찾게되어 403 오류
가 발생한다.
이에 먼저, 403 오류
시에 index.html
로 리다이렉션
설정을 아래와 같이 해주었다.
또한, 새로 고침시에 /user/index.html
을 찾을 수 있도록 CloudFront
에서 함수
를 하나 설정해 주었다.
// url-rewrite-single-page-apps
function handler(event) {
var request = event.request;
var uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
이제 CloudFront
에서 동작
에서 앞에서 생성한 함수
를 연결하여 동작 생성
을 해주면 이슈없는 배포 끝 ! 👍👍👍