개발놀이터

EC2 Docker + Nginx를 이용해 스프링 프로젝트 배포하기 본문

배포/Docker

EC2 Docker + Nginx를 이용해 스프링 프로젝트 배포하기

마늘냄새폴폴 2023. 6. 10. 21:12

이번 포스팅에선 EC2 인스턴스를 Docker와 Nginx를 이용해 배포하는 방법에 대해서 포스팅해보도록 하겠습니다. 

 

사실 해당 부분이 전체적인 CI / CD의 파이프라인을 놓고 봤을 때 그리 큰 부분을 차지하진 않습니다. 하지만 배포가 되는 것이야말로 CI / CD의 알파이자 오메가일 것입니다. 

 

사실 저는 모놀리식으로 배포를 한 경험이 있습니다. 이에대한 노고에 대해서는 아래의 링크에 잘 수록되어있습니다. 

 

https://coding-review.tistory.com/160

 

aws 배포 ec2 (1) : 모놀리식 배포

우선 aws ec2에 들어간다. 인스턴스 시작을 클릭! 더 많은 AMI 찾아보기를 클릭 후 우분투 리눅스를 둘중 하나 클릭 조금 내려가다 보면 키 페어를 선택하라고 나오는데 이부분은 새 키페어 생성을

coding-review.tistory.com

 

저때를 회상해보면 정말 고생했습니다. MySQL을 EC2 인스턴스에 설치 했는데 root 권한으로 들어갈 수가 없어서 별에별 삽질은 다했던 기억이 있네요. 

 

MySQL Server를 깔았다가 지웠다가 MySQL Client도 깔았다가 지웠다가 MySQL도 깔았다가 지웠다가 아주 별 x랄을 다했습니다. 

 

결국 프로젝트 자체를 배포하는 것은 포기하고 EC2 인스턴스만 배포하고 프로젝트를 종료했습니다. 정확히 10개월 전인데 약 1년전의 저와 다르게 지금은 또 많이 성장했기 때문에 이번엔 반드시 내 프로젝트를 전부 띄워보겠다. 라는 일념하나로 이번 프로젝트에 임했던 것 같습니다. 

 

서론이 길었군요 바로 시작해보죠. 

 

참고) 이번 포스팅은 EC2 인스턴스가 이미 존재한다는 전제로 진행됩니다. 

 

Docker + Nginx로 배포

이번 포스팅은 아래와 같은 순서로 진행됩니다. 

 

  1. Docker, Docker-compose 설치
  2. jdk 11 설치
  3. 내 프로젝트 깃 레포지토리에서 클론
  4. 깃 리포지토리에서 Git Bash를 이용해 테스트 케이스 삭제
  5. Dockerfile 작성
  6. Nginx 설정파일 작성
  7. docker-compose 작성

 

본격적으로 시작해보겠습니다. 

 

1. Docker, Docker-compose 설치

$ apt-get update
$ sudo apt-get install docker
$ sudo apt-get install docker-compose

 

도커는 항상 하던대로 설치합니다. 만약 깔려있으시면 다운 안받으셔도 됩니다!

 

2. jdk 11 설치

# aws corretto 다운로드
sudo curl -L https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.rpm -o jdk11.rpm

# jdk11 설치
sudo apt-get install openjdk-11-jdk

 

3. 내 프로젝트 깃 레포지토리에서 클론

$ sudo apt-get install git

우선 깃을 설치해주시고

 

$ git clone ${레포지토리 주소}

클론을 해줍니다. 

 

다음 파일들을 좀 정리할건데요. 먼저 루트 폴더에 깃 클론이 들어왔을겁니다. 

 

$ ls
capston 
*capston = 깃 클론 폴더

$ mkdir project
$ ls
capston project

$ mv capston project
$ ls
project

$ cd project

이렇게 프로젝트 폴더에 제 프로젝트를 넣어줄겁니다. 

 

그리고 해당 프로젝트로 들어가서 gradlew의 권한을 변경해줍니다. 

 

