linux 에서 docker compose로 mysql db 두 대를 띄운다.
아래 절차에 따라 하면 된다.
# 패키지 업데이트
sudo yum update -y
# docker 설치
sudo amazon-linux-extras enable docker
sudo yum install -y docker
# docker 시작 및 부팅 시 자동 실행
sudo systemctl start docker
sudo systemctl enable docker
# ec2-user를 docker 그룹에 추가 (sudo 없이 실행 가능)
sudo usermod -aG docker ec2-user
# ⚠️ 이 작업 후에는 재로그인 해야 반영됨
# docker compose plugin 설치 (Amazon Linux 2는 v2 권장)
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
mkdir -p $DOCKER_CONFIG/cli-plugins
curl -SL https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-linux-x86_64 \
-o $DOCKER_CONFIG/cli-plugins/docker-compose
chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
# 설치 확인
docker --version
docker compose version
mkdir -p ~/mysql-replication/{master_conf,slave_conf}
cd ~/mysql-replication
~/mysql-replication/
├─ docker-compose.yml
├─ master_conf/
│ └─ my.cnf
└─ slave_conf/
└─ my.cnf
version: '3.9'
services:
master:
image: mysql:8.0
container_name: mysql-master
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: testdb
ports:
- "3306:3306"
command: --default-authentication-plugin=mysql_native_password
volumes:
- ./master_conf:/etc/mysql/conf.d
- ./master_data:/var/lib/mysql
slave:
image: mysql:8.0
container_name: mysql-slave
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
ports:
- "3307:3306"
command: --default-authentication-plugin=mysql_native_password
depends_on:
- master
volumes:
- ./slave_conf:/etc/mysql/conf.d
- ./slave_data:/var/lib/mysql
[mysqld]
server-id=1
log-bin=mysql-bin
binlog-do-db=testdb
# 메모리 줄이기
innodb_buffer_pool_size=64M
innodb_log_buffer_size=8M
max_connections=50
[mysqld]
server-id=2
relay-log=relay-log-bin
# 메모리 줄이기
innodb_buffer_pool_size=64M
innodb_log_buffer_size=8M
max_connections=50
docker compose up -d
CREATE USER 'repl'@'%' IDENTIFIED BY 'replpass';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
→ File / Position 값 확인 (예: mysql-bin.000001, 154) <- 중요
docker exec -it mysql-slave mysql -uroot -prootpass
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='master',
SOURCE_USER='repl',
SOURCE_PASSWORD='replpass',
SOURCE_LOG_FILE='mysql-bin.000001', # 2번에서 확인한 값
SOURCE_LOG_POS=154; # 2번에서 확인한 값
START REPLICA;
SHOW REPLICA STATUS\G;
application.yml (또는 application.properties)에 아래처럼 적는다.
spring:
datasource:
url: jdbc:mysql:replication://master:3306,slave:3306/testdb
username: root
password: rootpass
driver-class-name: com.mysql.cj.jdbc.Driver
JDBC 드라이버는 Connection.setReadOnly(true/false) 기준으로 Master/Slave를 선택한다.
예제 코드:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class ReplicationTest implements CommandLineRunner {
@Autowired
private DataSource dataSource;
@Override
public void run(String... args) throws Exception {
try (Connection conn = dataSource.getConnection()) {
// 1. 기본 모드 (readOnly=false) → Master
System.out.println("Default readOnly = " + conn.isReadOnly());
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate("INSERT INTO test_table (name) VALUES ('master-write')");
System.out.println("✅ INSERT 성공 (Master)");
}
// 2. readOnly=true → Slave
conn.setReadOnly(true);
System.out.println("Now readOnly = " + conn.isReadOnly());
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM test_table")) {
if (rs.next()) {
System.out.println("✅ SELECT 성공 (Slave) → row count: " + rs.getInt(1));
}
}
// 3. readOnly=true 상태에서 쓰기 시도 → 실패 (Slave는 쓰기 불가)
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate("INSERT INTO test_table (name) VALUES ('slave-write')");
} catch (Exception e) {
System.out.println("🚨 Slave에 쓰기 시도 실패 = " + e.getMessage());
}
}
}
}
이렇게 되면 Replication URL이 정상적으로 Master/Slave를 구분해서 사용하고 있다는 걸 검증할 수 있다.

직접 Master-Slave 구조에서 자동 승격을 구현하려면 다음과 같은 추가 도구가 필요하다:
이런 도구들을 직접 설치하고 운영하면:
따라서 학습 목적이 아니라면 직접 구현은 높은 운영 비용과 리스크를 수반한다.
AWS, GCP, Azure 같은 클라우드 서비스 제공업체(CSP)에서는 자동 승격 기능을 이미 서비스 형태로 제공합니다.
예를 들어:
이를 활용하면: