일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- JS
- Passed by Value
- 알고리즘
- 식별자란
- input error
- 회고록
- 광고지구
- 유령 의존성
- JavaScript
- 인풋태그 엔터
- Mac OS NVM
- react portal
- react
- Client-Side Navigation
- next/link
- 원티드인턴십
- jsEvent Loop
- toast err
- 프로젝트
- Node
- CPU와 GPU의 차이점
- git
- 원티트 프리온보딩인턴십 1주차
- NVM
- Til
- 원티드프리온보딩
- NextJs
- CloudFront 무효화
- 향해99
- Redux
- Today
- Total
SUIN
[TIL] Github Action Deploy to AWS 처리 내가 마주한 이슈 본문
v2 시작되는 프로젝트에서 기존 v1에서 자동 배포된 내용을 참고해서 그대로 반영할 것인가
조금 더 도전해 볼 것인가 고민하던 난 이왕 다시 하는 거 새로 만들어보자! 하며 바로 도전해 보았다
기존 내가 알고 사용하던 워크플로우
name: CI-CD
on:
pull_request:
branches:
- main
jobs:
deploy:
name: 'Build & Deploy'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: ${{ secrets.NODE_VERSION }}
- name: Cache node modules
uses: actions/cache@v2
id: cache
with:
path: node_modules
key: npm-packages-${{ hashFiles('**/package-lock.json') }}
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: yarn install
- name: setting .env
run: |
echo "REACT_APP_SERVER_URL=$REACT_APP_SERVER_URL" >> .env.production
echo "REACT_APP_BUCKET_NAME=$REACT_APP_BUCKET_NAME" >> .env.production
echo "REACT_APP_REGION=$REACT_APP_REGION" >> .env.production
echo "REACT_APP_ACCESS=$REACT_APP_ACCESS" >> .env.production
echo "REACT_APP_SECRET=$REACT_APP_SECRET" >> .env.production
echo "REACT_APP_BUCKET_URL=$REACT_APP_BUCKET_URL" >> .env.production
env:
REACT_APP_SERVER_URL: ${{ secrets.REACT_APP_SERVER_URL }}
REACT_APP_BUCKET_NAME: ${{ secrets.REACT_APP_BUCKET_NAME }}
REACT_APP_REGION: ${{ secrets.REACT_APP_REGION }}
REACT_APP_ACCESS: ${{ secrets.REACT_APP_ACCESS }}
REACT_APP_SECRET: ${{ secrets.REACT_APP_SECRET }}
REACT_APP_BUCKET_URL: ${{ secrets.REACT_APP_BUCKET_URL }}
- name: Build
run: unset CI && yarn build
# aws user 연결
- 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: ap-northeast-2
# /build를 s3로 업로드
- name: Upload to S3
env:
BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME}}
run: |
aws s3 sync \
./build s3://$BUCKET_NAME
# 업로드한 s3 파일을 각 CDN 캐시 무효화하여 리프레시 하기
- name: CloudFront Invalidation
env:
CLOUD_FRONT_ID: ${{ secrets.DISTRIBUTION_ID}}
run: |
aws cloudfront create-invalidation \
--distribution-id $CLOUD_FRONT_ID --paths "/*"
새롭게 도전한 워크플로우
name: Deploy to AWS
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@master
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Cache node modules
id: npm-cache
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- if: steps.npm-cache.outputs.cache-hit == 'true'
run: echo 'npm cache hit!'
- if: steps.npm-cache.outputs.cache-hit != 'true'
run: echo 'npm cache missed!'
- run: npm ci
- name: Generate Environment Variables File for Production
run: |
echo "REACT_APP_SERVER_URL=$REACT_APP_SERVER_URL" >> .env.production
echo "REACT_APP_BUCKET_NAME=$REACT_APP_BUCKET_NAME" >> .env.production
echo "REACT_APP_REGION=$REACT_APP_REGION" >> .env.production
echo "REACT_APP_ACCESS=$REACT_APP_ACCESS" >> .env.production
echo "REACT_APP_SECRET=$REACT_APP_SECRET" >> .env.production
echo "REACT_APP_BUCKET_URL=$REACT_APP_BUCKET_URL" >> .env.production
env:
REACT_APP_SERVER_URL: ${{ secrets.REACT_APP_SERVER_URL }}
REACT_APP_BUCKET_NAME: ${{ secrets.REACT_APP_BUCKET_NAME }}
REACT_APP_REGION: ${{ secrets.REACT_APP_REGION }}
REACT_APP_ACCESS: ${{ secrets.REACT_APP_ACCESS }}
REACT_APP_SECRET: ${{ secrets.REACT_APP_SECRET }}
REACT_APP_BUCKET_URL: ${{ secrets.REACT_APP_BUCKET_URL }}
- name: Build
run: unset CI && npm run build
- name: deploy to s3
uses: jakejarvis/s3-sync-action@master
with:
args: --delete
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME}}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "ap-northeast-2"
SOURCE_DIR: 'build'
- name: Invalidate CloudFront
uses: chetan/invalidate-cloudfront-action@v2
env:
DISTRIBUTION: ${{ secrets.DISTRIBUTION_ID }}
PATHS: "/index.html"
AWS_REGION: "ap-northeast-2"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
내가 알게 된 내용. 정확하게 알았던 내용
1. 동작 이벤트
name :내가 만든 동작은 CI-CD가 아닌 CD 이므로 name 수정
Event : 기존 main으로 pull_request 동작시 액션이 수행되어야 했다면 push로 이벤트 변경
- v1에서는 develop 브랜치가 별도로 존재했지만 지금은 featuer 브랜치에서 main으로 바로 올리기 때문에 혹시 모를 동작을 대비해 push 이벤트로 수정이 되었다. (pr에서 merge시 혹시 모를 버그 예방... )
name: Deploy to AWS
on:
push:
branches:
- main
2. 노드 모듈 버전 설정
GitHub Actions에서는 기본적으로 CI 서버에 Node.js가 이미 설치가 되어 있어서 굳이 별도로 설치를 해 줄 필요는 없지만
GitHub Actions의 CI 서버는 주기적으로 이러한 소프트웨어가 업데이트되기 때문에 프로젝트에서 사용하는 정확한 버전의 Node.js를 설치하는 편이 더 안전하다고 한다.
- uses: actions/setup-node@v3
with:
node-version: 16
https://www.daleseo.com/github-actions-setup-node/
3. 노드 모듈 캐싱처리
path :인자로는 우분투 운영체제에서 npm이 패키지 저장소에서 내려받은 패키지를 CI 서버에 저장해 두는 경로를 지정
key : 인자로 GitHub의 캐시에서 데이터를 읽거나 쓸 때 사용되는 식별자를 명시하며 키값은 {소유자}/{저장소명}@{참조자}의 형태로 명시된다
npm ci를 적용한 이유
install , ci 두 가지 모두 결과적으로는 두 명령어 모두 의존성 목록을 설치하지만
npm install의 경우 package.json을 읽어 의존성 목록을 만들고 package-lock.json을 통해 설치할 의존성의 버전을 알려주는 것이기 때문에 npm install 시 package.json 에 의존성 목록에 추가될 것이고 package-lock.json 도 업데이트 된다.
ci의 경우 쓰기 권한이 없으며 package-lock.json 파일을 기반으로 의존성을 설치하고, package.json 은 버전 매칭 밸리데이션 용도로 사용된다. 다만 package-lock.json 이 무조건 존재해야만 하고, 만약 없으면 에러를 낸다.
만약 하나의 프로젝트에 여러 명의 개발자가 협업을 할 경우 각자의 로컬 환경에서 npm, node 버전 등이 서로 다를 수 있다. 이러한 상황에서 각자 npm install 실행한다면, 서로 다른 버전을 가지는 모듈을 가지는 경우가 생길 수 있으며 로컬 환경뿐만 아니라 CI/CD 등 서로 다른 환경에 의해 발생할 수 있다고 한다.
기존 프로젝트에 package-lock.json 파일 이 존재했기 때문에 ci로 처리하여 기존 node_modules 삭제 후 package-lock.json을 읽고 의존성 목록을 설치하는 방법을 선택했다.
- name: Cache node modules
id: npm-cache
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- if: steps.npm-cache.outputs.cache-hit == 'true'
run: echo 'npm cache hit!'
- if: steps.npm-cache.outputs.cache-hit != 'true'
run: echo 'npm cache missed!'
- run: npm ci
https://www.daleseo.com/github-actions-cache/
https://github.com/actions/setup-node
https://mygumi.tistory.com/409
4. env 선언
프로젝트 내 이미지 파일을 s3에 별도로 프런트가 관리되고 있었기 때문에 api server url과 함께 명시해 주었다.
- name: Generate Environment Variables File for Production
run: |
echo "REACT_APP_SERVER_URL=$REACT_APP_SERVER_URL" >> .env.production
echo "REACT_APP_BUCKET_NAME=$REACT_APP_BUCKET_NAME" >> .env.production
echo "REACT_APP_REGION=$REACT_APP_REGION" >> .env.production
echo "REACT_APP_ACCESS=$REACT_APP_ACCESS" >> .env.production
echo "REACT_APP_SECRET=$REACT_APP_SECRET" >> .env.production
echo "REACT_APP_BUCKET_URL=$REACT_APP_BUCKET_URL" >> .env.production
env:
REACT_APP_SERVER_URL: ${{ secrets.REACT_APP_SERVER_URL }}
REACT_APP_BUCKET_NAME: ${{ secrets.REACT_APP_BUCKET_NAME }}
REACT_APP_REGION: ${{ secrets.REACT_APP_REGION }}
REACT_APP_ACCESS: ${{ secrets.REACT_APP_ACCESS }}
REACT_APP_SECRET: ${{ secrets.REACT_APP_SECRET }}
REACT_APP_BUCKET_URL: ${{ secrets.REACT_APP_BUCKET_URL }}
5. s3 업로드
기존에는 Configure AWS credentials 선언 후 s3 버킷을 업데이트해 줬다면 이번엔 Configure AWS credentials 설정을 S3 업로드 시 함께 선언하는 방식으로 변경했다.
두 가지의 차이점은 이후 무효화에서 나타났다.
// 기존 s3 연결
- 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: ap-northeast-2
- name: Upload to S3
env:
BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME}}
run: |
aws s3 sync \
./build s3://$BUCKET_NAME
// 변경된 s3연결
- name: deploy to s3
uses: jakejarvis/s3-sync-action@master
with:
args: --delete
env:
AWS_S3_BUCKET: ${{ secrets.S3_BUCKET_NAME}}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: "ap-northeast-2"
SOURCE_DIR: 'build'
6. CloudFront 무효화
- name: CloudFront Invalidation
env:
CLOUD_FRONT_ID: ${{ secrets.DISTRIBUTION_ID}}
run: aws cloudfront create-invalidation --distribution-id $CLOUD_FRONT_ID --paths "/*"
만약 내가 Configure AWS credentials 선언을 deploy to s3 함께 적용 후 아래와 같이 선언한다면 에러를 보게 될 것이다...
왜냐면.. 그게 지금 나였으니.... ㅜㅜㅜㅜ 🥹
저번에 포스팅한 에러와 동일한 에러가 발생하게 되었는데 팀원에게 문의한 결과 이번엔 IAM 정책의 문제가 아니었다..
4시간의 검색 끝에 별도로 무효화 처리를 위해 추가 aws-access 처리를 한번 더 해주어야 한다는 내용을 알게 되었고 적용해 본 결과 정상적으로 동작하는 것을 알 수 있었다.
- name: Invalidate CloudFront
uses: chetan/invalidate-cloudfront-action@v2
env:
DISTRIBUTION: ${{ secrets.DISTRIBUTION_ID }}
PATHS: "/index.html"
AWS_REGION: "ap-northeast-2"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
https://github.com/chetan/invalidate-cloudfront-action
하나씩 확인하며 구현해 보니 동작원리를 알아가는 것이 재미있었고 마지막 성공의 희열은 정말,,, 말로 설명할 수 없을 만큼 행복하다.
오늘도 무한 4시간의 삽질을 통해 자동배포 완성!
마지막으로
출발....🚀
'TIL' 카테고리의 다른 글
[TIL] 광고지구 프로젝트 리팩토링 대상 정하기 (1차) (2) | 2023.03.26 |
---|---|
[TIL] 커리어 코칭 1일차 , 나는 어떤 사람인가 (0) | 2023.02.27 |
[TIL] 두번째 팀 프로젝트를 마치며 .. 끄적여보는 일기 (1) | 2022.11.22 |
[TIL] input undefined to a defined value error (0) | 2022.11.07 |
[TIL] interceptors.response 전역 error toast 처리 (0) | 2022.11.04 |