場景說明:mysql
既然說服務器,怎麼能離開各類數據庫呢?而 MySQL 顯然是最好用的數據庫之一。git
可是博主本身經驗來講,最討厭配 MySQL 的環境了,還好有 Docker 能夠簡單解決這個問題。github
使用思路:sql
Docker的容器是能夠被刪除、複製的。docker
但顯然,MySQL 做爲一個數據庫,是不能接受這樣的狀況發生(由於會致使數據丟失)。shell
初步的解決思路,是容器負責業務邏輯,而存儲數據存儲於容器外。數據庫
這樣,便實現了業務代碼(指 MySQL 的邏輯部分)與數據(指數據文件)分離的效果。express
其餘說明:安全
爲了方便省事,使用 MySQL5.6 版本。bash
由於 5.7 版本,會有一些很麻煩的事情出現。
命令:
docker pull mysql:5.6
複製代碼
效果:
拉取了 MySQL 5.6 版本最新的 image
[root@qq20004604 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-demo-01-express 0.0.1 416f1050c9bf 42 hours ago 907MB
mysql 5.6 98455b9624a9 2 weeks ago 372MB
複製代碼
命令:
docker container run --name [name] -p 3306:3306 -e MYSQL_ROOT_PASSWORD=[password] -d mysql:[version]
複製代碼
示例代碼:
docker container run --name mysql-demo -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234567890 -d mysql:5.6
複製代碼
說明:
docker container run
:經過image啓動容器,也能夠寫爲 docker run
,但推薦使用更全的命令;--name [name]
:生成的容器的名字,若是不寫,則會隨機生成一個名字;-p 3306:3306
:將容器端口映射本機端口;-e MYSQL_ROOT_PASSWORD=[password]
:設置環境變量,這裏指設置 MySQL 的默認密碼。注意,不須要帶括號也不須要帶引號來包裹密碼;-d mysql:[version]
:這裏指你基於哪一個 MySQL 來生成容器;示例代碼如上,效果是:
mysql-demo
;首先,咱們一般須要遠程訪問,因此要配置一下。
進入容器的 MySQL:
docker container ps -a
列出全部容器;docker container exec -it [containerID] /bin/bash
進入容器並輸入命令行;mysql -u root -p
進入mysql,會提示輸入密碼,輸入密碼便可(若是按我上面示例代碼,默認密碼是 1234567890
;對 MySQL 進行配置:
容許 MySQL 被遠程訪問:
grant all privileges on *.* to 'root'@'%' identified by '[password]';
flush privileges;
複製代碼
[password]
:是密碼,他被引號所包含在內,容許任何一個 IP 訪問 root 帳號經過上面這個密碼;此時狀況:
能夠在其餘機子上遠程訪問 MySQL,遠程訪問命令:
mysql -h [serverIP] -P 3306 -u root -p
複製代碼
而後輸入密碼便可登陸進去了
其餘:
the 'information_schema.session_variables' feature is disabled
這樣的報錯,嘗試使用 set @@global.show_compatibility_56=ON;
來解決。一般是由於使用 5.7 版本而不是 5.6 版本而出現的;等等,雖然 MySQL 跑起來了,可是數據還在容器裏呀?
解決方法很簡單,將容器內外 link 起來便可。
核心方法是建立容器時,經過參數:-v [容器外路徑]:[容器內路徑]
來實現。
這樣當容器內路徑(該文件夾)下內容有所改動時,會被同步到容器以外。
#### 2.五、測試收尾,移除舊的 MySQL 容器:
docker containers ps -a
查到全部容器,而後找到測試用的容器的 ID;docker rm [containerID]
刪除測試容器;### 三、數據持久化
命令:
docker run --name mysql-demo -v $PWD/mysqldata:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234567890 mysql:5.6
複製代碼
說明:
-v $PWD/mysqldata:/var/lib/mysql
;$PWD/mysqldata
,即當前目錄下($PWD
)的 mysqldata 文件夾下;/var/lib/mysql
(這個是 MySQL 默認目錄);理論上來講,咱們指望 Docker 鏡像生成容器並啓動完畢後,咱們就不須要進行管理了。
但實際上來講,不少時候並不能知足這樣的要求。
以 MySQL 爲例,一些權限管理、庫表預建立之類的事情,並不能在建立的時候就實現。
而且在我實際實踐中,MySQL 5.6 在做爲 咱們自定義的 Docker 的基礎鏡像時,雖然能夠正常運行。但若是生成容器時添加了持久化配置,卻會提示權限錯誤沒法正常運行。
由於這樣的緣由,我決定將本來一次性操做(生成鏡像後自動執行腳本),拆分爲兩步:
避免手動執行命令,所以咱們應該預先準備一些腳本。
先列出文件目錄:
create-image-mysql.sh # 運行這個腳本建立容器
app # 用於在容器內執行的內容放這裏
|--init.sh # shell腳本,在這裏將上面的SQL文件執行
|--data.sql # 預建立數據庫表SQL,用於在數據庫初始化後,建立一些須要的database和table
|--privileges.sql # 權限管理SQL,相關權限管理的SQL寫在這裏
複製代碼
其中:
create-image-mysql.sh
:這個腳本將於用於建立容器、建立數據持久化文件夾、將數據拷貝進容器並執行腳本;app
:這個文件夾內容將被拷貝進腳本,具體功能將在下面解釋;初始狀況下,咱們只有一個下載好的 MySQL5.6 鏡像(甚至都木有這個鏡像,但這個耗時就過久了)。因此這個腳本要作的事情不少,包括下載image,建立容器,將容器外腳本拷貝進容器,執行初始化腳本等。
文件內容:
#!/usr/bin/env bash
# 若是須要使用其餘鏡像,記得自行修改腳本
# 修改映射到本機的端口也同樣
appfilename="app"
mysqldatafilename="mysqldata"
imagename="docker-demo-02-mysql:0.0.1"
containername="mysql-demo"
# 創建持久化文件夾
if [ ! -d $mysqldatafilename ]; then
mkdir "$mysqldatafilename"
fi
echo "【1】下載 mysql:5.6.43 版本 image"
docker pull mysql:5.6.43
echo "下載完成或無需下載"
echo "【2】先用本來鏡像生成容器,初始化不須要密碼(後續添加),並進行持久化配置"
echo "$PWD/$mysqldatafilename"
docker run --name "$containername" -d -v "$PWD/$mysqldatafilename":/var/lib/mysql -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=yes mysql:5.6.43
# 若是本身手動執行的話,下面這行腳本能夠在建立容器時即添加帳號密碼
#docker run --name mysql-demo -d -v "$PWD/$mysqldatafilename":/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234567890 mysql:5.6.43
# 而後把 app 文件拷貝到容器裏面
echo "【3】而後把 app 文件拷貝到容器裏面"
docker cp "$PWD/$appfilename" "$containername":/
echo "【4】執行容器內的初始化腳本"
docker exec "$containername" sh "/$appfilename/init.sh"
複製代碼
說明:
全部在容器內,須要執行的內容,好比 SQL 腳本呀,或者是一些配置內容呀,都經過它來執行。
在這個腳本里,有如下命令:
#!/usr/bin/env bash
# 等待 MySQL 啓動完畢
echo '當前 mysql 服務狀態:'
echo `service mysql status`
echo "1.等待15秒,確保mysql已經啓動了,否則 SQL 可能沒法順利導入"
sleep 15
echo '當前 mysql 服務狀態:'
echo `service mysql status`
# 導入預建立庫表的sql文件
echo "2.開始導入數據"
mysql < /app/data.sql
echo '3.導入數據完畢.....並等待3秒.....'
sleep 3
# 因爲最開始設置mysql爲免密登錄,爲了安全,在此設置mysql密碼,並進行權限配置
echo '4.開始進行權限配置.....'
# 導入修改mysql權限設置的文件
mysql < /app/privileges.sql
echo '5.修改密碼完畢.....'
echo '----------------------------------------------------------'
echo "mysql容器啓動完畢。若是導入數據時,顯示 Can't connect to local MySQL server through socket,則說明導入失敗。容器外手動執行命令【docker exec mysql-demo sh /app/init.sh】便可"
echo '----------------------------------------------------------'
複製代碼
說明:
data.sql
文件中;正常狀況下, MySQL 每每須要預建立一些 database 和 table,以供程序使用,而這些最好在容器建立的時候就作到。
這裏是由 data.sql
文件來實現的。
在這個 SQL 文件裏,有如下內容:
-- 建立數據庫
DROP database IF EXISTS `docker_test_database`;
create database `docker_test_database` default character set utf8 collate utf8_general_ci;
-- 切換到test_data數據庫
use docker_test_database;
-- 建表
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- 插入數據
INSERT INTO `person` (`id`,`name`,`age` )
VALUES
(0,'Tom',18);
複製代碼
說明:
一個良好的數據庫必然會有多個不一樣權限的角色,只有這樣才能確保數據庫的安全性和穩定性。所以,咱們須要有一個權限管理SQL。
文件內容:
use mysql;
select host, user from user;
-- 任意地點的root帳號能夠用一個很是複雜的密碼登陸(瞎打的),用於禁止無密碼登陸
GRANT ALL ON *.* to root@'%' identified by 'fwefwefvvdsbwrgbr9jj24intwev0h0nbor32fwfmv1' with grant option;
-- 容許root用戶以密碼 123456 來登陸(僅限本地)
GRANT ALL ON *.* to root@'localhost' identified by '123456' with grant option;
-- 將 docker_test_database 數據庫的權限受權給建立的docker用戶,密碼爲 1234567890,但只能本機訪問(指容器內)
-- 若是用戶docker不存在,則建立用戶docker
GRANT ALL ON docker_test_database.* to docker@'localhost' IDENTIFIED by '1234567890';
-- 其餘任意地方能夠訪問,須要使用密碼 1654879wddgfg
GRANT ALL ON docker_test_database.* to docker@'%' IDENTIFIED by '1654879wddgfg';
-- mysql新設置用戶或權限後須要刷新系統權限不然可能會出現拒絕訪問:
FLUSH PRIVILEGES;
複製代碼
說明:
遠程驗證連接爲:
mysql -h [遠程主機IP地址] -P 3306 -u root -p
複製代碼
而後輸入密碼便可。
將以上文件拷貝到主機,而後執行 create-image-mysql.sh 腳本便可。會自動安裝並配置好 MySQL。
經過以上操做,咱們實現了需求。如今,咱們再來回顧一下這個需求作了什麼事情:
本項目資源請在個人github項目地址查看: