-
[Docker] docker를 사용하여 SpringBoot 배포 & 오류 과정Docker 2024. 5. 28. 17:46반응형
도커는 컨테이너 기반 가상화 기술을 이용하여 애플리케이션을 개발, 배포, 운영하기 위한 오픈 소스 플랫폼이다.
도커는 애플리케이션의 배포와 관리를 간소화하며 일관성 있는 환경을 유지할 수 있다. 개발 생산성과 운영 효율성 면에서 장점이 있다고 생각하여 도커를 채택하였다.
사전 준비.
1. 도커 공식 사이트에서 도커 다운 (https://docs.docker.com/desktop/install/mac-install/)
2. rosetta 설치 (도커 컨테이너 내에서 다른 아키텍처의 바이너리를 실행할 수 있도록 지원하는 도구)
2-1. $ softwareupdate --install-rosetta
Docker 클라이언트, 도커 호스트, 도커 레지스트리 간 흐름
1. [Client → Docker Host] 클라이언트는 도커 명령어를 사용하여 도커 호스트에 요청을 보냅니다.
2. [Docker Host] 도커 호스트는 클라이언트의 요청을 받아들이고, 해당 요청에 따라 컨테이너를 생성, 중지, 제거하거나 이미지를 관리합니다.
3. [Docker Host → Registry] 만약 클라이언트가 이미지를 생성하거나 업로드하려면, 도커 호스트는 해당 이미지를 도커 레지스트리에 업로드합니다.
4. [Registry] 도커 레지스트리는 이미지를 저장하고 관리하는 중앙 집중식 저장소입니다. 도커 호스트는 도커 레지스트리에 이미지를 업로드하거나 다운로드할 수 있습니다.
5. [Docker Host → Client] 컨테이너가 종료되면, 도커 호스트는 해당 컨테이너의 상태와 결과를 클라이언트에게 반환합니다.
- 이렇게 클라이언트, 도커 호스트, 그리고 도커 레지스트리는 도커 환경에서 상호 작용하며, 이미지의 업로드와 다운로드, 컨테이너의 생성과 관리 등의 작업을 수행합니다.(출처 - https://adjh54.tistory.com/350)
설정 정보
1. application.yml
external: api: key: {api key 값} url: https://open.api.nexon.com spring: datasource: url: jdbc:mysql://localhost:3306/mapleCombat?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8 username: {db ID} password: {db 비밀번호} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: dialect: org.hibernate.dialect.MySQLDialect format_sql: true
2. build.gradle
plugins { id 'java' id 'org.springframework.boot' version '2.7.7' id 'io.spring.dependency-management' version '1.1.0' } bootJar { archiveFileName = '2024-msg-server.jar' // JAR 파일 이름 설정 } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' // runtimeOnly 'com.mysql:mysql-connector-j' implementation 'mysql:mysql-connector-java:8.0.33' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'com.google.guava:guava:30.1-jre' implementation 'org.springframework.boot:spring-boot-starter-webflux' }
3. Dockerfile
FROM openjdk:11-jdk-slim WORKDIR /app ARG JAR_FILE=build/libs/*.jar #gradle에서 bootjar를 하면 bulid/libs 폴더안에 *.jar 파일이 생김. #파일 이름은 build.gradle 에서 '2024-msg-server.jar'로 설정함 COPY ${JAR_FILE} app.jar 해당 jar 파일을 app.jar로 복사함 ENTRYPOINT ["java", "-jar", "app.jar"]
4.docker-compose.yml
version: '3' services: mysql: image: mysql:latest container_name: mysql-container environment: MYSQL_ROOT_PASSWORD: {db 비밀번호} MYSQL_DATABASE: {db 이름} MYSQL_USER: {db user 이름} MYSQL_PASSWORD: {db 비밀번호} ports: - "3306:3306" maple-combat: image: 2024-msg-server:1.1 container_name: maple-combat-container ports: - "8080:8080" depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/mapleCombat?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8 SPRING_DATASOURCE_USERNAME: {db 아이디} SPRING_DATASOURCE_PASSWORD: {db 비밀번호}
현재 설정을 위와 같이 한 후.
시행 순서
1. gradle에서 bootjar
2. docker build -t 2024-msg-server:1.0 . 로 image 빌드
3. docker login
4. docker-compose up 으로 container에 올리기
Docker 상황
Image
1. name : 2024-msg-server , status : Inuse
2. name : mysql , status : Inuse
containers
1. name :projectone , status : Running(1/2)
1-1. name : mysql-container, Image : mysql , status : Running, port : 3306:3306
1-2. name : maple-combat-container, Image : 2024-msg-server , status : Exited(1) , port : 8080:8080
오류내용
mysql 데이터베이스와의 통신이 실패한 것이 원인으로 보인다.
Caused by: cohttp://m.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
Caused by: java.net.ConnectException: Connection refused (Connection refused)
시도1.
Docker Compose 파일 수정
spring: datasource: #url localhost를 mysql로 수정 url: jdbc:mysql://mysql:3306/mapleCombat?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8 username: {기존과 동일} password: {기존과 동일} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true
spring db 연결 설정을 localhost에서 컨테이너 이름으로 수정
version: '3' services: mysql: image: mysql:latest environment: MYSQL_ROOT_PASSWORD: {기존과 동일} MYSQL_DATABASE: {기존과 동일} MYSQL_USER: {기존과 동일} MYSQL_PASSWORD: {기존과 동일} ports: - "3306:3306" # 아래 수정 spring-server: build: context: . dockerfile: Dockerfile depends_on: - mysql ports: - "8080:8080"
결과.
여전히 같은 오류 출력.
2차 수정
Docker log 오류 메시지를 확인해보니 Public Key Retrieval is not allowed 문제가 있었음.
따라서 datasource url에서 allowPublicKeyRetrieval=true를 추가해주었다.
url을 아래와 같이 수정한 뒤
url: jdbc:mysql://mysql:3306/mapleCombat?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8&allowPublicKeyRetrieval=true
docker-compose up --build; 를 해주고 나니 port 8080:8080도 exited 되지 않고 정상 running 되었다.
하지만 새로운 오류가 생겼는데 postman으로 원래 하던 api test를 해봤는데 500, internal Server Error가 나왔다.
Docker log를 확인해 보니Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'type=MyISAM' at line 30
위의 에러는 type=MyISAM 구문 때문에 생기는 에러인데 Mysql5 버전과 8버전의 충돌때문에 일어나는 오류이다.
dialect: org.hibernate.dialect.MySQLDialect 으로 하면 mysql5버전이 되어서 문제가 생기는데 이를 dialect: org.hibernate.dialect.MySQL8Dialect으로 바꾸어서 다시 올리면 다시 running이 안되고 연결이 안되는 문제가 발생하였다.
3차 수정
application.yml 수정
external: api: key: {기존과 동일} url: https://open.api.nexon.com spring: datasource: url: jdbc:mysql://mysql:3306/mapleCombat?useSSL=false&serverTimezone=Asia/Seoul&characterEncoding=UTF-8&allowPublicKeyRetrieval=true username: {기존과 동일} password: {기존과 동일} driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: dialect: org.hibernate.dialect.MySQL8Dialect format_sql: true
dialect 부분 MySQL8Dialect 로 수정하여 mysql5와의 충돌 해결
build.gradle
dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.mysql:mysql-connector-j' // implementation 'mysql:mysql-connector-java:8.0.33' 수정 annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'com.google.guava:guava:30.1-jre' implementation 'org.springframework.boot:spring-boot-starter-webflux' }
docker-compose.yml
version: '3' services: mysql: image: mysql:latest container_name: mysql environment: MYSQL_ROOT_PASSWORD: {기존과 동일} MYSQL_DATABASE: {기존과 동일} MYSQL_USER: {기존과 동일} MYSQL_PASSWORD: {기존과 동일} ports: - "3306:3306" healthcheck: test: [ "CMD-SHELL", "mysqladmin ping -h localhost" ] interval: 10s timeout: 5s retries: 5 maple-combat: build: context: . dockerfile: Dockerfile container_name: maple-combat-container ports: - "8080:8080" depends_on: - mysql
image 를 직접적으로 적는것에서 build: context: . dockerfile : Dockerfile로 수정
environment에 url 정보 삭제 (application.yml에만 존재)
이후
docker-compose down
./gradlew clean bootJar
docker-compose up --build -d 를 사용하면 docker에 올라가고 postman test에서 정상 작동했다.
반응형