.NET遇上Docker - 使用Docker Compose组织Ngnix和.NETCore运行
本文工具準(zhǔn)備:
- Docker for Windows
- Visual Studio 2015 與 Visual Studio Tools for Docker
- 或 Visual Studio 2017 需要在安裝時(shí)選擇“容器開發(fā)支持”,如圖:
Docker的思想是將不同的應(yīng)用放在不同的容器中分開運(yùn)行,如運(yùn)行.NetCore Web的典型組合Nginx+.NETCore(kestrel),我們應(yīng)該使用一個(gè)容器運(yùn)行Nginx,另一個(gè)容器運(yùn)行.NETCore App。
之前還陷入一個(gè)誤區(qū),一直在研究如何將dotnet與Nginx配置實(shí)現(xiàn)到一個(gè)Dockerfile中,后來了解到Docker Compose才知道這兩者應(yīng)該分開到不同的容器。
服務(wù)器端安裝Docker與Docker Compose
見此文
DotnetCore的Dockerfile
一般來說通過Visual Studio 2015 Tools for Docker給項(xiàng)目添加Docker支持后,項(xiàng)目中就會(huì)有Dockerfile與docker-compose.xml的初始模板。只需要修改其中的內(nèi)容適應(yīng)我們的項(xiàng)目即可。
Visual Studio的2017可以在新建項(xiàng)目時(shí),或建立項(xiàng)目以后選擇添加Docker支持。
Visual Studio 2017稍有不同的是其將docker-compose.yml文件作為解決方案級(jí)文件來管理。這對(duì)于組合多個(gè)項(xiàng)目是很有幫助的。如圖:
本文最初編寫時(shí)項(xiàng)目使用的Visual Studio 2015,所以docker-compose.yml還都是在Web項(xiàng)目中。但下文的設(shè)置對(duì)這兩種組織方式都支持,稍微調(diào)整一下路徑即可。
首先是默認(rèn)Dockerfile的文件,我們將其配置為運(yùn)行dotnet
FROM microsoft/aspnetcore:1.0 ENTRYPOINT ["dotnet", "orgname.projname.WebApi.dll"] ARG source=. WORKDIR /app EXPOSE 5000 COPY $source /appaspnetcore這個(gè)Iamge有1.0和1.1兩個(gè)版本,根據(jù)項(xiàng)目所使用的.NETCore版本自行更換
單獨(dú)測(cè)試下這個(gè)Dockerfile的image生成
docker rmi orgname/projname.core:test docker build --rm -t orgname/projname.core:test -f Dockerfile .測(cè)試下鏡像作為容器運(yùn)行:
docker run --name projname.core.inst -p 5000:5000 orgname/projname.core:test測(cè)試完成后,把所有測(cè)試產(chǎn)物,如鏡像和容器,都刪除。
docker stop projname.core.inst docker rm -f projname.core.inst docker rmi orgname/projname.core:test在剛開始編寫Dockerfile打包鏡像時(shí),可能會(huì)反復(fù)進(jìn)行生成,運(yùn)行容器的步驟。為了方便測(cè)試,樓主把這些腳本整合成了一個(gè)buildtest.bat,如下。
@echo onSET /p app=.NETCoreWeb(d)Nginx(n) SET /p job=生成并運(yùn)行(r)清理(c) SET /p mode=交互運(yùn)行(i)后臺(tái)運(yùn)行(b)if "%app%"=="d" ( SET contName=projname.core.inst SET imagName=orgname/projname.core:test SET file=Dockerfile ) if "%app=%"=="n" ( SET contName=projname.core.pub.inst SET imagName=orgname/projname.core.pub:test SET file=Dockerfile-Nginx )if "%mode%"=="i" ( SET operate=-it ) if "%mode%"=="b" ( SET operate=-d )if "%job%"=="r" ( GOTO Build ) if "%job%"=="c" ( GOTO Clear ):Build docker stop %contName% docker rm -f %contName% docker rmi %imagName% docker build --rm -t %imagName% -f %file% . docker run %operate% --name %contName% -p 5000:5000 -e "ASPNETCORE_ENVIRONMENT=Staging" %imagName% GOTO End:Clear docker stop %contName% docker rm -f %contName% docker rmi %imagName% docker ps -a docker images GOTO End:End樓主一般用Docker for Windows做測(cè)試,自然也就寫了批處理的腳本,后來(這篇文章慢慢的攢了一段時(shí)間才最終完成)為了調(diào)試方便轉(zhuǎn)投PowerShell。
包括這個(gè)腳本在內(nèi)的本文提供的幾個(gè)腳本都非常好用,誰用誰知道。
Nginx的Dockerfile
首先是Nginx的配置文件,這是比較重要的一個(gè)配置,Nginx的Docker Image生成到時(shí)候會(huì)復(fù)制這個(gè)文件到Nginx Docker Image內(nèi)。
本文介紹普通的80端口的轉(zhuǎn)發(fā),配置如下:
server {listen 8081;location / {proxy_pass http://core-app:5000;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection keep-alive;proxy_set_header Host $host;proxy_cache_bypass $http_upgrade;}}注意 配置中的轉(zhuǎn)發(fā)地址,不再是localhost,而是需要根據(jù)link所指定的服務(wù)/容器的別名來確定。這個(gè)link參數(shù),在下面有示例。
這個(gè)涉及到Docker網(wǎng)絡(luò),這是個(gè)非常復(fù)雜的話題。
注意:nginx.conf需要ANSI編碼,且換行為L(zhǎng)inux格式,否則導(dǎo)入容器中可能會(huì)報(bào)錯(cuò)。(可以使用Notepad++編輯,使用VS編輯可能會(huì)出問題)
還可以配置Nginx使用HTTPS,或者使用Nginx配置簡(jiǎn)單的負(fù)載均衡,如果以后樓主有機(jī)會(huì)研究的話會(huì)再寫文章分享。
測(cè)試下Nginx的Docker Image的生成:
docker build --rm -t orgname/projname.core.pub:test -f Dockerfile-Nginx .啟動(dòng)容器來測(cè)試:
docker run --name projname.core.pub.inst -p 8081:8081 --link projname.core.inst:core-app orgname/projname.core.pub:test注意:link即指示鏈接到的之前創(chuàng)建的運(yùn)行.net core的容器,冒號(hào)后面部分是指定別名。這個(gè)別名就是前文Ngnix配置文件中,所轉(zhuǎn)發(fā)的地址。
如果啟動(dòng)Nginx容器后,可以通過Nginx訪問.NET Core Web App,說明到此為止的配置都是正確的。
可以繼續(xù)配置docker compose了。
清理測(cè)試產(chǎn)物:
docker stop projname.core.pub.inst docker rm -f projname.core.pub.inst docker rmi orgname/projname.core.pub:test將docker相關(guān)文件添加到項(xiàng)目發(fā)布文件
(VS2015)編輯project.json文件中publishOptions-include的數(shù)組,將Dockerfile、Dockerfile-Nginx、nginx.conf及docker-compose.yml添加到其中。
一般來說,按照之前步驟添加“Docker Support”后,插件會(huì)自動(dòng)將相關(guān)文件添加到project.json的publishOptions中,這一步進(jìn)行確認(rèn)就好。
(VS2017)在解決方案資源管理器中將Dockerfile、Dockerfile-Nginx、nginx.conf及docker-compose.yml包含在項(xiàng)目中。“復(fù)制到輸出目錄”選擇“如果較新則復(fù)制”。
發(fā)布項(xiàng)目
使用下面命令發(fā)布項(xiàng)目
dotnet publish --framework netcoreapp1.0 --configuration release --output publish.linux可以將這條命令保存為一個(gè)批處理文件,如publish.linux.bat,放到項(xiàng)目根目錄下
編輯Docker Compose配置文件
docker compose配置文件基本上就之前用到的docker build和docker run命令的另一種表述形式
version: '3'services:orgname.projname.webapi:image: orgname/projname.core:${TAG}build:context: .dockerfile: Dockerfileexpose:- "5000"container_name: projname.core.instenvironment:- ASPNETCORE_ENVIRONMENT=Developmentvolumes: - ./log:/app/log:rwdeploy:restart_policy:condition: alwaysorgname.projname.webapi.pub:image: orgname/projname.core.pub:${TAG}build:context: .dockerfile: Dockerfile-Nginxports: - "8081:8081"links: - orgname.projname.webapi:core-appcontainer_name: projname.core.pub.instvolumes:orgname.projname.webapi:注意,服務(wù)orgname.projname.webapi中,使用expose來暴露端口,因?yàn)槲覀儾恍枰獙⒍丝诒┞督odocker外部。另外我們也將日志輸出到掛在到Docker的主機(jī)目錄,這樣方便查看日志。
提示 強(qiáng)烈推薦使用version3版本的compose文件。version3中新增deploy選項(xiàng),可以實(shí)現(xiàn)docker run --restart選項(xiàng)的作用控制容器在失敗等情況下自動(dòng)重啟,從而保證服務(wù)的無人值守運(yùn)行。compose選項(xiàng)詳見此文檔
構(gòu)建Image
項(xiàng)目發(fā)布完成后,進(jìn)入發(fā)布文件夾publish,執(zhí)行下面的命令生成相關(guān)鏡像
docker-compose build提示,可以在使用docker compose生成之前,分別使用docker build單獨(dú)生成dotnet core和nginx的鏡像進(jìn)行測(cè)試,就像介紹Dockerfile那部分所述。
啟動(dòng)docker compose
確定compose生成好image后,就可以啟動(dòng)服務(wù)(容器)了:
docker-compose start可以使用下面的命令將Build、Start一起完成。
docker-compose up服務(wù)啟動(dòng)后,可以通過Nginx服務(wù)訪問.NET Core App。
上面的命令會(huì)在前臺(tái)運(yùn)行并打印日志到控制臺(tái)。
如果需要在后臺(tái)運(yùn)行“服務(wù)”,使用-d參數(shù):
docker compose啟動(dòng)的也是普通的容器,通過docker ps也可以看到compose啟動(dòng)的容器。
如果需要停止docker compose啟動(dòng)的服務(wù),使用:
docker-compose down注意:服務(wù)的容器將被刪除,所有容器中的數(shù)據(jù)(非主機(jī)掛載到容器目錄下)將丟失。
這一小節(jié)介紹的方式是在Docker for Windows中使用docker compose運(yùn)行服務(wù),而實(shí)際情況下我們需要在服務(wù)器去運(yùn)行docker compose,具體方式后文有介紹。
其它相關(guān)命令:
查看compose相關(guān)服務(wù)運(yùn)行狀態(tài):docker-compose ps
重啟compose中的服務(wù):docker-compose restart
環(huán)境
在程序開發(fā)中,在不同環(huán)境下使用不同的配置是很常見的情況。
如.NET Core就定義了三種默認(rèn)的環(huán)境 - Development、Staging和Production。
體現(xiàn)在配置文件上,有appsettings.json、appsettings.Staging.json及appsettings.Production.json等文件
樓主一般將其分別用作開發(fā)、測(cè)試和生產(chǎn)環(huán)境的配置,相信大部分人也都是這么干的。
.NET Core Web應(yīng)用會(huì)根據(jù)一個(gè)名為ASPNETCORE_ENVIRONMENT的環(huán)境變量來判斷應(yīng)用所處的環(huán)境。所以我們需要做的就是在生成鏡像時(shí)將這個(gè)變量傳入。
docker compose的environment就是做這個(gè)用的,比如我們將docker-compose.yml文件中orgname.projname.webapi這個(gè)服務(wù)的定義改為:
則我們的.NETCore應(yīng)用將以Staging環(huán)境運(yùn)行,并使用appsettings.Staging.json這個(gè)配置文件。
然后我們利用VS Tool for Docker創(chuàng)建的其它兩個(gè)文件(docker-compose.dev.debug.yml和docker-compose.dev.release.yml)來實(shí)現(xiàn)不同環(huán)境的配置分離(VS2017中這兩個(gè)文件中的dev改為vs)。
其實(shí)那兩個(gè)文件是用于VS集成的Docker調(diào)試和發(fā)布用的,不過我這里不打算依賴工具,而是通過命令行的形式完成工作。所以刪除兩個(gè)文件中原有的內(nèi)容,并改為我們自己所需。
要使兩個(gè)配置文件共同工作,最主要的還是靠docker compose對(duì)多配置文件的支持。其-f選項(xiàng)可以設(shè)置多次,docker compose會(huì)把其中的選項(xiàng)疊加。
如:
下面來分別看下用于不同環(huán)境的配置文件
首先是docker-compose.dev.debug.yml:
其中的env_file指定的staging.env用于演示,由于我們的例子需要配置的環(huán)境變量很少,所以無需使用這個(gè)文件。文件的格式很簡(jiǎn)單,就是鍵值對(duì)的格式:
ENV=VAL
注意,這個(gè)文件要使用ANSI編碼,不然會(huì)因?yàn)榫幋a問題導(dǎo)致實(shí)際定義的變量和期望定義的變量不一致。
提示:可以使用下面的命令,確認(rèn)compose執(zhí)行時(shí)的配置
docker-compose.exe -f docker-compose.yml -f docker-compose.dev.debug.yml config這對(duì)于檢查環(huán)境變量等設(shè)置是否正確很有幫助。在確認(rèn)無誤后再進(jìn)行build或up操作。上面說得env文件的編碼問題,就是通過config命令查出來的。(下文的composebuild.bat集成了這個(gè)檢查的功能)
然后是docker-compose.dev.release.yml,內(nèi)容也差不多:
version: '3'services:orgname.projname.webapi:environment:- ASPNETCORE_ENVIRONMENT=Production另外我們還要給測(cè)試和生產(chǎn)環(huán)境的image打上不同的tag。這個(gè)需要修改一下之前編輯的docker-compose.yml中服務(wù)定義中image那個(gè)配置:
image: orgname/projname.core:${TAG}image: orgname/projname.core.pub:${TAG}將它們的版本號(hào)都改為插值計(jì)算的方式。
docker compose可以由當(dāng)前執(zhí)行的環(huán)境中獲取這些值的定義。比如shell中EXPORT的變量,或者cmd中SET的變量。
在Windows下,我們借助如下的批處理(composebuild.bat)來幫助定義這個(gè)變量,并執(zhí)行docker compose命令:
這個(gè)腳本有一個(gè)小問題,在后續(xù)章節(jié),會(huì)介紹將Image推送到注冊(cè)中心,而推送到注冊(cè)中心需要一個(gè)tag操作。而這個(gè)腳本刪除這些被tag的Image,只會(huì)解除tag,而不刪除Image,最終導(dǎo)致本地殘留很多無tag的Image。可以全部工作結(jié)束后使用下面的PowerShell命令,統(tǒng)一刪除:
Get-ContainerImage | ? {$_.RepoTags -eq $null} | foreach { Remove-ContainerImage $_.ID }運(yùn)行這個(gè)命令需要安裝Docker-PowerShell,可參見此文
運(yùn)行這個(gè)批處理,選一下需要運(yùn)行的選項(xiàng)便可以通過docker compose在不同的環(huán)境下生成鏡像或啟動(dòng)服務(wù)。
注意:所有這些文件都記得加入project.json中(VS2015),包含到項(xiàng)目并復(fù)制到輸出目錄(VS2017)
添加到鏡像倉(cāng)庫(kù)
這是可選步驟,也可以在把Dockerfile和發(fā)布文件上傳到服務(wù)器并在服務(wù)器上生成鏡像。見總結(jié)。
可以使用Harbor構(gòu)建一個(gè)私有Docker倉(cāng)庫(kù)。Harbor相對(duì)于Docker官方庫(kù)就像GitLab相對(duì)于GitHub。Harbor的安裝和基本使用參見此文。
Docker的Image進(jìn)行分層存儲(chǔ),所以第一次push到私有倉(cāng)庫(kù)的上傳量比較大,之后將只是推送改變的層。數(shù)據(jù)傳輸量比較小。
push操作的操作的基本部分在那篇介紹Docker的文章中有介紹。這里我們只是給出腳本,可以按照提示執(zhí)行即可,嗯,這是一個(gè)PowerShell腳本(ImagesPush.ps1),不再是批處理了。
從鏡像倉(cāng)庫(kù)獲取并啟動(dòng)服務(wù)
通過Docker啟動(dòng)服務(wù),docker-compose.yml是必備的。(我們執(zhí)行docker-compose命令的目錄下必須有這個(gè)文件,不然分分鐘報(bào)錯(cuò)。)
我們之前那個(gè)docker-compose.yml文件所創(chuàng)建容器的鏡像是通過Build Dockerfile來得到的,這里我們要新建這樣的一個(gè)docker-compose.yml,其使用一個(gè)現(xiàn)成的Image來啟動(dòng)容器。
我們新建一個(gè)名為docker-compose.server.yml的文件(不要懷疑名字錯(cuò)了)。
與之前文件的最大不同,這個(gè)配置沒有了build這個(gè)小節(jié)。
而鏡像就需要從注冊(cè)中心拉取,直接上腳本(ImagesPull.ps1),然后稍作解釋:
是的,這是一個(gè)PowerShell腳本,PowerShell現(xiàn)在也可以用Linux,雖然還處在測(cè)試狀態(tài)。在CentOS7.3中有一堆顯示方面的bug,中文支持也沒有(所以上面的腳本沒有中文),主要功能方面還是很正常的。
Linux上安裝PowerShell可見此文檔。
腳本中,首先登錄鏡像倉(cāng)庫(kù)并下載鏡像,然后按照用戶輸入將docker-compose.server.yml進(jìn)行插值得到需要的docker-compose.yml文件,最后啟動(dòng)docker compose。
網(wǎng)絡(luò)
網(wǎng)絡(luò)方面,Docker-Conpose為應(yīng)用創(chuàng)建一個(gè)子網(wǎng)絡(luò),Docker-Compose將每個(gè)Service作為一個(gè)容器實(shí)例,并加入到這個(gè)網(wǎng)絡(luò)中,網(wǎng)絡(luò)中的容器可以彼此訪問。
容器間以容器名稱作為主機(jī)名來互相訪問。
Docker網(wǎng)絡(luò)這塊水很深,樓主對(duì)這個(gè)了解幾乎沒有。
總結(jié)
借用此部分墻裂推薦Cmder這個(gè)神奇,雖然時(shí)不時(shí)的會(huì)有光標(biāo)錯(cuò)位,中文重疊等問題,但絕對(duì)是取代自帶控制臺(tái)的必備工具。
最后總結(jié)一下,在上面的所有配置文件準(zhǔn)備妥當(dāng)后,每次修改得到新版本后只需要執(zhí)行下列步驟:
方式1:
方式2:
如果您有更好的實(shí)現(xiàn)方法,歡迎評(píng)論區(qū)指點(diǎn)一二。
轉(zhuǎn)載于:https://www.cnblogs.com/lsxqw2004/p/6709766.html
總結(jié)
以上是生活随笔為你收集整理的.NET遇上Docker - 使用Docker Compose组织Ngnix和.NETCore运行的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 读取Excel文件,并写入word
- 下一篇: 构建之法阅读心得(二)