이번에는 urdego 백엔드 서비스들의 CI&CD 를 위한 깃허브 액션 도입에 대해 다뤄 볼려 합니다
도입 계기
- urdego 프로젝트는 여러개의 마이크로서비스 (User, Content, Game, 등) 으로 구성되어있어 각 서비스의 코드 변경 시마다 수동으로 빌드, 테스트, 배포를 진행하기에는 무리가 있었다.
- 다수의 팀원이 협업하는 환경에서는 코드 병합시 의도치 않은 오류가 발생하거나 환경별 종속성으로 인한 문제가 드러나기도 하기에 코드 변경 사항에 대해 자동으로 빌드와 테스트를 실행하고 배포까지 자동화하는 도구가 필요했는데 Github Actions를 선택했다.
Self-hosted ??
- urdego는 이미 AWS의 EC2 비용이 부담스러워 홈서버로 구축했기에 Github Actions의 퍼블릭 클라우드 Runner를 사용하기보다 자체 인프라에서 구동되는 Self-hosted Runner를 통해 비용 효율성과 urdego 조직에 맞는 CI/CD를 구축하고자 했다.
구축방법
2가지 방법으로 나뉜다. 조직 단위( Organization Level ) vs 레포지토리 단위 (Repository Level)
조직 단위는 urdego조직안에서 사용할 수 있는 Runner를 설정하여 각 레포지토리는 이 Runner를 사용하도록 정의하는 것이고 레포지토리 단위는 해당 레포지토리에 사용되는 Runner를 생성하여 사용하는 방식이다.
전체적으로 백엔드 애플리케이션들은 urdego 조직안에서 마이크로서비스별로 레포지토리가 나누어져 있는 상태라서 개별 레포지토리 마다 Runner를 생성하는것은 자동화하는 과정조차도 비효율적이기에 조직에서 하나의 Runner를 생성해서 이를 각 레포지토리에서 사용할 수 있도록 조직 단위 Runner 생성을 선택했다.
조직 단위( Organization Level )
조직 Settings -> Actions -> Runners 에서 Self-hosted 러너를 생성
urdego 서버의 스펙에 맞게 리눅스와 x64를 선택했다.
서버에서 해당 명령어들을 차례대로 실행하고
./run.sh 대신 깃허브 액션이 백그라운드에서 실행되도록 서비스로 돌려줘야한다.
sudo systemctl status actions.runner.<조직이름>.<러너이름>.service
를 사용하여 서비스로 돌아가는지 확인해보면
잘 돌아가고 있는 모습을 확인!
이제 먼저 CI를 구축해보자
urdego 조직의 Content_Service 먼저 올려보려한다.
name: Spring Boot & Gradle CI Jobs (With dev branches pull_request)
on:
pull_request:
branches: [ dev ]
paths:
- 'src/**'
jobs:
build:
# 실행 환경
runs-on: [self-hosted, urdego]
steps:
- uses: actions/checkout@v3
# JDK 설정
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
# resources 폴더 생성
- name: resources 폴더 생성
run: |
mkdir -p ./src/main/resources
# yml 파일 생성
- name: yml 파일 생성
run: |
echo "${{ secrets.CONTENT_APPLICATION_DEFAULT }}" >> ./src/main/resources/application.yml
echo "${{ secrets.CONTENT_APPLICATION_PROD }}" >> ./src/main/resources/application-prod.yml
echo "${{ secrets.CONTENT_APPLICATION_DB }}" >> ./src/main/resources/database-prod.yml
# gradlew 실행 권한 부여
- name: Gradlew 실행권한 부여
run: chmod +x ./gradlew
# 빌드
- name: 빌드
run: ./gradlew clean build -x test
해당 CI_dev_be_pull_request.yml 파일을 ./github/workflow/ 위치에 놓아야 깃액션을 실행할 수 있다.
(application.yml 들은 깃허브 Secrets and variables 의 Actions에 정의해두어야한다.)
우선 트리거는 dev 브랜치로 pr 생성시로 해놓았고 src/**로 코드 변경이 있을때만 실행되도록 설정했다.
Jobs 에서 self-hosted중 urdego 라벨이 있는 urdego 러너를 선택하도록 설정했다. (아래 사진첨부)
해당 액션이 돌아가고 서버에서 확인해보면
빌드가 성공하고 _work 폴더에 Urdego_Content_Service가 생긴모습이다.
/home/jra1n/urdego/actions-runner/_work/Urdego_Content_Service/Urdego_Content_Service/ 경로를 보면
컨텐츠 서비스의 어플리케이션이 빌드되어 있는것을 볼 수 있다.
이제 이것을 통해 CD 작업을 진행해주면 되는것!
name: Spring Boot & Gradle CICD Jobs (With. dev branches push)
on:
push:
branches: [ dev ]
paths:
- 'src/**'
jobs:
build:
# 실행 환경 (urdego 서버)
runs-on: [self-hosted, urdego]
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
# application.yml 파일 설정
- name: resources 폴더 생성
run: |
mkdir -p ./src/main/resources
# yml 파일 생성
- name: yml 파일 생성
run: |
echo "${{ secrets.CONTENT_APPLICATION_DEFAULT }}" >> ./src/main/resources/application.yml
echo "${{ secrets.CONTENT_APPLICATION_PROD }}" >> ./src/main/resources/application-prod.yml
echo "${{ secrets.CONTENT_APPLICATION_DB }}" >> ./src/main/resources/database-prod.yml
# gradlew 실행 권한 부여
- name: Gradlew 실행권한 부여
run: chmod +x ./gradlew
- name: 빌드 (테스트 미포함)
run: ./gradlew clean build -x test
deploy:
# Docker 배포 작업
name: docker deployment
needs: build # deponeds on
runs-on: [self-hosted, urdego]
steps:
- name: docker-compose 생성
run: |
echo "${{ secrets.DOCKER_COMPOSE_CONTENT }}" >> ./docker-compose.yml
# 도커 컨테이너 중지 및 이미지 제거
- name: 도커 컴포즈 다운 및 이미지 제거
run: |
docker-compose down
# 특정 이미지 제거
docker rmi $(docker images --format "{{.Repository}}:{{.Tag}}" | grep 'content_service:latest') || echo "No content_service image to remove"
# 도커 컴포즈 실행
- name: 도커 컴포즈 실행
run: |
docker-compose up -d
이번엔 CI를 통한 CD작업을 진행하는 actions 파일인데 위와 다른점은
우선 트리거가 dev브랜치 pr -> push 로 변경되었다. 즉, pr을 생성후 merge시에 배포되도록 설정한다.
마찬가지로 빌드를 진행한후 작성해둔 docker-compose.yml 을 통해 서버에서 실행되도록 해준다.
version: '3.8'
services:
content_service:
build:
context: /home/jra1n/urdego/actions-runner/_work/Urdego_Content_Service/Urdego_Content_Service/
dockerfile: Dockerfile-dev
image: content_service
container_name: content_service
restart: unless-stopped
volumes:
- /urdego/user/content:/urdego/user/content
depends_on:
- mysql_content
environment:
- PROFILE=prod
ports:
- '8081:8081'
mysql_content:
image: mysql:8.0.32
container_name: mysql_content
restart: unless-stopped
ports:
- '3307:3306'
volumes:
- /home/jra1n/urdego/docker-compose/dev/content/volumes/mysql_content:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=##비밀
- MYSQL_DATABASE=content
networks:
urdego-network:
driver: bridge
pull_request 를 merge시에 Actions가 실행된다.
빌드후 어플리케이션 띄우기까지 40초도 안걸린다 후후
해당 컨텐츠 서비스가 서버에 올라간 모습
이제 나머지 유저서비스, 게임서비스, 게이트웨이, 디스커버리 (+ nginx 설정 추가) 까지 구축 시작..!
이후 결과물
다음에는 로깅, 트레이싱, 모니터링 달아보자
'Project > 어데고 (urdego)' 카테고리의 다른 글
[TensorFlow - NSFW] 부적절한 컨텐츠 감지 (0) | 2025.02.18 |
---|---|
[홈서버 구축] Public Cloud(AWS) -> On-premise(홈서버) 구축 전환 (1) | 2024.12.18 |
댓글