前言
接下來我們就要慢慢步入在.NET Core中使用Docker的殿堂了,在開始之前如題,我們需要搞清楚一些概念,要不然看到官方提供如下一系列鏡像,我們會一臉懵逼,不知道到底要使用哪一個。

AspNetCore Runtime VS .NetCore Runtime VS .NET Core SDK
本節我們所講解的官方所提供的一系列鏡像都是最新鏡像,而且閱讀本文的您還需明白一點,要是您看到其他博文中提供的鏡像以microsoft開頭,那么說明已過時不再可取。這里額外再多說一句,很多時候我們看到一些資料,然后親自實踐卻沒達到文章中所描述的效果,大部分情況下可能都是官方已更新導致,一切以官方文檔為主才是最佳。我們將官方所提供的鏡像作如下說明:
鏡像地址 |
鏡像名稱 | 鏡像說明 |
mcr.microsoft.com/dotnet/core/runtime |
.NET Core Runtime | 部署.NET Core控制台程序 |
mcr.microsoft.com/dotnet/core/runtime-deps | .NET Core Runtime Dependencies |
部署自包含的部署應用程序 |
mcr.microsoft.com/dotnet/core/sdk |
.NET Core SDK | 構建.NET Core(或ASP.NET Core應用程序) |
mcr.microsoft.com/dotnet/core/aspnet |
ASP.NET Core Runtime | 部署ASP.NET Core應用程序 |
上述對於.NET Core Runtime Dependencies鏡像包我沒做過多了解,在官方文檔上有對這個的詳細介紹名叫《SCD》,送上地址《https://docs.microsoft.com/en-gb/dotnet/core/deploying/index#self-contained-deployments-scd》,搞那么多包,好像很復雜似的,其實我們只需謹記如下兩點:
若需構建.NET Core應用程序,請使用.NET Core SDK
若需運行.NET Core應用程序,請使用.NET Core Runtime
比如上一節我們構建、發布應用程序直接在本地進行,所以我們只構建了.NET Core Runtime鏡像,若在鏡像中發布則還需提前下載.NET Core SDK鏡像,接下來我們運行webapi來說明通過SDK鏡像來構建程序,Runtime來運行程序。這里需要注意下,若下載了3.0預覽版本直接運行如下命令所創建的程序版本為3.0,此時可能會因缺少對應包而還原失敗,所以這里我們將通過命令( dotnet new globaljson --sdk-version 2.2.203 --force )回退到2.2穩定版,繼續往下走。
到這里為止我們並未如上一節那樣直接發布,我們將其直接拖到ubuntu中,如下:
這里針對上一節內容補充說一句(個人有強迫症,上一節創建的鏡像名稱為(hellowrold),這個鏡像所打的標簽單詞名稱打錯了,應該是helloworld,所以這里我們重命名下鏡像標簽名稱。又掌握了一個命令,哈哈。首先,我們查看鏡像,如下
在Docker中重命名鏡像標簽名稱有兩種方式,一是直接通過標簽名稱來重命名,而是通過鏡像id來重命名,如下:
docker tag hellowrold:latest helloworld:latest
或
docker tag 75a287b4f21c helloworld:latest
我們通過如上任何一種方式重命名后再查看鏡像,如下:
因為容器存在對舊鏡像的引用,所以舊的會仍然存在而不是以新的進行完全覆蓋,所以我們接下來執行如下命令將舊的鏡像給移除:
docker rmi hellowrold
通過執行如上命令會刪除別名/標簽,由於75a287b4f21c具有其他名稱,因此不會刪除實際圖像。
回到正題,接下來我們開始通過Dockerfile來構建webapi鏡像,如下:
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build WORKDIR /app COPY *.csproj ./ RUN dotnet restore COPY . ./ RUN dotnet publish -c Release -o out FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime WORKDIR /app COPY --from=build /app/out . ENTRYPOINT ["dotnet", "WebApi.dll"]
首先我們構建基礎鏡像SDK來構建應用程序,我們指定/app作為我們構建的工作目錄。然后將文件從本地文件系統復制到鏡像中,我們將只復制csproj文件並運行restore,然后復制其他剩余文件並運行dotnet publish來構建我們的應用程序並發布。該文件的運行時部分使用不同的docker基礎映像也就是使用aspnetcore-runtime映像,它復制構建中的所有文件,然后定義應用程序入口點。我們發現在整個構建鏡像過程的不同階段都是可交互的,因為如上我們第一階段獲取構建程序鏡像也就是別名為build,在第二階段獲取運行程序鏡像也就是runtime,我們引用了build。
從如上我們構建鏡像命令和上一節對比知道,構建命令可以通過 docker build . -t tagname 或 docker build -t tagname . 這兩種方式來進行皆可。構建鏡像就是基於上一鏡像層並創建一個新的鏡像層的過程,每個新的鏡像層都對應一個唯一的標識id,我們可以通過如下命令來查看鏡像構建的歷史記錄:
docker image history webapi:latest
鏡像“《none》”說明
當我們構建完鏡像后,我們查看鏡像列表會看到此時會多出了鏡像標簽名稱為none的,如下:
如上生成的鏡像none的作用是什么呢?我們是不是可以將其刪除呢?
優點:它用來維護中間鏡像層,因為對於每個Dockerfile說明的每一步驟,都會為中間層創建一個新的哈希值,通過允許緩存每個步驟來提高可重用性,減少磁盤使用量並加速docker構建。
缺點:它作為懸空鏡像,可能會導致磁盤空間問題,但是它被列為docker鏡像的一部分。(Docker中空的文件系統層是未使用的,並且沒有被任何鏡像所引用,因此我們需要一種機制讓Docker清除這些空的鏡像)
none的鏡像只是為臨時容器保存而已,由於Docker的架構,即使容器停止了,這些懸空的鏡像也依然會保留,所以我們可以對其進行清理,我們可以使用 docker rmi $(docker images -f "dangling=true" -q) 來清理它們,-f "dangling = true" -q顯示所有懸空鏡像,rmi將刪除所有這些圖像,若沒有任何懸空鏡像但執行了此命令,則會返回錯誤,但是我們可以使用 docker images prune -a (僅適用於1.25以上的docker版本)。
接下來則是創建並啟動容器運行程序,上一節我們在代碼中配置了端口號為5000,並且也通過 docker run -p 5050:5050 hellowrold 指定相同端口號運行程序,這里我們在代碼中並未配置端口,所以默認端口號為80,如下:
docker run webapi:latest
接下來如果我們訪問http:// localhost/api/values,我們會看到無法連接,也就是說沒有得到我們所期望的JSON響應。
這是為何呢?我們來看看docker給我們生成容器的名稱,docker給容器隨機生成例如如下一個名稱:
接下來我們通過終端運行容器管理命令來修復,我們首先將容器停止,然后進行移除,命令如下:
docker container stop gracious_chaplygin
docker container rm gracious_chaplygin
我們需要將gracious_chaplygi替換為從docker container ls返回的容器名稱,我們使用以下命令再次啟動容器:
docker run --name webapi --env ASPNETCORE_ENVIRONMENT=Production -p 80:80 webapi:latest
如上我們配置了3個參數,--name是容器啟動和運行時的名稱,--env允許我們將環境變量傳遞給正在運行的容器,-p允許我們將容器上的端口映射到在我們的機器上的端口。
如上容器已啟動,我們再次使用ls命令查看我們提供的名稱和端口映射:
上述我猜測可能是因為容器名稱隨機生成的問題,然后指定了容器名稱,結果好使了,但是上述我們再次獲取容器名稱時發現依然是隨機生成的容器名稱,所以我認為不是這個問題導致,和上一節我們運行容器做本節對比,只是指定了映射端口號,而本節未指定端口號,默認啟動端口號為80,容器也運行起來了呀,最終發現還是未指定端口號的緣故,因為當我啟動容器時,也如下明確指定端口號為80就好使了,所以這里需要注意下。
總結
本節我們講解了在Docker中安裝對應.NET Core鏡像包的問題,並且以一個例子來說明,同時呢,我們在上一節使用指令的基礎上又額外添加了對WORKDIR和RUN指令的使用,以及對容器停止、移除、鏡像列表查看、鏡像重命名、鏡像刪除、鏡像構建歷史記錄查看指令的使用。接下來我們會繼續通過例子來靈活使用各種指令,然后在這個過程中還涉及到一些可優化、以及Docker中比如卷、網絡更深入的講解。