serverless-next.js deploy

June 06, 2021

Next JS로 만든 웹 어플리케이션을 배포하는 방법은 다양합니다.

서버 인스턴스를 따로 올리고(ec2, lamda) 스태틱(Static) 한 파일을 s3에 저장해서 배포하는것이 가장 일반적인데, 최근 가장 힙(?)하게 사용되는 serverless next.js component를 사용한다면 많은 필요한 작업들을 아주~손쉽게 처리할 수 있습니다!

structure
serverless component를 설명하고 있는 그림

serverless component의 배포 과정이 어떻게 진행되는지 보여주는 그림입니다.
보는 그림과 같이 클라우드 프론트 설정과 함께 스태틱 파일은 자동으로 생성된 S3 버킷에 들어가게 되고, SSR, API 백엔드에 필요한 서버는 람다엣지에 배포됩니다.

그럼 현재 제가 진행하고 있는 사이드 프로젝트를 예시로 설정방법을 설명 드리겠습니다.

셋팅법

next.js 프로젝트에 serverless.yml 설정

# serverless.yml

myNextApplication:
  component: "@sls-next/serverless-component@{version_here}"
  #component: "@sls-next/serverless-component@1.19.0" -> 저는 1.19.0 버전을 사용합니다

AWS credentials 환경변수 설정

AWS를 사용하기 때문에 credentials을 설정해줘야 합니다.

AWS_ACCESS_KEY_ID=accesskey
AWS_SECRET_ACCESS_KEY=sshhh

로컬환경에서 배포를 하기 위해서는 위와 같이 AWS credential을 환경변수에 설정해줘야 하지만 보통은 github actions와 같은 ci tool을 사용하므로 저는 로컬에서 따로 설정하지 않았습니다.

github actions와 연동하는 법은 이후에 설명합니다.

배포 및 확인

npx serverless

몇 안되는 과정으로 next 빌드와 배포가 완료되었습니다

  1. S3 업로드 확인

    s3
    s3 버킷이 잘 생성 되었습니다.
  2. cloudfront 확인

    cloudfront
    cloudfront가 잘 생성 되었습니다.
  3. 람다엣지 확인

    lambda
    람다엣지도 잘 생성 되었습니다.
giphy
wow 이렇게 쉽게?

cloudfront가 임의로 제공하는 도메인으로 접속해서 캐쉬가 잘 동작하는지 확인해보겠습니다.

cache
히트다 히트
아주 깔끔하게 동작하네요!

Github Actions로 배포자동화 구축

action workflows 설정

기본적으로 배포 과정이 짧기 때문에 작성해야 할 yml 파일도 그렇게 복잡하지 않습니다 :D
신경써야 할 부분은 두가지 였습니다.

1. 프로덕션 환경변수 설정

Github Actions market place에는 workflows 설정에 필요한 여러가지 오픈소스를 제공하고 있습니다. SpicyPizza/create-envfile@v1 를 사용하면 깃헙 secrets 에 설정한 변수를 빌드에 필요한 환경변수 파일(*.env) 에 옮길 수 있습니다.

github_secrets
깃헙 셋팅에서 설정한 Repository secrets
name: Make envfile
uses: SpicyPizza/create-envfile@v1
with:
  envkey_NEXT_PUBLIC_DOMAIN_NAME: ${{ secrets.NEXT_PUBLIC_DOMAIN_NAME }}
  envkey_NEXT_PUBLIC_JAVASCRIPT_KEY: ${{ secrets.NEXT_PUBLIC_JAVASCRIPT_KEY }}
  envkey_NEXT_PUBLIC_REST_API_KEY: ${{ secrets.NEXT_PUBLIC_REST_API_KEY }}
  envkey_NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
  file_name: .env.production

create-envfile@v1을 사용하려면 envKey_를 변수 앞에 붙여줘야 하며 next 에서 제시하는 하는 네이밍(NEXT_PUBLIC_)대로 환경변수를 설정해 줍니다.

생성된 .env.production 파일

NEXT_PUBLIC_JAVASCRIPT_KEY=8d6b7ac...
NEXT_PUBLIC_REST_API_KEY=07f64dfd...
NEXT_PUBLIC_DOMAIN_NAME=https://d3egwu5gw26rxc.cloudfront.net/
NEXT_PUBLIC_API_URL=https://hushs-api.kscory.link/graphql

2. AWS credential 설정

AWS credential도 위와 같은 방법으로 aws-actions/configure-aws-credentials@v1을 사용할 수 있습니다.

name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
  aws-access-key-id: ${{ secrets.AWS_KEY }}
  aws-secret-access-key: ${{ secrets.AWS_SECRET }}
  aws-region: ap-northeast-2

최종:

name: CI
on:
  push:
    branches: [master] # 어떤 브랜치에서 trigger 할지 설정합니다.
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: borales/actions-yarn@v2.3.0
        with:
          cmd: install # will run `yarn install` command
      - name: Make envfile
        uses: SpicyPizza/create-envfile@v1
        with:
          envkey_NEXT_PUBLIC_DOMAIN_NAME: ${{ secrets.NEXT_PUBLIC_DOMAIN_NAME }}
          envkey_NEXT_PUBLIC_JAVASCRIPT_KEY: ${{ secrets.NEXT_PUBLIC_JAVASCRIPT_KEY }}
          envkey_NEXT_PUBLIC_REST_API_KEY: ${{ secrets.NEXT_PUBLIC_REST_API_KEY }}
          envkey_NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
          file_name: .env.production
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET }}
          aws-region: us-east-1
      - name: Deploy Next.js app
        run: npx serverless # 필요한 모듈을 설치하고 나서 serverless 명령어 실행

주의할 점

github actions를 사용해서 배포를 하게 되면 기존의 설정, 빌드 환경을 매번 다시 셋팅하기 때문에 배포 할 때마다 자동으로 이름이 생성된 s3 버킷, cloudfront distributionId, lambda function이 새로 만들어집니다.

이를 해결하기 위해서는 defaultLambda, bucketName 을 명시적으로 지정해주고 distributionId을 처음 생성된 ID로 지정해주면 됩니다.

# serverless.yml
myNextApplication:
  component: "@sls-next/serverless-component@1.19.0"
  inputs:
    name:
      defaultLambda: hushDefaultLamda # defaultLambda 이름을 지정해줍니다.
      imageLambda: hushImageLambda # image optimization을 위한 defaultimageLambda 이름을 지정해줍니다.
    bucketRegion: "ap-northeast-2"
    bucketName: "hush-static" # 내가 원하는 bucketName을 지정하면 자동으로 생성된 버킷 이름을 사용하지 않습니다.
    cloudfront:
      distributionId: "EFA4PDMIEXVIK" # serverless component가 자동으로 생성해준 id로 고정

참조

이전 - redux를 이용한 컴포넌트 렌더링 최적화