먼저, Docker가 설치되어 있어야 한다. 만약 Docker가 설치되지 않았다면 Docker 공식 사이트에서 설치할 수 있다.
Docker MySQL 이미지 찾기
docker search mysql
Docker MySQL 이미지 받기
docker pull ubuntu/mysql
네트워크 생성
Docker 컨테이너들이 서로 통신할 수 있도록 Docker 네트워크를 생성한다.
docker network create mysql-cluster
Master 컨테이너 생성
MySQL 마스터 역할을 하는 컨테이너를 생성한다.
docker run --name mysql-master -d --restart unless-stopped --network mysql-cluster -e MYSQL_ROOT_PASSWORD=root -e MYSQL_REPLICATION_USER=reluser -e MYSQL_REPLICATION_PASSWORD=reluser -p 3307:3306 ubuntu/mysql
MYSQL_ROOT_PASSWORD: MySQL 루트 계정의 비밀번호
MYSQL_REPLICATION_USER: 복제를 위한 사용자 계정 이름
MYSQL_REPLICATION_PASSWORD: 복제 사용자 비밀번호
-p 3307:3306: 3307 Port로 외부 접속 허용
--restart unless-stopped: 컨테이너가 충돌하거나 서버가 재부팅되면 자동으로 다시 시작
--network mysql-cluster: Docker 네트워크 안에서 컨테이너가 통신할 수 있게 설정
Slave 컨테이너 생성
Slave MySQL 컨테이너도 마찬가지로 생성한다.
docker run --name mysql-slave -d --restart unless-stopped --network mysql-cluster -e MYSQL_ROOT_PASSWORD=root -e MYSQL_REPLICATION_USER=reluser -e MYSQL_REPLICATION_PASSWORD=reluser -p 3308:3306 ubuntu/mysql
Master와 Slave의 Server ID 설정
MySQL 복제에서 Master와 Slave 서버는 각자 고유한 server_id를 가져야 한다. 두 서버의 server_id가 같으면 MySQL은 복제를 제대로 처리할 수 없기 때문에 복제 I/O 스레드가 중지된다.
Master의 my.cnf 수정(파일 위치: /etc/mysql/my.cnf) - Ubuntu 기준
vi /etc/mysql/my.cnf
[mysqld]
id-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
# Master에 추가
server-id=1
log-bin=mysql-bin
log-bin=mysql-bin: MySQL이 바이너리 로그를 기록하도록 설정하고 바이너리 로그 파일의 이름 접두어(prefix)를 설정
Slave의 my.cnf 수정 (파일 위치: /etc/mysql/my.cnf) - Ubuntu 기준
vi /etc/mysql/my.cnf
[mysqld]
id-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
# Slave에 추가
server-id=2
log-bin=mysql-bin
둘 다 my.cnf를 수정했기에 MySQL을 재시작을 해줘야 한다.
docker restart mysql-master
docker restart mysql-slave
Master 설정
Master에 접속하여 복제에 필요한 설정을 진행한다.
docker exec -it mysql-master bash
mysql -uroot -p
MySQL에 접속한 후, 아래 명령어로 복제 로그 및 설정을 확인하고 복제 사용자 권한을 부여한다.
# 복제 사용자 권한 설정
CREATE USER 'reluser'@'%' IDENTIFIED BY 'reluser';
GRANT REPLICATION SLAVE ON *.* TO 'reluser'@'%';
FLUSH PRIVILEGES;
# 복제 데이터베이스 및 테이블 생성
create database reldb;
use reldb;
create table reltable (id int, primary key(id));
desc reltable;
exit
Master에서 DB dump 하기
Master의 현재 DB 상태를 slave에 그대로 반영하기 위해 dump 한다.
mysqldump -u root -p --all-databases > tmp/master_dump.sql
dump 한 파일을 내 로컬 PC(호스트 PC)로 복사해 온다.
# 마스터 컨테이너에서 로컬로 dump 파일 복사
docker cp mysql-master:tmp/master_dump.sql ./master_dump.sql
# 슬레이브 컨테이너로 복사
docker cp ./master_dump.sql mysql-slave:tmp/master_dump.sql
Slave로 데이터 복구
slave 컨테이너로 복사한 dump 파일로 복구한다.
(mysql 비밀번호는 slave 컨테이너를 실행할 때 설정한 'MYSQL_ROOT_PASSWORD' 입력)
docker exec -it mysql-slave bash
mysql -u root -p < /tmp/master_dump.sql
다시 mysql에 접속하였을 때 Master와 동일하게 구성이 되었다면 정상적으로 복구된 것이다.
mysql -uroot -p
show databases;
Master 상태 확인
이제 Slave에서 Master와의 연결이 필요한데, 그전에 MASTER_LOG_FILE과 MASTER_LOG_POS의 값들을 알아야 한다. 이유는 Slave가 Master의 Binary Log에서 정확한 위치에서부터 복제를 시작할 수 있도록 하기 위해서다.
MASTER_LOG_FILE: 마스터 서버의 Binary Log 파일 이름
MASTER_LOG_POS: Binary Log 파일 내에서 Slave가 읽기 시작할 정확한 위치
# 다시 Master로 접속
docker exec -it mysql-master bash
mysql -uroot -p
show master status;
Slave 설정
위 값들을 알아냈다면 이젠 MySQL 복제(레플리카) 설정에서 Slave와 Master가 연결을 설정해줘야 한다.
# 다시 Slave로 접속
docker exec -it mysql-slave bash
mysql -uroot -p
CHANGE MASTER TO MASTER_HOST='172.18.0.2', MASTER_USER='reluser',
MASTER_PASSWORD='reluser', MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=1265;
START SLAVE;
SHOW VARIABLES LIKE 'read_only'; -- OFF
읽기 전용으로 변경
SET GLOBAL read_only = 1;
MASTER_HOST='172.18.0.2': 데이터를 복제할 Master 호스트 이름 또는 IP 주소를 지정(Master의 IP 주소는 더보기에 나와있는 명령어로 알 수 있다.)
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mysql-master
MASTER_USER='reluser': Master 서버에서 Slave 복제를 허용하는 사용자 이름을 지정
MASTER_PASSWORD='reluser': MASTER_USER로 지정된 사용자의 비밀번호
MASTER_LOG_FILE='mysql-bin.000002': Master 서버의 Binary Log 파일 이름을 지정
MASTER_LOG_POS=1265: Master 서버의 Binary Log 파일에서 Slave가 복제를 시작할 정확한 위치(byte offset)를 지정
Slave 상태 확인
다른 특별한 오류가 없었다면 Slave가 정상적으로 복제를 시작했는지 확인한다.
SHOW SLAVE STATUS\G;
비밀번호 에러가 났다면?
만약 비밀번호 에러가 났다면 Slave가 MySQL 마스터에 연결할 때 mysql_native_password 인증 방식을 사용하도록 변경하거나 보안 연결(TLS)을 활성화해야 한다. 복잡하기 때문에 기본적으로 인증 방식을 바꾸는 방법이 더 간단하다.
Last_IO_Error: Error connecting to source 'reluser@172.18.0.2:3306'. This was attempt 1/86400, with a delay of 60 seconds between attempts. Message: Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.
1. 마스터 서버에 접속하여 reluser의 인증 방식을 mysql_native_password로 변경한다.
docker exec -it mysql-master bash
mysql -uroot -p
2. reluser 사용자의 비밀번호를 변경하면서 인증 방식을 명시한다.
ALTER USER 'reluser'@'%' IDENTIFIED WITH mysql_native_password BY 'reluser';
FLUSH PRIVILEGES;
# File과 Position 재확인
show master status;
3. 그리고 다시 Slave 서버에 접속
docker exec -it mysql-slave bash
mysql -uroot -p
4. 슬레이브 재설정
STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO MASTER_HOST='172.18.0.2', MASTER_USER='reluser',
MASTER_PASSWORD='reluser', MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=1717;
START SLAVE;
5. 복제가 제대로 설정되었는지 확인
SHOW SLAVE STATUS\G;
복제 테스트
Master DB에 데이터를 삽입하고 Slave DB에서 동일한 데이터가 복제되는지 확인한다.
# 마스터에서 데이터 삽입
USE reldb;
INSERT INTO reltable (id) VALUES (1);
SELECT * FROM reltable;
# 슬레이브에서 데이터 확인
USE reldb;
SELECT * FROM reltable;
'Database & Data > MySQL' 카테고리의 다른 글
MySQL에서 PostgreSQL으로 마이그레이션 (Shell 환경) (0) | 2024.06.28 |
---|---|
[MySQL] 트랜잭션 격리 수준(간단한 정리) (0) | 2024.02.29 |
[MySQL] 쿼리 개선 기록 - 날짜 범위, 중복 제거 (0) | 2024.01.31 |
Local MySQL로 DB 서버 만들기(외부 IP에서 접속) (0) | 2023.08.26 |
로컬 DB 공유기 포트 포워딩 하는 방법(방화벽 설정 포함) (0) | 2023.08.26 |