-
Notifications
You must be signed in to change notification settings - Fork 0
[BE] 생애 첫 CI CD 도전기
박경미 edited this page Dec 14, 2023
·
8 revisions
Micro 서버 사양
vCPU 메모리 디스크 1개 1GB 50GB 원래 NPC에서 1년 동안 무료로 사용할 수 있는 Micro (Classic) 서버로 배포를 진행했었다. GitHub Actions를 완벽하게 작성했는데, 계속 docker run에서 타임아웃 문제가 발생했다. 무수히 많은 GitHub Actions 휴먼 에러를 수정해왔고 더 이상 틀린 부분이 없다고 확신할 수 있었다. 따라서 이는 서버 성능 문제라고 판단, 아래에 작성할 standard 서버로 변경하였고, 배포에 성공했다.
-
VPC & Public Subnet
- 개발 용이성을 위해 Reverse Proxy, WAS, DB를 모두 public subnet에 올렸다.
- 특히 API 개발 시 CLI보다 가독성이 좋고 편리한 workbench로 DB에 접속하여 DB 내용을 그때그때 확인하고 수정해야 했다.
- 추후 DB를 private subnet으로 옮겨 WAS에서만 DB에 연결되도록 할 예정이다.
-
s2-g2-s50 Server (VPC)
vCPU 메모리 디스크 서버 이미지 2EA 8GB 50GB Ubuntu 20.04 - 월 88,000원! 메모리 8GB면 1.43GB 이미지를 충분히 실행시킬 수 있겠지~?
-
Ubuntu 서버에서 docker를 설치한다.
apt-get update apt install docker.io snap install docker docker --version # 설치 확인용
-
be-develop
와main
브랜치에 push 될 때마다 배포하고 싶다. - GitHub Repository를 도커 이미지로 생성하고 싶다.
- Ubuntu 서버에서 위에서 생성한 도커 이미지를 실행하고 싶다.
name: CD
on:
push:
branches: [be-develop, main]
- name: GitHub Actions 워크플로우 이름 설정
- on: 트리거 이벤트 지정
- push 이벤트 발생 시,
-
be-develop
또는main
브랜치로의 push인지 감지하여 워크플로우 실행
-
- push 이벤트 발생 시,
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout...
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.x
- jobs:
deploy
라는 job이 정의됨 - runs-on: deploy는
ubuntu-latest
환경에서 실행 - steps: job이 수행할 각 단계
- uses: GitHub Marketplace에 호스팅된 액션 참조 & 사용
- with: 액션 사용 시 필요한 추가 매개변수 설정
- name: Install package
run: |
cd BE
npm ci
- name: Docker Login
run: docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker
run: |
cd BE
docker build -f Dockerfile -t traveline/traveline-docker .
- name: Push Docker
run: |
cd BE
docker push traveline/traveline-docker:latest
-
name: Install package
- run: Install package에서 실행할 스크립트 정의
- 백엔드 개발 폴더인
BE
로 이동 및 필요한 모듈 설치
-
name: Docker Login
- Docker 아이디와 비밀번호를 통해 도커에 로그인
- 도커 아이디와 비밀번호는 GitHub Secrets에 등록해두었음
-
name: Build Docker
- 백엔드 서버를 도커로 띄울 것이므로, BE 폴더로 이동하여 빌드 →
traveline/traveline-docker
이미지 생성
- 백엔드 서버를 도커로 띄울 것이므로, BE 폴더로 이동하여 빌드 →
-
name: Push Docker
- BE 폴더에서 컨테이너를 생성하였으므로, 다시 BE 폴더로 이동하여 도커 이미지를 Docker Hub에 푸시
- name: SSH Login
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USERNAME }}
password: ${{ secrets.SERVER_PASSWORD }}
port: ${{ secrets.SERVER_PORT }}
script: |
docker login --username ${{ secrets.DOCKER_ID }} --password ${{ secrets.DOCKER_PASSWORD }}
docker pull traveline/traveline-docker
docker stop traveline-container || true
docker rm traveline-container || true
docker run -e DB_HOST=${{ secrets.DB_HOST }} -d -p ${{secrets.EXTERNAL_PORT}}:${{secrets.INTERNAL_PORT}} --name traveline-container traveline/traveline-docker
-
name: SSH Login
- GitHub Actions에서
appleboy/ssh-action@master
액션을 사용하여 원격 서버에 SSH 로그인 - SSH 접속을 위한 host, username, password, port 변수를 with로 제공
- docker에 로그인하여 Docker Hub에서 서버 이미지를 pull 해오고, 기존에 실행되고 있던 컨테이너를 멈추고 삭제한 후, 새 서버 이미지를 실행한다.
-
|| ture
은 해당 명령어가 실패하더라도 무시하고 계속 진행하라는 의미
-
- GitHub Actions에서
name: CD
on:
push:
branches: [be-develop, main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout...
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Install package
run: |
cd BE
npm ci
- name: Docker Login
run: docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker
run: |
cd BE
docker build -f Dockerfile -t traveline/traveline-docker .
- name: Push Docker
run: |
cd BE
docker push traveline/traveline-docker:latest
- name: SSH Login
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USERNAME }}
password: ${{ secrets.SERVER_PASSWORD }}
port: ${{ secrets.SERVER_PORT }}
script: |
docker login --username ${{ secrets.DOCKER_ID }} --password ${{ secrets.DOCKER_PASSWORD }}
docker pull traveline/traveline-docker
docker stop traveline-container || true
docker rm traveline-container || true
docker run -e DB_HOST=${{ secrets.DB_HOST }} -e DB_PORT=${{ secrets.DB_PORT }} -e DB_USER=${{ secrets.DB_USER }} -e DB_PASSWORD=${{ secrets.DB_PASSWORD }} -e DB_DATABASE=${{ secrets.DB_DATABASE }} -e NCP_ACCESS_KEY_ID=${{ secrets.NCP_ACCESS_KEY_ID }} -e NCP_SECRET_ACCESS_KEY=${{ secrets.NCP_SECRET_ACCESS_KEY }} -e NCP_REGION=${{ secrets.NCP_REGION }} -e JWT_SECRET_ACCESS=${{ secrets.JWT_SECRET_ACCESS }} -e JWT_SECRET_REFRESH=${{ secrets.JWT_SECRET_REFRESH }} -e CLIENT_ID=${{ secrets.CLIENT_ID }} -e TEAM_ID=${{ secrets.TEAM_ID }} -e KEY_ID=${{ secrets.KEY_ID }} -e AUTH_KEY_LINE1=${{ secrets.AUTH_KEY_LINE1 }} -e AUTH_KEY_LINE2=${{ secrets.AUTH_KEY_LINE2 }} -e AUTH_KEY_LINE3=${{ secrets.AUTH_KEY_LINE3 }} -e AUTH_KEY_LINE4=${{ secrets.AUTH_KEY_LINE4 }} -e KAKAO_REST_API_KEY=${{ secrets.KAKAO_REST_API_KEY }} -e X_NCP_APIGW_API_KEY_ID=${{ secrets.X_NCP_APIGW_API_KEY_ID }} -e X_NCP_APIGW_API_KEY=${{ secrets.X_NCP_APIGW_API_KEY }} -e AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }} -e AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }} -e AWS_REGION=${{ secrets.AWS_REGION }} -e GREENEYE_SECRET_KEY=${{ secrets.GREENEYE_SECRET_KEY }} -e GREENEYE_DOMAIN_ID=${{ secrets.GREENEYE_DOMAIN_ID }} -e GREENEYE_SIGNATURE=${{ secrets.GREENEYE_SIGNATURE }} -d -p ${{secrets.EXTERNAL_PORT}}:${{secrets.INTERNAL_PORT}} --name traveline-container traveline/traveline-docker
백엔드끼리 코어 타임 이후에, 10시까지 나머지 공부까지 해가며 성공한 배포라서 무척 값지다.
암튼 yml 파일로 배포에 성공했기 때문에, 앞으로도 계속 참고하면서 잘 해나갈 수 있을 것 같다~!