최근 피우다 프로젝트라는 공모전에 다섯 명으로 팀을 꾸려 참가하였다. 개발 경력이 가장 길었기에 PM이자 팀장 포지션으로 다른 개발자들을 서포트하는 포지션으로 프로젝트에 임하게 되었다.
AWS를 통해 프론트엔드와 백엔드를 배포하는 CI/CD를 전체적으로 구성하였는데, 전체적인 아키텍처는 위와 같았다. freetier를 사용하는 수준에서 처리할 수 있었고, 수많은 AWS의 서비스를 사용함으로써 AWS 아키텍처의 기본기를 제대로 다뤄보았다고 생각했다.
이번 포스팅은 프론트엔드편과 백엔드편으로 나뉘어 배포하는 과정을 나타낸다. 해당 과정에 대해서 다시 한번 블로그에 복기함으로써 어떤 식으로 아키텍처를 구성했는지 리마인드함과 동시에 다른 개발자들도 참고할 수 있게 글을 작성한다.
이번 포스팅에서 다룰 전반적인 구조는 위와 같이 구성될 것이다.
본론
먼저 준비물은 다음과 같다.
- 도메인 네임 : 필자는 가비아에서 구매
- AWS Freetier : 굳이 쓰지 않아도 되지만, 본 포스팅은 Freetier 기반을 상정하고 쓰였음
위 준비물이 모두 준비되었다면, 배포를 진행해보자.
프론트엔드 배포 이론
먼저, 프론트엔드의 배포는 어떻게 이루어지는가? 그것에 대해서 근본적으로 생각해보자. 이 부분에 대해서 잘 아는 사람이라면 넘어가도 괜찮은 페이즈다.
개발자라면 프론트엔드 페이지는 주로 React를 써서 개발한다는 사실을 알 것이다. React는 어떻게 파일들을 제공하는 것일까? 간단하게 CLI를 통해서 프론트엔드 배포가 어떻게 이루어지는지 확인해 보자. npm이 깔려있어야 할 것이다. 먼저 다음의 명령어를 통해 react init으로 리액트 프로젝트를 실행한다.
# create-react-app을 전역적으로 설치 ( global )
npm install -g create-react-app
# my-app이라는 이름의 프로젝트 생성
npx create-react-app my-app
위 명령어를 치면 약간의 로딩과 함께 리액트 프로젝트가 세팅된다. 그 후 cd my-app 명령어를 통해 해당 프로젝트 디렉터리에 들어가서 어떤 디렉토리가 있는 지 확인해 보면 아래와 같다.
여기서 npm start를 통해서 웹앱을 실행시킬 수 있지만, 그것은 개발환경을 위해서 실행하는 것이다. 배포를 하기 위해서는 정적 콘텐츠를 제공해야 한다.
npm run build
따라서 위의 명령어를 입력하고, 다시 현재 디렉토리에 대해서 확인해보면 build라는 파일이 생긴 것을 알 수 있고, 안에 있는 파일들을 확인해보면 들여 쓰기나 띄어쓰기가 없어진 압축된 정적 콘텐츠들이 생성된다. 이러한 html + css + js를 서빙해주기만 하면 프론트엔드의 배포는 끝난다. 이를 배포하기 위해서는 nginx, apache HTTP Server 등을 통해서 내 컴퓨터의 80번 포트로 접속한 경우 해당 정적 콘텐츠를 뿌려주는 방식이다.
이제 이러한 배포 과정을 AWS와 github actions를 사용해서 자동화해 보자.
IAM 생성 그리고 S3 버킷
AWS에서 정적 콘텐츠의 저장을 담당해 주는 서비스는 S3 bucket이다. 그리고 해당 서비스를 배포하기 위해 IAM(Identity and Access Management)이라는 것을 생성하여 추후에 github actions에 사용할 것이기 때문에 두 가지 서비스를 만들어준다. 가장 먼저 IAM을 만들어 보자. IAM이 필요한 이유는 아래와 같이 github actions에서 AWS의 리소스를 요청할 때, credential을 통해서 접근해야 한다. 그렇기 때문에 IAM을 생성하고, IAM을 통해 ACCESS_KEY와 SECRET_ACCESS_KEY를 저장해 둔다!
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
Amazon IAM
이제 IAM 콘솔에 들어가서 사용자를 만들어보자. 아래와 같이 적당한 이름을 통해 만들어본다. 이름은 frontend-deploy, 백엔드 배포는 추후 backend-deploy로 할 예정이다.
그 후 권한 설정에서 직접 정책 연결 - AmazonS3FullAccess를 연결한다.
사용자를 생성하고 나면 IAM에 해당 사용자가 있는 것을 확인할 수 있다. 이제 이를 통해서 키를 발급해야 하기 때문에 해당 사용자를 클릭하자
위 페이지에서 frontend-deploy 사용자를 클릭하자.
그 후 액세스 키 만들기를 눌러, 키를 만들어 준다.
위 페이지에서 적당한 것을 클릭하고 넘어가서 생성하면 액세스 키와 시크릿 액세스 키를 받을 수 있다.
여기까지 왔다면 IAM은 끝났다. 다음과 같은 몇 가지들을 저장하고 나서 S3로 넘어가자.
- 액세스 키
- 비밀 액세스 키
Amazon S3
AWS console에서 버킷을 만든다.
적당한 이름과 함께 버킷을 만들어보자. 설정해줘야 하는 부분만 사진으로써 나타낸다.
퍼블릭 액세스 차단 설정을 해제한다. 나머지는 건드리지 않고 버킷을 생성한다.
그 후 bucket에 두 가지 설정을 해줘야 한다. 속성과 정책이다. 버킷을 클릭하고 속성 탭에 들어가 스크롤을 쭉 내려보면 다음과 같은 섹션을 확인할 수 있는데 활성화해 준다.
편집 버튼을 눌러 위와 같이 설정한 후 설정을 마친다.
다음으로는 권한 탭에서 버킷 정책을 설정해야 한다.
버킷 정책은 아래와 같이 입력한다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::tistory-test/*"
}
]
}
S3에 올라간 모든 정적 콘텐츠들은 모든 사용자가 확인할 수 있어야 하기 때문에 이렇게 구성하면 된다. 이제 다음 페이즈로 넘어가서 동적 콘텐츠를 사용자들이 확인할 수 있게 하자
CloudFront ( CDN )
S3 버킷을 서울 리전에 만든 후, 해외에 있는 사용자들이 정적 콘텐츠를 요청하게 되면 트래픽이 해외로 나가게 되어 웹페이지를 꽤나 늦게 받아보게 된다. 이러한 S3의 리소스를 CloudFront를 통해서 배포하면 손쉽게 전 세계의 사용자들을 대상으로 빠르게 웹사이트를 서빙할 수 있으며, 캐싱 등의 기능을 지원하기 때문에 S3와 CloudFront 조합은 굉장히 좋다.
먼저 CloudFront를 만들어보자. AWS의 해당 서비스 콘솔에 접근하여 생성 버튼을 눌러준다.
위와 같이 Origin domain을 눌러 S3 버킷을 지정해 줄 수 있는데, 클릭 후 웹 엔드포인트로 설정을 눌러 80번 포트로 데이터를 서빙할 수 있도록 해준다.
그 후 일단은 보안 보호 비활성화를 눌러준다. AWS WAF나 Shield와 같은 보안과 관련된 기능들을 추가할 수 있으나, 비용이 발생할 수 있는 부분이기 때문에 원하는 설정을 따르면 된다. 필자는 둘 다 비활성화로 했다. 마지막으로는 설정의 가격 분류인데, CloudFront는 전 세계에 216개의 엣지 로케이션이 있다. 사용자가 동적 컨텐츠를 요청하면 가장 가까운 엣지 로케이션에 캐시된 데이터를 가져오는데, 위에서부터 순서대로 216, 100, 200개의 엣지 로케이션을 쓰겠다는 의미가 된다. 엣지 로케이션이 많을수록 비용이 더 나가는데, 맨 밑의 옵션을 선택하여 생성해 준다.
그 후 해당 배포 도메인 이름의 CDN url로 접속하면 페이지를 확인할 수 있다. 이제 프론트엔드 배포의 마지막으로 AWS Route53에 대한 설정만 남았다.
Route53 도메인 설정
Route53은 다양한 트래픽을 라우트 시켜주는 AWS의 서비스 이름이다. 웹사이트의 도메인이 cloudfront.net으로 끝나는 것을 바라는 사람은 아마도 없을 것이다. 가비아에서 도메인 네임을 구매하였는데, 해당 도메인 네임을 통해서 웹사이트에 접근할 수 있도록 하자.
먼저, 도메인 네임을 통해서 인증서를 발급받아야 하기 때문에 ACM(AWS Certificate Manager)이라는 서비스를 이용해야 한다. 해당 도메인에 대한 소유권을 확인하고 인증서를 발급받은 후, 구매한 도메인 네임을 통한 연결에 인증서를 통해 cloudfront로 연결하는 역할을 해야 한다.
Route 53 생성
일단 Route 53을 생성하자. 해당 콘솔로 이동한다.
위에서 도메인 이름을 입력하고, 생성을 클릭하면 호스팅 영역이 생성된다.
위와 같이 테스트용 Route 53을 생성해 보았다. 여기서 설정해줘야 하는 부분이 NS 유형(네임서버)에 해당하는 값/트래픽 라우팅 대상을 도메인 네임을 구매한 지점에 직접 써줘야 한다는 점이다!
위와 같이 ( 위 사진은 가비아 ) 직접 도메인을 구매한 곳에 접속하여 네임 서버를 하나씩 순서대로 써준다. 가비아의 경우에는 로그인 - my가비아 - 도메인 - 네임서버 설정이다. 설정을 마치면, 인증서를 발급하기 위해 ACM 콘솔로 넘어간다.
ACM 요청
ACM 콘솔로 접근하여, ACM을 요청해야 한다. 그전에 가장 중요한 것은 ACM을 버지니아 북부에 생성해야 한다는 것이다! 추후에 백엔드 서버를 배포할 때에는 서울 리전에 만들어, 서울 리전에 있는 인스턴스로 연결해 주지만, Cloudfront와 Route53을 연결하기 위해서는 꼭 버지니아 북부(us-east-1)에 만들어줘야 한다.
CloudFront 배포에 사용할 SSL 인증서를 미국 동부(버지니아 북부) 리전으로 마이그레이션
AWS Certificate Manager(ACM)에 Amazon CloudFront 배포와 연결하려는 SSL 인증서가 있습니다. 하지만 인증서가 미국 동부(버지니아 북부)(us-east-1) AWS 리전에 있지 않기 때문에 인증서를 배포와 연결할 수 없
repost.aws
버지니아 북부를 선택했다면, 퍼블릭 인증서 요청을 선택하고 다음으로 넘어간다.
위에서 본인의 도메인 이름을 집어넣고 요청을 누르면. 발급이 진행되고, 몇 분 이내에 발급이 완료된다.
그 후 해당 인증서를 클릭한다.
Route 53에서 레코드 생성 버튼을 클릭해 방금 만들었던 route53과 연결한다. 그렇다면 레코드가 하나 생겼을 것이다. 마지막으로 route53에서 호스팅 영역 생성을 눌러 A 유형 레코드를 아래와 같이 추가한다.
위 과정까지 완료했다면 이제는 Github actions에 대한 설정만 남았다. 설정하기 전에 알아둬야 할 정보는 아래와 같다.
- S3 버킷 이름
- IAM의 access key
- IAM의 secret access key
Github actions
이제 github actions를 통해서 코드가 PR 되거나 메인에 올라온 경우, 테스트할 수 있도록 해보자. 먼저 특정 레포지토리에서 세팅을 진행하자. 위에서 확인한 키를 통해서 아래처럼 secrets를 세 가지 세팅한다.
그 후 레포지토리에서 .github/workflows/deployment.yaml을 만들고 아래의 코드를 삽입한다.
name: deploy to aws
on:
push:
branches:
- main
pull_request:
branches:
- main
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
AWS_REGION: ap-northeast-2
jobs:
cicd:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20.x' # 프로젝트에서 사용하는 node의 버전을 명시한다.
- name: Cache yarn dependencies
uses: actions/cache@v3
with:
path: |
node_modules
~/.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install # npm, yarn, pnpm 등 사용하는 패키지 매니저를 통해 의존성 설치
- name: Build the project
run: yarn build # 사용하는 패키지 매니저를 통해 빌드
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Upload to S3
run: |
aws s3 sync ./dist s3://${{ env.S3_BUCKET_NAME }} --delete
위 코드를 입력하고, 메인에 merge 하면 앞으로 머지된 코드가 배포된다.
위 과정을 거치면 CI/CD 구현이 끝난다. freetier 정책에 따르면 비용은 크게 발생하지 않는다. 위에서 사용한 아키텍처를 간략하게 도식화하면 아래와 같다.
이제 앞으로는 백엔드 배포의 CI/CD를 포스팅할 예정이다. 전체적인 아키텍처는 아래와 같이 구성될 예정이다.
다음 포스팅에서는 Server-Developer가 Github actions를 통해 위의 flow로 배포가 자동화되도록 구성할 예정이다.
마치며
CI/CD 파이프라인을 구성함으로써 코드 배포 주기를 빠르게 하는 것만을 넘어서 클라우드 엔지니어가 배포를 자동화하고 다른 일을 할 수 있도록 할 수 있게 되는 점이 굉장히 좋았다.
팀원들이 구축하기 힘든 로직을 API Gateway 및 Lambda를 써서 Cloud의 리소스에 접근할 수 있도록 돕거나 간단한 서버를 만들어 띄우는 일을 보조하여 백엔드 개발자를 돕는 등 다른 활동에 리소스를 쓸 수 있게 되면서 프로젝트 전반적으로 굉장히 좋았다. 다양한 이점들을 말하면 목이 아프지만, 이러한 프로젝트나 해커톤의 상황에서는 정말 많은 시간을 아낄 수 있는 개발 주기를 단축시키는 훌륭한 것은 분명한 것 같다.
'DevOps > AWS' 카테고리의 다른 글
AWS를 통한 백엔드 배포 ( ECS, ALB, Route53 ) (7) | 2024.10.21 |
---|