接上一篇博文《把AspDotNetCoreMvc程序運行在Docker上-part2:修改容器以及發佈鏡像》,此次咱們看看如何使用docker存儲數據。html
背景mysql
以前的示例都只有一個網站應用,其顯示的數據是放在內存中,能夠查看DummyRepository的實現方式。這樣的數據除了用於演示沒有什麼用處。這一部分,將擴展數據存儲功能,用比較實際的存儲方式,把數據保存到MySql數據庫中。git
那麼MySql數據庫放在哪裏呢?用傳統部署站點的方式,數據庫應該部署在獨立的服務器上,那麼用於docker也應該有數據庫專用的容器。可能有的人會說,數據庫放在跟應用站點容器中,不是更方便的嗎?對於示例我想能夠這麼作,可是用於實戰的話,會致使耦合,不易於對單獨或者單獨的數據庫進行橫向的擴容。因此這部分的示例將會把MySql數據庫部署到獨立的容器中。github
瞭解volumeweb
在演示以前,須要瞭解docker中的volumesql
volume從字面意思理解就是表示容量、體積,它的功能將數據存儲獨立於容器以外,能夠這麼理解:刪除容器以後,數據還會保留。這麼看來不就是相似於數據庫的功能嗎?docker
volume示例數據庫
對於volume的使用咱們能夠舉個例子來講比較形象json
在Docker服務器上建立以下文件Dockerfile.volumes,內容以下瀏覽器
FROM alpine:3.4
WORKDIR /data
ENTRYPOINT (test -e message.txt && echo "File exists" || (echo "Creating File..." && echo Hello, Docker $(date + '+%X') > message.txt)) && cat message.txt
這個文件包含了建立容器的命令
1.拉取鏡像alpine:3.4(這是一個很小的Linux發行版)
2.設置WORKDIR
3.設置啓動命令,一看就懂,就是看message.txt是否存在,不存在則建立並寫入建立時間,不然直接顯示內容
而後建立鏡像
docker build . -t shenba/vtest -f Dockerfile.volumes
建立並運行一個容器
docker run --name vtest shenba/vtest
而後在輸出中能看到以下信息
Creating File...
Hello, Docker 07:10:05
說明是新建的
因爲這個容器其餘啥也沒幹,全部運行完畢以後就直接關閉了,咱們調用啓動命令
docker start -a vtest
這時候的輸出是
File exists
Hello, Docker 07:10:05
沒問題,說明文件是保存在容器中了
那麼咱們把容器刪掉再建立看看什麼效果
docker rm -f vtest
docker run --name vtest shenba/vtest
輸出以下
Creating File...
Hello, Docker 07:13:56
建立了新文件,而且輸出的時間也變了,說明以前的文件已經不存在了
接下來咱們使用volume來解決刪除容器後數據丟失的問題
首先修改Dockerfile.volumes文件,在第一個命令以後插入以下命令
VOLUME /data
接着執行build命令更新鏡像
docker build . -t shenba/vtest -f Dockerfile.volumes
建立volume,在建立容器的時候會被用到
docker volume create -name testdata
刪除以前的容器
docker rm -f vtest
再次建立容器,這裏指定了/data的數據是保存在testdata這個volume中
docker run --name vtest -v testdata:/data shenba/vtest
一樣能看到輸出
Creating File...
Hello, Docker 07:25:27
那麼咱們先刪除這個容器,而後再次建立一個容器
docker rm -f vtest
docker run --name vtest -v testdata:/data shenba/vtest
這時候的輸出內容是
File exists
Hello, Docker 07:25:27
說明message.txt這個文件是被保存在外部的volume中,不受容器刪除的影響。
使用volume存儲MySql數據
好了有了這麼一個例子以後,咱們接下來將咱們的AspDotNetCoreMvc程序的數據保存到MySql數據庫中。(爲何用Mysql,而不是微軟當家SqlServer,那是應爲這裏用的是Linux docker平臺,SqlServer運行在Linux還太新了,還不瞭解,避免踩到坑)
既然要用MySql,那首先有個MySql的鏡像。跟傳統方式不一樣吧,不用本身安裝MySql,直接拉個鏡像下來(這個命令須要些時間執行,可考慮配置國內鏡像)
docker pull mysql:8.0.0
而後建立一個volume
docker volume create --name productdata
而後建立mysql的容器
docker run -p 3306:3306 -d --name mysql -v productdata:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password -e bind-address=0.0.0.0 mysql:8.0.0
這裏幾個參數說明一下
-p 3304:3304 設置宿主機的3304端口映射到容器的3304端口,這樣能夠在宿主機訪問到容器裏的mysql
-d 後臺運行容器
-e 是設置環境變量,這裏設置了兩個變量,一個是密碼,一個是地址綁定
-v 指定使用的volume,後面的/var/lib/mysql是根據mysql鏡像裏設置的路徑配置的,要查看這個路徑可使用以下命令 docker insepect mysql:8.0.0,在輸出的內容中能夠看到以下信息
"Volumes": {
"/var/lib/mysql": {}
}
由於設置的是後臺運行,因此看不到詳細的日誌,不過能夠經過如下命令查看
docker log -f mysql
從日誌中咱們能夠看到以下字樣
MySql is ready….
代表mysql服務已經成功運行了,整個過程比本身手動安裝mysql簡單多了(前提是docker環境已經搭好)
準備好MySql的docker容器以後,接着更新咱們的AspDotNetCoreMvc程序,讓數據存儲指向MySql,改動過程不詳細描述,這裏有修改好的代碼分支
https://github.com/shenba2014/AspDotNetCoreMvcDocker/tree/mysql
代碼拉取下來後執行以下修改
修改appsettings.json中DBHOST的IP地址,指向MySql容器所在宿主機器的IP,若是docker就安裝在開發機,那麼可設置爲localhost
而後執行以下命令(確保mysql的容器已正常運行)
dotnet restore
dotnet ef migrations add Initial
dotnet ef database update
執行完上述命令以後,就會在MySql建立books數據庫,而且建立了數據表Book.
咱們能夠經過如下方式在docker容器上執行mysql命令來查看咱們新建的數據庫和表
docker exec -it mysql /bin/bash
而後進入到mysql容器下的bash命令,繼續執行以下命令
mysql -uroot -p
輸入密碼(這裏的密碼在以前建立鏡像的時候設置的)以後就會進行mysql的命令行
show databases;
use books;
show tables;
能夠看到只有一個表Book
接下來更新咱們的shenba/aspdotnetcoremvc鏡像
首先仍是執行如下publish命令
dotnet publish --framework netcoreapp2.0 --configuration Release --output dist
將dist文件夾拷貝docker所在服務器(若是開發機就是docker服務器可忽略這步)
確保dist文件夾同級別的目錄下有Dockerfile文件,這個文件具體內容在項目代碼根目錄下有
而後執行以下命令更新鏡像
docker build . -t shenba/aspdotnetcoremve -f Dockerfile
執行完畢以後,還不能當即建立這個鏡像的容器,由於咱們的容器是依賴於MySql數據庫容器,咱們的應用程序鏡像是經過docker內部的網絡來訪問MySql數據庫容器。這個網絡,不是咱們配置的localhost,其具體的訪問地址是由docker設置好的
咱們能夠經過如下命令查看看docker的默認虛擬network的IP地址信息
docker network inspect bridge
在輸出結果中咱們能夠看到相似以下的輸出
"Containers": {
"d4e5cf975ad5e3ff11620c02f9b626fa4d0042faab83fa9d0ea86801d2cce452": {
"Name": "mysql",
"EndpointID": "39818b04606078f600a3ab55ef76949807d6528b978ec24d0f91cd5f4217b610",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
這是咱們的mysql容器使用的網絡配置信息,IPv4Address就是給其餘容器訪問的IP地址。
查看項目的Startup.cs的代碼,咱們的DBHOST是經過參數讀取的。在運行ef migrations命令時,咱們是經過appsettings.json中的DBHOST來設置具體的MySql所在服務器地址,實際上就是docker宿主機器的IP地址,由於咱們作了映射,因此實際訪問的是MySql容器。
而後在運行階段,咱們能夠經過指明環境變量的方式來設置這個值
docker run -d --name bookApp -p 3000:80 -e DBHOST=172.17.0.2 shenba/aspdotnetcoremvc
執行完成這個命令以後,就會在mysql容器中插入一些種子數據。而且從輸出信息中能看到執行了建立種子數據的過程
Applying Migrations...
Creating Seed Data...
而後經過瀏覽器訪問
http://{ip}:3000就能看到數據是從mysql裏讀取的
而且從新經過docker exec -it mysql /bin/bash進入mysql可再次確認裏面的數據
mysql -uroot -p
use books;
select * from Books;
好了到這裏已經完成了,目前實現了兩個容器之間的通信,一個是包含web應用的容器,一個包含數據的mysql容器,說的比較囉嗦,實際上他們的結構圖以下,沒有想象的那麼複雜。