把AspDotNetCoreMvc程序運行在Docker上-part3:使用獨立的存儲容器

接上一篇博文《把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容器,說的比較囉嗦,實際上他們的結構圖以下,沒有想象的那麼複雜。

clipboard

相關文章
相關標籤/搜索