AWS CodePipeline과 Amazon s3를 통한 정적 웹사이트 CI/CD 구축(Next.js)

gon Kim
elecle
Published in
23 min readFeb 25, 2021

Adding CI/CD to your static website with AWS CodePipeline and Amazon S3(Next.js) (English Version Below)

Next.js는 손쉽게 서버사이드렌더링(SSR) 프로젝트를 구성할 수 있는 좋은 React 프레임워크입니다. 뿐만 아니라, 간단히 next export 명령어를 통해 쉽게 정적(static) 웹사이트를 생성할 수 있는 훌륭한 프레임워크이기도 합니다. Next.js를 통해 정적인 웹페이지를 생성하고, AWS CodePipeline과 Amazon S3을 통해 배포하는 간단한 CI/CD 파이프라인을 구축할 수 있습니다.

이 글을 통해..

  • GitHub 코드 변경 시 CodePipeline에 지정된 단계를 통해 Github Repository 코드를 자동으로 빌드하고 배포하는 CI/CD 파이프라인을 구축할 수 있습니다.
  • CodePipeline을 통해 Github Repository의 코드를 CodeBuild를 통해 빌드 할 수 있도록 설정할 수 있고, 이 때, buildspec.yml을 통해 지정된 빌드 명령어가 실행되며, 빌드 결과물은 output artifact로 지정하여 다음 프로세스로 전달시킵니다.
  • CodePipeline을 통해 빌드 결과물을 S3에 업로드하도록 설정할 수 있습니다.
  • S3를 정적인 웹사이트 호스팅을 위한 버킷으로 사용할 수 있습니다.

먼저 읽어보세요

  1. Amazon S3를 이용한 정적 페이지 호스팅
  2. AWS CodePipeline을 통한 웹사이트 배포 자동화
  • 이 글에서는 AWS Guide에서 S3를 통한 정적 웹사이트 배포와 CodePipeline을 통해 배포 자동화 과정이 설명되어 있지만, 빌드와 세부적인 설정, Next.js를 프로젝트에 특정하여 진행할 수 있는 통합적인 프로세스를 서술하고자 합니다.

Warm up

Next.js를 통해 정적 호스팅을 위한 static 파일을 생성해보세요.

// package.json
{
...,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export -o dist",
},
...
}

npm run build; npm run export;

  • /dist 디렉토리에 정적 파일을 생성하도록 지정하였습니다.

S3 버킷을 생성하세요

  • “속성” 탭 하단에 “정적 웹 사이트 호스팅” 설정을 활성화하세요. 인덱스 문서를 지정하세요.
  • “권한” 탭에서 퍼블릭 액세스 차단을 비활성화하여 외부에서 S3 버킷 주소를 통해 페이지에 접근할 수 있도록 하세요.

S3 버킷에 생성된 모든 static 파일을 업로드하세요

  • 모든 파일을 S3 버킷 기본 경로상에 업로드합니다.

S3 버킷 상의 파일이 업로드 되었는지 확인하세요

  • <s3-bucket-name>.s3.<aws-region>.amazonaws.com/index.html에서 Next.js에서 생성된 초기 화면을 확인할 수 있습니다.
  • 정적 웹 사이트 주소로 생성된 <s3-bucket-name>.s3-website.<aws-region>.amazonaws.com/ 을 통해 접근할 경우 파일 경로를 지정하지 않아도 해당 경로의 index.html 파일을 보여줍니다.

CodePipeline을 통한 CI/CD 구축

CodePipeline 콘솔에서 파이프라인 생성을 시작하세요. (좌측 Step에 따라 설정할 수 있는 내용입니다.)

Step 1. 파이프라인 설정 선택

  • 적당한 파이프라인 이름을 선택하고, 기존 서비스 역할이 없다면 새 서비스 역할을 생성하면 됩니다.

Step 2. 소스 스테이지 추가

  • 소스 공급자로 GitHub(버전 2)를 선택합니다(2021년 2월 25일 현재)
  • AWS CodeCommit나 다른 공급자를 선택해도 좋지만, 여기에서는 GitHub을 통해 코드를 관리하여 웹페이지를 배포하는 프로세스를 목적으로 합니다.
  • GitHub에 연결하고, PipeLine이 트리거 될 희망하는 리포지토리와 브랜치 이름을 선택합니다.

