github actions와 aws를 이용한 cicd pipeline 구축
- 서버 배포 세부 설정 (aws s3 + cloudfront 배포)
- IAM 계정 생성 및 admin 권한 부여
- github secret key 설정 및 yml 파일 작성
참....쉽죠?
들어가기 전에, 저는 이번 토이 프로젝트를 처음으로 ci/cd를 구축해 보았습니다.
프론트엔드 개발자로서 참여하였고, 이전에도 간단한 프로젝트에 참여해 본 적이 있었지만 본격적으로 aws s3+cloudfront를 활용한 서버배포 + ci/cd 구축은 이번이 처음이라서 이렇게 간단히 정리합니다.
다음에는 이번 프로젝트 내내 저를 엄청 괴롭힌 cors에 대해서도 간단히 정리해볼 예정입니다. 그러나 한가지 말할 것은 cors는 대부분 서버 문제라서 프론트엔드가 할 만한것은 거의 없다는 점....... 프론트엔드 코드가 잘못된 게 아니라 99.99퍼센트 서버 측 설정이 어디가 삐꾸난 거라서 일단 헬프부터 치고 봐야 합니다...
저는 원래 보안 외길인생이었다가 잘못 길을 들인 덕에 개발도 접하게 되었고 이제는 개발 커리어만 산더미처럼 쌓여버린 사람이 되어버렸지만.....이렇게 되어버린 이상 개발도 공부하면서 보안도 지향하는 사람이 되어야죠. 허허
앞으로 블로그에 보안 관련 글이랑 개발 관련 글이 자주 올라올 예정이니 많은 관심 부탁드림니다.....😍
ci/cd
지속적 통합(Continuous Integration) 및 지속적 제공/배포(Continuous Delivery/Deployment)
ci(지속적 통합)는 코드 변경 사항을 공유 소스 코드 리포지토리에 지속적으로 통합(코드 커밋 -> 푸시 -> 머지)하는 과정의 자동화를 의미합니다. 즉 쉽게 말해 해당 리포지토리에 소스 코드 변경 사항이 생길 때마다 푸시 / 머지 하는 과정을 지속적 / 자동적으로 한다는 의미입니다.
cd(지속적 제공 및 배포)는 코드 변경 사항의 통합, 테스트, 제공을 나타내는 과정으로 ci와 달리 변경 사항을 우리가 배포하고자 하는 환경에 자동으로 릴리스하는 과정까지 포함하는 자동화 과정을 의미합니다.
즉 우리가 코드를 변경하였고, 배포된 서버에 어떻게 동작하는지 확인하고 싶다 -> 자동적으로 빌드 후 배포해서 테스트하도록 함!
만약 ci/cd 파이프라인이 없을 경우, 우리가 기존의 코드에서 수정을 했다고 가정해봅시다.
코드를 수정하면 커밋하고 푸시 -> 머지한 후 빌드해서 배포하는 조금(아니 많이 번거로운...ㅎ) 번거로운 과정을 일일이 거쳐서 다시 서버로 배포해야 합니다. 그런데 만약 내가 새로 수정한 코드에서 오류가 난다면??

