Docker

[Docker-compose] Mysql , SpringBoot 배포

쭈녁 2024. 4. 6. 23:17

Srpingboot Dockerfile

FROM openjdk:23-jdk
CMD ["./gradlew", "clean", "build"]
ARG FILE_NAME=demo-0.0.1-SNAPSHOT.jar
ARG JAR_FILE=build/libs/${FILE_NAME}
COPY ${JAR_FILE} app.jar
ENV TZ=Asia/Seoul
ENTRYPOINT ["java", "-jar", "/app.jar"]

 

FROM : 빌드에 사용될 이미지 버전

CMD :  쉘(shell)에서 커맨드를 실행하는 것처럼 이미지 빌드 과정에 필요한 커맨드 실행 (clean, build 예약)

ARG : 사용할 인자 정의 (빌드 된 jar파일 이름과 jar가 있는 경로 값)

ENV : 환경 변수 지정

ENTRYPOINT : 이미지를 컨테이너로 띄울 때 마다 실행할 커맨드 지정

 

Springboot 프로젝트 구조

 

1. 데이터베이스와 테이블은 docker 컨테이너가 올라갈 때 명령어로 초기화

2. 초기 데이터는 Springboot 프로젝트의 InitDb 클래스를 통해 Jpa로 세팅

 

create_table.sql

USE my-project-db;

CREATE TABLE member (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255)
);

CREATE TABLE article (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255),
    content VARCHAR(255)
);

 

 

InitDb 클래스

@Profile("local")
@Component
@RequiredArgsConstructor
public class InitDb {
    private final InitService initService;


    @PostConstruct
    public void initData() {
        initService.init();
    }

    @Component
    @RequiredArgsConstructor
    static class InitService {
        @PersistenceContext
        private EntityManager em;

        @Transactional
        public void init() {
            for (int i = 1; i <= 4; i++) {
                em.persist(Member.builder().name("회원 " + i).build());
                em.persist(Article.builder().title("제목" + i).content("내용" + i).build());
            }
        }
    }

}

 

docker-compse.yml

version: '3'

services:
  #mysql 빌드
  database:
    #docker 컨테이너 이름지정
    container_name: springboot-demo-db
    #빌드에 사용될 이미지
    image: mysql/mysql-server:8.0.2-1.0.0
    #mysql 환경변수 (ENV)
    environment:
      MYSQL_DATABASE: my-project-db
      MYSQL_ROOT_HOST: '%'
      MYSQL_ROOT_PASSWORD: 1234
      TZ: 'Asia/Seoul'
    #외부 포트와 내부포트의 매핑정보
    ports:
      - "13306:3306"
    #컨테이너가 실행될 때 수행할 명령어 -> docker run 명령어 commend 와 동일 , Dockerfile 의  CMD
    #언어를 바꿔주지 않고 먼저 init 데이터 넣으니까 깨지는 현상 발생함!! 실행 순서도 중요한듯
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --skip-character-set-client-handshake
    #volume 정의 데이터베이스 초기 세팅을 위해 실행할 sql 파일을
    #docker contain 의 /docker-entrypoint-initdb.d 경로에 저장하여 실행하도록 함
    volumes:
      - .\src\main\resources\mysql\initdb.d:/docker-entrypoint-initdb.d
    # depends_on 에서 선행 되어야하는 서비스가 정상적으로 올라왔는지 확인하도록 플로우를 짜야 compose 내부의 서비스들이 순서대로 정상 작동한다.
    healthcheck:
      #아무리 찾아도 mysql healthcheck 는 ping 으로 하는것밖에 못찾아봤음
      test: mysqladmin ping -h localhost -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
      interval: 10s
      timeout: 5s
      retries: 5
    #mysql의 네트워크 연결
    networks:
      - jun-test-network


  #springboot 빌드
  application:
    container_name: springboot-demo-application
    #Springboot의 빌드 -> 이미지 는 Dockerfile 에 정의된 방식으로 진행
    build:
      dockerfile: Dockerfile
    #boot 의 포트 매핑
    ports:
      - "18080:8080"
    #boot의 환경 변수 설정 (ENV)
    environment:
      # 컨테이너 내부에서 통신할 때는 외부에 노출된 포트가 아닌 내부 포트로 매핑해야한다.
      SPRING_DATASOURCE_URL: jdbc:mysql://springboot-demo-db:3306/my-project-db
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: 1234
    #boot는 mysql 과 의존관계에 있으므로 아래와 같이 설정
    depends_on:
      #의존관계에 있는 서비스가 특정 상태일때 실행하도록 지정
      database:
        condition: service_healthy
    #boot의 네트워크 연결
    networks:
      - jun-test-network
    
#해당 docker-compose 가 실행될 때 네트워크 추가
networks:
  jun-test-network:
    driver: bridge


 

docker-compose 실행

 

빌드된 내역(실패한거 레전드~)

 

컨테이너

 

Spring boot 로그(initDB 생성 확인)

 

배포된 프로젝트의 swagger 확인