본문 바로가기

Docker

Docker compose 설정 및 각종 테스트

728x90

Docker compose란?

여러 개의 Docker Container를 정의하고 이들을 하나의 애플리케이션으로 관리할 수 있게 해주는 것

 

  • 여기서는 두 개의 컨테이너를 동일 네트워크에 포함시킬 예정
  • 네트워크는 별도로 설정하지 않으면 기본값인 bridge로 설정
  • docker compose를 사용하면 자동으로 브릿지 네트워크가 생기고 두 컨테이너는 해당 네트워크에 종속

0. 시작 전 현재 Image와 Container 확인

  • application.yml에서 server.port=8081로 포트 번호를 변경해준 modify-port-image 파일 한 개만 존재

docker-compose.yml 생성 및 mysql 설정

1. root 컨텍스트에 docker-compose.yml 파일 생성

 

2. docker-compose.yml 파일 작성

version: '3.8'
services:
  db:
    image: mysql:8.0
    container_name: mysql-container
    environment:
      MYSQL_ROOT_PASSWORD : 1234
      MYSQL_DATABASE: test
    ports:
      - "3306:3306"
  • version : '3.8'
    • Docker compose 파일의 버전
  • services
    • 서비스를 정의
  • db
    • 데이터베이스 서비스의 이름
  • image : mysql:8.0
    • 사용할 Docker Image를 지정, 여기서는 공식 MySQL Docker Image를 사용하여 8.0버전을 가져옴
  • container_name : mysql-container
    • 컨테이너 이름 지정
    • ex) docker run --name <컨테이너 이름>에서 컨테이너 이름을 지정하던 것과 동일, 아래 결과에서 확인
  • environment
    • MySQL 컨테이너에 전달할 환경 변수 설정
    • MySQL 컨테이너는 이 환경 변수를 읽어서 MySQL 서버를 설정
      • MYSQL_ROOT_PASSWORD : MySQL root 사용자의 비밀번호 설정
      • MYSQL_DATABASE : MySQL 데이터베이스의 이름 설정
      • MYSQL_USER : MySQL 사용자의 이름 설정
      • MYSQL_PASSWORD : MySQL 사용자의 비밀번호 설정
  • ports
    • 호스트와 컨테이너 간의 포트 매핑 정의
      • - "3306:3306"  → -"호스트 포트:컨테이너 포트"
      • 단, 로컬 컴퓨터에 MySQL이 설치되어 있으면 3306포트를 사용 중이기 때문에 아래와 같은 에러 발생

호스트의 포트를 변경하여 다시 시작

  • mysql의 이미지를 다운 받는데 약 30초 정도 소요

  • Docker Image에 mysql 이미지 추가

Container에 나의 Root 이름과 같은 'simple-spring-boot'라는 컨테이너 추가

  • 클릭 시 docker-compose.yml의 container_name : mysql-container로 설정했기에 동일한 이름의 컨테이너가 존재

 

3. 스프링(applicaiton.yml)과 mysql 연결

server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect
  • docker-compose의 DB 정보를 작성해야 함
  • 모든 설정이 끝난 뒤 가장 아래에서 수정하여 다시 시도

spring + mysql docker-compose 생성

1. docker-compose.yml 내용 변경

version: '3.8'
services:
    myapp:
      image: modify-port-image
      container_name: springboot-container
      build:
        context: .
        dockerfile: Dockerfile
      depends_on:
        db :
          condition: service_healthy
      ports:
        - "8081:8081"

    db:
      image: mysql:8.0
      container_name: mysql-container
      environment:
        MYSQL_ROOT_PASSWORD : 1234
        MYSQL_DATABASE: test
      ports:
        - "3307:3306"
      healthcheck:
        test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p1234 && sleep 5"]
        interval: 5s
        retries: 10
  • 현재 서비스는 myapp, db 두 개의 서비스가 정의
  • myapp
    • Spring Boot 어플리케이션 서비스의 이름
  • image : modify-port-image
    • Spring Boot 어플리케이션에 사용할 Docker 이미지를 지정
    • port가 8081로 설정된 modify-port-image로 지정
  • build
    • context : . 
      • docker-compose.yml이 있는 현재 디렉토리를 빌드 컨텍스트로 사용하겠다는 의미
    • dockerfile : Dockerfile
      • context로 지정된 디렉토리에 있는 Dockerfile을 사용하여 이미지를 빌드하겠다는 의미
  • depends_on : db
    • db 서비스를 먼저 실행 시키라는 의미
  • condition : service_healthy
    • 의존할 서비스(db)의 상태가 건강한 지(정상 작동되는 서버인지) 확인
  • healthcheck
    • 아래의 내용들로 서버 상태 확인
    • test, interval, retries : 5초 간격으로 10번 ping 보내서 상태를 확인

2. IntellJ에서 docker-compose.yml 실행 또는 터미널에서 docker compose up 명령어

  • mysql-container가 실행 중이기 때문에 계속하여 health check를 함

  • mysql-container의 상태가 Waiting → Healthy가 된 후 springboot-container가 Started로 변경