(지옥의 시작)
그러면 위의 또 번거로운 과정을 거쳐야 합니다. 이 과정을 오로지 '커밋하고 푸시' 하는 과정 하나만으로 서버에 배포 후 코드가 잘 작동하는지 바로 테스트해볼 수 있도록 하는 게 바로 위의 ci/cd 파이프라인입니다. 즉 머지하고 빌드하고 또 aws s3 버킷에 배포하는 과정 없이 바로 배포해서 테스트가 가능한 것....!
규모가 작은 프로젝트면 몰라도, 규모가 조금이라도 큰 프로젝트에서는 ci/cd 파이프라인을 구축한 후 코드 업데이트를 하는 것이 한결 낫습니다.
ci/cd 파이프라인
주로 Jenkins, github actions, Bamboo, circleCI가 많이 쓰입니다.
여기서 저는 github actions를 이용하여 cicd 파이프라인을 구축하였으므로 github actionflow를 활용한 cicd 파이프라인 구축에 대해 알려드리고자 합니다.
github action
- workflow
- 레포지토리에서 실행할 수 있는 자동화 프로세스
- yaml 파일로 작성되며, 하나의 폴더 안에 여러 workflow가 존재할 수 있다.
- event
- workflow 실행을 트리거하는 특정 액션 or 규칙
- Job
- 가상 환경(ex> Ubuntu)에서 여러 step들로 이루어진 일종의 프로세스의 집합
- step
- 프로세스 단위로 명령을 내리거나 action 수행
- action
- workflow의 가장 작은 빌드 단위로, job을 구성하기 위 step들의 조합으로 구성된 일종의 독립적 명령이다.
.github/workflows/ 폴더에 yml 파일이 위치해 있어야 하는지도 먼저 확인해야 합니다. 여기서 .github 폴더의 위치는 레포지토리의 루트 폴더에 위치해 있습니다.
name: CI/CD Pipeline for mogether
on:
push:
branches:
- test
jobs:
build-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- name: Cache Node.js dependencies
uses: actions/cache@v2
with:
path: frontend/mogether/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('./frontend/mogether/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
working-directory: ./frontend/mogether
run: npm install --force
- name: Build the project
working-directory: ./frontend/mogether
env:
CI: false
run: npm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_2 }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_2 }}
aws-region: ap-northeast-2
- name: Deploy to S3
run: aws s3 sync ./frontend/mogether/build s3://mo-gether-front --delete
- name: Invalidate CloudFront cache
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
일단 전체 코드는 이렇습니다.
저는 github actions + s3+ cloudfront를 사용하였습니다.
IAM 유저 생성 및 access key 발
aws로 접속합니다.
github-actions 유저 생성 후 권한을 아래와 같이 설정해 줍니다
- AmazonS3FullAccess
- CloudFrontFullAccess
- IAMUserChangePassword
AWS credential 인증을 위해 IAM 유저 하나를 만들고, 권한을 설정해준 후 Access Key ID와 Secret Access Key를 가져와 github의 환경변수로 설정해 줍니다.
이제부터 github에서는 access key를 이용해 aws의 위의 3가지 권한에 대해 접근을 할 수 있습니다.
만약 github이 털린다면....? key도 털리니까 당연히 보안적으로 위험해지게 되겠죠? 그래서 요즘은 IAM user 사용보다는 IAM role 사용이 권장되고 있기는 합니다. 이에 대해서는 나중에 정리하도록 하겠습니다.
기초 세팅이 완성되었으니 코드를 분석하는 것만 남았습니다.
여기서 s3 + cloudfront로 서버가 이미 배포되었다는 가정 하에 진행하겠습니다. (s3 버켓 주소가 이미 나와있고, cloudfront의 주소가 이미 나와있다는 가정 하에 진행된다는 의미)
on:
push:
branches:
- test
'test'라는 브랜치에서 'push'라는 이벤트가 일어나면 action을 시작합니다.
build-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- name: Cache Node.js dependencies
uses: actions/cache@v2
with:
path: frontend/mogether/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('./frontend/mogether/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
우분투에서 동작하고, node 버전을 명시해 주어야 합니다.
cmd에서 node --version 을 치면 간단하게 node 버전을 알 수 있습니다.
cache node.js dependencies의 경우 만약 이전에 의존성 문제로 에러 로그가 남아 있다면 action에 지정하고 가는 게 훗날 코드 수정 시 에러 확률을 줄일 수 있습니다. (꼭 필요한 과정은 아닙니다.)
- name: Install dependencies
working-directory: ./frontend/mogether
run: npm install --force
- name: Build the project
working-directory: ./frontend/mogether
env:
CI: false
run: npm run build
path에서 지정된 dependency를 모두 설치한 후(참고로 설치할 때 의존성 충돌 문제로 자꾸 안되길래 npm install 시 뒤에 --force를 붙여주었습니다.) 마지막으로 빌드 파일을 ./frontend/mogether 폴더 아래에 만들어 줍니다. (npm run build)
만약 의존성 충돌 문제가 없을 경우 run: npm install만 해도 되지만, 만약 충돌날 경우 강제로라도 빌드해서 배포해야 하므로 --force를 붙여주도록 합시다...
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_2 }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_2 }}
aws-region: ap-northeast-2
- name: Deploy to S3
run: aws s3 sync ./frontend/mogether/build s3://mo-gether-front --delete
- name: Invalidate CloudFront cache
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
마지막으로 aws credential을 지정함으로서 github action이 aws에 접근할 수 있도록 설정합니다. id와 key는 github settings에서 설정한 환경변수 값을 입력해 주고, aws - region은 IAM 유저를 생성한 지역을 입력해 줍니다.
그리고 S3 배포를 위한 S3 버킷 주소도 입력해 줍니다.
마지막으로 cloudfront 환경에 배포하였으므로 cloudfront 무효화도 설정하고 가야 합니다.
만약 빌드 시 이전 값이 반영되지 않을려면 cloudfront 무효화 과정을 거쳐야 하므로 invalidate cloudfront cache도 설정하고 넘어갑시다.
이렇게 yml 문서 작성이 끝났습니다.
.github/workflows 폴더 아래에 .yml 파일로 저장하고, 이제 지정한 브랜치에서 push를 진행할 경우 자동적으로 코드 테스트 및 배포를 진행하는 것을 확인할 수 있습니다.
추가로 push 뿐만 아니라 자동적으로 merge 과정까지 포함해서 넣을 수 있습니다.