基於k8s搭建mysql主從同步

    網絡上有很多基於K8S搭建mysql主從同步的文章,其中有很多都源自於下面這篇文章,我們權且就叫它參考文章吧:

    https://www.jianshu.com/p/509b65e9a4f5

    這篇文章裏的方法是沒有問題的,但是因爲作者在做實驗的時候用到的mysql官方的docker鏡像比較老,如果採用官方最新的鏡像(基於mysql8.0.15)用參考文章裏的方法會遇到一些錯誤,這裏記錄一下自己在搭建過程中遇到的各種坑以免以後遇到同樣的問題又折騰半天。

    宿主機操作系統:Mac

    虛擬機操作系統:CentOS 7

    mysql基礎鏡像:  mysql官方最新鏡像(基於mysql8.0.15)

    先大概列舉一下遇到的坑,然後在詳述血淚史:

    (1) 構建鏡像時出現gpg: ..... not assigned;

    (2) 主庫容器出錯,出現...for the right syntax to use near 'IDENTIFIED BY'錯誤;

    (3) 宿主機連接不到K8S的NodePort;

    (4) 主從同步時出現error connecting to master錯誤,錯誤碼2061;

    (4) 主從同步時出現The slave I/O thread stops because master and slave have equal MySQL server ids錯誤;

    下面開始詳細記錄一下過程

構建鏡像

    首先需要構建mysql主庫和從庫的基礎鏡像,按照參考文獻中的做法,將構建官方基礎鏡像的Dockerfile等下載下來,下下來後會看到有三個東東:

    按照參考文章的做法,我們需要做兩件事:修改Dockerfile和docker-entrypoint.sh,當然寫參考文章的作者非常貼心,怎麼改,改動添加到文件中哪個位置都已經告訴我們了,於是歡天喜地的按照文章中的做法一字不落的搞定,然後開始構建鏡像:

    docker build -t="edgetech/mysql-master:v1" .

    接下來遇到了取經路上的第一個小鬼,構建鏡像時提示下面這樣的錯誤:

    gpg: ...... not assigned

    完全不清楚這個錯誤是什麼鬼,網上搜索大半天也沒有找到解決方案,束手無策之際隨手又重新執行了一遍docker build命令,我靠,居然可以了!好吧,看來是網絡問題,繼續往前走。

K8S中部署並運行mysql主從集羣

    把構建好的鏡像上傳到docker hub上,現在可以開始寫K8S的資源文件了,爲了能在宿主機上連接mysql,稍微改了一下,用NodePort的方式,首先是mysql-master-rc.yaml:

    然後是mysql-master-service.yaml:

     接下來是mysql-slave相關的,基本上類似,先看看mysql-slave-rc.yaml:

     好,趕緊的先運行起來:

     kubectl create -f ...

     喝杯小茶,坐等POD被調度起來,一段時間後通過kubectl get pods查看進度,What!!!,mysql-master對應的POD狀態居然是:CrashLoopBackOff,這是什麼情況,看樣子是主庫的容器掛掉了,得看看這個容器內部到底發生了什麼:

     docker ps -a

     發現主庫對應的容器確實處於Exited狀態,查看一下這個容器的日誌:

     docker logs ...

     看到這樣一行日誌:... for the right syntax to use near 'IDENTIFIED BY',看樣子是構建鏡像時修改了配置文件有點問題,參考文章中說要在docker-entrypoint.sh加入下面的代碼:

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" 
echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" 
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

     但是mysql 8.0開始這種寫法會出問題,其實打開參考文章鏈接原文,下面的評論區已經有人指出了錯誤的地方:

echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}"

     但是這哥們好事只做了一半,沒有告訴我們正確的寫法,其實只要把這一句後面的IDENTIFIED BY這一部分去掉就可以了,正確的寫法:

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" 
echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' | "${mysql[@]}" 
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

     好吧,重新構建一下鏡像、上傳,然後再次運行,這次沒問題了,kubectl get pods,發現狀態OK,都是Runing。

