ㅎㅇ
안녕하세요, 스프링 레거시 환경에서 war 파일 was에 붙여 배포 어떻게 하냐는 문의가 많아 그냥 간단하게 정리해봅니다.
목표
아주 기본적인 ci-cd를 구축해보겠습니다.
vpc public subnet에 ec2를 올리고 ci-cd 작업까지 완료하는 걸 목표로 해보겠습니다. (public subnet은 아무나 접근 가능하기 때문에 보안상 좋지 않으니 추후 private으로 옮기는 것도 고려해보세요)
build.gradle 파일
우선 build.gradle 파일에 war 파일을 만드는 코드를 추가해줍시다.
plugins {
id 'java'
id 'war'
}
그냥 플러그인에 war 넣으면 돼요 간단하죠?
이제 도커 파일을 만들어봅시다
FROM tomcat:9.0.107-jdk17-temurin
# WAR 파일 복사
COPY build/libs/dolfin_back_log-1.0-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
EXPOSE 8080
저희 팀은 톰캣 9.0.107 버전을 쓰기 때문에 저렇게 정의해주었구요
로컬에서 프로젝트 실행하면 build 폴더에 war파일이 생성될 겁니다.
배포를 위해선 톰캣에 war파일을 붙여야하니, war파일의 경로를 저기 적어주시면 됩니다.
옆에 붙어있는 /usr/local 이 부분은 빌드할 때 생성된 war파일을 톰캣에 ROOT.war라는 이름으로 복사하는 겁니다.
도커로 간단하게 톰캣 만들고 war파일 붙이는 걸 해봤구요, 이제 이 도커 파일로 이미지 만들어서 도커 허브 레포지토리에 집어넣어야 합니다.
도커 허브 접속해서 레포지토리 만들기

이렇게 도커 허브 회원가입 하고 접속해서 바로 레포지토리 만들어 주고요
private으로 만들면 도커 허브 아이디랑 비밀번호 알고 있는 사람만 이미지 다운받을 수 있습니다.
보안을 위해서 private으로 하는 게 맞으나 설정 귀찮으신 분들은 그냥 public으로 하세요, 다만 레포 public이니까 다른 사람들 모르게 도커 허브 유저네임이랑 레포 이름은 숨겨야합니다.
여기선 public으로 작업할게요
aws ec2 만들기
이제 저희가 배포할 ec2를 만들어 줍시다.

아마존 리눅스 사용해줄게요
리눅스 기반으로 aws ec2 최적화 시켜서 만들어진 운영체제입니다 이거 쓰는 걸 추천 해여

키 만들어주세요, 서버 접속할 때 이 pem 키 사용해서만 접속 가능하게 제어할 수 있습니다.
저희 cicd 코드 작성할 때도 저 pem키 이용해서 접속할 거에요
언제든 사용할 수 있는 위치에 저장해두세요

보안 그룹은 방화벽입니다. 보안 그룹에서 들어오는 요청과 나가는 요청을 제어할 수 있어요

저는 private 서브넷에 배포했고 ssh만 열어뒀어요 어차피 로그만 발송하는 서버라서 요청 들어올 일도 없고 아웃 바운드만 9094 카프카랑 cloudwatch 발송 가능하게 열어줬습니다.
여러분은 여러분 상황에 맞게 방화벽 설정해주세요, 방화벽 설정 아직 잘 모르시겠으면 그냥 모든 트래픽 허용으로 해두셔도 됩니다. 다만 그렇게 하면 어디서든 접속할 수 있으니 우선 모든 트래픽으로 해두고 공부하시고 나서 다시 바꾸세요

EBS 볼륨 크기랑 종류 정하는건데 하드 디스크나 SSD 생각하시면 됩니다.
저는 로그만 쏠 거라 기본 모델에 15GB만 해줄게요
프리티어는 기본 모델에 30GB까지 이용가능합니다.

성공적으로 생성이 되었군요
이제 로그 서버에 접속해서 도커 컴포즈 파일과 환경변수 파일을 올려줄 것입니다.
SSH로 EC2 접속하기

