使用 Docker Compose 搭建 MySQL 數據庫主從複製實例

說明

因爲是單機同時運行主從實例,僅用於開發環境或學習主從複製配置。html

項目地址 github.com/TomCzHen/my…node

文件結構

├── docker-compose.yaml
├── env
│   ├── base.env
│   ├── master.env
│   └── node.env
├── .env
├── init-db-sql
│   ├── init-master.sh
│   ├── init-node.sh
│   ├── sakila-data.sql
│   └── sakila-schema.sql
└── README.md
複製代碼

env

根目錄下的 .env 文件做用域是在 docker-compose.yaml 中,而 env 路徑下的文件做用與容器內部環境變量,二者做用不一樣。mysql

  • .env
TAG=5.7.20

MASTER_SERVER_ID=1
NODE_1_SERVER_ID=10
NODE_2_SERVER_ID=20

MASTER_MYSQL_ROOT_PASSWORD=master_root_pwd
NODE_MYSQL_ROOT_PASSWORD=node_root_pwd
複製代碼

docker-compose.yaml

version: "3.3"

services:
  
 mysql-master: &mysql
 image: mysql:${TAG}
 container_name: mysql-master
 restart: unless-stopped
 env_file:
 - env/base.env
 - env/master.env
 environment:
 - MYSQL_ROOT_PASSWORD=${MASTER_MYSQL_ROOT_PASSWORD}
 ports:
 - "3306:3306"
 expose:
 - "3306"
 volumes:
 - mysql-master-data:/var/lib/mysql
 - ./init-db-sql/sakila-schema.sql:/docker-entrypoint-initdb.d/1-schema.sql
 - ./init-db-sql/sakila-data.sql:/docker-entrypoint-initdb.d/2-data.sql
 - ./init-db-sql/init-master.sh:/docker-entrypoint-initdb.d/3-init-master.sh
 command: [
      "--log-bin=mysql-bin",
      "--server-id=${MASTER_SERVER_ID}",
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_unicode_ci",
      "--innodb_flush_log_at_trx_commit=1",
      "--sync_binlog=1"
      ]

 mysql-node-1: &mysql-node
    <<: *mysql
 container_name: mysql-node-1
 env_file:
 - env/base.env
 - env/node.env
 environment:
 - MYSQL_ROOT_PASSWORD=${NODE_MYSQL_ROOT_PASSWORD}
 - MASTER_MYSQL_ROOT_PASSWORD=${MASTER_MYSQL_ROOT_PASSWORD}
 ports:
 - "3307:3306"
 depends_on:
 - mysql-master
 volumes:
 - mysql-node-1-data:/var/lib/mysql
 - ./init-db-sql/sakila-schema.sql:/docker-entrypoint-initdb.d/1-schema.sql
 - ./init-db-sql/sakila-data.sql:/docker-entrypoint-initdb.d/2-data.sql
 - ./init-db-sql/init-node.sh:/docker-entrypoint-initdb.d/3-init-node.sh
 command: [
      "--server-id=${NODE_1_SERVER_ID}",
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_unicode_ci",
      ]
  
 mysql-node-2:
    <<: *mysql-node
 container_name: mysql-node-2
 ports:
 - "3308:3306"
 volumes: 
 - mysql-node-2-data:/var/lib/mysql
 - ./init-db-sql/sakila-schema.sql:/docker-entrypoint-initdb.d/1-schema.sql
 - ./init-db-sql/sakila-data.sql:/docker-entrypoint-initdb.d/2-data.sql
 - ./init-db-sql/init-node.sh:/docker-entrypoint-initdb.d/3-init-node.sh
 command: [
      "--server-id=${NODE_2_SERVER_ID}",
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_unicode_ci",
      ]
    

volumes:
 mysql-master-data:
 mysql-node-1-data:
 mysql-node-2-data:
複製代碼

因爲使用了 YAML 的引用語法,能夠經過 docker-compose config 查看完整的內容。這裏配置了一個主庫,兩個從庫,能夠根據需求改變從庫數量。git

初始化實例

...
 volumes:
 - mysql-master-data:/var/lib/mysql
 - ./init-db-sql/sakila-schema.sql:/docker-entrypoint-initdb.d/1-schema.sql
 - ./init-db-sql/sakila-data.sql:/docker-entrypoint-initdb.d/2-data.sql
 - ./init-db-sql/init-master.sh:/docker-entrypoint-initdb.d/3-init-master.sh
    ...
複製代碼

基礎鏡像會在初始化(僅首次運行)時按文件名順序執行 /docker-entrypoint-initdb.d 下的 .sql .sh 等文件,詳細信息能夠查看鏡像說明頁面:github

hub.docker.com/_/mysql/sql

