본문 바로가기

devops

docker-compose를 이용한 MySQL서버를 배포하고 Spring연동하기

728x90

1. Spring

(1) Gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
}

 

테스트를 위해 springweb,spring-data-jpa,lombok,mysql를 추가해줍니다.

(2) application.yml

spring:
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true

logging.level:
    org.hibernate.SQL: debug

 

Member 테이블이 만들어지는 sql log를 볼 수 있도록 yml파일에 설정합니다.

(3) Domain

@Entity
@NoArgsConstructor
@Getter
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    private String name;

    @Column(unique = true)
    private String email;

    public Member(String name,String email){
        this.name = name;
        this.email = email;
    }
}

 

이름과 이메일을 가지는 Member class를 생성합니다.

(4) Repository

public interface MemberRepository extends JpaRepository<Member,Long>{

}

(5) Dto

@Getter
@NoArgsConstructor
public class MemberSaveDto {
    private String name;
    private String email;
}

 

Member를 저장할 때 쓰이는 이름과 이메일을 받아오는 Dto를 생성합니다.

(6) Controller

@RestController
@AllArgsConstructor
public class MemberController {

    private final MemberRepository memberRepository;

    @PostMapping("/member")
    public Long saveMember(@RequestBody MemberSaveDto memberSaveDto){
        Member member = new Member(memberSaveDto.getName(), memberSaveDto.getEmail());
        memberRepository.save(member);

        return member.getId();
    }

    @GetMapping("/member")
    public List<Member> findAllMember(){
        return memberRepository.findAll();
    }

    @GetMapping("/member/{id}")
    public Member findMember(@PathVariable Long id){

        return memberRepository.findById(id).get();
    }
}

Member를 저장하고 Member들의 정보를 들고오는 api를 가지는 Controller를 생성합니다.

2.ubuntu(docker-server)

(1) mysql 이미지 Pull

docker pull mysql:8.0

 

mysql 이미지를 받아옵니다.

 

(2) mysql.env 파일

MYSQL_DATABASE=[database_name]
MYSQL_ROOT_HOST=%
MYSQL_ROOT_PASSWORD=[password]
TZ=Asia/Seoul

(3) spring.env 파일

SPRING_DATASOURCE_URL=jdbc:mysql://[mysql-container-name]:3306/[database_name]?allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=[password]

 

database_name과 password 는 2의 mysql.env파일과 동일하게 작성합니다.

 

(4) docker-compose.yml

version: '3'
services:
  docker_gradle:
    container_name: docker_gradle
    image: docker_gradle
    ports:
      - "8081:8081"
    env_file:
      - ./spring/spring.env
    depends_on:
      mysql:
        condition: service_healthy
  mysql:
    container_name: mysql
    image: mysql:8.0
    restart: unless-stopped
    env_file:
      - ./mysql/mysql.env
    ports:
      - "13306:3306"
    command:
      - "mysqld"
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_unicode_ci"
    healthcheck:
      test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD']
      interval: 10s
      timeout: 2s
      retries: 100

mysql 컨테이너가 생성되고 MySQL 데이터베이스가 생성되는데 시간이 조금 소요됩니다.

mysql 데이터베이스가 생성되지 않은 상태로 spring server 가 올라가면 database connection에러가 발생합니다.

그러므로 mysqladmin ping을 이용하여 mysql 데이터베이스가 생성되었는지 검사하고,mysql 데이터베이스가 완전히 생성되었을 때 spring server container를 생성합니다.

(5) 실행 및 확인

1. docker compose 실행

docker compose up

spring log

docker compose를 daemon 모드로 실행하지 않고 spring server와 mysql server가 잘 연동되는지 확인합니다.

 

2. mysql container 접속

# mysql container 접속
docker exec -it [mysql_container_name] bash

3. mysql 접속

# mysql 접속
mysql -u root -p

mysql 접속화면

4. member 테이블 확인

# database 목록 확인
show databases;

# database 선택
use test;

# table 목록 확인
show tables;

테이블 확인

 

위의 명령어를 이용하여 member 테이블이 생성되었는지 확인합니다.

(6) volumes 설정

1. conf.d / utf8.cnf

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

[mysql]
default-character-set = utf8mb4

[client]
default-character-set = utf8mb4

 

 

2.conf.d / log.cnf

[mysqld]
general_log=ON
general_log_file=/var/log/mysql/general.log

log_error=/var/log/mysql/error.log

slow_query_log=ON
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
log-queries-not-using-indexes

log_timestamps=SYSTEM

3. docker-compose.yml

version: '3'
services:
  docker_gradle:
    container_name: docker_gradle
    image: docker_gradle
    restart: on-failure
    ports:
      - "8081:8081"
    env_file:
      - ./spring/spring.env
    depends_on:
      mysql:
        condition: service_healthy
  mysql:
    container_name: mysql
    image: mysql:8.0
    restart: unless-stopped
    env_file:
      - ./mysql/mysql.env
    ports:
      - "13306:3306"
    volumes:
      - ./mysql/data:/var/lib/mysql
      - ./mysql/log:/var/log/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d
    healthcheck:
      test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 -u root --password=$$MYSQL_ROOT_PASSWORD']
      interval: 10s
      timeout: 2s
      retries: 10

 

컨테이너가 삭제 될 시 mysql의 로그와 데이터는 사라지기 때문에 volume mount를 통해 데이터와 로그를 보관합니다.

728x90