CH_04_02_MySQL 구축
4.2 MySQL 구축
MySQL 컨테이너를 구축하기 위한 전체 디렉터리 구성은 다음과 같습니다.
.
├── containers
│ └── mysql
│ ├── Dockerfile
│ └── etc
│ └── mysql
│ └── conf.d
│ └── slowlog.cnf
└── secrets
├── mysql_root_password
└── mysql_user_password
4.2.1 MySQL 컨테이너 설정 확장하기
많은 서비스가 그렇듯, MySQL 역시 기본 설정만으로 모든 요구사항을 충족하기는 어렵습니다. Nginx가 /etc/nginx/conf.d 디렉터리에 설정 파일을 추가하여 기능을 확장하는 것처럼, MySQL 컨테이너도 유사한 방식으로 커스텀 설정을 적용할 수 있습니다.
설정 파일 위치 확인
먼저, 공식 MySQL 이미지가 설정을 어떻게 관리하는지 직접 확인해 보겠습니다. docker exec 명령어를 사용하면 실행 중인 컨테이너 내부에 들어가 파일 시스템을 탐색할 수 있습니다.
# 실행 중인 MySQL 컨테이너의 셸에 접속합니다.
# (컨테이너 이름 'backend_mysql_1'은 실제 환경에 맞게 변경하세요.)
$ docker exec -it backend_mysql_1 bash
# /etc 디렉터리로 이동하여 my.cnf 파일의 내용을 확인합니다.
bash-5.1# cd /etc
bash-5.1# cat my.cnf
my.cnf 파일은 MySQL의 핵심 설정 파일입니다. 그 내용을 살펴보면 커스텀 설정을 추가할 수 있는 중요한 단서를 찾을 수 있습니다.
# /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.4/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
host-cache-size=0
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/
파일의 가장 마지막 줄에 있는 !includedir /etc/mysql/conf.d/ 지시어가 바로 핵심입니다. 이 지시어는 MySQL 서버가 시작될 때 /etc/mysql/conf.d/ 디렉터리 안에 있는 모든 .cnf 확장자 파일을 자동으로 읽어와 설정에 포함하도록 만듭니다.
커스텀 설정 파일 추가
이 원리를 이용하여, 우리는 성능 분석에 유용한 슬로 쿼리(Slow Query) 로그 설정을 추가해 보겠습니다. 프로젝트의 containers/mysql/etc/mysql/conf.d/ 경로에 slowlog.cnf 파일을 생성합니다.
containers/mysql/etc/mysql/conf.d/
└── slowlog.cnf <- 이 파일을 추가합니다.
slowlog.cnf 파일의 내용은 다음과 같습니다.
[mysqld]
# 슬로 쿼리 로그 기능 활성화
slow_query_log = on
# 슬로 쿼리 로그 파일 경로 지정
slow_query_log_file = /var/log/mysql/mysql-slow.log
# 1초 이상 실행되는 쿼리를 슬로 쿼리로 간주
long_query_time = 1
# 인덱스를 사용하지 않는 쿼리도 로그에 기록
log_queries_not_using_indexes = on
이 설정 파일은 다음과 같은 역할을 합니다.
- 슬로 쿼리 로그 활성화: 실행 시간이 오래 걸리는 쿼리를 추적하는 기능을 켭니다.
- 로그 파일 지정: 슬로 쿼리가 발생했을 때 기록될 로그 파일의 위치를 지정합니다.
- 시간 기준 설정: 1초를 초과하는 쿼리를 슬로 쿼리로 판단합니다.
- 인덱스 미사용 쿼리 로깅: 최적화가 필요한 쿼리를 쉽게 찾을 수 있도록 인덱스를 사용하지 않는 쿼리도 기록합니다.
이제 Dockerfile에서 slowlog.cnf 파일을 컨테이너 이미지의 /etc/mysql/conf.d/ 디렉터리로 복사하도록 설정하면, 컨테이너가 시작될 때 해당 설정이 자동으로 적용됩니다. 이처럼 docker exec를 통해 컨테이너의 내부 동작을 이해하면, 보다 체계적이고 안정적으로 설정을 관리할 수 있습니다.
알겠습니다. docker exec를 통해 컨테이너 내부 설정을 직접 확인하고, 이를 바탕으로 커스텀 설정을 적용하는 과정을 상세히 포함하여 문서를 다시 작성해 드리겠습니다. 초보자도 따라 할 수 있도록 실제 실행 과정을 보여주는 것이 중요하죠.
다음은 요청하신 내용을 반영하여 전문적으로 다듬은 문서입니다.
4.2 MySQL 구축
MySQL 컨테이너를 구축하기 위한 전체 디렉터리 구성은 다음과 같습니다.
.
├── containers
│ └── mysql
│ ├── Dockerfile
│ └── etc
│ └── mysql
│ └── conf.d
│ └── slowlog.cnf
└── secrets
├── mysql_root_password
└── mysql_user_password
4.2.1 MySQL 컨테이너 설정 확장하기
많은 서비스가 그렇듯, MySQL 역시 기본 설정만으로 모든 요구사항을 충족하기는 어렵습니다. Nginx가 /etc/nginx/conf.d 디렉터리에 설정 파일을 추가하여 기능을 확장하는 것처럼, MySQL 컨테이너도 유사한 방식으로 커스텀 설정을 적용할 수 있습니다.
설정 파일 위치 확인
먼저, 공식 MySQL 이미지가 설정을 어떻게 관리하는지 직접 확인해 보겠습니다. docker exec 명령어를 사용하면 실행 중인 컨테이너 내부에 들어가 파일 시스템을 탐색할 수 있습니다.
# 실행 중인 MySQL 컨테이너의 셸에 접속합니다.
# (컨테이너 이름 'backend_mysql_1'은 실제 환경에 맞게 변경하세요.)
$ docker exec -it backend_mysql_1 bash
# /etc 디렉터리로 이동하여 my.cnf 파일의 내용을 확인합니다.
bash-5.1# cd /etc
bash-5.1# cat my.cnf
my.cnf 파일은 MySQL의 핵심 설정 파일입니다. 그 내용을 살펴보면 커스텀 설정을 추가할 수 있는 중요한 단서를 찾을 수 있습니다.
# /etc/my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.4/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
host-cache-size=0
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/
파일의 가장 마지막 줄에 있는 !includedir /etc/mysql/conf.d/ 지시어가 바로 핵심입니다. 이 지시어는 MySQL 서버가 시작될 때 /etc/mysql/conf.d/ 디렉터리 안에 있는 모든 .cnf 확장자 파일을 자동으로 읽어와 설정에 포함하도록 만듭니다.
커스텀 설정 파일 추가
이 원리를 이용하여, 우리는 성능 분석에 유용한 슬로 쿼리(Slow Query) 로그 설정을 추가해 보겠습니다. 프로젝트의 containers/mysql/etc/mysql/conf.d/ 경로에 slowlog.cnf 파일을 생성합니다.
containers/mysql/etc/mysql/conf.d/
└── slowlog.cnf <- 이 파일을 추가합니다.
slowlog.cnf 파일의 내용은 다음과 같습니다.
[mysqld]
# 슬로 쿼리 로그 기능 활성화
slow_query_log = on
# 슬로 쿼리 로그 파일 경로 지정
slow_query_log_file = /var/log/mysql/mysql-slow.log
# 1초 이상 실행되는 쿼리를 슬로 쿼리로 간주
long_query_time = 1
# 인덱스를 사용하지 않는 쿼리도 로그에 기록
log_queries_not_using_indexes = on
이 설정 파일은 다음과 같은 역할을 합니다.
- 슬로 쿼리 로그 활성화: 실행 시간이 오래 걸리는 쿼리를 추적하는 기능을 켭니다.
- 로그 파일 지정: 슬로 쿼리가 발생했을 때 기록될 로그 파일의 위치를 지정합니다.
- 시간 기준 설정: 1초를 초과하는 쿼리를 슬로 쿼리로 판단합니다.
- 인덱스 미사용 쿼리 로깅: 최적화가 필요한 쿼리를 쉽게 찾을 수 있도록 인덱스를 사용하지 않는 쿼리도 기록합니다.
이제 Dockerfile에서 slowlog.cnf 파일을 컨테이너 이미지의 /etc/mysql/conf.d/ 디렉터리로 복사하도록 설정하면, 컨테이너가 시작될 때 해당 설정이 자동으로 적용됩니다. 이처럼 docker exec를 통해 컨테이너의 내부 동작을 이해하면, 보다 체계적이고 안정적으로 설정을 관리할 수 있습니다.
4.2.2 MySQL Dockerfile
이제 커스텀 설정 파일(slowlog.cnf)을 MySQL 이미지에 포함시키기 위한 Dockerfile을 작성합니다.
# containers/mysql/Dockerfile
# 공식 MySQL 8.0.33 이미지를 기반으로 새로운 이미지를 생성합니다.
FROM mysql:8.0.33
# 호스트의 커스텀 설정 파일 디렉터리를 컨테이너 내부의 설정 디렉터리로 복사합니다.
COPY ./etc/mysql/conf.d /etc/mysql/conf.d
이 Dockerfile은 매우 간단합니다. COPY 명령어를 통해 우리가 생성한 slowlog.cnf 파일이 포함된 conf.d 디렉터리 전체를 이미지의 /etc/mysql/conf.d로 복사합니다. 이렇게 빌드된 이미지는 실행될 때 자동으로 슬로 쿼리 로그 설정을 적용하게 됩니다.
4.2.3 Docker Compose를 이용한 서비스 정의
이제 docker-compose.yaml 파일을 통해 MySQL 서비스를 최종적으로 정의합니다. 이 파일은 Dockerfile을 사용하여 이미지를 빌드하고, 데이터베이스 운영에 필요한 환경 변수, 보안 정보, 데이터 영속성 등을 체계적으로 관리합니다.
# compose.yaml
version: "3.9"
services:
mysql:
# 이미지 빌드 방법을 정의합니다.
build:
context: ./containers/mysql # Dockerfile이 위치한 경로
# 컨테이너 실행에 필요한 환경 변수를 설정합니다.
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_DATABASE: taskapp
MYSQL_USER: taskapp_user
MYSQL_PASSWORD_FILE: /run/secrets/mysql_user_password
# 외부의 민감한 정보를 안전하게 컨테이너에 전달합니다.
secrets:
- mysql_root_password
- mysql_user_password
# 데이터베이스 데이터를 영속적으로 저장하기 위해 볼륨을 마운트합니다.
volumes:
- mysql_data:/var/lib/mysql
# 호스트와 컨테이너의 포트를 연결합니다.
ports:
- "3307:3306"
# 최상위 키에서 secrets를 정의합니다.
secrets:
mysql_root_password:
file: ./secrets/mysql_root_password # 호스트에 저장된 비밀번호 파일 경로
mysql_user_password:
file: ./secrets/mysql_user_password
# 최상위 키에서 명명된 볼륨(named volume)을 정의합니다.
volumes:
mysql_data:
상세 설명
build.context:docker-compose가 이미지를 빌드할 때 사용할Dockerfile의 위치를 지정합니다../containers/mysql디렉터리로 지정하면, 해당 경로의Dockerfile을 사용하여mysql서비스 이미지를 빌드합니다.environment: 컨테이너 환경 변수를 설정합니다.MYSQL_ROOT_PASSWORD_FILE:MYSQL_ROOT_PASSWORD와 달리, 비밀번호가 저장된 파일의 경로를 값으로 받습니다. 이는 비밀번호를 환경 변수에 직접 노출하지 않아 보안에 더 안전한 방식입니다.MYSQL_DATABASE,MYSQL_USER,MYSQL_PASSWORD_FILE: 컨테이너가 처음 시작될 때 지정된 이름으로 데이터베이스와 사용자를 자동으로 생성합니다. 사용자 비밀번호 역시 파일로부터 안전하게 읽어옵니다.
secrets: Docker Compose를 사용하여 민감한 데이터를 관리하는 가장 안전하고 권장되는 방법입니다.- 최상위
secrets블록에서 시크릿의 이름(mysql_root_password)과 실제 비밀번호가 담긴 호스트의 파일 경로(file: ./secrets/...)를 정의합니다. - 서비스(
mysql) 내의secrets블록에서 사용할 시크릿의 이름을 참조하면,docker-compose는 호스트의 비밀번호 파일 내용을 읽어 컨테이너 내부의/run/secrets/<시크릿_이름>경로에 임시 파일을 생성하여 마운트합니다. - 이 메커니즘 덕분에,
MYSQL_ROOT_PASSWORD_FILE환경 변수가/run/secrets/mysql_root_password파일을 읽어 비밀번호를 설정할 수 있게 됩니다. 중요한 것은 비밀번호 파일 자체(secrets디렉터리)를 절대로 Git과 같은 버전 관리에 포함해서는 안 된다는 점입니다.
- 최상위
volumes: 컨테이너가 삭제되더라도 데이터를 보존하기 위해 사용합니다. (3.5장 영속성 데이터 참고)mysql_data:/var/lib/mysql:mysql_data라는 이름의 볼륨(Named Volume)을 컨테이너의/var/lib/mysql디렉터리(MySQL이 실제 데이터를 저장하는 경로)에 마운트합니다.- 최상위
volumes블록에mysql_data:를 선언함으로써 도커가 관리하는 영속적인 데이터 저장 공간을 생성합니다. 이를 통해 컨테이너를 재생성해도 모든 데이터베이스 정보는 그대로 유지됩니다.
ports: 호스트 컴퓨터와 컨테이너 간의 네트워크 포트를 연결합니다."3307:3307": 호스트 컴퓨터의3307번 포트로 들어오는 요청을 컨테이너 내부의3307번 포트로 전달합니다. 이를 통해 로컬 PC의 개발 도구에서localhost:3307로 접속하여 컨테이너의 MySQL 서버에 연결할 수 있습니다.