K8S NodePort連接不上的問題

     我們從宿主機上用Navicat來連接一下試試,填入虛擬機的IP地址和NodePort映射的master庫的端口30002連一下,問題又來了,居然連不到,K8S的NodePort不可能有問題吧,防火牆也是關掉的呀?肯定是哪裏的配置有問題,果然網上搜了一下,有高人指點:

     https://blog.csdn.net/weixin_34346099/article/details/87525499

     原來是selinux搞的鬼,按文中的說法操作一下:

setenforce 0
iptables --flush
iptables -tnat --flush
service docker restart
iptables -P FORWARD ACCEPT

    宿主機上再次用navicat連接,果然OK。

MYSQL主從同步問題

    現在數據庫可以正常連接上了,來試試主從同步是否OK,在master上創建一個數據庫,並建立表,隨便加一些數據,然後進入從庫,navicat上敲一下命令:

     show slave status    

     哇靠,問題又來了,上面的SQL告訴我error connecting to master...,並且Last_IO_Errno爲2061,只好再次網上求援,下面這個文章詳細說明了出現這個錯誤的原因:

     https://blog.csdn.net/wawa8899/article/details/86689618

     看來是因爲我們用了mysql最新的官方鏡像,所以參考文章中的改法已經不適用了,修改一下構建主鏡像的docker-entrypoint.sh,改成下面這樣:    

echo "CREATE USER '$MYSQL_REPLICATION_USER'@'%' IDENTIFIED WITH 'mysql_native_password' BY '$MYSQL_REPLICATION_PASSWORD' ;" | "${mysql[@]}" 
echo "GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%' ;" | "${mysql[@]}" 
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"

     注意改動點,第一行創建用戶那裏增加了 IDENTIFIED WITH 'mysql_native_password',按照網上那篇文章的說法,是因爲MySQL8.0默認指定使用需要SSL的身份驗證插件caching_sha2_password,因此需要繞過繞過SSL插件的驗證,改爲mysql_native_password驗證來做同步複製。

     重新制作鏡像,然後利用新鏡像再次驗證主從同步,果不其然還有坑,這一次show slave status報出了下面的錯誤:

     The slave I/O thread stops because master and slave have equal MySQL server ids...

     用show variables like 'server_id'分別在主庫和從庫看一下,果然這個值都是1,在看看之前對Dockerfile的修改,主庫用sed將server_id設置成了1:

RUN sed -i '/\[mysqld\]/a server-id=1\nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf

     而存庫則設置成了一個隨機值:

RUN RAND="$(date +%s | rev | cut -c 1-2)$(echo ${RANDOM})" && sed -i '/\[mysqld\]/a server-id='$RAND'\nlog-bin' /etc/mysql/mysql.conf.d/mysqld.cnf

     按說主從庫的server id不應該相同,但怎麼就一樣了呢?仔細看看Dockerfile,原來用了mysql官方鏡像以後,參考文章中添加這兩處修改的地方已經不適用了,要改一改,看看問題在哪裏:

     原文中的:     

     最新的:

     

     注意到了嗎,最新的官方鏡像裏,會將構建上下文中的config目錄拷貝到容器的/etc/mysql裏,這樣我們的修改其實是被覆蓋掉了,所以要把RUN sed -i ....這一句放到 COPY config/ /etc/mysql/這一句的下面。

     對主和從的Dockerfile又重新進行修改後構建鏡像,再次測試,這次再也沒有出錯了,主從同步OK。

總結

     其實搭建基於K8S的Mysql主從配置過程中遇到的這些問題,大多都源自於使用了官方最新的mysql鏡像,而參考文章中的做法用的則是比較老的,導致如果完全照搬會出現問題,好在所有這些問題都比較容易解決,這裏記錄一下避免將來踩同樣的坑,掉同一條河。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章