在上一part《把AspDotNetCoreMvc程序運行在Docker上-part4:實現負載均衡》中,咱們經過幾個比較複雜的步驟在docker平臺上實現了對網站程序的負載均衡,配置步驟比較多。若是實際的站點較少,整個架構比較簡單的狀況下,這麼作沒有太大問題,若是應用較多的時候,會容易出錯。那麼這時候咱們可能會想到本身寫一些腳原本實現自動化,固然這是可行的。然而docker已爲咱們着想好,給咱們提供了docker-compose功能,利用它咱們能夠實現對複雜應用的管理,包括容器、網絡、volume等。html
準備工做node
先刪除上一part咱們建立的容器、網絡和volume(不用以爲惋惜,後面用上docker-compose能夠輕易實現)mysql
docker rm -f $(docker ps -aq)
docker network rm $(docker network ls -q)
docker volume rm $(docker volume ls -q)linux
安裝docker-composegit
在linux平臺上須要手動執行以下命令安裝github
sudo curl -L https://github.com/docker/compose/releases/download/1.17.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-composesql
sudo chmod +x /usr/local/bin/docker-composedocker
(最新版本能夠從這裏https://github.com/docker/compose/releases獲知)數據庫
安裝以後,運行docker-compose –version檢查是否成功npm
準備MVC站點程序
能夠從這裏下載
https://github.com/shenba2014/AspDotNetCoreMvcDocker/tree/docker-compose
而後執行
dotnet restore
bower install
一會用到這個站點程序建立一個鏡像以及對應的容器
建立docker-compose配置文件
新建docker-compose.yml文件(在docker所在宿主服務器直接建立也能夠)
version: "3"
volumes:
productdata:
networks:
frontend:
backend:
services:
mysql:
image: "mysql:8.0.0"
volumes:
- productdata:/var/lib/mysql
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD=password
- bind-address=0.0.0.0
這個文件足夠的自描述,把上一節咱們用到的內容都做出了定義,仍是簡單解釋一下
version:版本號,目前最新的是3.0
volumes:以前的《把AspDotNetCoreMvc程序運行在Docker上-part3:使用獨立的存儲容器》裏面有介紹過,用於在docker容器外存儲數據
networks:在上一part說過,定義了兩個網絡:frontend和backend
services:定義將要用到的容器,這裏只定義了mysql容器,這些參數跟使用docker create命令建立容器的參數一致。具體可參考上一part《把AspDotNetCoreMvc程序運行在Docker上-part4:實現負載均衡》。
docker-compose執行構建
執行以下構建命令
docker-compose –f docker-compose.yml build
輸出結果
WARNING: Some networks were defined but are not used by any service: frontend, backend
mysql uses an image, skipping
這裏的警告信息意思是咱們定義的兩個網絡還沒被任何服務組件使用。
運行了這個命令只是定義,並無真正的建立volume、network或者容器。
接下來運行docker-compose.yml定義的應用,纔會真正的建立內容
docker-compose -f docker-compose.yml up
能夠理解爲啓動剛纔咱們定義的組件,而後會有一堆的輸出內容
WARNING: Some networks were defined but are not used by any service: frontend
Creating network "dockertemp_backend" with the default driver
Creating dockertemp_mysql_1 ...
Creating dockertemp_mysql_1 ... done
Attaching to dockertemp_mysql_1
很明顯docker-compose在依次建立network、容器實例。
名字看起來比較奇怪,都帶了dockertemp_前綴。由於docker-compose.yml所在的目錄命令是dockertemp,因此最終提供的名稱有這個前綴,避免了命名衝突。
而爲何是mysql_1,帶有_1後綴,後續會用到,這裏是爲了用於橫向擴展作集羣的時候用到。
進一步經過以下命令驗證volume、network和容器是建立成功的
docker volume ls
docker netowrk ls
docker ps –a
使用docker-compose –f docker-compose.yml down -v可刪除network、容器和volume,全自動完成(保存在volume的數據也會刪除,若是要保留volume把-v去掉便可)。
如今docker-compose文件裏只定義了一個service,接下來繼續添加MVC站點容器以及負載均衡容器。
添加MVC站點容器以及負載均衡容器
首先從如下路徑下載代碼
https://github.com/shenba2014/AspDotNetCoreMvcDocker/tree/docker-compose
這個分支跟以前的不同,增長了對支持docker-compose的一些改動。
代碼拉下來以後執行以下命令
dotnet restore
dotnet publish --framework netcoreapp2.0 --configuration Release --output dist
cd dist | npm install
dist文件夾裏的內容就是咱們後續要用到的MVC站點內容。
從源代碼查看完整的docker和docker-compose.yml文件
先看看docker文件的更新內容
FROM microsoft/aspnetcore:2.0.0
COPY dist /app
COPY dist/node_modules/wait-for-it.sh/bin/wait-for-it /app/wait-for-it.sh
RUN chmod +x /app/wait-for-it.sh
WORKDIR /app
EXPOSE 80/tcp
ENV WAITHOST=mysql WAITPORT=3306
ENTRYPOINT ./wait-for-it.sh $WAITHOST:$WAITPORT --timeout=0 && exec dotnet AspDotNetCoreMvcDocker.dll
紅色部分是新增的內容,這裏拷貝了一個wait-for-it的腳本到了容器內部,而且在ENTRYPOINT裏設置了等待mysql啓動以後再啓動MVC容器。
簡單解釋一下,由於使用了docker-compose啓動容器以後,咱們不能確保mysql容器服務是否已正常啓動,若是mysql沒有啓動,那麼站點也無法使用。因此容器必須在mysql容器啓動以後執行,這裏就引入了一個npm的package:wait-for-it,這個只能在Linux平臺下使用。
接下打開完整的docker-compose.yml文件,這裏只列出新增的service(完整文件內容不列出,可查看代碼)
dbinit:
build:
context: .
dockerfile: Dockerfile
networks:
- backend
environment:
- INITDB=true
- DBHOST=mysql
- DBPASSWORD=password
depends_on:
- mysql
mvc:
build:
context: .
dockerfile: Dockerfile
networks:
- backend
- frontend
environment:
- DBHOST=mysql
- DBPASSWORD=password
depends_on:
- mysql
loadbalancer:
image: dockercloud/haproxy
ports:
- 3000:80
links:
- mvc
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- frontend
這裏才原來的基礎上增長了dbinit,mvc和loadbalancer三個service,分別描述以下
dbinit:主要是用於初始化數據庫,這裏是把它當作一個容器來執行,實際在完成了數據庫初始化自後就會退出。
mvc:這裏就是MVC站點的容器,跟咱們上一part定義MVC的參數相似。主要是增長了depends_on參數,指明mvc容器依賴於mysql容器。
loadbalancer:顧名思義,就是負載均衡服務器容器,經過links參數指向了其代理的站點是MVC容器,而且經過volumes參數配置了/var/run/docker.sock文件映射爲主機的文件,具體做用不描述,主要是爲了在擴容的時候通知到負載均衡服務器。
啓動站點
把上一步的dist文件夾docker、docker-compose.yml文件拷貝到docker服務器(若是開發機就是docker服務器能夠忽略),而後在這些文件的所在目錄執行以下命令
docker-compose -f docker-compose.yml build
這個命令以前提到過,相似於編譯,檢查是否有錯誤,實際上不會建立容器
接着運行
docker-compose -f docker-compose.yml up dbinit
開啓dbinit容器,以前咱們提到,這個dbinit也是個MVC容器,可是隻是負責數據庫初始化,完成以後會自動關閉,這是這個命令的output
Creating network "dockertemp_frontend" with the default driver
Creating network "dockertemp_backend" with the default driver
Creating volume "dockertemp_productdata" with default driver
Creating dockertemp_mysql_1 ...
Creating dockertemp_mysql_1 ... done
Creating dockertemp_dbinit_1 ...
Creating dockertemp_dbinit_1 ... done
Attaching to dockertemp_dbinit_1
dbinit_1 | wait-for-it.sh: waiting for mysql:3306 without a timeout
dbinit_1 | wait-for-it.sh: mysql:3306 is available after 16 seconds
dbinit_1 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
dbinit_1 | No XML encryptor configured. Key {1b1e827d-d1d0-4d0c-a92d-8632ee0791ef} may be persisted to storage in unencrypted form.
dbinit_1 | Preparing Database...
dbinit_1 | Applying Migrations...
dbinit_1 | Creating Seed Data...
dbinit_1 | Database Preparation Complete
dockertemp_dbinit_1 exited with code 0
從output能夠看到有一個等待mysql啓動的步驟,等待了16秒。而後是執行了數據庫初始化,建立表以及插入一些種子數據。最後一個行輸出代表該容器自動退出。
好了數據庫準備好以後,就能夠啓動MVC和負載均衡容器,仍是經過docker-compose命令
docker-compose -f docker-compose.yml up mvc loadbalancer
執行完成以後,就能夠訪問咱們的MVC站點了,這裏咱們只啓用了一個MVC站點,試試從瀏覽器打開http://192.168.115.136:3000/,一切正常的話就能看到網站和數據了
作了這麼多步驟,就是爲了實現負載均衡,接下來一行命令讓他當即擴容到4個MVC站點
docker-compose -f docker-compose.yml scale mvc=4
秒級擴容就是這簡單,不信的話運行docker ps看看下面是否是有4個MVC站點容器,還不相信的話手動多刷幾回http://192.168.115.136:3000/,會發現from server的值是會發生變化的。
好了,若是這時候要實現優雅降級怎麼辦,沒問題,仍是一行命令
docker-compose -f docker-compose.yml scale mvc=1
系統自動移除了三個MVC站點容器,固然也是秒級的。
最後關閉全部服務的命令是
docker-compose -f docker-compose.yml stop
寫了這麼多就是爲了描述docker-compose的使用方法,對比上一part,實際上就是把以前的工做都放到一個批處理文件裏執行,將全部服務當作一個總體來管理,同時也提供了遍歷站點擴容和降級的方式。看起來已經很方便了,固然還沒完,後續還有大招。