1. 환경 변수 처리
springboot-kotlin 에서 dotenv를 사용해서 환경변수를 처리하는 방법은 아래 링크 글에 적었었음
https://whitepro.tistory.com/891
이제 .env를 제외하고 코드는 github에 올라가있는 상태
2. Docker Image Build
Dockerfile 코드
FROM amazoncorretto:17
VOLUME /tmp
COPY build/libs/*.jar /app.jar
COPY ./.env /.env
EXPOSE 8080
ENTRYPOINT ["java", "-Dspring.profiles.active=prod","-jar", "/app.jar"]
이 코드는 build/libs/*.jar라는(*는 모든 파일) 이름의 파일을 이미지로부터 생성되는 컨테이너의 파일 시스템상 /app.jar 위치에 복사하고,
java -jar 명령어를 이용해서 prod라는 환경으로 실행한다.
나의 경우 .env 파일도 있기 때문에, 컨테이너에서도 이 파일을 참조할 수 있도록 COPY ./.env /.env 구문을 추가해주었다.
커맨드별 더 자세한 내용은 공부하면 됨. 이 내용을 image로 만들어서 dockerhub에 푸시하고 EC2에서 container로 실행할 예정이다.
ref.) https://lucas-owner.tistory.com/48
$ docker login -u {내 dockerhub ID} //이후 비밀번호도 입력한다.
$ docker build -t {dockerhub 아이디}/{생성할 이미지 이름}
$ docker images // 잘 생성되었는지 확인
$ docker push {내 dockerhub ID}/{생성할 이미지 이름} // dockerhub에 이미지를 푸시함
docker desktop이나 dockerhub 홈페이지의 내 계정/repositories에서 생성된 이미지를 확인할 수 있다.
** 만약 arm64(macOS m1 등의) architecture의 컴퓨터를 사용하고 있다면, 아래 내용을 추가로 진행해줘야한다.
ref.) https://kim-dragon.tistory.com/152
macOS m1 등은 arm64라는 OS를 사용하고, (보통의) EC2는 linux로 생성 시 amd64 체제이다. 그래서 만약 arm64에서 위 build image 명령어대로 image를 만들고 EC2에서 image를 실행하면 아래 같은 에러 메시지가 뜬다.
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested 2720383e9fd9......
그래서 위 내용대로 build후에 아래와 같은 명령어로 다시 build 해야한다.
# image 목록 확인
$ docker images
$ docker image inspect {위 목록의 image ID 기입} | grep Architecture
## 이렇게 출력될 것임 : "Architecture": "arm64",
# linux/amd64
$ docker build --platform linux/amd64 -t {dockerhub 계정이름}/{이미지 이름} .
$ docker push {dockerhub 계정이름}/{이미지 이름} .
그리고나서 dockerhub에서 확인해보면 linux/amd64용으로 이미지가 올라간 것을 확인할 수 있다.
(중요) Docker Image 개념
로컬 PC에서 build된 파일을 기반으로 Image를 만들게 된다. 위 Dockerfile의 구문에서 COPY build/libs/*.jar 구문 자체가 Image가 되는데 이 때 빌드된 파일에 대한 스냅샷 정보가 Image에 포함된다. 즉, 로컬에서 변경한 코드가 Image를 만들 때 포함된다. 이 사실은 다음 두 가지를 포함한다.
- EC2에서 빌드할 필요가 없다. 로컬에서 빌드 후 image를 푸시하고, EC2에서는 Image를 내려받기만 하면 된다.
- Github에 code 변경사항을 저장하는 것은 Image를 만드는 것과 별개다. build 당시의 코드를 기반으로 Image를 만든다.
나는 처음에 Image를 빌드한다는 것은 그냥 여러 명령어의 모음일 뿐, 로컬 컴퓨터에서의 변경사항을 포함한다고 생각하지 못했다. 그래서 문제의 원인을 찾지 못하고 시간을 많이 소요했는데, 그러면서 Docker Image에 대한 개념을 좀 더 정립했던 것 같다.
3. EC2 생성 및 docker, git 설치
EC2 인스턴스 생성방법은 참고자료도 많고 너무 간단해서 생략. '연결'도 pem 키가 있는 디렉토리에서 EC2 상세 페이지에 나오는 'ssh -i ...' 명령어를 복사해서 치면 접속가능
EC2 내부에서 docker와 git 설치
$ sudo yum install docker -y
$ sudo yum install git -y
4. git ssh key 등록 및 clone
(Docker Image에 build 파일이 포함되어 있으므로 필수 과정이 아님)
ec2에서 github에 등록된 내 계정의 repository에 접근하기 위해서 ec2에서 요청을 보내는 유저가 github에 등록된 내 계정임을 ssh key를 통해 증명한다.
ref.) https://seosh817.tistory.com/322
$ cd ~/.ssh
$ ssh-keygen -t rsa -C {github ID 이메일} // 이후 구문 설정하라는 것 같은건 그냥 Enter
$ cat id_rsa.pub // 생성된 ssh key의 pub용 내용 확인 -> 복사
- github에 ssh키를 등록한다.
프로필 > Settings > SSH and GPG Keys -> New SSH Keys에 title을 입력하고 Key는 복사한 값을 입력
- EC2에서 git clone을 실행한다.
5. .env 파일 로컬에서 EC2로 복사해주기
filezila를 통해서 또는 scp 명령어로 .env 파일을 EC2에 복사된 디렉토리에 넣어준다.
- FileZila 다운받고 실행, 아래 그림에서 가리키는 버튼 클릭
- 새 사이트 -> 이름 설정 -> SFTP 프로토콜 -> 호스트 및 사용자란을 입력하면 된다. 이 내용들은 EC2에 보면 나와있고, 사용자명은 ec2로 접속했을 때 cd ~ 명령어로 사용자 루트 경로로 이동해서 알 수 있다. (ubuntu 기반 OS가 아니면 ec2-user로 설정되어있다)
연결이 정상적으로 잡히고 나면, 리모트 쪽으로 .env 파일을 옮겨주면 된다.
나중엔 이런 기초적인 방법말고, AWS Parameter Store를 사용한다던가, 비밀관련 내용들을 암호화 처리하는 등의 방법을 적용할 것이다. 지금 초보 단계에서는 굳이 그것까지 공부할 필요는 없어보인다.
6. java 설치 및 gradle build
(Docker Image에 build 파일이 포함되어 있으므로 필수 과정이 아님)
빌드는 로컬 PC에서 하고, Docker Image를 push한 뒤, EC2에서는 Image만 pull 해오는게 좋다.
EC2를 처음 실행했다면 java가 없어서 gradle 명령어로 build가 불가능하다. 다음 명령어를 입력한다.
$ sudo yum install java-17-amazon-corretto -y
# 설치 확인
$ java -version
프로젝트 디렉토리로 이동해서 build를 실행한다.
$ ./gradlew build
# 혹시 Permission denied 발생 시
$ chmod +x gradlew
빌드를 다시 해야한다면, 기존 build 파일들을 지우는 명령어
$ ./gradlew clean
! 혹시 build 시에 아래 처럼 terminal 화면이 멈춘것 같고 시간만 오르기 시작한다면, EC2가 free tier 레벨이라서 Memory가 부족해서 그런 것일 수 있다. 일단 build를 중단하기 위해서 [Control + X] | [Control + Z]를 누르고 기다려본다. 그리고 인스턴스를 중지시킨다. 중지 중 -> 중단 됨 인 상태에서 인스턴스를 다시 시작하고 정상 시작까지 기다린다.
그리고 아래 메모리 조정 부분을 추가 처리한다.
ref.) https://sundries-in-myidea.tistory.com/102
참조 링크에 있는 것처럼 swap 영역을 늘려주어 강제로 메모리를 늘리면 메모리 부족에 의한 threshold를 방지할 수 있다.
(dd 명령어를 치고나면 약 10~20초간 잠시 뻗음)
# dd 명령어, 128MB 씩 16개의 공간 할당
$ sudo dd if=/dev/zero of=/swapfile bs=128M count=16
# 스왑 파일에 대한 읽기 및 쓰기 권한 업데이트
$ sudo chmod 600 /swapfile
# linux 스왑 영역 설정
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
# 확인
$ sudo swapon -s
# /etc/fstab을 편집해서 부팅 시 스왑 파일 활성화
$ sudo vi /etc/fstab
# 파일 끝에 다음 문구 추가 (i 눌러서 INSERT MODE, ESC로 빠져나오고, :wq로 저장 후 종료)
/swapfile swap swap defaults 0 0
# 확인
$ free
7. Docker 실행 및 image 실행
ref.) https://league-cat.tistory.com/347
docker가 실행 중인지 확인하고, 아니라면 docker를 실행해준다. (실행 중이 아닌데 명령어 입력 시, Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? 라는 문구가 출력됨)
$ sudo systemctl status docker
$ sudo systemctl start docker
$ sudo systemctl enable docker
이제 docker image로 컨테이너를 실행하여 서버를 띄운다.
ref.) https://lucas-owner.tistory.com/48
$ sudo docker run -d -p 8080:8080 {dockerhub 계정}/{이미지 이름}
# Docker 실행중인 컨테이너 확인
$sudo docker ps
# Docker 정지된 컨테이너 확인(실행중인것도 출력)
$sudo docker ps -a
! 혹시 docker ps 명령어에서 아무런 container가 실행되고 있지 않다면, docker ps -a 명령어로 container ID를 확인 후 아래 명령어로 log를 확인해보면 된다.
$ docker logs {docker container ID}
! 혹시 no main manifest attribute, in /app.jar
ref.) https://blog.leocat.kr/notes/2020/01/23/gradle-create-executable-jar-with-spring-boot
에러 메시지가 발생하면, build/libs 내부의 .jar 파일을 압축해제해서 Meta 파일에 정상적으로 MainClass가 지정되어있는지 살펴보면 된다. tar -xvf로 .jar 파일의 압축을 풀 수 있다.
$ tar -xvf {내가 빌드한 jar 파일}
그리고 MANIFEST.MF 파일을 cat 명령어로 열어보면 Start-Class 부분이 정확하게 들어가있어야한다.
만약 이상이 없는 것 같은데, EC2에서 잘 안된다면 EC2에서도 이와 같은 방식으로 확인해볼 수 있다.
다만 EC2에 tar 명령어가 작동하지 않는다면, 다음 명령어로 unzip을 설치 및 활용해볼 수 있다.
$ sudo yum install unzip
$ unzip {jar 파일 이름}
! 혹시 Dockerfile에서 잘못된 부분을 발견했다면
dockerfile 수정 후, remote dockerhub에 다시 push, EC2에서 아래 명령어들을 이용하여 원래 image들을 제거하고 다시 remote에서 이미지를 불러와야한다.
$ docker prune container
$ docker prune image
$ docker rmi {기존에 남아있던 image ID}
'Project > Poppin' 카테고리의 다른 글
스프링부트 Swagger 3.0, JPAAuditing, ZonedDateTime (1) | 2023.12.02 |
---|---|
SpringBoot Kotlin 프로젝트 Docker, AWS로 서버 구성하기-2. RDS, Route 53, 로드밸런서 등 (0) | 2023.11.26 |
kotlin build file name 변경하기, mainClass 설정 (0) | 2023.11.25 |
SpringBoot-Kotlin 프로젝트에 dotenv 적용하기 (1) | 2023.11.25 |
Google OAuth2.0 소셜 로그인 플로우 - React, Kotlin(Spring boot), Authorization code grant 방식 (0) | 2023.11.19 |