이번 포스트는 한글로 작성!
원래는 자동 배포를 위해 CI/CD 작업을 하던 중, YAML이 뭔지 궁금해졌다. GitHub Actions에서 workflow를 위한 설정 작업에 yml 파일이 쓰이는데, 그래도 알고 쓰면 좋지 않을까 생각이 들었다.
내가 직접 YAML 문법을 기초부터 쌓아나가며 작성하는 것보다, 정규표현식처럼 그때그때 찾아보고 AI랑 대화하며 이해/작성 할 수 있는 정도면 충분하다고 판단했다. 딱 한 번만 정리하면 될 듯!
YAML은 JSON의 상위 호환 파일 형식이다. JSON 파일을 그대로 YAML 확장자로 바꿔도 유효하다.
문법은 어떨까? 나무위키에 아주 잘 정리되어 있다. (https://namu.wiki/w/YAML)
# 주석을 지원한다!
# '', "" 모두 지원한다. \n같은 이스케이프 문자나 :같은 yaml 문법에 쓰이는 기호를 쓸 땐 quote로 감싸야 한다.
# 프로퍼티 이름에 띄어쓰기도 가능하다.
example: 'with quotes'
example: without quotes
# >, | 를 사용해 긴 문장을 표현할 수 있다. >는 space, |는 \n 역할이다.
한글도: 지원한다는 사실
# null을 사용 가능하며, ~ 기호로 단축 표현할 수 있다.
null value: null
null shorthand: ~
# 배열은 - 로 구분한다.
array:
- apple
- banana
- 12345
- a: b
# json 스타일도 가능하다. 그러나 json의 배열 기능을 보완하는데 있어 yaml의 장점이 있다는 사실.
# 따옴표나 쉼표를 쓰지 않기 위해 yaml이 하이픈을 만들었으니 위처럼 사용하자.
json style array: [
apple,
'banana',
12345,
a: b,
]
# 객체는 들여쓰기와 :로 구분
object:
name: namu wiki
type: dictionary
primary color:
gradient:
start: 0x00A495
end: 0x13AD65
header: 0x008275
# 마찬가지로 따옴표와 쉼표, 중괄호같은 낭비를 없애기 위해 yaml이 있으니 위처럼 쓰도록 하자.
json style object: {
name: namu wiki,
"type": "dictionary",
}
implicit null: # 이러면 암묵적으로 null이 들어간다.
이 정도만 알고 있어도 Github Actions를 다루는데는 문제 없다고 판단!
이제 Github Actions의 공식 문서로 들어가보자. (https://docs.github.com/en/actions/about-github-actions/understanding-github-actions)
공식 문서에는 이렇게 쓰여있다.
GitHub Actions는 특정 event가 발생했을 때 작동되는 workflows의 모임이다.
event - push, pull request, create issue같은 일들
workflows - event나 수동적으로 트리거되었을 때 작동되는 작업들의 모임
workflows는 어떤 일들을 할 수 있을까?
- building and testing PR
- deploying an application
- adding a label whenever a new issue is opened
그렇다면 하나의 workflow가 트리거되었을 때 어떤 일이 일어나는지 보자.
우리가 workflows를 잘 정의해주기만 하면, GitHub에서 알아서 이를 처리할 가상 머신 runner를 돌려 작업들을 처리한다!
그런데 GitHub Actions에선 왜 YAML로 workflows를 정의할까?
사실 잘 모르겠음
다만 그 구조가 사람이 읽고 쓰기 편하고, 또 configuration을 하기에 최적화된 문법이라고 나와있다. 실제로 docker나 머신러닝, 딥러닝의 모델 설정 등 '설정'이 필요한 부분에서 주로 쓰이는 듯.
GitHub Actions에서 정의된 workflows의 예시를 봐도
1. 어느 환경 위에서
2. 무슨 작동을
3. 어떻게 실행할 것인지
를 꽤나 단순한 파일로, 게다가 사람이 읽고 쓰기 편하게 적고 있다는 걸 어렴풋이 느끼긴 했다.
마침 다음 주 중 도커를 써보려고 책도 빌렸는데, 이참에 YAML 문법을 배워놔서 다행인듯.
Quickstart를 읽으며 한 번 감을 잡아보자. (https://docs.github.com/en/actions/writing-workflows/quickstart)
1. 프로젝트 루트 디렉토리에서 .github/workflows 폴더를 생성한다.
2. 그 안에 github-actions-demo.yml 파일을 생성한다.
연습도 해볼 겸 Quickstart에서 알려주는 형식을 입맛대로 바꿔봤다.
# GitHub Actions 탭에서 보일 이름입니다.
name: GitHub Actions Demo
# action 페이지 내 workflow 목록에서 보일 이름입니다.
run-name: ${{ github.actor }} is testing out GitHub Actions
# workflow를 트리거할 event를 정의합니다. 여기서는 repository에 'push'할 경우 트리거됩니다.
on: push
# 실행할 작업을 정의합니다.
jobs:
# 작업의 고유한 이름입니다. Explore-GitHub-Actions라는 작업을 정의했어요.
Explore-GitHub-Actions:
# GitHub Actions가 이 작업을 위해 할당할 가상 머신의 운영체제입니다. ubuntu의 최신 버전을 사용할 거예요.
runs-on: ubuntu-latest
# 각각의 작업을 정의합니다. 작업들은 순차적으로 진행될 거예요.
steps:
- run: echo "짠! 작업이 ${{ github.event_name }} event에 의해서 작동되었습니다!"
- run: echo "이 작업은 깃헙이 호스트한 ${{ runner.os }} 위에서 돌아가고 있어요~"
- run: echo "당신의 브랜치는 ${{ github.ref }}이고, 당신의 레포지토리는 ${{ github.repository }}입니다."
- name: 작업에 이름을 붙일 수도 있습니다.
run: echo "이름을 붙인 작업은 이렇게 실행하고요."
# uses를 통해 GitHub에 정의된 기능을 사용할 수 있어요.
- name: Check out repository code
uses: actions/checkout@v4
- run: echo "${{ github.repository }}는 러너가 clone헀어요."
- run: echo "workflow가 당신의 코드를 테스트하기 위해 준비되었습니다."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "이 작업의 상태는 ${{ job.status }}입니다."
- run: echo "테스트"
Repository의 Actions 페이지를 들어가면 이렇게 나타난다.
그리고 List files in the repository 로 이름붙인 작업의 실행 결과를 보면
짠! 현재 내 프로젝트 루트 디렉토리에 존재하는 파일들의 리스트를 보여준다.
실행한 결과를 보니 yaml 문법에서는
ls ${{ github.workspace }}
로 쓰였지만 /home/runner/work/waffle_rookie_review/waffle_rookie_review 에 들어간 파일 리스트를 뽑는 커맨드가 입력되어 있다.
runner에서 내 프로젝트를 clone하는데, 이때 waffle_rookie_review라는 최상위 폴더에 프로젝트를 위한 메타 데이터 파일들이 들어가있고, 그 안에 진짜 clone된 프로젝트가 있는 게 아닐까 추측했다. 이를 AI한테 물어봤고, 사실 검정은 안 한 답변을 얻었다.
- 최상위 폴더(/home/runner/work/<repository-name>)에는 일반적으로 다음과 같은 데이터가 포함됩니다:
- GitHub Actions 관련 메타데이터: 워크플로 실행 중 생성되는 임시 파일들이 저장될 수 있습니다.
- 실제 클론된 프로젝트: 이 폴더 내부에 실제 리포지토리가 클론됩니다.
- GitHub Actions는 작업 공간을 격리하고 관리하기 위해 이러한 계층 구조를 사용합니다:
- 최상위 폴더는 여러 워크플로 간 충돌을 방지하기 위한 작업 공간으로 사용됩니다.
- 하위 폴더에 실제 프로젝트를 클론하여 워크플로 작업을 수행합니다.
- /home/runner/work/<repository-name>/<repository-name> 구조는 GitHub Actions에서 표준으로 사용하는 방식이며, 첫 번째 <repository-name>에는 메타데이터와 실제 프로젝트 디렉토리가 모두 포함될 수 있습니다.
음음. 그렇습니다.
얼추 Actions를 위한 YAML 사용법은 익힌 듯하니... 이번에는 루키 과정에서 사용한 yml 파일들을 직접 읽고 이해해볼 시간이다.
CI file
name: ci
# workflow를 트리거 할 event 모임
# main branch로의 PR, 혹은 main branch로의 push
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
# 작업의 이름은 ci
ci:
# 최신 버전의 ubuntu 환경에서 실행
runs-on: ubuntu-latest
steps:
# 현재 workflow가 실행되는 repository를 runner에 체크아웃(clone)하는 명령어
- uses: actions/checkout@v4
# runner 환경에 node.js를 설치하는 명령어
- uses: actions/setup-node@v4
with:
node-version: '20.11.1'
# repository의 의존성을 설치하는 단계
- name: Install dependencies
run: yarn install
# 문제가 없는지 확인해라!!
- name: Check
run: yarn check-all
Deploy file
name: deploy-client
on:
# main 브랜치에 push하여 자동 실행
push:
branches:
- main
# GitHub UI에서 Run Workflow 버튼을 눌러 수동 실행
workflow_dispatch:
jobs:
# deploy라는 이름의 job
deploy:
name: Deploy
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./apps/client
steps:
# 현재 Repository를 clone
- name: Checkout
uses: actions/checkout@v4
# Node.js 환경 설치
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20.11.1"
- name: Set environment variables
# .env.local 파일 생성
# GitHub Secrets에 저장된 값을 읽어와 .env.local에 추가
run: |
touch .env.local
echo "VITE_GOOGLE_CLIENT_ID=${{ secrets.VITE_GOOGLE_CLIENT_ID }}" >> .env.local
# 배포 시 필요 없는 msw 파일 삭제
- name: Remove msw files
run: |
find . -name "mockServiceWorker.js" -delete
# 의존성 설치 후 build
- name: Build & Export
run: |
yarn install
yarn build
- name: Deploy to S3 and Invalidate Cloudfront in prod mode
# AWS 환경 변수 설정
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ap-northeast-2
# S3에 업로드 후 CloudFront 캐시 무효화
run: |
aws s3 sync ./dist s3://intern-hasha-client --delete
aws cloudfront create-invalidation --distribution-id ENNREX04O38RJ --paths "/*"
여기서
echo "내용을 쓰고" >> <file name>
명령어는 내용을 해당 파일에 추가하는 명령어다. 단순히 echo만 쓰면 화면에 내용을 출력하는 명령어지만 저렇게 쓰면 쓰기도 가능하다는 사실!
이제 내가 Next.js로 작성한 앱을 배포하기 위해 베껴다 쓴 YAML file이 어떻게 생겨먹었는지 알 수 있다!
한 번 보자구요.
name: deploy to S3
# main 브랜치로 push 할 때 workflow 실행
on:
push:
branches:
- main
# 환경 변수 설정
env:
S3_BUCKET_NAME: ${{ secrets.S3_BUCKET_NAME }}
CODE_DEPLOY_APPLICATION_NAME: ${{ secrets.CODE_DEPLOY_APPLICATION_NAME }}
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: ${{ secrets.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }}
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
# 레포지토리 clone
- name: Checkout
uses: actions/checkout@v3
# Bun 설치 및 관련 환경 변수 설정
- name: Setup Bun
run: |
curl -fsSL https://bun.sh/install | bash
echo "BUN_INSTALL=$HOME/.bun" >> $GITHUB_ENV
echo "PATH=$HOME/.bun/bin:$PATH" >> $GITHUB_ENV
# 프로젝트 의존성 설치
- name: Install dependencies
run: bun install
# Next.js 앱 빌드
- name: Build next app
run: bun run build
# 빌드한 파일과 프로젝트 소스를 압축해 .zip 파일로 만들기
- name: Make zip file
run: zip -qq -r ./rookie_review.zip . -x "node_modules/*"
# -qq: quit 모드로 실행 (에러나 경고메세지만 출력하도록 함)
# -r: 지정된 디렉토리를 재귀적으로 압축 (하위 디렉토리와 파일들 모두 압축)
# -x "node_modules/*": node_modules 폴더 제외
# Github Action에서 AWS의 권한 자격을 얻어오는 단계
- 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: ap-northeast-2
# 압축된 파일을 S3에 업로드
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./rookie_review.zip s3 ://$S3_BUCKET_NAME/rookie_review.zip
# aws s3 cp: AWS CLI 명령어로 파일 복사
# --region ap-northeast-2: 업로드 대상 리전 설정
# 파일을 S3 버킷의 루트 디렉토리에 업로드.
# S3에 업로드 된 빌드 파일을 이용해 CodeDeploy가 정의된 동작을 하도록 트리거
- name: Code Deploy
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=rookie_review.zip
패키지 관리를 Bun으로 하는 것만 내가 직접 고쳤고, 나머지는 대부분 블로그 https://velog.io/@tt8784/Nextjs%EB%A5%BC-github-action-EC2-pm2%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B04 를 참조했다.
그런데 적힌 내용 중 수정할 부분들이 있다.
1.
- name: Checkout
uses: actions/checkout@v3
checkout@v3는 Node.js 옛날 버전을 사용한다. 대신에 최신 버전인 checkout@v4로 바꾸기!
2.
strategy:
matrix:
node-version: [18.x]
여기서는 여러 버전을 테스트하지 않으므로 딱히 매트릭스 전략이 필요하지 않다. 그리고 Node.js version도 18로 옛날 버전이므로 최신 환경으로 바꿔줄 필요가 있다.
strategy를 없애고 Node.js 환경을 설치하는 명령어를 bun 설치 다음 작업으로 추가해줬다.
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.11.1'
그리고 배포 전략이나 빌드 캐싱 등 다양한 방법으로 배포의 안전성과 속도를 향상시키는 방법이 있지만 우선 패스.
얼추 YAML이 뭔지는 알겠고, 또 환경 설정이 뭔지도 알겠다.
'공부 > 코딩' 카테고리의 다른 글
Next.js 앱 배포하기 - EC2, nginx, pm2 (1) | 2025.03.02 |
---|---|
와플 스튜디오 루키 과정 복습하기 7 - nginx configuration and CD (1) | 2025.03.02 |
와플 스튜디오 루키 과정 복습하기 5 - Distribution with AWS EC2 (No Versel) (0) | 2025.02.25 |
와플 스튜디오 루키 과정 복습하기 - 4: create API in Next.js (0) | 2025.02.23 |
와플 스튜디오 루키 과정 복습하기 - 3: AWS S3, image upload (0) | 2025.02.22 |