Step 3. 빌드 스테이지 추가(추후 설정 가능)

  • AWS CodeBuild를 선택하고 새로운 프로젝트를 생성합니다.
  • 프로젝트 이름 및 환경을 설정하고 기존 서비스 역할이 없다면 새 서비스 역할을 생성합니다.
  • Buildspec의 경우 buildspec 파일을 사용하는 것으로 하겠습니다.
  • Next.js 프로젝트 최상단에 buildspec.yml 파일을 다음과 같이 생성할 수 있습니다.
# buildspec.ymlversion: 0.1 # 임의의 버전 이름phases:
install:
commands:
- npm install
build:
commands:
- npm run build
- npm run export
# npm 명령어는 정적 파일 생성을 위해 package.json에 작성한 scripts에 맞게 작성합니다.
artifacts: # CodeBuild의 output artifcats를 지정합니다.
files: - '**/*'
base-directory: 'dist' # dist 디렉토리의 모든 파일이 해당됩니다.

Artifact 란?

CodePipeline 상의 설정에서 Artifact를 지정하게 됩니다. Artifact라는 단어가 와닿지 않아 이해하기 다소 생소했는데, 쉽게 말해 각 단계에서 사용하는 입력물과 결과물에 해당하는 개념으로 보면 문제가 없습니다.

buildspec.yml 에서는 빌드 단계의 output artifacts를 설정해야 다음 단계에서 적절한 파일들이 S3으로 배포되도록 할 수 있고, 이 부분에서 artifact개념을 확실히 이해하는 것이 필요합니다.

예를 들어, 본 정적 웹사이트 배포에서는

  1. GitHub Repository 상의 Code가 CodePipeline 상 첫번째 단계 Source의 output artifact가 됩니다. 이것을 SourceArtifact라고 지정하여 다른 단계에서 input으로 사용할 수 있습니다.
  2. CodePipeline 상 두번째 단계 Build에서는 SourceArtifact를 input으로 하여 CodeBuild를 통해 빌드를 수행합니다. SourceArtifact는 Github 프로젝트 경로상의 파일 그 자체가 되고, 프로젝트 코드에서 같은 경로상의 dist 디렉토리에 빌드 결과물이 생성되도록 지정해놓았습니다(package.json 상 npm run export 명령어). 방금 작성한 buildspec.yml을 통해 이 단계의 output artifact를 dist 디렉토리의 모든 파일로 사용하게 됩니다.
  3. 이어서 설명할 세번째 배포 단계는 빌드 단계의 output artifact인 dist 디렉토리의 모든 파일(Warm-up 단계에서 업로드했던 바로 그 파일이죠)을 input artifact로 s3에 업로드 하는 단계가 됩니다.
  4. 이전 단계에서의 결과물을 특정한 이름의 artifact로 지정해놓기 때문에(SourceArtifact 등) 바로 다음 단계 뿐만 아니라 Pipeline 상의 단계를 뛰어넘은 다른 단계에서도 해당 결과물을 input으로 사용할 수 있게 됩니다.
  • Artifact에 대한 자세한 설명은 여기를 참고하세요.

Step 4. 배포 스테이지 추가

  • 배포 공급자로 Amazon S3을 선택합니다.
  • Warm-up에서 만들어놓았던 S3 버킷을 설정하고, 배포 경로는 “배포하기 전에 파일 압축 풀기”를 선택하고 배포 경로를 비워서 기본 경로에 파일이 업로드 될 수 있도록 합니다.

Step 5. 검토 후 생성

  • 설정 내용을 검토하여 생성을 완성하면 파이프라인이 실행됩니다.

웹페이지 확인 및 CI/CD 테스트

<s3-bucket-name>.s3-website.<aws-region>.amazonaws.com/ 에서 업로드된 정적 파일이 호스팅되고 있는 것을 확인할 수 있습니다.

  • Git 프로젝트상에서 코드를 변경하여 설정한 브랜치로 커밋하고 푸쉬하면 CodePipeline이 실행되어 진행 상황을 확인할 수 있고, 단계별 진행 상황을 확인할 수 있습니다.

Troubleshootings

IAM role

  • CodePipeline, CodeDeploy 등 매 단계에서 적절한 권한 부여가 필요합니다. 직접 권한을 부여하거나 권한 관리자에게 단계 실행시 발생하는 권한을 부여받아 진행하세요

CodePipeline Artifacts

  • 파이프라인 구축 후 S3에 생성된 파일이 배포하고자 하는 정적 파일과 다르다면, CodePipeline 설정에서 Artifacts가 올바르게 지정되고 있는지를 확인하세요.