$ sudo chmod 755 gradlew
반드시 gradlew가 있는 디렉토리안에서 진행해야합니다. 
저의 경우 /project/capston 으로 들어간 상태에서 진행했습니다.

 

그리고 빌드를 진행합니다. 근데..?

$ ./gradlew build

이렇게 뜨는 분들 분명 있을겁니다. 테스트케이스가 실패한 경우!

 

저도 테스트가 잘못된줄 알고 로컬에서 테스트를 돌려본 결과 잘 통과하는 것을 확인했습니다. 하지만 gradle로 빌드했을 때 테스트케이스에서 오류가 발생했습니다. 

 

이런저런 해결방법을 찾아봤는데 결국 해결하지 못했구요... 결국 모든 테스트케이스를 gitignore 하기로 결정했습니다. 

 

어차피 실제 배포때는 테스트케이스는 필요없으니까요. 

 

4. 깃 레포지토리에서 Git Bash를 이용해 테스트케이스 삭제

저의 경우 windows 10 환경에서 진행했습니다. 

 

바탕화면에 아무 폴더나 하나 생성해주세요. 저는 Git이라는 이름으로 폴더를 생성했습니다. 

 

만약 자신의 컴퓨터에 Git을 설치했다면 Git Bash라는 명령 프롬프트가 다운받아져 있을겁니다. 혹시 없으시다면 구글링으로... (포스팅의 결이 다르기 때문에.. 이해부탁드립니다)

 

그리고 폴더를 여시고 맨 바닥에 오른쪽 클릭 > Git Bash 클릭!

 

# 깃 시작
$ git init

# 깃 리포지토리와 연결
$ git remote add origin ${깃 리포지토리 주소}

# pull
$ git pull

# src로 이동
$ cd src

# test 폴더에 있는 캐시 삭제, test 폴더 삭제
$ git rm --cached -r test
$ git rm -rf test

# "test delete" 라는 커밋 메시지와 함께 커밋
$ git commit -m "test delete"

# 깃 push
$ git push origin master

 

이렇게 명령어 쭉 따라 치시면 테스트폴더가 삭제되고 깃 리포지토리에 저장됩니다!

 

그리고 스프링 부트 프로젝트의 .gitignore 파일에 

