이전에는 하나의 서버 내에서 Docker-Compose 기반으로 MySQL Replication을 구성하였으나,
이번에는 같은 VPC 내 서로 다른 서버에 위치한 MySQL 인스턴스 간의 Replication 구성 과정을 기록하였습니다.
현재 구성
서버 1: Docker, MySQL (Master)
서버 2: Docker, MySQL (Slave)
DB 환경 설정
Master DB 설정
인증서 생성
MySQL Replication에서
caching_sha2_password
인증 방식을 그대로 유지하려면 SSL 연결이 필수입니다. 이를 위해 서버 측에서 사용할 인증서를 직접 생성합니다.
mkdir -p /etc/mysql/certs && cd /etc/mysql/certs
# 1. CA 생성
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem -subj "/CN=MySQL_CA"
# 2. Server 인증서
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -out server-req.pem -subj "/CN=MySQL_Server"
openssl x509 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
# 3. Client 인증서
openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -out client-req.pem -subj "/CN=MySQL_Client"
openssl x509 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem
# 4. 권한 설정
chmod 644 server-key.pem server-cert.pem ca.pem
Slave 서버로 인증서 복사
SSL 연결을 위해 Master에서 생성한 인증서를 Slave 쪽에도 복사해줍니다.
Slave에도 동일한 디렉터리 구조(
/etc/mysql/certs/
)가 있어야합니다.
scp /etc/mysql/certs/* root@{슬레이브 서버 IP}:/etc/mysql/certs/
my.cnf 작성
vim /home/ubuntu/my.cnf
[client]
# 클라이언트의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4
[mysql]
# MySQL의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4
[mysqld]
# SSL 인증을 위한 CA, 서버 인증서, 서버 키 경로 설정
ssl-ca=/etc/mysql/certs/ca.pem
ssl-cert=/etc/mysql/certs/server-cert.pem
ssl-key=/etc/mysql/certs/server-key.pem
# 보안 연결(SSL)만 허용
require_secure_transport=ON
# MySQL 서버의 문자 집합을 utf8mb4로 설정합니다.
character-set-server = utf8mb4
# MySQL 서버의 정렬을 utf8mb4_unicode_ci로 설정합니다.
collation-server = utf8mb4_unicode_ci
# 서버의 기본 시간대를 GMT+9로 설정합니다.
default-time-zone = '+9:00'
# 이진 로그를 사용하여 MySQL 서버에서 발생한 변경 사항을 기록합니다. mysql-bin은 이진 로그 파일의 이름을 지정합니다.
log-bin = mysql-bin
# MySQL 서버의 고유한 식별자를 설정합니다. 이 식별자는 MySQL 복제(replication) 설정에서 사용됩니다.
server-id = 1
MySQL 실행
docker run -d \
--name master \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_USER=admin_ohy \
-e MYSQL_PASSWORD=adminpassword \
-e MYSQL_DATABASE=today-table \
-p 3306:3306 \
-v /home/ubuntu/mysql_data:/var/lib/mysql \
-v /etc/mysql/certs:/etc/mysql/certs \
-v /home/ubuntu/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:8.0.33
Slave DB 설정
Slave는 Master에서 전달받은 데이터를 그대로 반영하는 역할을 하므로, 읽기 전용 설정 및 relay log 설정이 필요합니다.
my.cnf 작성
vim /home/ubuntu/my.cnf
[client]
# MySQL 클라이언트의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4
[mysql]
# MySQL의 기본 문자 집합을 utf8mb4로 설정합니다.
default-character-set = utf8mb4
[mysqld]
# MySQL 서버의 문자 집합을 utf8mb4로 설정합니다.
character-set-server = utf8mb4
# MySQL 서버의 정렬을 utf8mb4_unicode_ci로 설정합니다.
collation-server = utf8mb4_unicode_ci
# 서버의 기본 시간대를 GMT+9로 설정합니다.
default-time-zone = '+9:00'
# 복제를 위해 바이너리 로깅을 활성화합니다.
log_bin = mysql-bin
# 복제를 위한 서버 식별자를 설정합니다.
server_id = 2
# MySQL 슬레이브 서버에서 중계 로그를 저장할 위치를 지정합니다.
relay_log = /var/lib/mysql/mysql-relay-bin
# 슬레이브 서버에서 변경 사항을 이진 로그에 기록하도록 합니다.
log_replica_updates = ON
# 슬레이브 서버를 읽기 전용 모드로 설정합니다.
read_only
MySQL 실행
docker run -d \
--name slave \
-e MYSQL_ROOT_PASSWORD=rootpassword \
-e MYSQL_USER=admin_ohy \
-e MYSQL_PASSWORD=adminpassword \
-e MYSQL_DATABASE=today-table \
-p 3306:3306 \
-v /home/ubuntu/mysql_data:/var/lib/mysql \
-v /etc/mysql/certs:/etc/mysql/certs \
-v /home/ubuntu/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:8.0.33
MySQL Replication 설정
Master 쪽 EC2의 퍼블릭 IP 또는 프라이빗 IP 확인
같은 VPC라면 프라이빗 IP
다른 VPC/인터넷 상이라면 퍼블릭 IP
curl ifconfig.me # 퍼블릭 IP
hostname -I # 프라이빗 IP
보안 그룹에서 포트 열기
Master 쪽 EC2 보안 그룹에서 3306 포트를 Slave 서버의 IP에만 허용해야 합니다.
Master 설정
docker exec -it master bash # Master 계정에 접속하기 위해 명령어 입력
mysql -u root -p # mysql을 root 계정으로 접속
grant all privileges on *.* to '계정이름'@'%' with grant option;
flush privileges;
Slave 설정을 위해 master 에서는 특정 정보만 가져오면 됩니다.
아래의 명령어를 콘솔에 입력해줍니다.
show master status;

Slave 설정에 필요하므로 File(mysql-bin.000001), Position(564)를 기억해둡니다.
Slave 설정
docker exec -it slave bash # Slave 계정에 접속하기 위해 명령어 입력
mysql -u root -p # mysql을 root 계정으로 접속
grant all privileges on *.* to '계정이름'@'%' with grant option;
flush privileges;
stop slave;
CHANGE MASTER TO MASTER_HOST='{master-db의 네트워크 IP}',
MASTER_USER='{계정 이름}',
MASTER_PASSWORD='{계정 비밀번호}',
MASTER_LOG_FILE='{master-db의 바이너리 파일 이름}',
MASTER_LOG_POS={master-db에서 조회한 파일 포지션},
MASTER_SSL=1,
MASTER_SSL_CA = '/etc/mysql/certs/ca.pem',
MASTER_SSL_CERT = '/etc/mysql/certs/client-cert.pem',
MASTER_SSL_KEY = '/etc/mysql/certs/client-key.pem';
start slave;
상태 확인
show slave status\G;
정상적으로 연결되었다면 아래와 같은 항목들을 확인할 수 있습니다:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Using_SSL: Yes
Seconds_Behind_Master: 0