안녕하세요. 이번 글에서는 MySQL 데이터베이스 환경을 Docker를 이용하여 구축하는 방법에 대해 알아보겠습니다.
1. 개요
Docker를 사용하여 데이터베이스 환경을 구축하면 다음과 같은 이점이 있습니다:
- 개발 환경의 일관성 유지
- 빠른 설정 및 배포
- 격리된 환경에서의 안전한 테스트
- 버전 관리 용이성
우리 프로젝트에서는 MySQL 8.0.31 버전을 사용하며, 초기 스키마 및 데이터 설정을 자동화하여 편리한 개발 환경을 구성할 것입니다.
2. 도커 디비 구성을 위한 디렉토리 트리 구조
먼저 Docker 관련 파일들의 구조를 살펴보겠습니다:
docker/
└── db/
├── Dockerfile
├── compose.yml
├── init_scripts/
│ ├── 001_DDL.sql
│ └── 002_DCL.sql
└── mysql/
└── my.cnf
3. Dockerfile 작성
Dockerfile
은 다음과 같이 작성합니다:
FROM mysql:8.0.31
COPY mysql/my.cnf /etc/mysql/my.cnf
COPY init_scripts /docker-entrypoint-initdb.d
RUN chmod 644 /docker-entrypoint-initdb.d/*.sql
이 Dockerfile은 다음 작업을 수행합니다:
- MySQL 8.0.31 이미지를 기반으로 합니다.
- 커스텀 MySQL 설정 파일을 컨테이너 내부로 복사합니다.
- 초기화 SQL 스크립트를 컨테이너의 적절한 위치로 복사합니다.
- SQL 스크립트의 실행 권한을 설정합니다.
4. Docker Compose 파일 작성
compose.yml
파일을 다음과 같이 작성합니다:
version: '3.8'
services:
board-db:
build:
context: ./
dockerfile: Dockerfile
container_name: board_db_container
image: board-db:latest
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: board_db
TZ: Asia/Seoul
volumes:
- board_db_data:/var/lib/mysql
- ./mysql/my.cnf:/etc/mysql/my.cnf
- ./init_scripts:/docker-entrypoint-initdb.d
restart: always
volumes:
board_db_data:
이 설정은 다음을 정의합니다:
- 서비스 이름과 컨테이너 이름
- 포트 매핑 (호스트의 3306 포트를 컨테이너의 3306 포트로 매핑)
- 환경 변수 (root 비밀번호, 데이터베이스 이름, 시간대)
- 볼륨 설정 (데이터 영속성, 설정 파일, 초기화 스크립트)
5. 초기화 SQL 스크립트
init_scripts
폴더에 있는 SQL 파일들은 컨테이너가 처음 시작될 때 실행됩니다.
001_DDL.sql
파일의 일부 내용:
DROP DATABASE IF EXISTS board;
CREATE DATABASE board CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE board;
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
userId VARCHAR(45) NOT NULL,
password VARCHAR(64) NOT NULL,
nickname VARCHAR(45) NOT NULL,
isAdmin TINYINT(1) DEFAULT 0,
createTime DATETIME DEFAULT CURRENT_TIMESTAMP,
updateTime DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
isWithdraw TINYINT(1) DEFAULT 0,
status ENUM('DEFAULT', 'ADMIN', 'DELTED') DEFAULT 'DEFAULT'
);
-- 기타 테이블 생성 쿼리
002_DCL.sql
파일의 내용:
CREATE USER 'developer'@'%' IDENTIFIED WITH mysql_native_password BY '12345';
GRANT ALL PRIVILEGES ON board.* TO 'developer'@'%';
CREATE USER 'developer'@'localhost' IDENTIFIED WITH mysql_native_password BY '12345';
GRANT ALL PRIVILEGES ON board.* TO 'developer'@'localhost';
CREATE USER 'developer'@'_gateway' IDENTIFIED WITH mysql_native_password BY '12345';
GRANT ALL PRIVILEGES ON board.* TO 'developer'@'_gateway';
FLUSH PRIVILEGES;
-- 기타 권한 설정
이 SQL 스크립트는 세 가지 다른 호스트 패턴으로 'developer' 사용자를 생성하고 있습니다. 각각의 이유와 목적을 설명해드리겠습니다:
1. `'developer'@'%'`:
- '%'는 모든 호스트를 의미합니다.
- 이 사용자는 어떤 IP 주소에서든 데이터베이스에 접속할 수 있습니다.
- 주로 원격 접속이 필요한 개발 환경이나 다양한 서버에서의 접근을 허용할 때 사용됩니다.
2. `'developer'@'localhost'`:
- 이 사용자는 오직 데이터베이스 서버가 실행 중인 로컬 머신에서만 접속할 수 있습니다.
- 로컬 개발 환경에서 사용되거나, 보안상의 이유로 로컬 접속만을 허용하고 싶을 때 사용됩니다.
3. `'developer'@'_gateway'`:
- '_gateway'는 특정 네트워크 구성, 특히 Docker 네트워크에서 사용되는 특별한 호스트명입니다.
- Docker 컨테이너 간 통신에서 사용될 수 있으며, 특정 게이트웨이나 프록시를 통한 접근을 허용합니다.
이렇게 세 가지 다른 호스트 패턴으로 사용자를 생성하는 이유는 다음과 같습니다:
- 유연성: 다양한 환경(로컬, 원격, 특정 네트워크)에서의 접속을 지원합니다.
- 보안: 필요에 따라 접근을 제한할 수 있습니다. 예를 들어, 특정 상황에서는 로컬 접속만 허용하고 싶을 수 있습니다.
- Docker 지원: '_gateway' 사용자는 Docker 네트워크 환경에서의 특별한 접근을 지원합니다.
이 접근 방식은 개발, 테스트, 그리고 다양한 배포 환경에서 유연하게 대응할 수 있도록 해줍니다. 하지만 실제 프로덕션 환경에서는 보안을 위해 더 제한적인 접근 정책을 사용해야 할 수 있습니다.
6. MySQL 설정 파일
my.cnf
파일에서 필요한 MySQL 설정을 정의할 수 있습니다:
# /db/conf.d/my.cnf
[client]
default-character-set = utf8mb4 # 클라이언트의 기본 문자 집합을 utf8mb4로 설정합니다. 이는 이모지와 같은 4바이트 문자를 지원하여 다양한 언어와 기호를 처리할 수 있습니다.
[mysql]
default-character-set = utf8mb4 # mysql 커맨드 라인의 기본 문자 집합을 utf8mb4로 설정합니다. 이는 이모지와 같은 4바이트 문자를 지원하여 다양한 언어와 기호를 처리할 수 있습니다.
[mysqld]
pid-file = /var/lib/mysql/mysqld.pid # MySQL 서버 프로세스 ID를 저장하는 파일의 경로를 설정합니다. 이는 서버가 실행 중인지 확인하고 제어하는 데 사용됩니다.
socket = /var/run/mysqld/mysqld.sock # MySQL 서버의 소켓 파일 경로를 설정합니다. 이는 MySQL 클라이언트가 서버에 연결하는 데 사용됩니다.
datadir = /var/lib/mysql # MySQL 데이터베이스 파일이 저장되는 디렉토리 경로를 설정합니다. 모든 데이터베이스 파일과 로그 파일이 이 위치에 저장됩니다.
#log-error = /var/log/mysql/error.log # MySQL 서버의 에러 로그 파일 경로를 설정합니다. 서버에서 발생하는 오류 및 경고가 이 파일에 기록됩니다.
authentication_policy = mysql_native_password
default-time-zone = '+09:00'
bind-address = 0.0.0.0 # MySQL 서버가 모든 네트워크 인터페이스에서 연결을 수락하도록 설정합니다. 이를 통해 서버가 외부 네트워크에서 접근 가능하게 됩니다.
max_allowed_packet = 1G # MySQL 서버가 허용하는 최대 패킷 크기를 1GB로 설정합니다. 이는 서버가 처리할 수 있는 최대 단일 쿼리 크기를 정의합니다.
max_connect_errors = 1000000 # 최대 허용 연결 오류 횟수를 1,000,000으로 설정합니다. 이 값에 도달하면 해당 호스트의 연결이 차단됩니다. 이는 무차별 대입 공격을 방지하는 데 도움이 됩니다.
# InnoDB 설정
default_storage_engine = InnoDB # 기본 저장 엔진을 InnoDB로 설정합니다. InnoDB는 트랜잭션을 지원하고 데이터 무결성을 보장합니다.
innodb_buffer_pool_instances = 2 # InnoDB 버퍼 풀 인스턴스를 2개로 설정합니다. 버퍼 풀 크기가 1GB 이상일 때 인스턴스 수를 늘려 성능을 향상시킬 수 있습니다.
innodb_buffer_pool_size = 1G # InnoDB 버퍼 풀 크기를 1GB로 설정합니다. 이는 메모리 내 데이터 및 인덱스를 캐싱하여 디스크 I/O를 최소화합니다. 일반적으로 전체 RAM의 70-80%까지 사용할 수 있습니다.
innodb_file_per_table = 1 # 각 테이블에 독립적인 테이블 스페이스 파일을 사용하도록 설정합니다. 이는 데이터 관리를 용이하게 하고 성능을 향상시킵니다.
innodb_flush_log_at_trx_commit = 0 # 트랜잭션 커밋 시 로그를 디스크에 플러시하지 않도록 설정하여 성능을 향상시킵니다. 이 설정은 데이터 손실 위험을 증가시킬 수 있으므로 개발 환경에서 주로 사용됩니다.
innodb_flush_method = O_DIRECT # 직접 I/O를 사용하여 디스크에 데이터를 기록합니다. 이는 버퍼 캐시를 우회하여 디스크 I/O 성능을 향상시킵니다.
innodb_log_buffer_size = 16M # InnoDB 로그 버퍼 크기를 16MB로 설정합니다. 이는 트랜잭션 로그가 디스크에 기록되기 전에 메모리에 저장되는 크기를 정의합니다.
innodb_redo_log_capacity = 512MB # InnoDB Redo 로그 용량을 512MB로 설정합니다. 이는 재시작 시 복구 시간을 단축하고 성능을 향상시킵니다.
innodb_stats_on_metadata = 0 # 메타데이터 액세스 시 InnoDB 통계를 업데이트하지 않도록 설정합니다. 이는 SHOW TABLE STATUS 같은 명령의 성능을 향상시킵니다.
#innodb_temp_data_file_path = ibtmp1:64M:autoextend:max:20G # 임시 데이터 파일의 경로 및 최대 크기를 설정합니다. 이는 대용량 임시 테이블을 처리할 때 유용합니다.
#innodb_thread_concurrency = 4 # 선택 사항: 시스템의 CPU 수(1 또는 2개 감소)로 설정하여 CPU 사용량을 제어합니다. 예: 시스템에 8개의 CPU가 있으면 6 또는 7로 설정하고 MySQL/MariaDB가 생성하는 전체 부하를 확인합니다.
innodb_read_io_threads = 64 # InnoDB 읽기 I/O 스레드 수를 64개로 설정합니다. 이는 동시 읽기 작업을 더 잘 처리할 수 있도록 도와줍니다.
innodb_write_io_threads = 64 # InnoDB 쓰기 I/O 스레드 수를 64개로 설정합니다. 이는 동시 쓰기 작업을 더 잘 처리할 수 있도록 도와줍니다.
# 연결 설정
max_connections = 100 # MySQL 서버의 최대 동시 연결 수를 100으로 설정합니다. 이는 서버가 동시에 처리할 수 있는 최대 클라이언트 수를 정의합니다.
back_log = 512 # MySQL 서버가 대기할 수 있는 최대 연결 요청 수를 512로 설정합니다. 이 값이 너무 낮으면 서버가 새로운 연결 요청을 거부할 수 있습니다.
thread_cache_size = 100 # 스레드 캐시 크기를 100으로 설정합니다. 캐시된 스레드를 재사용하여 새 스레드를 생성하는 비용을 줄일 수 있습니다.
thread_stack = 192K # 각 스레드의 스택 크기를 192KB로 설정합니다. 이는 각 스레드가 사용할 메모리 양을 정의합니다.
interactive_timeout = 180 # 대화형 세션의 타임아웃 시간을 180초로 설정합니다. 이 시간이 지나면 대기 상태의 대화형 세션이 자동으로 종료됩니다.
wait_timeout = 180 # 대기 중인 세션의 타임아웃 시간을 180초로 설정합니다. 이 시간이 지나면 대기 상태의 세션이 자동으로 종료됩니다.
max_heap_table_size = 1G # 메모리 내 테이블의 최대 크기를 1GB로 설정합니다. 이는 임시 테이블의 크기를 제한하여 메모리 사용을 제어합니다.
tmp_table_size = 1G # 임시 테이블의 최대 크기를 1GB로 설정합니다. 이는 디스크 기반 임시 테이블이 사용되기 전에 메모리 내에서 사용할 수 있는 임시 테이블 크기를 제한합니다.
character-set-client-handshake = FALSE # 클라이언트와 서버 간의 문자 집합 핸드셰이크를 비활성화하여 서버가 항상 설정된 문자 집합을 사용하도록 강제합니다.
character-set-server = utf8mb4 # 서버의 기본 문자 집합을 utf8mb4로 설정합니다. 이는 이모지와 같은 4바이트 문자를 지원하여 다양한 언어와 기호를 처리할 수 있습니다.
collation-server = utf8mb4_unicode_ci # 서버의 기본 콜레이션을 utf8mb4_unicode_ci로 설정합니다. 이는 유니코드 대소문자 구분 없는 비교를 지원합니다.
secure-file-priv = "/var/lib/mysql-files" # 보안 파일 경로를 빈 문자열로 설정하여 외부 파일 작업에 대한 제한을 해제합니다.
[mysqldump]
quick # 덤프 중에 행을 빨리 가져오기 위해 각 테이블을 덤프할 때 row-by-row 방식을 사용합니다.
quote_names # 테이블과 열 이름에 따옴표를 사용하여 이름이 예약어일 때 문제를 방지합니다.
max_allowed_packet = 1G # mysqldump가 허용하는 최대 패킷 크기를 설정합니다.
7. Docker 컨테이너 실행
다음 명령어로 Docker 컨테이너를 실행합니다:
docker-compose up -d
이 명령어는 compose.yml
파일에 정의된 대로 MySQL 컨테이너를 백그라운드에서 실행합니다.
8. 데이터베이스 접속 확인
컨테이너가 정상적으로 실행되었다면, 다음 명령어로 MySQL에 접속할 수 있습니다:
docker exec -it board_db_container mysql -u developer -p
비밀번호를 입력하고 나면, MySQL 프롬프트가 나타나며 데이터베이스 조작이 가능합니다.
결론
이렇게 Docker를 이용하여 MySQL 데이터베이스 환경을 구축했습니다. 이 방식은 개발 환경의 일관성을 유지하고, 팀원 간의 설정 차이로 인한 문제를 최소화할 수 있습니다. 다음 글에서는 이 데이터베이스를 활용하여 유저 API를 구현하는 방법에 대해 알아보겠습니다.
이 글은 프로젝트의 실제 구현을 바탕으로 작성되었으며, Docker를 이용한 데이터베이스 환경 구축 과정을 상세히 설명하고 있습니다. 코드 예제와 함께 각 단계별 설명을 제공하여 독자들이 쉽게 따라할 수 있도록 구성했습니다.
'프레임워크 > 자바 스프링' 카테고리의 다른 글
대규모 트래픽 게시판 구축 시리즈 #5: MySQL 데이터베이스 연결 설정 (1) | 2024.09.05 |
---|---|
대규모 트래픽 게시판 구축 시리즈 #4: 프로젝트 초기 셋업 (3) | 2024.09.05 |
대규모 트래픽 게시판 구축 시리즈 #2: 프로젝트 기획 및 요구 사항 (0) | 2024.09.05 |
대규모 트래픽 게시판 구축 시리즈 #1: 프로젝트 기획 및 요구 사항 (0) | 2024.09.05 |
[spring cloud][ecommerce] 개요 & 구성 (0) | 2024.08.12 |