Initializing a fresh instancedocker

When a container is started for the first time, a new database with the specified name will be created and initialized with the provided configuration variables. Furthermore, it will execute files with extensions .sh, .sql and .sql.gz that are found in /docker-entrypoint-initdb.d. Files will be executed in alphabetical order. You can easily populate your mysql services by mounting a SQL dump into that directory and provide custom images with contributed data. SQL files will be imported by default to the database specified by the MYSQL_DATABASE variable.shell

注:sakila 是 MySQL 的官方示例數據庫 dev.mysql.com/doc/sakila/…數據庫

配置實例參數

...
 command: [
      "--log-bin=mysql-bin",
      "--server-id=${MASTER_SERVER_ID}",
      "--character-set-server=utf8mb4",
      "--collation-server=utf8mb4_unicode_ci",
      "--innodb_flush_log_at_trx_commit=1",
      "--sync_binlog=1"
      ]
    ...
複製代碼

使用執行參數能夠不依靠 my.cnf 對實例進行配置,詳細資料能夠查看鏡像說明頁面:bash

hub.docker.com/_/mysql/

Configuration without a cnf file Many configuration options can be passed as flags to mysqld. This will give you the flexibility to customize the container without needing a cnf file. For example, if you want to change the default encoding and collation for all tables to use UTF-8 (utf8mb4) just run the following:

$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
複製代碼

If you would like to see a complete list of available options, just run:

$ docker run -it --rm mysql:tag --verbose --help
複製代碼

主從配置

init-master.sh
#!/bin/bash

set -e
 # create replication user

mysql_net=$(ip route | awk '$1=="default" {print $3}' | sed "s/\.[0-9]\+$/.%/g")

MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root \
-e "CREATE USER '${MYSQL_REPLICATION_USER}'@'${mysql_net}' IDENTIFIED BY '${MYSQL_REPLICATION_PASSWORD}'; \
GRANT REPLICATION SLAVE ON *.* TO '${MYSQL_REPLICATION_USER}'@'${mysql_net}';"
複製代碼

在主庫中添加用於複製的賬號,因爲鏡像默認開啓 --skip-name-resolve 參數,所以只能經過 IP 配置權限。

注:腳本中是獲取容器默認網關網段後添加用戶,不適用於生產環境。

init-node.sh
#!/bin/bash
 # check mysql master run status

set -e

until MYSQL_PWD=${MASTER_MYSQL_ROOT_PASSWORD} mysql -u root -h mysql-master ; do
 >&2 echo "MySQL master is unavailable - sleeping"
  sleep 3
done
 # create replication user

mysql_net=$(ip route | awk '$1=="default" {print $3}' | sed "s/\.[0-9]\+$/.%/g")

MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root \
-e "CREATE USER '${MYSQL_REPLICATION_USER}'@'${mysql_net}' IDENTIFIED BY '${MYSQL_REPLICATION_PASSWORD}'; \
GRANT REPLICATION SLAVE ON *.* TO '${MYSQL_REPLICATION_USER}'@'${mysql_net}';"
 # get master log File & Position

master_status_info=$(MYSQL_PWD=${MASTER_MYSQL_ROOT_PASSWORD} mysql -u root -h mysql-master -e "show master status\G")

LOG_FILE=$(echo "${master_status_info}" | awk 'NR!=1 && $1=="File:" {print $2}')
LOG_POS=$(echo "${master_status_info}" | awk 'NR!=1 && $1=="Position:" {print $2}')
 # set node master

MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root \
-e "CHANGE MASTER TO MASTER_HOST='mysql-master', \
MASTER_USER='${MYSQL_REPLICATION_USER}', \
MASTER_PASSWORD='${MYSQL_REPLICATION_PASSWORD}', \
MASTER_LOG_FILE='${LOG_FILE}', \
MASTER_LOG_POS=${LOG_POS};"
 # start slave and show slave status

MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql -u root -e "START SLAVE;show slave status\G"
複製代碼

配置從庫時會先等待主庫就緒,並在從庫鏈接到主庫獲取必要的參數值進行從庫初始化並開啓從庫複製狀態。

使用說明

根據須要調整變量值與腳本,修改 docker-compose.yaml 中各個實例暴露的端口,在項目目錄下執行 docker-compose up -d 部署編排。

使用 docker-compose logs mysql-master 能夠查看對應容器輸出日誌。

使用 docker exec -ti mysql-master bash 可進入對應容器控制檯環境。

其餘

GTIDs 模式須要調整腳本與編排文件中的執行參數。若是想使用容器來爲已有實例添加從庫,須要修改 init-node.sh 將 File 與 Position 做爲環境變量傳入應該更合適。

相關文章
相關標籤/搜索