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