3. Postman을 이용하여 정상 작동 확인


Database를 연동한 것이기 때문에 제대로 DB에 저장이 되는 지 확인이 필요하기 때문에 간단한 CRUD 생성 필요

JPA와 Lombok 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.projectlombok:lombok'

 

다음과 같이 간단하게 Service 없이 Entity, Dto, Controller, Repository만 구성

Docker Container가 켜져 있으면 서버포트를 바꾸지 않는 이상 충돌이 발생하여 반드시 끌 것

BoardController

package com.example.simplespringboottest.board;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/board")
@RequiredArgsConstructor
public class BoardController {
    private final BoardRepository boardRepository;

    @GetMapping("/board")
    public ResponseEntity<List<BoardDto>> allList(){
        List<Board> entityList = boardRepository.findAll();
        List<BoardDto> dtoList = entityList.stream().map(BoardDto::new).collect(Collectors.toList());
        System.out.println(dtoList);
        if(!dtoList.isEmpty())
            return new ResponseEntity<>(dtoList, HttpStatus.OK);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }

    @PostMapping("/board")
    public ResponseEntity<String> addArticle(@RequestBody BoardDto boardDto){
        Board board = new Board(boardDto);
        Board res = boardRepository.save(board);
        if(res != null)
            return ResponseEntity.status(HttpStatus.OK).body("게시글 등록 완료");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

BoardRepository

package com.example.simplespringboottest.board;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BoardRepository extends JpaRepository<Board, Long> {
}

Board

package com.example.simplespringboottest.board;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
public class Board {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;

    public Board(BoardDto dto){
        this.id = dto.getId();
        this.title = dto.getTitle();
        this.content = dto.getContent();
    }
}

BoardDto

package com.example.simplespringboottest.board;

import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class BoardDto {
    private Long id;
    private String title;
    private String content;

    public BoardDto(Board board){
        this.id = board.getId();
        this.title = board.getTitle();
        this.content = board.getContent();
    }
}

Postman으로 정상 작동 확인


 

Docker compose로 확인

1. IntelliJ 서버 종료

2. 코드가 변경되었으므로 Docker를 처음부터 다시 진행

3. 빌드

4. docker build -t add-board-service-image . → 새로운 이미지 생성

5. 기존 컨테이너 삭제 

  • IntelliJ의 docker-compose.yml에서 재시작 또는 docker compose up 명령어
  • 아래의 빨간 네모칸의 상태가 정지가 된 것이 있으면, 뭔가 문제가 발생했다는 의미

 

6. Postman 확인

 


※ 주의사항

application.yml 또는 application.properties의 url이 localhost로 설정하지 않도록 주의

docker-compose.yml의 enviroment도커의 mysql 인증 ID, Password, Database이기 때문에

application.yml을 모놀리식에서 사용하던 것처럼 하면 안 되고 docker-compose.yml에 맞춰주여야 함

단, 아래처럼 하면 build 시 실패가 나오긴 하지만 무시하고 진행

빌드 시 에러


docker-application.yml과 application.yml 설정 다르게하여 오류 발생 테스트

  • application.yml 파일
    • url, root, password 모두 나의 로컬에 맞춤
server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQLDialect



 

  • docker-compose.yml 파일
    • environment 정보를 docker 내부의 mysql에 생성할 정보로 생각하고 작성함
version: '3.8'
services:
    myapp:
      image: yml-mismatch-image
      container_name: springboot-container
      build:
        context: .
        dockerfile: Dockerfile
      depends_on:
        db :
          condition: service_healthy
      ports:
        - "8081:8081"

    db:
      image: mysql:8.0
      container_name: mysql-container
      environment:
        MYSQL_ROOT_PASSWORD : root
        MYSQL_DATABASE: dockerdb
        MYSQL_USER : user
        MYSQL_PASWOORD : user
      ports:
        - "3307:3306"
      healthcheck:
        test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p1234 && sleep 5"]
        interval: 5s
        retries: 10

 

1. 빌드

2. 설정 파일 변경되었으니 새로운 이미지 생성

  • docker build -t yml-mismatch-image .

3. 도커 컨테이너 삭제

4. docker compose up

5. container 내부에서 spring 서비스 에러로 중단된 것 확인

  • 대략 Database 연동 시 에러가 발생하였다는 문제


에러는 확인하였으니 application.yml 파일의 DB 연동 정보를 docker-compose.yml에 맞춤

1. 빌드

2. 설정 파일 변경되었으니 새로운 이미지 생성

  • docker build -t yml-match-image .

3. 기존 컨테이너 삭제

4. docker compose up

5. 컨테이너 안의 두 서비스 모두 정상 작동 확인

6. Postman 확인

 

application.yml과 docker.compose.yml 변경 사항

728x90

'Docker' 카테고리의 다른 글

[Docker Compose] Spring Boot + MySQL + Redis  (0) 2024.08.21
Docker 설치 및 환경 설정  (0) 2024.08.09
Docker란?  (0) 2024.08.08
컨테이너 vs 가상머신(VM)  (0) 2024.08.08