Spring Boot 프로젝트를 Docker와 Github Actions를 사용하여 EC2 서버에 자동으로 배포하는 과정입니다.
CI/CD 구축은 기존 수동 배포 방식을 자동화하여, 코드 변경 시마다 매번 서버에 직접 접속해 작업하는 불편함을 줄이고 배포 속도를 높일 수 있습니다.
기존 배포 방법의 문제점
기존에는 CI/CD를 구축하지 않고, 수동으로 Spring Boot 프로젝트를 빌드한 후, jar 파일을 EC2에 FileZilla 를 이용하여 전송한 다음 java -jar 명령어를 통해 애플리케이션을 실행했습니다.
nohup java -jar Tiing-BE-0.0.1-SNAPSHOT.jar &
기존 배포 방법
1. Spring Boot 프로젝트를 로컬에서 빌드하여 .jar 파일 생성
2. EC2 서버로 파일을 전송 (FileZilla 사용)
3. EC2에서 java -jar 명령으로 서버 실행
해당 과정은 코드 수정이 빈번할 때마다 매번 EC2에 접속하여 동일한 작업을 반복해야 했기 때문에 매우 비효율적이었습니다. CI/CD 구축은 이러한 수동 배포를 자동화하여 개발 생산성을 크게 높이는 중요한 역할을 합니다.
Github Actions와 Docker를 활용한 CI/CD의 장점
GitHub Actions를 통해 CI를 구현하여 코드를 푸시하거나 PR이 생성될 때마다 Spring Boot 프로젝트가 자동으로 빌드되고 테스트됩니다. 이렇게 하면 코드가 변경될 때마다 테스트가 수행되어 코드의 품질을 보장할 수 있습니다.
• 자동화: 코드가 변경되면 Github Actions가 빌드, 테스트, 배포 과정을 자동으로 처리합니다.
• Docker 이미지: 프로젝트를 Docker 이미지로 만들면 서버 환경에 영향을 받지 않고 일관된 실행 환경을 제공합니다.
• 편리성: Github Actions를 사용하여 Jenkins 같은 외부 CI 서버를 구성할 필요 없이 Github 내에서 모든 작업을 처리할 수 있습니다.
배포 환경
- Java 17
- Gradle
- EC2: Ubuntu 22.04 (프리티어)
- Docker & Docker Hub
- 로컬 PC: M1 Mac OS
- Spring Boot 2.6.2
1. Dockerfile 생성 및 설정
먼저, Spring Boot 프로젝트를 Docker로 실행할 수 있도록 Dockerfile을 생성합니다. Dockerfile은 프로젝트를 Docker 이미지로 빌드하는 과정을 정의합니다. Spring Boot 애플리케이션을 Docker 컨테이너로 실행할 수 있게 만듭니다.
# 1. OpenJDK 17 이미지를 사용하여 기반 이미지로 설정
FROM openjdk:17
# 2. ARG로 JAR 파일의 경로를 지정 (Gradle 빌드 결과물)
ARG JAR_FILE=build/libs/*.jar
# 3. JAR 파일을 Docker 이미지의 app.jar로 복사
COPY ${JAR_FILE} app.jar
# 4. 애플리케이션을 실행하는 명령어
ENTRYPOINT ["java", "-jar", "/app.jar"]
2. Github Actions workflow 파일 작성
Github Actions는 코드 변경이 발생할 때마다 자동으로 CI/CD 파이프라인을 실행하도록 설정할 수 있습니다.
.github/workflows/gradle.yml 파일을 생성하고 다음 내용을 추가합니다.
이 파일은 CI/CD 파이프라인을 정의하며, 다음 작업을 자동화합니다:
• Spring Boot 프로젝트 빌드
• Docker 이미지 빌드: Spring Boot 프로젝트를 Docker 이미지로 빌드합니다.
• DockerHub로 Push: 빌드한 이미지를 DockerHub에 업로드합니다.
• EC2에서 이미지 Pull: DockerHub에서 이미지를 EC2로 가져와서 실행합니다.
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0
- name: Build with Gradle Wrapper
run: ./gradlew build
- name: Build without Cache
run: ./gradlew clean build --no-build-cache
dependency-submission:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0
3. GitHub Secrets 설정
GitHub Actions에서 민감한 정보를 다룰 때는 GitHub Secrets를 활용하여 안전하게 관리합니다. secrets.DOCKERHUB_USERNAME, secrets.DOCKERHUB_PASSWORD, secrets.EC2_HOST, secrets.EC2_PRIVATE_KEY 등의 값은 GitHub 레포지토리 설정에서 Settings > Secrets and variables에서 설정할 수 있습니다.
1. DOCKER_USERNAME: Docker Hub의 사용자 이름
2. DOCKER_PASSWORD: Docker Hub의 비밀번호
3. EC2_HOST: 배포할 EC2 인스턴스의 퍼블릭 IP
4. EC2_PRIVATE_KEY: EC2에 접근할 수 있는 PEM 키
gradle.yml
name: Java CI with Gradle and Docker
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
- name: Build with Gradle Wrapper
run: ./gradlew bootJar
# Docker 이미지 Build
- name: Build Docker image
run: docker build -t ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test:latest .
# DockerHub Login (push 하기 위해)
- name: Docker Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# DockerHub에 Docker 이미지 Push
- name: Docker Hub Push
run: docker push ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test
# EC2에 Docker 이미지를 배포하는 단계
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Connect to EC2 and Pull Docker Image
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }} # EC2 인스턴스 퍼블릭 DNS
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }} # EC2 PEM 키
script: |
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test:latest
sudo docker stop $(sudo docker ps -q)
sudo docker run -d --name spring-cicd-test -p 80:8080 ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test:latest
sudo docker system prune -f
트러블 슈팅
EC2에 Docker가 설치되지 않은 경우
EC2 인스턴스에서 “docker: command not found” 오류가 발생하는 경우 EC2 인스턴스에 Docker를 설치해야 합니다. 아래 Docker 설치 명령어를 EC2에 입력하여 설치합니다.
sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
EC2 인스턴스에 Docker를 설치했더라도 GitHub Actions 워크플로우 내에서 해당 명령이 실행되지 않으면 동일한 오류가 발생할 수 있습니다. 아래와 같이 GitHub Actions 워크플로우에 Docker 설치 명령을 추가합니다.
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Connect to EC2 and Install Docker if not available
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }} # EC2 인스턴스 퍼블릭 DNS
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }} # EC2 PEM 키
script: |
sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker ubuntu
docker --version # Docker가 설치되었는지 확인
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test:latest
sudo docker stop $(sudo docker ps -q)
sudo docker run -d --name spring-cicd-test -p 80:8080 ${{ secrets.DOCKER_USERNAME }}/spring-cicd-test:latest
sudo docker system prune -f
위 과정을 통해 GitHub Actions와 Docker를 사용하여 Spring Boot 프로젝트를 EC2에 자동으로 배포할 수 있는 CI/CD 파이프라인을 구축했습니다.
'BackEnd > JAVA SPRING' 카테고리의 다른 글
[Spring Boot] Apache Kafka 연동 (0) | 2024.10.08 |
---|---|
[Kafka] Apache Kafka (3) | 2024.10.08 |