├── 02-master-database.sql ├── 5.5 ├── Dockerfile ├── init-slave.sh └── replication-entrypoint.sh ├── 5.6 ├── Dockerfile ├── init-slave.sh └── replication-entrypoint.sh ├── 5.7 ├── Dockerfile ├── init-slave.sh └── replication-entrypoint.sh └── README.md /02-master-database.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE test; 2 | USE test; 3 | CREATE TABLE names(id INT AUTO_INCREMENT KEY, name VARCHAR(10)); 4 | INSERT INTO names (name) VALUES ('test1'), ('test2'); 5 | -------------------------------------------------------------------------------- /5.5/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.5 2 | ENV REPLICATION_USER replication 3 | ENV REPLICATION_PASSWORD replication_pass 4 | COPY replication-entrypoint.sh /usr/local/bin/ 5 | COPY init-slave.sh / 6 | ENTRYPOINT ["replication-entrypoint.sh"] 7 | CMD ["mysqld"] 8 | -------------------------------------------------------------------------------- /5.5/init-slave.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # TODO: cover slave side selection for replication entities: 3 | # * replicate-do-db=db_name only if we want to store and replicate certain DBs 4 | # * replicate-ignore-db=db_name used when we don't want to replicate certain DBs 5 | # * replicate_wild_do_table used to replicate tables based on wildcard patterns 6 | # * replicate_wild_ignore_table used to ignore tables in replication based on wildcard patterns 7 | 8 | REPLICATION_HEALTH_GRACE_PERIOD=${REPLICATION_HEALTH_GRACE_PERIOD:-3} 9 | REPLICATION_HEALTH_TIMEOUT=${REPLICATION_HEALTH_TIMEOUT:-10} 10 | MYSQLDUMP_HOST=${MYSQLDUMP_HOST:-$MASTER_HOST} 11 | MYSQLDUMP_PORT=${MYSQLDUMP_PORT:-$MASTER_PORT} 12 | 13 | check_slave_health () { 14 | echo Checking replication health: 15 | status=$(mysql -u root -e "SHOW SLAVE STATUS\G") 16 | echo "$status" | egrep 'Slave_(IO|SQL)_Running:|Seconds_Behind_Master:|Last_.*_Error:' | grep -v "Error: $" 17 | if ! echo "$status" | grep -qs "Slave_IO_Running: Yes" || 18 | ! echo "$status" | grep -qs "Slave_SQL_Running: Yes" || 19 | ! echo "$status" | grep -qs "Seconds_Behind_Master: 0" ; then 20 | echo WARNING: Replication is not healthy. 21 | return 1 22 | fi 23 | return 0 24 | } 25 | 26 | 27 | echo Updating master connetion info in slave. 28 | 29 | mysql -u root -e "RESET MASTER; \ 30 | CHANGE MASTER TO \ 31 | MASTER_HOST='$MASTER_HOST', \ 32 | MASTER_PORT=$MASTER_PORT, \ 33 | MASTER_USER='$REPLICATION_USER', \ 34 | MASTER_PASSWORD='$REPLICATION_PASSWORD';" 35 | 36 | sleep 5 37 | 38 | mysqldump \ 39 | --protocol=tcp \ 40 | --user=$REPLICATION_USER \ 41 | --password=$REPLICATION_PASSWORD \ 42 | --host=$MYSQLDUMP_HOST \ 43 | --port=$MYSQLDUMP_PORT \ 44 | --hex-blob \ 45 | --all-databases \ 46 | --add-drop-database \ 47 | --master-data \ 48 | --flush-logs \ 49 | --flush-privileges \ 50 | | mysql -u root 51 | 52 | echo mysqldump completed. 53 | 54 | echo Starting slave ... 55 | mysql -u root -e "START SLAVE;" 56 | 57 | echo Initial health check: 58 | check_slave_health 59 | 60 | echo Waiting for health grace period and slave to be still healthy: 61 | sleep $REPLICATION_HEALTH_GRACE_PERIOD 62 | 63 | counter=0 64 | while ! check_slave_health; do 65 | if (( counter >= $REPLICATION_HEALTH_TIMEOUT )); then 66 | echo ERROR: Replication not healthy, health timeout reached, failing. 67 | break 68 | exit 1 69 | fi 70 | let counter=counter+1 71 | sleep 1 72 | done 73 | 74 | -------------------------------------------------------------------------------- /5.5/replication-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | 4 | cat > /etc/mysql/conf.d/repl.cnf << EOF 5 | [mysqld] 6 | log-bin=mysql-bin 7 | relay-log=mysql-relay 8 | #bind-address=0.0.0.0 9 | #skip-name-resolve 10 | EOF 11 | 12 | # If there is a linked master use linked container information 13 | if [ -n "$MASTER_PORT_3306_TCP_ADDR" ]; then 14 | export MASTER_HOST=$MASTER_PORT_3306_TCP_ADDR 15 | export MASTER_PORT=$MASTER_PORT_3306_TCP_PORT 16 | fi 17 | 18 | if [ -z "$MASTER_HOST" ]; then 19 | export SERVER_ID=1 20 | cat >/docker-entrypoint-initdb.d/init-master.sh <<'EOF' 21 | #!/bin/bash 22 | 23 | echo Creating replication user ... 24 | mysql -u root -e "\ 25 | GRANT \ 26 | FILE, \ 27 | SELECT, \ 28 | SHOW VIEW, \ 29 | LOCK TABLES, \ 30 | RELOAD, \ 31 | REPLICATION SLAVE, \ 32 | REPLICATION CLIENT \ 33 | ON *.* \ 34 | TO '$REPLICATION_USER'@'%' \ 35 | IDENTIFIED BY '$REPLICATION_PASSWORD'; \ 36 | FLUSH PRIVILEGES; \ 37 | " 38 | EOF 39 | else 40 | # TODO: make server-id discoverable 41 | export SERVER_ID=2 42 | cp -v /init-slave.sh /docker-entrypoint-initdb.d/ 43 | cat > /etc/mysql/conf.d/repl-slave.cnf << EOF 44 | [mysqld] 45 | log-slave-updates 46 | relay-log-recovery=1 47 | EOF 48 | fi 49 | 50 | cat > /etc/mysql/conf.d/server-id.cnf << EOF 51 | [mysqld] 52 | server-id=$SERVER_ID 53 | EOF 54 | 55 | exec docker-entrypoint.sh "$@" 56 | 57 | -------------------------------------------------------------------------------- /5.6/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.6 2 | ENV REPLICATION_USER replication 3 | ENV REPLICATION_PASSWORD replication_pass 4 | COPY replication-entrypoint.sh /usr/local/bin/ 5 | COPY init-slave.sh / 6 | ENTRYPOINT ["replication-entrypoint.sh"] 7 | CMD ["mysqld"] 8 | -------------------------------------------------------------------------------- /5.6/init-slave.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # TODO: cover slave side selection for replication entities: 3 | # * replicate-do-db=db_name only if we want to store and replicate certain DBs 4 | # * replicate-ignore-db=db_name used when we don't want to replicate certain DBs 5 | # * replicate_wild_do_table used to replicate tables based on wildcard patterns 6 | # * replicate_wild_ignore_table used to ignore tables in replication based on wildcard patterns 7 | 8 | REPLICATION_HEALTH_GRACE_PERIOD=${REPLICATION_HEALTH_GRACE_PERIOD:-3} 9 | REPLICATION_HEALTH_TIMEOUT=${REPLICATION_HEALTH_TIMEOUT:-10} 10 | MYSQLDUMP_HOST=${MYSQLDUMP_HOST:-$MASTER_HOST} 11 | MYSQLDUMP_PORT=${MYSQLDUMP_PORT:-$MASTER_PORT} 12 | 13 | check_slave_health () { 14 | echo Checking replication health: 15 | status=$(mysql -u root -e "SHOW SLAVE STATUS\G") 16 | echo "$status" | egrep 'Slave_(IO|SQL)_Running:|Seconds_Behind_Master:|Last_.*_Error:' | grep -v "Error: $" 17 | if ! echo "$status" | grep -qs "Slave_IO_Running: Yes" || 18 | ! echo "$status" | grep -qs "Slave_SQL_Running: Yes" || 19 | ! echo "$status" | grep -qs "Seconds_Behind_Master: 0" ; then 20 | echo WARNING: Replication is not healthy. 21 | return 1 22 | fi 23 | return 0 24 | } 25 | 26 | 27 | echo Updating master connetion info in slave. 28 | 29 | mysql -u root -e "RESET MASTER; \ 30 | CHANGE MASTER TO \ 31 | MASTER_HOST='$MASTER_HOST', \ 32 | MASTER_PORT=$MASTER_PORT, \ 33 | MASTER_USER='$REPLICATION_USER', \ 34 | MASTER_PASSWORD='$REPLICATION_PASSWORD';" 35 | 36 | mysqldump \ 37 | --protocol=tcp \ 38 | --user=$REPLICATION_USER \ 39 | --password=$REPLICATION_PASSWORD \ 40 | --host=$MYSQLDUMP_HOST \ 41 | --port=$MYSQLDUMP_PORT \ 42 | --hex-blob \ 43 | --all-databases \ 44 | --add-drop-database \ 45 | --master-data \ 46 | --flush-logs \ 47 | --flush-privileges \ 48 | | mysql -u root 49 | 50 | echo mysqldump completed. 51 | 52 | echo Starting slave ... 53 | mysql -u root -e "START SLAVE;" 54 | 55 | echo Initial health check: 56 | check_slave_health 57 | 58 | echo Waiting for health grace period and slave to be still healthy: 59 | sleep $REPLICATION_HEALTH_GRACE_PERIOD 60 | 61 | counter=0 62 | while ! check_slave_health; do 63 | if (( counter >= $REPLICATION_HEALTH_TIMEOUT )); then 64 | echo ERROR: Replication not healthy, health timeout reached, failing. 65 | break 66 | exit 1 67 | fi 68 | let counter=counter+1 69 | sleep 1 70 | done 71 | 72 | -------------------------------------------------------------------------------- /5.6/replication-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | 4 | cat > /etc/mysql/conf.d/repl.cnf << EOF 5 | [mysqld] 6 | log-bin=mysql-bin 7 | relay-log=mysql-relay 8 | #bind-address=0.0.0.0 9 | #skip-name-resolve 10 | EOF 11 | 12 | # If there is a linked master use linked container information 13 | if [ -n "$MASTER_PORT_3306_TCP_ADDR" ]; then 14 | export MASTER_HOST=$MASTER_PORT_3306_TCP_ADDR 15 | export MASTER_PORT=$MASTER_PORT_3306_TCP_PORT 16 | fi 17 | 18 | if [ -z "$MASTER_HOST" ]; then 19 | export SERVER_ID=1 20 | cat >/docker-entrypoint-initdb.d/init-master.sh <<'EOF' 21 | #!/bin/bash 22 | 23 | echo Creating replication user ... 24 | mysql -u root -e "\ 25 | GRANT \ 26 | FILE, \ 27 | SELECT, \ 28 | SHOW VIEW, \ 29 | LOCK TABLES, \ 30 | RELOAD, \ 31 | REPLICATION SLAVE, \ 32 | REPLICATION CLIENT \ 33 | ON *.* \ 34 | TO '$REPLICATION_USER'@'%' \ 35 | IDENTIFIED BY '$REPLICATION_PASSWORD'; \ 36 | FLUSH PRIVILEGES; \ 37 | " 38 | EOF 39 | else 40 | # TODO: make server-id discoverable 41 | export SERVER_ID=2 42 | cp -v /init-slave.sh /docker-entrypoint-initdb.d/ 43 | cat > /etc/mysql/conf.d/repl-slave.cnf << EOF 44 | [mysqld] 45 | log-slave-updates 46 | master-info-repository=TABLE 47 | relay-log-info-repository=TABLE 48 | relay-log-recovery=1 49 | EOF 50 | fi 51 | 52 | cat > /etc/mysql/conf.d/server-id.cnf << EOF 53 | [mysqld] 54 | server-id=$SERVER_ID 55 | EOF 56 | 57 | exec docker-entrypoint.sh "$@" 58 | 59 | -------------------------------------------------------------------------------- /5.7/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.7 2 | ENV REPLICATION_USER replication 3 | ENV REPLICATION_PASSWORD replication_pass 4 | COPY replication-entrypoint.sh /usr/local/bin/ 5 | COPY init-slave.sh / 6 | ENTRYPOINT ["replication-entrypoint.sh"] 7 | CMD ["mysqld"] 8 | -------------------------------------------------------------------------------- /5.7/init-slave.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # TODO: cover slave side selection for replication entities: 3 | # * replicate-do-db=db_name only if we want to store and replicate certain DBs 4 | # * replicate-ignore-db=db_name used when we don't want to replicate certain DBs 5 | # * replicate_wild_do_table used to replicate tables based on wildcard patterns 6 | # * replicate_wild_ignore_table used to ignore tables in replication based on wildcard patterns 7 | 8 | REPLICATION_HEALTH_GRACE_PERIOD=${REPLICATION_HEALTH_GRACE_PERIOD:-3} 9 | REPLICATION_HEALTH_TIMEOUT=${REPLICATION_HEALTH_TIMEOUT:-10} 10 | MYSQLDUMP_HOST=${MYSQLDUMP_HOST:-$MASTER_HOST} 11 | MYSQLDUMP_PORT=${MYSQLDUMP_PORT:-$MASTER_PORT} 12 | 13 | check_slave_health () { 14 | echo Checking replication health: 15 | status=$(mysql -u root -e "SHOW SLAVE STATUS\G") 16 | echo "$status" | egrep 'Slave_(IO|SQL)_Running:|Seconds_Behind_Master:|Last_.*_Error:' | grep -v "Error: $" 17 | if ! echo "$status" | grep -qs "Slave_IO_Running: Yes" || 18 | ! echo "$status" | grep -qs "Slave_SQL_Running: Yes" || 19 | ! echo "$status" | grep -qs "Seconds_Behind_Master: 0" ; then 20 | echo WARNING: Replication is not healthy. 21 | return 1 22 | fi 23 | return 0 24 | } 25 | 26 | 27 | echo Updating master connetion info in slave. 28 | 29 | mysql -u root -e "RESET MASTER; \ 30 | CHANGE MASTER TO \ 31 | MASTER_HOST='$MASTER_HOST', \ 32 | MASTER_PORT=$MASTER_PORT, \ 33 | MASTER_USER='$REPLICATION_USER', \ 34 | MASTER_PASSWORD='$REPLICATION_PASSWORD';" 35 | 36 | mysqldump \ 37 | --protocol=tcp \ 38 | --user=$REPLICATION_USER \ 39 | --password=$REPLICATION_PASSWORD \ 40 | --host=$MYSQLDUMP_HOST \ 41 | --port=$MYSQLDUMP_PORT \ 42 | --hex-blob \ 43 | --all-databases \ 44 | --add-drop-database \ 45 | --master-data \ 46 | --flush-logs \ 47 | --flush-privileges \ 48 | | mysql -u root 49 | 50 | echo mysqldump completed. 51 | 52 | echo Starting slave ... 53 | mysql -u root -e "START SLAVE;" 54 | 55 | echo Initial health check: 56 | check_slave_health 57 | 58 | echo Waiting for health grace period and slave to be still healthy: 59 | sleep $REPLICATION_HEALTH_GRACE_PERIOD 60 | 61 | counter=0 62 | while ! check_slave_health; do 63 | if (( counter >= $REPLICATION_HEALTH_TIMEOUT )); then 64 | echo ERROR: Replication not healthy, health timeout reached, failing. 65 | break 66 | exit 1 67 | fi 68 | let counter=counter+1 69 | sleep 1 70 | done 71 | 72 | -------------------------------------------------------------------------------- /5.7/replication-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eo pipefail 3 | 4 | cat > /etc/mysql/mysql.conf.d/repl.cnf << EOF 5 | [mysqld] 6 | log-bin=mysql-bin 7 | relay-log=mysql-relay 8 | #bind-address=0.0.0.0 9 | #skip-name-resolve 10 | EOF 11 | 12 | # If there is a linked master use linked container information 13 | if [ -n "$MASTER_PORT_3306_TCP_ADDR" ]; then 14 | export MASTER_HOST=$MASTER_PORT_3306_TCP_ADDR 15 | export MASTER_PORT=$MASTER_PORT_3306_TCP_PORT 16 | fi 17 | 18 | if [ -z "$MASTER_HOST" ]; then 19 | export SERVER_ID=1 20 | cat >/docker-entrypoint-initdb.d/init-master.sh <<'EOF' 21 | #!/bin/bash 22 | 23 | echo Creating replication user ... 24 | mysql -u root -e "\ 25 | GRANT \ 26 | FILE, \ 27 | SELECT, \ 28 | SHOW VIEW, \ 29 | LOCK TABLES, \ 30 | RELOAD, \ 31 | REPLICATION SLAVE, \ 32 | REPLICATION CLIENT \ 33 | ON *.* \ 34 | TO '$REPLICATION_USER'@'%' \ 35 | IDENTIFIED BY '$REPLICATION_PASSWORD'; \ 36 | FLUSH PRIVILEGES; \ 37 | " 38 | EOF 39 | else 40 | # TODO: make server-id discoverable 41 | export SERVER_ID=2 42 | cp -v /init-slave.sh /docker-entrypoint-initdb.d/ 43 | cat > /etc/mysql/mysql.conf.d/repl-slave.cnf << EOF 44 | [mysqld] 45 | log-slave-updates 46 | master-info-repository=TABLE 47 | relay-log-info-repository=TABLE 48 | relay-log-recovery=1 49 | EOF 50 | fi 51 | 52 | cat > /etc/mysql/mysql.conf.d/server-id.cnf << EOF 53 | [mysqld] 54 | server-id=$SERVER_ID 55 | EOF 56 | 57 | exec docker-entrypoint.sh "$@" 58 | 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | NOTE: THIS PROJECT WAS DEVELOPED AS A RPOOF OF CONCEPT PROJECT THAT HAS NEVER BEEN USED 3 | 4 | PLEASE CHECK THE CODE AND USE IT ON YOUR OWN RISK 5 | ``` 6 | 7 | Docker images to support implicit mysql replication support. 8 | 9 | Features: 10 | * based on official mysql images 11 | * when you start the slave, it starts with replication started, 12 | * no manual sync (mysqldump) is needed, 13 | * slave fails to start if replication not healthy 14 | 15 | Additional environment variables: 16 | * REPLICATION_USER [default: replication] 17 | * REPLICATION_PASSWORD [default: replication_pass] 18 | * REPLICATION_HEALTH_GRACE_PERIOD [default: 3] 19 | * REPLICATION_HEALTH_TIMEOUT [default: 10] 20 | * MASTER_PORT [default: 3306] 21 | * MASTER_HOST [default: master] 22 | * MYSQLDUMP_PORT [default: $MASTER_PORT] 23 | * MYSQLDUMP_HOST [default: $MASTER_HOST] 24 | 25 | # Start master 26 | 27 | ``` 28 | docker run -d \ 29 | --name mysql_master \ 30 | -e MYSQL_ALLOW_EMPTY_PASSWORD=1 \ 31 | bergerx/mysql-replication:5.7 32 | ``` 33 | 34 | # Start slave 35 | 36 | ``` 37 | docker run -d \ 38 | --name mysql_slave \ 39 | -e MYSQL_ALLOW_EMPTY_PASSWORD=1 \ 40 | --link mysql_master:master \ 41 | bergerx/mysql-replication:5.7 42 | ``` 43 | 44 | # Test the replication 45 | ``` 46 | cat 02-master-database.sql | docker exec -i mysql_master mysql 47 | docker exec -it mysql_slave mysql -e 'select * from test.names' 48 | ``` 49 | --------------------------------------------------------------------------------