일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- foreach
- reflection
- Locking Read
- MySQL
- iterator
- MVCC
- Lock
- gc
- Di
- Atomic Type
- 자바
- 스프링
- 가비지 컬렉터
- Varchar
- CAS
- text
- java
- Synchronized
- iterable
- db
- 백엔드
- 동시성
- jpa
- 데이터 타입
- 가비지 컬렉션
- 동시성 문제
- Today
- Total
과정을 즐기자
팀 프로젝트를 위한 github actions CI/CD 세팅 본문
프로젝트를 진행하면서 서비스를 배포하는 방법에는 여러 가지가 있습니다.
먼저 단순한 방법으로는 내 로컬 PC에서 프로젝트를 빌드하여 scp 명령어로 운영 서버로 파일을 전송하고 서버에 들어가서 해당 파일을
실행 시키는 방법이 있습니다. 하지만 매번 이러한 과정을 수행하는 것은 굉장히 번거로운 작업입니다.
이를 개선하기 위해서 운영 서버에서 github에 있는 코드를 가져와서 프로젝트를 빌드하고 프로젝트를 실행하도록 하는
쉘 스크립트를 작성할 수도 있습니다.
하지만 이러한 경우도 여전히 단점이 존재합니다. 우선 개발자가 운영 서버에 직접 접속하여 쉘 스크립트를 실행해야 합니다.
또한 운영 서버에서 프로젝트를 빌드하기 때문에 운영 서버의 리소스를 낭비할 수 있다는 단점도 있습니다.
이러한 단점들은 개발자가 많아질 수록 서버가 많아질 수록 더욱 커질 수 있습니다.
📚 CI/CD가 뭔데?
위와 같은 단점들을 개선하기 위해서 CI/CD를 구축해볼 수 있습니다. 그렇다면 CI/CD란 무엇일까요?
CI(Continuous Integration)는 지속적 통합이라는 말입니다. 여기서의 통합이라는 의미는 단순히 github에 코드를 통합한다는 의미는
아닙니다. 여기서의 통합은 테스트를 모두 통과하여 빌드된 프로젝트가 유지된다는 의미입니다.
CD(Continuous Deployment)는 지속적 배포라는 말입니다. CI 프로세스를 통과한 프로젝트를 배포하는 것을 말합니다.
📘 그래서 왜 쓰는데?
이전의 단점들을 바탕으로 CI/CD 사용 이유에 대해 생각해보겠습니다.
1. 빌드하는 환경을 통일할 수 있다.
만약 각자의 로컬 PC에서 프로젝트를 빌드하고 운영 서버로 전송한다면 배포마다 빌드하는 환경이 달라 문제가 발생할 수도 있습니다.
2. 직접 서버에 들어가지 않고도 배포할 수 있다.
배포 과정을 단순화하기 위해 쉘 스크립트를 만든다고 하더라도 쉘 스크립트를 실행하기 위해 직접 서버로 들어가야 하는데
이 과정을 반복하면 굉장히 번거로울 수 있습니다.
3. 운영 서버의 리소스를 사용하지 않고 빌드할 수 있다.
로컬 PC에서 빌드하고 운영 서버로 전송하지 않고 환경을 통일하기 위해 직접 운영 서버에서 빌드를 한다면
그 빌드 과정에서 이는 서버의 비즈니스 관련 트래픽을 처리할 리소스를 사용하게 됩니다.
따라서 CI/CD를 구축하여 배포 과정을 자동화하면 함께 개발하는 개발자들의 실수를 줄여주고 편의성을 줍니다.
이는 개발자가 많아질 수록 서버가 많아질 수록 장점이 더 커집니다.
📙 Github Actions
저는 이번 프로젝트를 하면서 CI/CD를 위한 툴로 github actions를 선택했습니다.
보통 JVM 계열의 프로젝트를 진행한다면 Jenkins를 가장 많이 사용하지만 github과 연동하여 가장 단순하게 적용할 수 있는 툴이
github actions이기 때문에 선택하였습니다. 또한 github actions의 가장 큰 단점이 비용 문제일 수 있는데 public으로 생성한
프로젝트라면 비용이 발생하지 않기 때문에 이번 프로젝트에서는 문제가 되지 않았습니다.
📗 적용 해보자
우선 아래와 같이 github repo에 들어가서 Actions를 클릭해줍니다.
Actions에 들어가서 New workflow를 클릭해줍니다.
저는 Gradle을 이용하여 빌드를 하였기 때문에 Java With Gradle을 선택하였습니다.
선택을 하면 repo에서 /.github/workflows 아래에 yml 파일을 생성할 수 있습니다.
저는 yml 파일로 백엔드 애플리케이션 빌드를 위한 backend-build.yml과 배포를 위한 backend-deploy.yml 2가지를 생성했습니다.
backend-build.yml
먼저 전체 yml 설정은 다음과 같습니다.
전체 과정을 요약해보면 우분투 가상 환경에서 JDK 17을 설정하고, Gradle를 활용해 백엔드 프로젝트를 빌드한 후 생성된
jar 파일을 SSH를 통해 서버로 전송합니다.
name: Backend Build with Gradle
on:
pull_request:
branches: [ "main", "backend-main" ]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Github Repository 파일 불러오기
uses: actions/checkout@v4
- name: JDK 17버전 설치
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: application yml 파일 설정
run: |
mkdir -p src/main/resources
mkdir -p src/test/resources
echo "${{ secrets.MAIN_APPLICATION_YML }}" > src/main/resources/application.yml
echo "${{ secrets.MAIN_APPLICATION_DEV_YML }}" > src/main/resources/application-dev.yml
echo "${{ secrets.MAIN_APPLICATION_PROD_YML }}" > src/main/resources/application-prod.yml
echo "${{ secrets.TEST_APPLICATION_YML }}" > src/test/resources/application.yml
echo "${{ secrets.TEST_APPLICATION_TEST_YML }}" > src/test/resources/application-test.yml
working-directory: backend
- name: 테스트 및 빌드
run: ./gradlew clean build
working-directory: backend
- name: 빌드된 파일 이름 변경
run: mv ./build/libs/*.jar ./moim-today.jar
working-directory: backend
- name: SCP로 EC2에 빌드된 파일 전송하기
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.BE_SERVER_IP }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: backend/moim-today.jar
target: /home/ubuntu/deploy/tobe
실행 조건
- main 또는 backend-main 브랜치에 풀 리퀘스트가 생성될 때
- 수동으로 워크플로를 실행할 때 (workflow_dispatch)
작업(Job)
- 운영 환경: ubuntu-latest 이미지
- 단계(Steps):
- GitHub Repository 파일 불러오기:
- actions/checkout@v4 액션을 사용하여 현재 리포지토리의 파일을 체크아웃합니다.
- JDK 17버전 설치:
- actions/setup-java@v4 액션을 사용하여 Temurin JDK 17을 설치합니다.
- application.yml 파일 설정:
- backend 디렉터리 내에 필요한 application.yml 파일들을 생성합니다.
- MAIN_APPLICATION_YML, MAIN_APPLICATION_DEV_YML, MAIN_APPLICATION_PROD_YML, TEST_APPLICATION_YML, TEST_APPLICATION_TEST_YML과 같은 시크릿 변수를 사용하여 해당 내용을 파일에 기록합니다. (민감한 정보가 유출되지 않도록)
- 테스트 및 빌드:
- backend 디렉터리에서 ./gradlew clean build 명령을 실행하여 Gradle 빌드를 수행합니다.
- 빌드된 파일 이름 변경:
- backend/build/libs 디렉터리에 있는 빌드된 JAR 파일을 moim-today.jar로 이름을 변경합니다.
- SCP로 EC2에 빌드된 파일 전송하기:
- appleboy/scp-action@v0.1.7 액션을 사용하여 빌드된 JAR 파일을 EC2 서버로 전송합니다.
- 이 때 사용되는 정보는 시크릿 변수로 제공됩니다: BE_SERVER_IP, SSH_USER, SSH_PRIVATE_KEY
- 파일은 /home/ubuntu/deploy/tobe 디렉터리에 전송됩니다.
- GitHub Repository 파일 불러오기:
backend-deploy.yml
name: Deploy Backend Application
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: SSH로 EC2에 접속하여 배포하기
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.BE_SERVER_IP }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script_stop: true
script: |
rm -rf /home/ubuntu/deploy/current
mkdir /home/ubuntu/deploy/current
cp /home/ubuntu/deploy/tobe/backend/moim-today.jar /home/ubuntu/deploy/current/moim-today.jar
cd /home/ubuntu/deploy/current
sudo fuser -k -n tcp 8080 || true
nohup java -jar moim-today.jar > /dev/null 2>&1 &
실행 조건
- 수동으로 워크플로를 실행할 때 (workflow_dispatch)
작업(Job)
- 운영 환경: ubuntu-latest 이미지
- 단계(Steps):
- SSH로 EC2에 접속하여 배포하기:
- appleboy/ssh-action@v1.0.3 액션을 사용하여 EC2 서버에 SSH로 접속합니다.
- 접속에 필요한 정보는 시크릿 변수로 제공됩니다: BE_SERVER_IP, SSH_USER, SSH_PRIVATE_KEY
- script_stop: true 옵션을 사용하여 스크립트 실행 중 오류가 발생하면 작업을 중지합니다.
- 다음 명령들을 실행하는 스크립트를 수행합니다:
- /home/ubuntu/deploy/current 디렉터리를 삭제합니다.
- 새로운 /home/ubuntu/deploy/current 디렉터리를 생성합니다.
- /home/ubuntu/deploy/tobe/backend 디렉터리에 있는 moim-today.jar 파일을 current 디렉터리로 복사합니다.
- current 디렉터리로 이동합니다.
- 현재 8080 포트를 사용 중인 프로세스를 종료합니다.
- moim-today.jar 파일을 백그라운드에서 실행합니다.
(로그는 /dev/null로 리다이렉트하여 출력하지 않고 따로 로그 파일로 관리)
- SSH로 EC2에 접속하여 배포하기:
🌟 정리
먼저 프로젝트의 배포 방식과 CI/CD가 필요한 이유에 대해 알아보았습니다. CI/CD는 개발자들에게 실수할 확률을 줄여주고
편의성을 제공합니다. 이번 프로젝트에서는 github actions를 이용하여 CI/CD를 적용 하였습니다.
이제 github에 main, backend-main에 push 하거나 pr을 날리게 되면 테스트가 통과할 때만 통일된 환경에서
프로젝트를 빌드하여 유지할 수 있습니다. 또한 서버에 접속하지 않더라도 github에서 해당 워크 플로우들을 실행하여
배포를 진행할 수 있습니다.
참고한 자료
'DevOps' 카테고리의 다른 글
EC2에 Nginx 구성하여 도메인, Https 적용하기 (0) | 2023.05.29 |
---|---|
가상 메모리를 사용하여 서버의 부족한 RAM 해결하기 (0) | 2023.05.11 |