CI (Continuous Integration, 지속적 통합)
CI, 즉 지속적 통합은 새로운 코드의 변경 사항이 정기적으로 빌드 및 테스트 되어 한 레포지토리에서 통합되는 것을 의미합니다.
개발자들이 협업을 진행할 때, 병합 과정에서의 충돌을 방지할 수 있고 작업을 빠르고 효율적으로 진행할 수 있습니다.
그럼 깃허브 액션을 사용하여 Node 파일을 CI 세팅해봅시다.
Github Actions Secrets
먼저 깃허브 액션을 사용하기 위해, .env 파일 내용을 환경변수로 등록해야 합니다.
setting > security > secrets and variables > actions 으로 들어가서 .env 파일의 내용을 환경변수로 등록해주세요.
New Repository secrete 버튼을 눌러서 환경변수를 등록할 수 있습니다!
Workflows
다음으로 CI 를 위한 작업 파일을 만들어주어야 합니다. 프로젝트에서 .github/workflows/deploy.yml 파일을 만들어주세요.
on:
push:
branches: [develop]
pull_request:
branches: [develop]
develop 브랜치에 push 하거나 pull request를 날릴 때 작업을 수행합니다.
build:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [16.x]
steps:
- name: Checkout source code.
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Check Npm -v
run: npm -v
버전 등 프로젝트에 필요한 라이브러리를 세팅합니다.
- name: create env file
working-directory: ./
run: |
pwd
touch .env
echo PORT=${{ secrets.PORT }} >> .env
echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
echo SLACK_URL=${{ secrets.SLACK_URL }} >> .env
echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
echo TEST_ACCESS_TOKEN=${{ secrets.TEST_ACCESS_TOKEN }} >> .env
echo FIXED_ACCESS_TOKEN=${{ secrets.FIXED_ACCESS_TOKEN }} >> .env
cat .env
.env 파일을 생성합니다. (레포지토리에 노출되지 않아야 하는 파일이므로 별도로 생성되어야 합니다.)
- name: build server files
working-directory: ./
run: |
yarn
yarn run build
프로젝트를 build 합니다.
전체 코드
name: deploy
on:
push:
branches: [develop]
pull_request:
branches: [develop]
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [16.x]
steps:
- name: Checkout source code.
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Check Npm -v
run: npm -v
- name: create env file
working-directory: ./
run: |
pwd
touch .env
echo PORT=${{ secrets.PORT }} >> .env
echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
echo SLACK_URL=${{ secrets.SLACK_URL }} >> .env
echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
echo TEST_ACCESS_TOKEN=${{ secrets.TEST_ACCESS_TOKEN }} >> .env
echo FIXED_ACCESS_TOKEN=${{ secrets.FIXED_ACCESS_TOKEN }} >> .env
cat .env
- name: build server files
working-directory: ./
run: |
yarn
yarn run build
CI TEST
develop 브랜치에 push 또는 PR을 날리면 위와 같이 정상적으로 실행된 것을 확인할 수 있습니다. 충돌 없이 잘 통합되었을 때의 결과 입니다. 또한, 왼쪽의 Jobs > build 탭을 선택하면 yml 파일을 수행한 과정과 로그를 확인할 수도 있습니다.
CD (Continuous Deployment, 지속적 배포)
CD, 즉 지속적 배포는 새로운 코드의 변경 사항이 레포지토리를 넘어서 프로덕션 환경까지 릴리즈 되는 것을 의미합니다. 다시 말해서 자동으로 배포해주는 것입니다. 이 포스팅에서는 AWS의 Code deploy를 활용하여 EC2 까지 자동으로 배포되도록 설정해보겠습니다.
AWS S3
깃허브 액션에서 빌드한 프로젝트를 저장하기 위해 AWS에서 S3를 생성해주어야 합니다.
S3 > 버킷 > 버킷 만들기로 이동해주세요.
우선 버킷 이름 설정 및 AWS 리전만 확인 후 버킷 만들기를 실행해서 버킷을 만들어주세요.
AWS IAM - Codedepoly, S3
EC2가 S3와 Codedeploy를 이용할 수 있도록 권한을 부여해야 합니다.
IAM > 역할 > 역할생성 으로 이동해주세요.
AWS 서비스와 EC2를 선택하고 다음으로 넘어가주세요.
AWSCodeDeployFullAccess 와 AmazonS3FullAccess 권한을 선택해주세요.
이름을 지정하고, 확인 및 검토 후 역할을 생성해주세요.
EC2 권한 부여
EC2에 권한을 부여하기 위해, 프로젝트를 배포할 EC2의 작업 > 보안 > IAM 역할 수정으로 들어가주세요.
위 단계에서 만든 IAM을 선택하고 IAM 역할을 업데이트 해주세요.
AWS IAM - Codedeploy
다음으로 Codedeploy를 위한 IAM을 생성해야 합니다.
IAM 생성으로 다시 돌아와서 CodeDeploy를 검색하여 선택해주고 다음으로 넘어가주세요.
권한 정책을 확인하고 다음으로 넘어가주세요.
역할 이름을 지정하고 역할을 생성해주세요.
Code Deploy
다음으로 코드 자동 배포화를 위해 codedeploy의 애플리케이션을 생성해주어야 합니다.
CodeDeploy > 애플리케이션 > 애플리케이션 생성으로 들어가주세요.
이름을 지정하고, EC2/온프레미스를 선택하여 애플리케이션을 생성해주세요.
생성한 애플리케이션으로 들어가서, 하단에서 배포 그룹을 생성해주어야 합나디ㅏ. 배포 그룹 생성을 눌러주세요.
배포 그룹 이름을 지정하고, 위에서 만든 IAM 역할을 서비스 역할에서 선택해주세요.
환경 구성에서 EC2 인스턴스를 선택하고 태그 그룹에서 키와 값을 선택해주세요.
AWS IAM 사용자
다음으로 깃허브 액션에서 S3에 접근하여 파일을 배포할 수 있도록 사용자를 생성해주어야 합니다.
AWS > IAM > 사용자 > 사용자 추가로 이동해주세요.
사용자 이름을 지정하고, 자격 증명 유형에서 액세스 키 - 프로그래밍 방식 액세스를 선택하고 다음으로 넘어가주세요.
권한 설정에서 기존 정책 직접 연결을 선택하여 AWSCodeDeployFullAccess와 AmazonS3FullAccess를 검색하여 추가한 후 다음으로 넘어가주세요.
다음을 선택하여 과정 확인 및 검토 후, 사용자를 생성하면 Access Key Id와 Secret Access Key를 얻을 수 있습니다. 해당 페이지를 한번 나가면 다시는 찾을 수 없으니..!! 개인적인 공간에 복붙해두거나 csv 파일을 꼭 미리 받아주시길 바랍니다.
복붙 또는 받아둔 파일에서 Access Key Id와 Secret Access Key를 CI에서 진행한 것과 같이 깃허브에 환경 변수로 등록해주세요.
EC2 Codedeploy Agent 설치
AWS에서 생성 및 설정해야 하는 과정은 끝났습니다. 이제 EC2를 연결하여 우분투로 접속하여 해당 과정을 수행해주세요.
기본적으로 프로젝트에서 필요한 npm, yarn, git, node, pm2은 미리 설치해주시기 바랍니다.
$ sudo apt update
$ sudo apt install awscli
awscli를 설치합니다.
$ sudo aws configure
AWS Access Key ID : 다운 받은 csv 파일 내에 Access Key ID
AWS Secret Access KEy : 다운 받은 csv 파일 내에 Secret Access Key
Default region name : ap-northeast-2
Default output format : json
앞서 사용자 추가해서 얻은 Access Key Id와 Secret Access Key를 입력하고, 리전과 포맷을 지정해주세요.
$ wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
$ chmod +x ./install
agent 파일을 설치하고, 권한을 추가해주세요.
$ sudo apt-get install ruby
$ sudo ./install auto
$ sudo service codedeploy-agent status
codedeploy agent 파일을 설치해주세요.
$ sudo vim /etc/init.d/codedeploy-startup.sh
파일을 생성하고,
#!/bin
sudo service codedeploy-agent restart
위 내용으로 복붙하여 작성해주세요.
$ sudo chmod +x /etc/init.d/codedeploy-startup.sh
권한 추가 합니다.
appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/build
overwrite: yes
permissions:
- object: /home/ubuntu
pattern: '**'
owner: ubuntu
group: ubuntu
hooks:
AfterInstall:
- location: scripts/after-deploy.sh
timeout: 300
runas: ubuntu
프로젝트 루트에 appspec.yml 파일을 추가하여 위 내용을 추가해주세요.
destination에서 EC2 배포 파일을 빌드하고, location의 파일에서 빌드 후 작업을 정의합니다.
after-deploy.sh
빌드 후 이루어질 작업을 정의하는 파일입니다. 프로젝트에서 scripts/after-deploy.sh 파일을 추가하여 아래의 내용을 추가해주세요.
#!/bin/bash
REPOSITORY=/home/ubuntu/build
cd $REPOSITORY
sudo /usr/bin/yarn
sudo /usr/bin/pm2 start dist
우분투로 프로젝트가 옮겨진 후, yarn 하고 pm2 start dist 하여 배포합니다.
deploy.yml 파일 추가
CI 단계에서 작성했던 deploy.yml 파일에 아래 내용을 추가해줍니다.
- name: zip file
run: zip -r smeme.zip ./dist ./scripts ./appspec.yml ./.env ./package.json ./prisma
dist, scripts, appspec, .env, package.json, prisma 파일을 zip 파일로 묶어 생성합니다. DB 툴로 prisma를 사용하고 있으므로 ./prisma도 추가해주어야 합니다.
- name: AWS configure 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
사용자 추가에서 얻은 access key를 지정해줍니다.
- name: upload to S3
run: aws s3 cp --region ap-northeast-2 ./smeme.zip s3://smeme-bucket/deploy/
S3에 업로드 합니다.
- name: deploy with AWS codeDeploy
run: aws deploy create-deployment
--application-name smeme-codedeploy
--deployment-config-name CodeDeployDefault.AllAtOnce
--deployment-group-name smeme-group
--s3-location bucket=smeme-bucket,bundleType=zip,key=deploy/smeme.zip
codeploy를 통해 프로젝트를 배포합니다.
전체 코드
name: deploy
on:
push:
branches: [develop]
pull_request:
branches: [develop]
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [16.x]
steps:
- name: Checkout source code.
uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Check Npm -v
run: npm -v
- name: create env file
working-directory: ./
run: |
pwd
touch .env
echo PORT=${{ secrets.PORT }} >> .env
echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
echo SLACK_URL=${{ secrets.SLACK_URL }} >> .env
echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
echo TEST_ACCESS_TOKEN=${{ secrets.TEST_ACCESS_TOKEN }} >> .env
echo FIXED_ACCESS_TOKEN=${{ secrets.FIXED_ACCESS_TOKEN }} >> .env
cat .env
- name: build server files
working-directory: ./
run: |
yarn
yarn run build
- name: zip file
run: zip -r smeme.zip ./dist ./scripts ./appspec.yml ./.env ./package.json ./prisma
- name: AWS configure 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
run: aws s3 cp --region ap-northeast-2 ./smeme.zip s3://smeme-bucket/deploy/
- name: deploy with AWS codeDeploy
run: aws deploy create-deployment
--application-name smeme-codedeploy
--deployment-config-name CodeDeployDefault.AllAtOnce
--deployment-group-name smeme-group
--s3-location bucket=smeme-bucket,bundleType=zip,key=deploy/smeme.zip
CD TEST
develop 브랜치에 머지하고 깃허브 액션을 확인하면 정상적으로 실행 완료된 결과를 확인할 수 있습니다. 이를 확인하고 배포된 EC2의 ip로 API를 테스트 해보면 정상적으로 변경 사항이 반영된 것을 확인할 수도 있습니다.
효율적인 개발 작업을 위해 초반에 여러 레퍼런스를 참고하여 CICD를 세팅하였으나, 해당 프로젝트에서는 prisma를 사용하는 차별점이 있어서 deploy.yml 파일을 잘못 작성하여 CD TEST를 계속 실패하였습니다. prisma를 사용할 경우에는 deploy.yml 파일에서 ./prisma 파일을 추가해주고, 추가적으로 pakage.json 파일에서 script에
"postinstall": "prisma generate",
위 내용을 추가해주세요. npx prisma generate 과정이 필요합니다. DB의 변경으로 삽질을 경험하면서 기록 겸 공유로 포스팅을 작성하였습니다.
References