buildspec.yml in CodeBuild

  • CodeBuild에서 사용될 buildspec.yml을 적절하게 설정해주세요. 로컬 환경에서 배포에 사용되는 명령어를 build 내 단계에 맞게 지정합니다.
  • 올바른 artifacts를 설정하여 S3에 배포되는 웹사이트 호스팅에 필요한 파일들이 정상적으로 나올 수 있도록 해주세요.

Amazon S3에서의 경로 접근 문제

  • S3 호스팅 주소와 정적 웹 사이트 생성을 위한 호스팅 주소는 다릅니다. S3 주소를 통해서는 설정된 키 별 파일 경로로만 접근이 가능하여 업로드한 파일 자체의 이름이 url이 됩니다.
  • 예를 들어, /account/setting.html로 업로드된 파일은 /account/setting으로 접근할 수 없으며, 해당 주소로 접근하게 하기 위해서는 /account/setting.html 파일 이름을 /account/setting으로 변경해야 합니다.
  • 그러나 정적 웹사이트 생성 설정을 활성화 하여 생성된 s3-website주소를 활용하면 각 파일에 대한 설정 없이 /account/setting으로 해당 페이지에 접근할 수 있게 됩니다.
  • 이는 CloudFront를 통해 사이트를 배포할 때에 간과하기 쉬운 문제로, 반드시 s3-website 주소를 활용하여야 번거로운 설정 없이 적절한 url path로 페이지에 접근할 수 있습니다.

추가적으로

  • CI/CD가 구축된 정적 s3-website 는 CloudFront로 연결하여 조금 더 용이하게 관리할 수 있을 것입니다.
  • CodePipeline에 알림을 설정하여 배포의 각 단계 혹은 파이프라인 과정의 실행과 실패, 성공 시 Slack 등으로 알람을 받을 수 있습니다.

마지막으로

  • Amazon 공식 문서를 통해 CodePipeline 구축과 s3를 통한 정적 웹사이트 배포에 대한 전반적이고 상세한 내용을 확인할 수 있었지만, 주로 Troubleshooting에 해당하는 부분에서 시간소요가 많이 발생했습니다.
  • 그럼에도 AWS 서비스 상에서 통합 배포 환경을 구축하는 과정 자체는 매우 쉽고 직관적으로 초기 단계의 프로젝트에서도 파이프라인을 구축하는 것이 Why Not?이라는 생각이 듭니다. AWS CodePipeline을 통해 번거로운 배포를 손쉽게 자동화해보세요!

English Version Below

Adding CI/CD to your static website with AWS CodePipeline and Amazon S3(Next.js)

Next.js is a “good-enough” React framework for Server Side Rendering structure. The framework is also an easy static site generator with next export command. By generating static website via Next.js, you can easily deploy your project on AWS s3 with AWS CodePipeline

Through this article…

  • You can build a CI/CD pipeline that automatically builds and deploys your source code following steps of AWS CodePipeline.
  • You can set your source code from GitHub Repository to build through AWS CodeBuild in CodePipeline. You can set build command in buildspec.yml file and the build result is transferred to the next step as an output artifact.
  • You can upload the build output via CodePipeline.
  • You can use S3 for static website hosting bucket.

Prerequisites

  1. Hosting a static website using Amazon S3
  2. Automate static website deployment to Amazon S3
  • These AWS guide articles explains static website deployment through S3 and static website deployment automation, through this article describes integrated progress with more specific configurations in CodePipeline process, and with more specific aspects with Next.js static site generationWarm up

Warm up

Create Static HTML files for static deploy with Next.js

// package.json
{
...,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export -o dist",
},
...
}

npm run build; npm run export;

  • the target directory is specified as /dist for output files

Create S3 bucket

  • Activate the “Static website hosting” setting under the “Properties” tab. Specify index.html for root document path.
  • Disable “Restrict Public Access” in the “Permissions” tab to allow external access to the page to S3.

Upload all static files to S3 bucket

  • Upload all files from dist directory to the default path of your S3 bucket.

Check if all files are uploaded to the s3 bucket

  • html files can be accessed from s3 path and directory path
  • check your page by accessing to “<s3-bucket-name>.s3.<aws-region>.amazonaws.com/index.html”
  • When accessing through <s3-bucket-name>.s3-website.<aws-region>.amazonaws.com/ (which is created by enabling static website hoosting), you can access with normal url address(not by file path)

Building CI/CD through CodePipeline

Create your pipeline in CodePipeline console. Below are the steps on the left side of console.

Step 1. Select Pipeline Settings

  • Enter any pipeline name, and create a new role if there is no existing service role.

