AWS EC2 프리티어 인스턴스에서 Docker를 사용하여 Spring 웹 애플리케이션을 실행하는 과정을 포스팅한다.
AWS EC2 프리티어 인스턴스(OS ubuntu)를 생성한다.
보안그룹에 80, 443, 22, 8080 포트를 열어준다.
ssh로 EC2 인스턴스에 연결한다 최초 연결 시 서버 신뢰 문제로 경고가 발생하는데 yes입력하면 연결이 이루어진다.
프리티어 인스턴스는 메모리가 부족하여 크래시가 발생할 수 있기 때문에 스왑 메모리를 추가해준다.
# 2GB 크기의 스왑 파일을 생성
sudo fallocate -l 2G /swapfile
# 해당 파일의 읽기/쓰기 권한을 소유자에게만 부여
sudo chmod 600 /swapfile
# 스왑 파일을 스왑 영역으로 설정
sudo mkswap /swapfile
# 스왑 활성화
sudo swapon /swapfile
# 재부팅 시에도 유지될 수 있도록 수정
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
자바를 설치한다.
# 패키지 업데이트
sudo apt update
# 자바 설치
sudo apt install openjdk-17-jdk
# 자바 설치 확인
java -version
# JAVA_HOME 설정전 설치경로 확인
sudo update-alternatives --config java
# JAVA_HOME 설정
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.bashrc
# PATH에 java 실행파일이 포함된 경로를 추가
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
# 변경된 환경 변수를 적용
source ~/.bashrc
도커를 설치한다.
# 패키지 목록을 업데이트
sudo apt update
# 도커 설치
sudo apt install -y docker.io
도커 설치 후 실행한다.
# 도커를 실행한다.
sudo systemctl start docker
# 재부팅 시에도 도커가 자동으로 시작되도록 설정
sudo systemctl enable docker
# 현재 사용자가 sudo없이 도커 명령어를 사용할 수 있도록 권한부여
sudo usermod -aG docker $USER
로컬로 돌아와서 scp를 사용하여 EC2 서버에 프로젝트 디렉토리를 업로드한다. exit하면 ssh연결을 종료할 수 있다.
프로젝트의 도커파일 스크립트다.
# scp로 프로젝트 디렉토리 EC2에 업로드
scp -i "키페어 경로" -r 프로젝트디렉토리경로 ubuntu@ec2주소:/home/ubuntu
# 업로드가 정상적으로 되었다면 프로젝트 디렉토리의 경로는 /home/ubuntu/디렉토리명이다.
cd /home/ubuntu/프로젝트명
#위치를 이동 시킨 후 그래들을 사용하여 프로젝트를 빌드 jar파일을 생성한다.
./gradlew build
빌드에 성공했다면 도커 이미지를 생성한다.
# 도커 이미지 생성
# -t는 내가 지정한 이름으로 이미지를 생성
# .는 해당 디렉토리의 Dockerfile을 사용하여 이미지를 빌드
docker build -t my-springboot-app .
이미지를 생성했지만 이름이 none으로 생성되는 문제가 발생하여 dockerfile을 수정했다.
이미지가 정상적으로 생성된 걸 확인할 수 있다. 컨테이너를 실행한다.
# 도커 컨테이너를 실행
# -d : 백그라운드에서 컨테이너를 실행
# -p 호스트와 컨테이너 매핑
docker run -d -p 8080:8080 이미지명
컨테이너가 실행하자마자 종료되는 문제가 발생했다. 로그를 확인하니 app.jar 파일을 찾을 수 없다는 문제여서
Dockerfile을 다시 수정해야했다.
# 1단계: 빌드된 JAR 파일을 복사하여 실행
FROM openjdk:17-jdk-slim
WORKDIR /app
# 빌드된 JAR 파일을 app.jar로 복사
COPY build/libs/docker-test-0.0.1-SNAPSHOT.jar /app/app.jar
# 포트 설정
EXPOSE 8080
# Spring Boot JAR 실행
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
다시 이미지를 빌드하고 컨테이너를 실행한다. 종료된 컨테이너를 삭제하고 잘못 생성된 이미지도 삭제해준다.
# 종료된 컨테이너 모두 삭제
docker container prune
# 도커 이미지 리스트
docker images
# 해당 이미지 삭제
docker rmi <image_id>
# 이미지 빌드
docker build -t 이미지명 .
# 컨테이너 실행
docker run -d -p 8080:8080 이미지명
이제 EC2의 Public IPv4 주소를 통해 애플리케이션에 접속할 수 있다.
사실 엄청난 시행착오가 있었다. 최초에는 dokerfile의 스크립트가 잘못된 것이 문제였다. dokerfile 수정만 잘해줬다면 금방 해결할 수 있는 문제였는데.. jar 파일이 mainclass를 찾지 못한다는 것을 원인으로 보고 별짓을 다했다,,,,, dependency수정만 몇번,, dockerfile 수정만 몇십번,,, jar파일의 내부를 확인하고,, 실행되자마자 종료되는 컨테이너의 내부에도 들어가 jar파일의 상태를 확인하고,,,, 그 과정에서 메모리가 부족해 서버가 멈추고,,, 재시작하고 삽질을 너무 많이 했다.