/src/main/resources/application.yml
/src/main/resources/application-google.properties
/src/main/resources/application-kakao.properties
/src/main/resources/application-naver.properties
/src/test/*

이렇게 추가해주시면 됩니다. 

 

5. Dockerfile 작성

이제 모든 전처리 과정이 끝났습니다. 본격적으로 배포를 시작해보죠. 

 

Dockerfile은 프로젝트 폴더 옆에 만들어 주시는게 국룰이랍니다. (Chat GPT 피셜) 

 

$ ls
capston
# 이렇게 자신의 프로젝트가 옆에 있는 상태인 디렉토리에서

$ vim Dockerfile

$ ls
capston Dockerfile
# 모두 마무리되면 이런 형태로

자신의 프로젝트 옆에다 Dockerfile을 만들어줍니다. 

FROM openjdk:11-jdk

# JAR_FILE 변수 정의 -> 기본적으로 jar file이 2개이기 때문에 이름을 특정해야함
ARG JAR_FILE=./capston/build/libs/DevopsTestKotlin-0.0.1-SNAPSHOT.jar

# JAR 파일 메인 디렉토리에 복사
COPY ${JAR_FILE} app.jar

# 시스템 진입점 정의
ENTRYPOINT ["java","-jar","/app.jar"]

 

JAR_FILE 은 자신의 SNAPSHOT.jar 이 있는 곳을 가리켜야합니다. 아니면 절대경로로 적어주셔도 됩니다. 

 

6. Nginx 설정파일 작성

# nginx 디렉토리 생성
$ mkdir nginx

# nginx 디렉토리로 이동
$ cd nginx

# conf.d 디렉토리 생성
$ mkdir conf.d

# conf.d 디렉토리로 이동
$ cd conf.d

# app.conf 파일 생성
$ vim app.conf

이렇게 nginx의 설정파일을 만들어주고

 

server {
	listen 80;
    access_log off;
    
    location / {
    	proxy_pass http://spring:8080;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

app.conf 내용물은 위와같이 적어주시면 됩니다. 

 

그렇게 하고 Dockerfile이 있는 곳에서 디렉토리를 확인해보면 이렇게 되어있겠죠. 

 

$ ls
capston Dockerfile nginx

 

7. docker-compose.yml 작성

 

거의 다왔습니다. 이제 docker-compose.yml을 Dockerfile 옆에다 생성해줍니다. 

 

version: "3.8"
services:
  web:
    image: nginx
    ports:
      - 80:80
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
    depends_on:
      - spring
  spring:
    build: .
    ports:
      - 8080:8080

 

하나씩 설명해보자면

 

image : 이미지는 nginx를 쓰겠다는 의미입니다. 이렇게 적어두면 알아서 이미지를 받아옵니다. 

ports : 80포트로 들어오는 nginx를 로드밸런싱하여 8080 포트로 라우팅시키겠다는 의미입니다. 즉, nginx는 딱히 아무것도 하지않고 포트만 샥 하고 바꿔주는 역할을 합니다. 

volumes : 우리가 방금 만들었던 nginx의 설정파일을 컨테이너의 /etc/nginx/conf.d 폴더로 바인딩시키겠다는 의미입니다. 

build : 옆에 온점 반드시 찍으셔야합니다!

ports : 스프링 프로젝트의 포트를 8080으로 설정하겠다는 의미입니다. 

 

이제 이렇게 모두 설정하시면 프로젝트 구조는 이렇게 됩니다. 

project
  - capston
    - build.gradle
    - gradlew
    - build
    - gradle
    - gradlew.bat
    - settings.gradle
    - src
  - Dockerfile
  - docker-compose.yml
  - nginx
    - conf.d
      - app.conf

조금 복잡한데요. 잘 따라오셨는지요!

 

마지막으로 컨테이너를 띄워보겠습니다. 

 

$ docker-compose -f ./docker-compose.yml up -d
# 위와같은 명령어를 쓰기 위해서는 반드시 docker-compose가 있는 디렉토리에서 명령어를
# 실행하셔야 합니다.

 

그러면 nginx의 이미지를 내려받고 컨테이너로 띄워줍니다. 그리고 저희 프로젝트도 띄워지죠. 

 

$ docker ps

모든 컨테이너가 올라갔습니다. 

 

이제 EC2의 퍼블릭 IP 뒤에 8080포트를 달아주면?

 

http://${EC2 퍼블릭 IP}:8080

 

짜잔 완벽하게 배포된 것을 확인할 수 있습니다. 

 

 

마치며

이번 여정은 정말 복잡하고 길었습니다. 음... 솔직히 1년전의 저보고 하라고 하면 절대 못했을 듯 한 시도였습니다. 지금이야 여유도 생기니 리눅스도 공부하고 도커도 공부했지만 1년전의 저는 스프링 시큐리티도 잘 못다루던 애송이였으니까요. 

 

이제 첫 걸음마... 는 아니고 세번째 걸음마를 뗐습니다. 첫 번째는 mysql 도커로 배포후 외부연결, 두 번째는 redis 도커로 배포 후 외부연결, 그리고 세번째가 도커를 이용해 스프링 프로젝트 배포

 

정말 긴 여정이었습니다. 하지만 앞으로 해야할게 정말 많습니다. Route 53으로 도메인 달아줘야하고, ACM으로 HTTPS 통신도 해야하고 ACM을 ELB를 이용해 로드밸런싱 해야합니다. 

 

그리고 대망의 Nginx를 이용해 Blue / Green 배포까지!

 

이 모든 과정을 거쳐야 온라인 쇼핑몰 ver.2 카테고리에 포스팅할 수 있을 것 같습니다. 

 

혹시나 이 긴 여정에 도움이 필요하신 분들을 위해 자세히 포스팅할 예정이니까요. 앞으로 잘부탁드립니다. 

 

긴 글 읽어주셔서 감사합니다. 오늘도 즐거운 하루 되세요~