이건 제 터널링 서버 퍼블릭 주손데 저는 프라이빗 서브넷에 배포해서 터널링해서 들어가야 되니까 터널링 서버 주소 복사한 거고
여러분은 그냥 퍼블릭 서브넷에 배포한 메인 서버 퍼블릭 주소 복사하시면 됩니다.

아까 다운 받았던 pem키 있죠? 그 디렉토리까지 이동하고 나서, 다음 명령어 입력해주세요
ssh -i [펨키 이름.pem] ec2-user@[public ip 주소]
처음 접속할 때는 뭐 막 뜰텐데 그냥 yes 입력하고 엔터 치면 접속할 수 있습니다.
그럼 위 사진처럼 접속 가능할 거구요 저는 프라이빗 서브넷으로 들어가야하니 한 번 더 ssh -i 해줄게요
EC2 서버 내부에서 밑 작업 해두기

우선 아무것도 없는 상태니까 저희가 작업할 폴더부터 mkdir로 만들어줍시다.
저는 dolfin-log로 폴더 만들었구요
vi 명령어로 docker compose 파일 만들어줄게여
version: '3.8'
services:
app:
image: [도커 허브 유저네임]/[아까 우리가 팠던 도커 허브 레포지토리 이름]
ports:
- "8080:8080"
env_file:
- ./dolfin-log.env
이거 넣어주시면 됩니다.
이미지는 본인에 맞게 수정해주시구요
밑은 저희가 프로젝트에서 사용할 환경변수 파일입니다. 이름 기억해두세요
이제 도커 컴포즈 파일이랑 동일한 위치에 환경변수 파일 만들겁니다.
똑같이 vi 명령어 써서 dolfin-log.env 파일 만들어 줍시다.
KAFKA_BROKER_SERVER=
AWS_ACCESS_KEY=
AWS_SECRET_KEY=
환경변수 파일은 그냥 이런식으로 여러분 application.properties에 쓸 ${AWS_ACCESS_KEY} 이름 똑같이 해서 값 넣어주시면 됩니다.
스프링에서 환경변수 주입 받을 때 우선순위가 application.properties 파일 보다 .env 파일이 우선순위가 더 높아서 저기에 작성한 환경변수가 우선적으로 들어가서 실행될 거에요

대충 뭐 ls 해서 환경변수 파일 잘 만들어졌나 확인 해봤구요 이제 도커 명령어 사용해야 되니까 도커랑 도커 컴포즈 다운받아 줍시다.
도커, 도커 컴포즈 다운
# 1. Docker 설치
sudo yum update -y
sudo amazon-linux-extras enable docker
sudo yum install -y docker
sudo service docker start
sudo usermod -aG docker ec2-user
# 2. Docker Compose V2 설치 (plugin 방식)
mkdir -p ~/.docker/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.27.1/docker-compose-linux-x86_64 \
-o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
그냥 이 명령어 실행하면 바로 다운됩니다.
이제 본격적으로 깃허브 액션을 통한 cicd 코드를 작성해봅시다.
CI-CD 코드

