Docker-Compose實現Mysql主從

2022-06-09 15:01:20

1. 簡介

通過使用docker-compose 搭建一個主從資料庫,本範例為了解耦 將兩個server拆分到了兩個compose檔案中,當然也可以放到一個compose檔案中

演示mysql版本:5.7.16

2. 部署流程

master節點:

  1. 安裝mysql-server
  2. 修改設定
  3. 建立用於同步的賬號並授權
  4. 檢查相關設定

slave節點:

  1. 安裝mysql-server
  2. 修改設定
  3. 選擇主節點
  4. 檢查相關設定並驗證同步功能

3. master節點

3.1 安裝mysql

  1. 建立mysql資料夾並進入資料夾(資料夾名稱mysql)

  2. 建立docker-compose檔案內容如下

    # docker-compose.yml
    version: '3'
    services:
      mysql:
        restart: "no"
        image: mysql:5.7.16
        container_name: mysql-master
        volumes:
          - ./datadir:/var/lib/mysql
          - ./conf/mysql:/etc/mysql
        environment:
          - "MYSQL_ROOT_PASSWORD=123456"
          - "TZ=Asia/Shanghai"
        ports:
          - 3306:3306
        networks:
          - mysql-net
    networks:
      mysql-net:
        driver: bridge
    

    注意:因為要把組態檔掛在到服務中去,所以要先把容器中的組態檔copy到宿主機上

    1. 先啟動一個用於copy檔案的容器

      $ docker run --name mysql-temp -e MYSQL_ROOT_PASSWORD=root --rm -d  mysql:5.7.16
      
    2. mysql-temp容器中的組態檔copy出來,現在conf資料夾中就是mysql自帶的所有組態檔

      $ docker cp mysql-temp:/etc/mysql conf
      

    3. 因為當前conf目錄中的my.cnf還是個link,所以直接使用當前目錄中的備份檔案作為主要的組態檔

      $ mv my.cnf.fallback my.cnf
      
  3. 修改組態檔my.cnf

    在檔案的最下方加入設定資訊

    [mysqld]
    log-bin=mysql-bin # 開啟 binlog
    server-id=1 # 當前server在cluster中的id,必須保證在cluster中唯一
    #只保留7天的二進位制紀錄檔,以防磁碟被紀錄檔佔滿(可選)
    expire-logs-days = 7
    #不備份的資料庫 (可選)
    binlog-ignore-db=information_schema  
    binlog-ignore-db=performation_schema
    binlog-ignore-db=sys
    
  4. 啟動mysql服務,通過輸出內容得知真實的網路名稱為mysql_mysql-net,也就是當前所在資料夾的名稱拼接了檔案中指定的網路名稱

  5. 服務啟動完畢後,建立用於同步的使用者並授權

    建立的使用者名稱稱為slave密碼為123456

    CREATE USER 'slave' @'%' IDENTIFIED BY '123456';
    GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave' @'%';
    #重新整理許可權
    FLUSH PRIVILEGES;
    
  6. 檢視master狀態資訊

    SHOW MASTER STATUS;
    #檢視Mater資料有哪些slave
    select * from information_schema.processlist as p where p.command = 'Binlog Dump'; 
    

4. slave節點

安裝步驟同master相同,只把需要修改的展示一下,當前的目錄結構如下

docker-compose.yaml 主要修改了網路相關的資訊和container_name(網路名稱上面有解釋)

version: '3'
services:
  mysql:
    restart: "no"
    image: mysql:5.7.16
    container_name: mysql-slave
    volumes:
      - ./datadir:/var/lib/mysql
      - ./conf:/etc/mysql
    environment:
      - "MYSQL_ROOT_PASSWORD=123456"
      - "TZ=Asia/Shanghai"
    ports:
      - 3307:3306
    networks:
      - mysql_mysql-net
networks:
  mysql_mysql-net:
    external: true # 來自外部

my.cnf新增的內容如下:

[mysqld]
server-id=2
relay_log=relay-log
#開啟唯讀 意味著當前的資料庫用作讀,當然這也只會影響到非root的使用者,如果使用root使用者操作本庫是不會有影響的
read_only=ON

設定完成後啟動salve server,連線slave並關聯master節點

  • MASTER_HOST:直接使用container_name
  • MASTER_LOG_FILE/MASTER_LOG_POS:直接使用安裝master步驟中的最後一步的值,其實就是指定同步的bin-log檔名稱和Offset
CHANGE MASTER TO
MASTER_HOST='mysql-master',
MASTER_USER='slave',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;

管理完成後 啟動salve

START SLAVE;

最後檢視slave status

SHOW SLAVE STATUS;

5. 驗證

在master上建立test資料庫並建立user表,重新整理檢視salve庫,出現了對應的庫表

經驗證資料同步也沒有問題。

6. 可能遇到的問題

SHOW SLAVE STATUS時發現 slave_io_running=No salve_sql_running=No,可能的原因有很多,可以檢視如下的欄位中輸出的內容

可能的原因:

  1. 主從網路不通
  2. 兩臺節點的server-id重複,直接修改對應的id即可
  3. 資料庫的uuid相同(可能是因為資料庫檔案是直接copy過來的導致的),在對應的庫下生成不同於master的uuid到auto.cnf中即可
  4. sql執行失敗,可能是slave剛新增進來,也沒有master庫的資料庫instance,導致操作對應的庫時slave這邊根本沒有對應的instance或者table又或是記錄,引發的報錯。這個只能具體問題具體解決了
  5. master和slave的MASTER_LOG_FILE/MASTER_LOG_POS值設定的有問題,在slave節點上STOP SLAVE;然後重新連線下master即可

7. 同步部分資料庫範例或表

在master節點上新增設定【可選】(如果只希望從庫讀取到部分範例)

在my.cnf檔案中加入如下設定

#需要同步的資料庫名 有多個庫新增多行即可
binlog-do-db=test
binlog-do-db=test1
#排除的資料庫
binlog-ignore-db=sys

salve端:在my.cnf檔案中加入如下設定,這樣的話salve只會讀取設定的db或table,master對其他db的操作也不會影響slave

#如果salve庫名稱與master庫名相同,使用本設定 
replicate-do-db=test
#如果master庫名[test]與salve庫名[test001]不同,使用以下設定[需要做對映] 
#replicate-rewrite-db = test -> test001
#如果不是要全部同步[預設全部同步],則指定需要同步的表 
#replicate-wild-do-table=test.user
#replicate-wild-do-table=test.role