Spring Boot로 GitHub Actions 기반 CI/CD 구축하며 마주한 문제와 해결 과정

송현진·2025년 3월 29일
0

Spring Boot

목록 보기
1/23

CI -> CD -> CI/CD 통합

초기에는 배포까지는 고려하지 않고 CI만 구현한 상태로, 빌드는 잘 작동하고 있었다.
하지만 기능이 하나둘 늘어나며 EC2에 직접 배포가 필요해졌고, 기존 CI는 그대로 두고 CD workflow만 별도로 새로 작성했다.

그러나 .jar 파일을 전송하고 EC2에서 실행하는 과정에서 여러 문제가 발생했다. 특히 GitHub Actions가 EC2에 SSH로 접속한 뒤 애플리케이션을 실행시키면, 세션 종료와 동시에 Spring Boot 앱도 같이 종료되는 문제가 있었다.

이 문제를 해결하기 위해 CI와 CD를 하나의 workflow로 통합했고, GitHub Actions는 단순히 실행 명령만 전달하고, 실행 책임은 EC2 내부의 start.sh 스크립트로 위임하는 방식으로 구조를 안정화시켰다.

문제 상황 및 해결

상황 1: scp 전송 시 호스트 인증 문제

처음 scp 명령어로 .jar 파일을 EC2에 전송할 때,
다음과 같은 메시지와 함께 GitHub Actions가 멈추거나 실패하는 문제가 발생했다.

Host key verification failed.

이는 GitHub Actions가 EC2에 처음 접속할 때 ~/.ssh/known_hosts에 등록된 호스트 키가 없어서 인증을 거부한 것이다.

해결

이를 해결하기 위해 scp 명령에 다음 옵션을 추가했다

-o StrictHostKeyChecking=no

이 옵션은 처음 연결 시 자동으로 호스트 키를 수락하고 진행하도록 설정하는 것으로, CI/CD 환경처럼 자동화된 환경에서는 보안 리스크를 감수하고라도 실용적인 해결책이 된다.

이 설정을 통해 GitHub Actions에서 scp가 매번 사용자 확인 없이 EC2로 파일을 안전하게 전송할 수 있게 되었다.

상황 2: GitHub Actions 세션 종료 시 앱도 종료되는 문제

GitHub Actions에서 EC2로 SSH 접속 후 아래처럼 앱을 백그라운드로 실행시켰다.

script: |
  nohup java -jar ... > app.log 2>&1 &

하지만 결과는 다음과 같이 세션 종료와 함께 프로세스도 죽었다.

Process exited with status 143 from signal TERM

해결

이 문제는 단순히 nohup, disown, setsid로는 해결되지 않았다. 결국 실행을 EC2 내부에서 처리하도록 구조 자체를 바꿨다.

  • EC2 내부에 /home/ec2-user/start.sh 스크립트를 작성
  • 기존 프로세스가 켜져 있을 수 있으므로 pkill로 먼저 종료 처리
  • nohup + java -jar + application.yml 실행을 EC2에서 수행
  • GitHub Actions에서는 단순히 start.sh만 호출

start.sh 생성
nano /home/ec2-user/start.sh 후 작성
Ctrl + O 저장, Ctrl + W 종료

#!/bin/bash
pkill -f 'java -jar' || echo "No app running"
nohup java -jar /home/ec2-user/coupangclone-0.0.1-SNAPSHOT.jar \
  --spring.config.location=file:/home/ec2-user/application.yml > /home/ec2-user/app.log 2>&1 &

상황 3: MySQL 사용자 권한 부족으로 앱 실행 실패

Spring Boot에서 MySQL에 연결은 되었지만, 테이블 생성이나 쿼리 실행 시 다음과 같은 에러가 발생했다.

Access denied; you need (at least one of) the RELOAD privilege(s)

이는 Spring Boot 앱에서 사용하는 DB 계정에 권한이 부족한 것이 원인이었다.

해결

MySQL root 계정으로 접속 후, 해당 사용자에게 필요한 권한을 부여했다.

mysql -u root -p

비밀번호를 입력하고 mysql> 프롬프트가 나타나면 정상 접속된 것이다.

GRANT ALL PRIVILEGES ON <schema>.* TO '사용자'@'%' IDENTIFIED BY '비밀번호';
FLUSH PRIVILEGES;

이후 아래 명령어로 권한이 정상적으로 부여되었는지 확인한다.

SHOW GRANTS FOR '사용자'@'%';

또한 JDBC URL에 아래 옵션을 추가해 인증 에러도 함께 해결했다.

spring:
  datasource:
    url: jdbc:mysql://<host>:3306/<schema>?allowPublicKeyRetrieval=true&useSSL=false

allowPublicKeyRetrieval=trueuseSSL=false는 MySQL 8 이상에서 인증 오류를 방지하는 옵션이다.

📁 최종 통합된 ci-cd.yml 코드

📝 배운점

  • GitHub Actions에서 SSH 세션이 닫히면 백그라운드 실행도 함께 종료될 수 있다
  • 자동화 환경에서는 scp나 ssh 시 사용자 확인을 회피할 수 있는 옵션이 필요
  • 실행을 EC2에 위임하는 구조가 훨씬 안정적이다
  • 문제 발생 시 tail, ps, scp -v, 로그 추적 등 디버깅 습관이 핵심이다
  • application.yml 같은 민감 정보는 GitHub Secrets + Base64 인코딩 방식으로 안전하게 처리 가능
  • MySQL 계정은 최소한의 권한 이상이 필요하며, Spring Boot 실행 전 DB 사용자에게 충분한 권한을 부여해야 한다
profile
개발자가 되고 싶은 취준생

0개의 댓글