폴더 위치랑 폴더 명 주의해주세요, 저거 이름이랑 위치 들리면 깃허브 액션 실행 안 됩니다.
저 폴더 위치랑 이름 그대로 잘 입력했으면 깃허브 액션 바로 돌아갑니다.
name: Java CI/CD with Gradle
on:
push:
branches: [ "main" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Grant Execute Permission For Gradlew
run: chmod +x gradlew
- name: Gradle Caching
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build With Gradle
run: ./gradlew build -x test
- name: docker image build
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/dolfin-log .
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: docker Hub push
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/dolfin-log
deploy:
runs-on: ubuntu-latest
needs: build
if: github.event_name == 'push'
steps:
- name: Deploy to EC2 via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PEM_KEY }}
proxy_host: ${{ secrets.SSH_TUN_HOST }} # 퍼블릭 IP를 가진 중간 서버
proxy_username: ${{ secrets.SSH_USER }} # 터널링 서버의 사용자
proxy_key: ${{ secrets.SSH_PEM_KEY }}
port: 22
script: |
set -e
echo " [1] 아까 만든 dolfin-log 디렉토리로 이동"
cd ~/dolfin-log
echo " [2] 도커 이미지 pull"
docker pull ${{ secrets.DOCKERHUB_USERNAME }}/dolfin-log
echo " [3] 도커 컴포즈 재시작"
docker compose down
docker compose up -d
echo " 배포 완료"
ci-cd 코드 전체 복붙했는데 주의할 점 알려드릴게요
일단
- name: docker image build
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/dolfin-log .
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: docker Hub push
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/dolfin-log
이렇게 도커 이미지 사용하는 부분에 뒷 부분 보시면 dolfin-log 보일 겁니다. 저거 제 레포지토리 이름인데 여러분이 만든 레포 이름으로 바꿔주세요 전부다
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PEM_KEY }}
proxy_host: ${{ secrets.SSH_TUN_HOST }} # 퍼블릭 IP를 가진 중간 서버
proxy_username: ${{ secrets.SSH_USER }} # 터널링 서버의 사용자
proxy_key: ${{ secrets.SSH_PEM_KEY }}
port: 22
script: |
이 부분 저는 private subnet 사용해서 프록시 서버 둔 건데
여러분은 그냥 porxy로 시작하는 거 다 지워주시면 됩니다.
코드 설명은 안 할게요 궁금하시면 찾아오십셔
환경변수 설정하기
ci-cd 코드에
${{ secrets.SSH_HOST }}
이런식으로 작성된 환경변수 전부 깃허브 시크릿에서 주입받는 거라 환경변수 설정하러 가야합니다.

깃허브 레포 -> setting -> 왼쪽 바에서 저거 찾은 다음에 레포지토리 시크릿 만들면 됩니다.
초록색 버튼 클릭해주세여

이렇게 들어갈 값 전부 입력하시면 됩니다.
ssh_host는 퍼블릭 ip주소구요
ssh_pem_key는 저희 다운받았던 펨키 전문 다 집어넣으시면 됩니다.
ssh_user는 유저네임인데 아마존 리눅스의 기본값은 ec2-user 입니다. 이름 바꾼 거 아니시면 저 값 집어넣으면 돼요
터널링 서버 주소는 여러분 필요 없고 도커 허브 아이디 비밀번호 저기 입력하면 돼요
대망의 테스트

아까 만든 ci-cd 파일이랑, 도커 파일 푸시 합시다. 이거 넣으면 바로 깃허브 액션 실행될 거에요

이런 젠장 에러가 났군요, 에러를 살펴보니 gradlew 파일의 형식이 다른 거 같습니다.
war 배포의 차이 때문일까요?
이유는 블로그 작성 다 하고 개인적으로 찾아보겠습니다.
아무튼 gradlew 파일 형식이 다르면 다시 만들면 됩니다.

기존에 존재하던 gradlew 파일 rm으로 다 지워줬구요,
다시 gradle wrapper 실행해서 빌드 관련 파일 전부 다시 실행시켜 줬습니다.
새로 생성된 gradlew, gradle 뭐 4개 파일 다시 깃 레포에 푸시해줬구요 결과를 살펴봅시다.

성공 ~!
혹시 모르니 다시 ec2 접속해서 docker ps로 잘 돌아가나 확인해봅시다.

예 잘 돌아가네요
로그도 한 번 찍어봅시다.
docker logs dolfin-log-app-1

굿 로그 살펴보니 파티션도 할당 받고 카프카 브로커랑 연결 잘 됐네요
CI-CD 성공 ~~
이건 보안 신경 아예 안 쓰고 기초적인 ci cd 배포 작업 한 거니까 알아두세요
https랑 Auto Scailing 적용이랑 nat gateway 설정이랑 환경변수랑 도커 컴포즈 파일 s3에서 관리하고, rds 프라이빗 서브넷으로 분리하는 거 나중에 올릴 거니까 관심있으면 보세요