[CI/CD] Jenkins + GitHub Actions + EC2 자동 배포 구축

Yoon Soojeong·2025년 12월 3일

00. CI/CD

  1. CI(Continuous Integration) : 지속적 통합, 개발자들이 작성한 코드를 자주 통합하는 프로세스, 통합 과정에서 발생하는 문제를 조기에 발견할 수 있다.
  2. CD(Continuous Deployment) : 지속적 배포, 빌드 및 테스트에 통과한 코드를 자동으로 프로덕션 환경에 배포, 빠른 피드백 루프가 가능하다.
  • 일반적인 CI/CD 파이프라인
코드 작성 → Git Push → 자동 빌드 → 자동 테스트 → 배포 → 모니터링
    ↓                      ↓             ↓           ↓        ↓
  개발자              CI 서버        테스트 통과    EC2 서버   로그/알림
  • 나는 Jenkins와 Gihub Actions를 이용해서 다음과 같은 흐름으로 진행했다.
  • 전체 동작 흐름
  1. 로컬에서 소스코드 수정 -> Github main 브랜치에 push

  2. Jenkins가 Poll SCM으로 감지 / Github Actions가 이벤트 감지

  3. Gitbhub Actions에서 빌드 후 JAR + 스크립트 EC2로 전송

  4. start.sh 실행 -> 이전 버전 종료 + 새 버전 실행

  5. 브라우저에서 EC2 Public IP:8080 접근!

    -> 도커로 컨테이너를 띄우고, 인스턴스 생성까지 다시 해보았다.

+ EC2 보안 그룹에서 포트 개방


Spring Boot 기본 포트는 8080이므로
EC2 인바운드 규칙에 TCP 8080, 소스 0.0.0.0/0을 혀용해야 브라우저로 접근할 수 있다.

01. Jenkins에서 gradlew 권한 설정하기


  1. gradlew 파일(Gradle Wrapper)을 실행 가능한 프로그램으로 바꿔서 Jenkins가 실행할 수 있도록 권한을 주는 작업.
    gradlew = Gradle을 다운로드하고 실행하도록 도와주는 스크립트.
    로컬에서는 권한이 있지만 Jenkins 서버는 새로 clone한 파일이기 때문에 실행권한이 없다!
    그래서 첫 단계로 실행 권한 부여를 해주는 것...
  2. Tasks = clean build -x test
    -> Jenkins가 gradlew에게 어떤 작업을 하라고 지시하는 부분
    = clean(이전 빌드 결과 폴더 삭제) build(프로젝트 전체 빌드) -x test(테스트 코드 실행을 제외-처음 연결할때는 테스트 코드가 실패해서 빌드가 실패하는 것을 피하기 위해!)

01. 젠킨스 Poll SCM vs Github Actions 트리거 구조 비교

CI/CD에서 배포 자동 실행 시점이 어떻게 결정되는지는 굉장히 중요한 개념이다.
내가 직접 겪으면서 이해한 것들을 요약해본다.

  • Jenkins -> Poll SCM 방식
    Github에 변화가 생겼는지 일정 주기로 감시(Polling)하는 방식이다.
H/2 * * * *

- cron 스케줄
- 2분마다 Github repo의 상태를 확인한다.
+ Jenkins에서 H/2의 의미 :
H는 Jenkins가 job을 여러개 균등으로 분배하기 위해 사용하는 해시기반 랜덤시드!
/2는 2분마다 실행
-> Jenkins가 정한 특정 2분 간격
- 변경 사항이 있으면 build, 없으면 그냥 종료!
- githib Webhook 설정 없이도 동작하지만 딜레이가 생기고 서버가 Github에 접속해야하므로 트래픽이 낭비된다...

  • Github Actioins -> push 이벤트 기반(Webhook 방식)
    Github 서버가 이벤트를 생성하고 스스로 Actions를 유발(트리거)함.
    즉,

    Github이 먼저 "변경됐어~! 실행해라!" 라고 알려주는 방식!
    - 즉각 실행되고 Github 서버가 직접 이벤트를 발송하여 안정적이고 polling이 불필요하여 트래픽 낭비가 없다.
    - 단순한 설정

on:
  push:
    branches: [ "main" ]
-> main에 푸시되자마자 자동 빌드 + 배포
-> Actions에서 한 실제 작업 흐름
1. 코드 checkout
2. JDK 21 환경 구성
3. Gradle 빌드
4. start.sh를 EC2로 업로드
5. JAR 업로드
6. SSH 접속해서 start.sh 실행 -> 배포

02. 막혔던 부분

  1. EC2 app.log에서 다음과 같은 에러를 확인하였다.
nohup: failed to run command '/usr/bin/java': No such file or directory
  • 원인 : 인스턴스를 다시 생성하여 EC2에 자바를 설치하는걸 잊었다...
    기존 인스턴스를 삭제하고 새 인스턴스를 생성한 경우 새 환경에는 java가 기본 설치되어 있지 않기 때문에
sudo dnf install java-21-amazon-corretto.x86_64 -y
java -version 
  • 해결 : java 21 설치 후 버전까지 확인!
  1. 잘못된 jar 이름 실행

    start.sh = EC2에서 돌아가는 애플리케이션을 종료하고 새 버전으로 다시 실행하는 스크립트.

여기서 처음에 jar 이름이 잘못되어... 수정해주었다.

pkill -f bitcoinlion-0.0.1-SNAPSHOT.jar || echo "No app running"  #이전 버전 종료
sleep 15 #안전하게 종료 대기
nohup /usr/bin/java -jar /home/ec2-user/bitcoinlion-0.0.1-SNAPSHOT.jar > /home/ec2-user/app.log 2>&1 &   #새 버전 실행 + 백그라운드 실행, /home/ec2-user/app.log 기록

-> 깃 푸시 -> Jenkins 자동 빌드 -> EC2 성공 실행

0개의 댓글