기존에 개인 프로젝트를 진행할 때는, EC2에 Tomcat Servlet 프로젝트 배포 문서처럼 GitHub에서 수정 사항이 발생할 때마다, git pull, tomcat 중단 후 재실행 등 여러 명령어를 매번 입력하던 번거로움이 존재하였는데, 참고 링크 2처럼, 배포 스크립트를 .sh 파일로 만들어서, 변경 사항이 발생할 때마다 여러 명령어를 한 번에 수행하거나, 아래에서 Docker Images를 생성하는 등 배포 과정을 단순화한다면 훨씬 더 효율적으로 프로젝트를 진행할 수 있겠다는 생각이 들었다.
1. Docker
도커의 장점
- Consistent Environment: Dockerfile을 통해 서버 운영기록을 코드로 남길 수 있다. 또한, 서로 다른 환경에서 Dockerfile을 통해 동일하게 실행될 수 있다.-> 이는 팀원이 협업할 때, 프레임워크 버전 등 여러 버전을 일치시킬 수 있어서 쉬울 것으로 보인다.
- 서버의 확장: 만약 프로젝트 규모가 커져서 서버를 옮기거나 확장해야 할 때, 도커를 사용하면 Docker Image만 가져와 새로운 서버에 동일한 환경을 쉽게 구축할 수 있다.
- 그 외 이유들은 위 링크 혹은 구글링 참고
개인 프로젝트에서 Docker를 사용해야 하는 이유?
현재 프로젝트에서 Docker가 사용되는 곳은 크게 두 가지임
- EC2에 Spring Boot jar 배포
- 문장 유사도 검증시 AWS Lambda를 사용하는데, 이 때 python code(ML libarary import 포함)를 Docker image로 업로드
이 중 2번의 경우, 여러 머신러닝 라이브러리를 코드에서 사용하기 때문에 Docker를 사용하는 것이 거의 반강제이나, 1번의 경우 실제 배포해서 창업을 위한 프로젝트가 아닌 졸업 작품 프로젝트이므로 EC2 Instance를 하나 이상 사용할 것 같지 않다. 따라서 EC2 인스턴스에 초기 환경 구축(Java 11 설치 등)을 한 이후, 환경이 수정될 것 같지는 않지만, 원활한 관리 및 추후 서버 확장 가능성을 고려하여 Docker를 사용하기로 하였다.
2. Spring Boot + Docker + EC2 배포
Docker를 사용해 EC2에 이미지가 업로드되는 절차
- Dockerfile을 build해서 Docker image 파일을 생성
- Docker image 파일을 dockerhub으로 push
- EC2에서 dockerhub에 존재하는 docker image 파일을 pull로 받아온다.
- docker run 명령 등을 통해 docker image 파일 실행
2-1. Intellij .jar 파일 빌드
./gradlew clean
./gradlew build
# -x test: 테스트 실행 X
./gradlew build -x test
2-2. Dockerfile 생성 및 dockerhub 리포지토리 생성
FROM openjdk:11
ARG JAR_FILE=*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
build.gradle 수정
위 스택오버플로우에 따르면, Spring Boot 2.5.0 이후로 .jar 및 -plain.jar 파일 2개가 생성되어서, Docker image가 생성되지 않는 오류가 발생할 수 있으므로, 아래 내용을 추가해야 한다.
// build.gradle에 아래 내용 추가
jar {
enabled = false
}
이후 dockerhub에서 repository를 생성한다.
https://hub.docker.com/r/moojun/menjil-be-dev
docker tag란?
The Docker tag helps maintain the build version to push the image to the Docker Hub. The Docker Hub allows us to group images together based on name and tag. Multiple Docker tags can point to a particular image. Basically, As in Git, Docker tags are similar to a specific commit
. Docker tags are just an alias for an image ID.
2-3. Docker image 생성 및 dockerhub에 push
# macOS M1 chip의 경우 --platform linux/amd64 옵션을 추가해야 함
docker build --platform linux/amd64 -t moojun/menzil-be:[tag] .
# e.g) docker build --platform linux/amd64 -t moojun/menzil-be:0.0.1 .
# 정상 build 조회
docker images
# push dockerhub
docker push moojun/menzil-be:[tag]
2-4. EC2 기본 환경 구축
- EC2, Security Group 생성 및 Elastic IP 설정(내용 생략)
- EC2에 Docker 설치
- docker image pull
# pull
sudo docker pull moojun/menjil-be-dev:[tag]
# run docker
sudo docker run -p 8080:8080 moojun/menjil-be-dev:[tag]
# Run docker background
sudo docker run -d --name 'test1' -p 8080:8080 moojun/menjil-be-dev:[tag]
# show log
sudo docker log [container id]
2-5. Docker 명령어
# 현재 이미지 확인
sudo docker images
# 이미지 삭제
sudo docker rmi [image id]
# 컨테이너 확인
sudo docker container ls -a
# 동작 중인 컨테이너 확인
sudo docker ps
# 컨테이너 중지
sudo docker stop [container name or id]
# 컨테이너 삭제
sudo docker rm [container id]
결론
gradle .jar build -> Dockerfile build -> image push -> image pull -> docker run
과정을 통해 프로젝트를 EC2에 배포할 수 있다.- 하지만 이 과정에서, 두 가지 불편한 점을 확인하였다.
- 프로젝트를 재배포 하는 과정에서, 기존에 실행 중이던 도커 컨테이너를 중단한 뒤, 새로 받은 이미지의 컨테이너를 실행해야 하는 점.
- 위의 절차(gradle .jar build -> ...) 가 조금 번거롭다
첫 번째의 경우 '무중단 배포' 등의 개념으로 해결할 수 있을 것 같으며, 두 번째는 GitHub Action, Jenkins 등 CI/CD 도구를 사용해서 자동화 하는 것으로 대체할 수 있을 것으로 생각한다.
참고 링크
'멘질멘질] 2023 졸업 프로젝트' 카테고리의 다른 글
JPA Repository Test] @SpringBootTest vs @DataJpaTest (0) | 2023.06.09 |
---|---|
Spring Boot] CORS 해결 (0) | 2023.06.09 |
Spring Boot] 프로젝트를 진행하는 과정에서 원칙 정리 (0) | 2023.06.09 |
GitHub Action, Docker, EC2를 사용한 Spring Boot 프로젝트 배포 자동화 (0) | 2023.06.09 |
AWS] 시작 전 초기 세팅 (0) | 2023.06.09 |