ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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)

    https://docs.docker.com/get-started/overview/#docker-architecture

     

     

    설정 정보

    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에서 정상 작동했다.

     

     

    반응형

    댓글

Designed by Tistory.