寫在前面的話
《Docker+SpringBoot+Mybatis+thymeleaf的Java博客系統開源啦》
《Java開源博客My-Blog之docker容器組件化修改》
My Blog項目已經開源了兩個多月,也收獲了不少star,在這里謝謝各位朋友的建議及幫助。由於個人原因,這個開源項目最初的定位其實是一個docker技術與springboot框架整合的Java博客系統實戰項目,而且是一個容器技術的練手項目,技術的偏重也更多的在容器技術及容器編排上。
雖然上個版本做了一些改動,將docker踢出主目錄,原因也是為了照顧其他關注和想要使用My Blog的朋友能夠很快的上手項目,但是docker容器技術依然是這個項目不可缺少的一部分,從項目創建那一刻即是如此,今后也是如此,只不過為了項目更友好而做了一些改動使其不會強耦合於項目中。
問題描述
從項目開源至今,大大小小的問題已經發現且解決了不少,但是直到近期才完全修復掉的一個大問題就是mysql容器重復初始化導致原數據被抹去的bug。
熟悉這個項目的朋友應該知道,項目初期為了讓mysql容器可以自動初始化數據花了多少精力,但是這個一直讓我覺得很完美的改動卻有一個非常致命的缺陷,一旦數據容器mysql掛掉了或者需要重啟,原先的數據就都沒了,即使只是重啟也會抹去原先的數據,這個就很尷尬了,我原以為最堅硬的盔甲卻成了最柔弱的軟肋,這件事真的讓我低迷了很久。
一開始並沒有發現這個問題,而是在項目運行一段時間之后,某一天由於服務器資源問題(服務器配置差)需要重啟,進而導致myblog容器和mysql容器也得重啟,但是在重啟后發現原來添加的博客數據及留言數據消失了!
取而代之的是schema.sql中的幾條初始化數據,當時也認真確認是否存在錯誤操作導致了數據被清空,結果就是一切流程都正常,過程中並沒有誤操,這個問題也只有在重啟時會出現,這是流程設計的問題而且是一個十分致命的問題,如果不解決,將是這個項目最大的一個污點。
問題原因
FROM mysql:5.7
ENV MYSQL_DATABASE test
ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
COPY setup.sh /mysql/setup.sh
COPY schema.sql /mysql/schema.sql
COPY privileges.sql /mysql/privileges.sql
#設置容器啟動時執行的命令
CMD ["bash", "/mysql/setup.sh"]
以上為mysql容器的Dockerfile文件,文件中定義了容器的啟動語句是執行setup.sh腳本文件,即mysql容器每次啟動都會執行setup.sh,包括第一次啟動及此后的重啟,而每次執行setup.sh都會重新初始化數據,這里的數據初始化包括什么呢?查看docker-extension/mysql目錄下的文件可知,此過程會刪除原來的數據庫,重新插入初始化數據庫中的數據及數據庫的用戶權限,再次目瞪狗呆。
過程記錄
一開始並沒有意識到嚴重性,因此也並沒有投入特別多的精力在這個問題上,而是把重點更多的放在其他bug的修復上,但是隨着自己博客數據的增多,及使用此項目的朋友漸漸增多,有一天我忽然有種重壓在心頭的感覺,對於技術人員來說,web應用發生數據丟失這種事情實在是一件頭痛的事,有過這種經歷的人都會抗拒類似事件的出現,試想一下,運行良好的網站由於重啟,導致數據全部丟失了,這種事情誰受得了,而且還是用了My Blog項目,是可忍孰不可忍!
雖然知道嚴重性,也無法容忍這個bug繼續存在於項目中,但是卻一直找不到合適的解決辦法,容器啟動過程中,能夠修改的也就是shell語句了,而原來的語句是直接執行,並沒有判斷是否已經存在tale數據庫,因此會導致覆蓋問題,新的setup.sh文件中一定要解決數據庫是否存在的判斷問題。
一開始是根本沒思路,通過一點點的動手實踐,整個思路也漸漸清晰,通過shell腳本執行mysql命令,並根據得到的輸出判斷是否已經存在項目數據庫,如果已經存在,就不再進行初始化,而是不進行任何操作即可,如果不存在,即第一次啟動mysql容器,則進行數據初始化操作。
主要問題有:
- shell如何執行數據庫操作;
- 能夠直接被shell操作的命令且可以判斷目標數據庫是否存在的語句較少;
- 得不到輸出(error直接退出);
- shell操作字符串的一些問題。
雖然現在很簡單的就將問題整理出來,但是在實際操作過程中卻是困難重重,上面所羅列的任何一個問題處理不掉,修復工作都無法繼續進行,經過一次又一次的調試失敗,最終找到了能夠執行且可以用來判斷數據庫的sql語句,終於解決掉了這個bug,卡着進度最久的就是這個步驟,在shell腳本中始終無法處理mysql服務器返回的信息,接下去的判斷邏輯根本無法執行。
如圖,在執行'mysql > use tale;'sql命令時,每次都有此錯誤返回,雖然是預想中的返回,如果針對此錯誤返回值即可正確的判斷是否已存在tale數據庫,但是shell在執行到此語句時,收到此錯誤信息就直接退出進程了,因此根本無法繼續進行。
針對shell操作字符串的一些問題,也單獨整理了兩篇筆記,可以在我的博客目錄中看到,這里就不在貼鏈接了。
雖然只有這么一個段落,但是前前后后有兩周的時間都在考慮及實踐如何修復這個問題,setup.sh文件也如上圖中local history一樣,一次又一次的修改。問題終於解決了,該如何形容心情呢?暴露出的最大弱點修復了,皆大歡喜,如釋重負,活在夢里...
處理結果
新版本的mysql容器:
第一次啟動的日志輸出
重啟時的日志輸出
如圖所示,最終得到了想要的結果,重啟時可以正確的判斷容器中的mysql服務器中是否已經存在tale數據庫,如果已經存在則不再重新初始化數據,修復了這個較為嚴重的bug。
問題修復之后,緊接着也就更新了阿里雲容器倉庫中的鏡像,因為原鏡像的版本較低依然存在此問題。
# 標記本地鏡像,將其歸入阿里雲鏡像倉庫
docker tag dockerextension_mysql registry.cn-hangzhou.aliyuncs.com/13/myblog:mysql
# 登錄阿里雲容器倉庫
docker login ...
# 上傳鏡像至容器倉庫
docker push registry.cn-hangzhou.aliyuncs.com/13/myblog:mysql
上傳成功,最新版的mysql鏡像已經不存在那個嚴重的bug了。
結語
永遠不要把你今天可以做的事留到明天做。拖延是偷光陰的賊。抓住他吧!
有問題,還是要解決的,不管你想着拖多久,該解決的還是要去解決。
這是一篇bug修復的復盤文章,也是一篇工作筆記,如果是第一次了解該項目,相信你即使看完后也是一臉懵逼,這是十分正常的,如果你想繼續了解該項目可以查看整個系列文章Java開源博客My-Blog(SpringBoot+Docker)系列文章,也可以到我的GitHub倉庫或者開源中國代碼倉庫中查看源碼及詳細的部署過程和使用文檔。
首發於我的私人博客,編輯於2017年7月25日凌晨00:46。