Step 2. Add Source Stage

  • Select GitHub(version 2) as the source provicer(as of February 25, 2021)
  • You can choose AWS CodeCommit or another source provicer, but this article aims to describe the process by managing code in GitHub
  • After connecting your GitHub, choose desired repository and branch name where the Pipeline can be triggered.

Step 3. Add build stage(this step can be set later)

  • Select AWS CodeBuild and create a new CodeBuild Project
  • Enter project name and configurations and create a new role if there is no existing service role.
  • Select “use buildspec.yml file” on the leftside.
  • You can create a buildspec.yml file at the top directory of your Next.js project like this:
# buildspec.ymlversion: 0.1 # arbitrary version name for managementphases:
install:
commands:
- npm install
build:
commands:
- npm run build
- npm run export
# follow npm command declared in package.json file.
artifacts: # Specifies the output artifacts of CodeBuild stage.
files: - '**/*'
base-directory: 'dist' # by setting base-directory and files like this, all files in the dist directory become output artifacts.

What is Artifact?

Artifacts are specified between stages of CodePipeline. Artifact can be a bit unfamiliar with the word at first, but in simple terms, artifact is the concept of referring to the inputs and outputs used in each step.

It is important to properly set the output artifacts of CodeBuild stage in the buildspec.yml file, so that the appropriate files are transferred to S3, thus basic understanding of the artifact concept is necessary.

  1. In this article, the code on GitHub Repository becomes the output artifact of first step(Source) on CodePipeline. You can call it SourceArtifact and use as an input in another step.
  2. In the second stage(Build Stage), SourceArtifact becomes the input of CodeBuild process. SourceArtifact includes files from the GitHub Project default path, and the source code is built and the output is created in the /dist directory(check package.json above with npm run export command). The buildspec.yml file above specifies that all files in dist directory are output artifacts of this stage.
  3. The third step, Deploy, uses these files of dist directory as an input artifact, and the files are uploaded to S3.
  4. Since the output artifacts of each step can be specified with names(Sourceartifact, etc.), output artifacts can be used as an input in not only the very next step, but also in other steps of the pipeline.
  • You can read more about CodePipeline Artifact concept here.

Step4. Add Deployment Stage

  • Select Amazon S3 as Deployment Provider.
  • Select S3 bucket, and check “Unzip files before Deployment” so that the files can be uploaded to the default path.

Step5. Review and Create

  • Review configurations and complete the creation, then let the pipeline run.

Check your Webpage and test CI/CD

The hosted static files can be checked at <s3-bucket-name>.s3-website.<aws-region>.amazonaws.com/.

  • If you change your code in the Git project, commit to the branch you set, and push, CodePipeline is triggered and you can check the pipeline progress of each stage.

Troubleshootings

IAM role

  • If you change your code in the Git project, commit to the branch you set, and push, CodePipeline is triggered and you can check the pipeline progress of each stage.

CodePipeline Artifacts

  • If the files created in S3 after Build stage are different from the files you want to deploy, check whether Artifacts is correctly specified in the CodePipeline settings.

buildspec.yml in CodeBuild

  • Please set the appropriate buildspec.yml. Specify the exact commands you use in deploying in your local environment for the steps in build.
  • Set the correct artifacts in the file so that the files required for hosting the website can be output normally(to dist directory)

Path Access Problems in Amazon S3

  • The S3 hosting address and the static website hosting address are different. Via S3 hosting address, you can access to the path by file name key.
  • For example, if a file is uploaded as /account/setting.html , you cannot access from /account/setting. You must change your file name to /account/setting for the path.
  • However, by enabling static website deployment option, you can access /account/setting(even if the file is /account/setting.html) via s3-website address.
  • Using s3-website address since this path problem can easily occur, and using s3-websidte address prevents you from being frustrated from complicated configurations.

Additionally…

  • Static s3-websites with CI/CD can be managed more easily by connecting to CloudFront.
  • By setting notifications in CodePipeline, you can receive alarms from each stage of pipeline process via e.g. slack.(with AWS Chatbot)

Finally…

  • The Official Amazon documentation provides overall details of constructing CodePipeline, and guidelines to deploy a static website through s3. However, there are parts where troubleshooting takes much time, and the official documentation doesn’t help.
  • Nevertheless, the process of building an integrated deployment environment on AWS services is quite easy and intuitive, and thus we think “Why Not?” build a pipeline even in an early stage of your development. Easily automate deployment process with AWS CodePipeline!

--

--