標籤:程式 dcl release str div 操作 parent publish x64
原文連結:https://dzone.com/articles/the-evolution-of-a-linux-container
現在,.NET開發人員可以無障礙地使用如Docker這樣的Linux容器,那麼讓我們來嘗試如何以正確的方式配置一個容器。
可能,文章的標題改成“Linux容器開發人員的演變”會更好。由於.NET可在Linux(以及Windows和macOS)上運行,所以整個世界的Linux容器和微服務已經開放給了.NET開發人員。
有著大量的開發人員,長期的運行記錄和優異效能指標的.NET,現在給以Windows為中心的開發人員提供了一個使用Linux容器的機會。
雖然在Linux容器中嘗試運行.NET代碼是誘人的,同時也會產生一些細微差別,但是這樣做是不會錯的。你可以很容易地將一些.NET程式碼推送到鏡像中。
畢竟,一切都發生的這麼快,一定都很好。 對不對?
事實並非如此。讓.NET代碼運行在Linux容器中並不是一件簡單的事情,但請記住:“先讓它工作,然後讓它工作得很快。”
在下面的例子中,上文說的“很快”指的是構建鏡像所需的時間,啟動鏡像所需的時間和鏡像內部代碼的效能。本文將首先討論鏡像的構建時間和啟動時間,接著會將一個簡單的.NET程式運行在基於容器的應用上,然後觀察鏡像大小的變化,最終縮短鏡像的構建和載入時間。此外,代碼最佳化是本文的另一個主題。
短暫的停留
考慮一個非常簡單的微服務樣本,它只給出一個“Hello world”類型的HTTP響應。也就是說,當在瀏覽器中填寫URL,你就會得到一個包括主機名稱的Web頁面。
我們可從這個程式碼程式庫中(https://github.com/donschenck/dotnet_docker_msa)下載源碼,並製作第一個Dockerfile(Dockerfile.attempt1),接著使用以下命令構建鏡像:
# docker build -t attempt1 -f Dockerfile.attempt1 .
然後在容器中運行鏡像:
# docker run -d -p 5000:5000 --name attempt1 attempt1
將瀏覽器的URL指向主機的IP地址,情況如下:
數字
第一次構建鏡像,一共耗時95秒。其中,下載紅帽企業Linux(簡稱RHEL)鏡像與安裝.NET SDK,這些檔案一共490MB。最終,鏡像大小為659MB。
一般而言,鏡像的後續構建將更快,因為Docker化的鏡像已經在主機上可用。改變源碼後,我們再次運行構建。這一次構建鏡像,大約耗時50秒,得到了相同大小的鏡像,也是659MB。
鏡像的大小很重要。因為鏡像使用作業系統的儲存空間,雖然空間便宜,但它仍然是有限的商品。當定期使用容器時,我們很容易忽略過時的鏡像,然而它仍然在佔用磁碟。如果你不注意的話,磁碟空間將很快用盡。
如何使鏡像儘可能的小?
移除鏡像不需要的部分
使用命令dotnet restore --no-cache可以消除任何緩衝,這樣鏡像的大小下降到608.6MB,減少了50.6 MB,同比縮小超過7%。
在構建鏡像之前構建應用
應用是在容器中運行鏡像時構建.NET程式的。這耗時大約1.6秒——雖然時間不長,但卻是在浪費時間。
在恢複之前插入的dotnet build命令,並在構建鏡像之前構建應用,這樣的話容器將會更快地啟動。這個結果可在Dockerfile.attempt3中實現。
與此同時,鏡像大小卻增加到610.2MB,而我們還得運行dotnet build,雖然現在花這個時間,但卻可在每次啟動容器時受益。
運行Dotnet Publish命令
因為容器是一個運行時環境,那我們為什麼不使用dotnet publish命令發布代碼,然後把代碼放入鏡像呢?如果這樣做的話,我們就沒必要在鏡像中安裝.NET程式了。畢竟,我們需要的是一個可在任何地方獨立啟動並執行應用。
使用dotnet發布代碼,會減少鏡像大小和縮短容器啟動時間。更改project.json檔案,注釋掉中紅框的內容,這告訴編譯器此檔案為一個平台構建。您可以在中看到它:
接下來,我們使用dotnet publish -c Release -r rheh.7.2-x64發布代碼,這會把所有的編譯檔案和運行時檔案,放入一個檔案夾,我們把此檔案夾複製到鏡像中。
因為我們不再需要安裝.NET程式,只要一個包含RHEL檔案的基礎鏡像即可,這樣就減少了鏡像的大小。這是Dockerfile的第四次迭代——Dockerfile.attempt4:
FROM registry.access.redhat.com/rhel7RUN yum install -y libunwindRUN yum install -y libicuADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/WORKDIR /opt/app-root/src/EXPOSE 5000CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]
請注意,yum install命令將安裝一些.NET需要的依賴檔案,然後運行docker build命令,最終產生一個694.6MB的鏡像。
誰需要緩衝?
多次運行yum install命令,前一次操作將為後一次構建緩衝。如果在每個yum install命令之後,我們立即清除緩衝,效果將會很好。下面是Dockerfile的第五次迭代———Dockerfile.attempt5:
FROM registry.access.redhat.com/rhel7RUN yum install -y libunwind && yum clean allRUN yum install -y libicu && yum clean allADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/WORKDIR /opt/app-root/src/EXPOSE 5000CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]
基於Dockerfile.attempt5構建的鏡像,其大小減少到293.7MB,這比第一次構建縮小了55%。
堆疊命令
對Dockerfile做最後更改,我們需要堆疊yum install命令,具體內容如下所示:
FROM registry.access.redhat.com/rhel7RUN yum install -y libunwind libicu && yum clean allADD bin/Release/netcoreapp1.0/rhel.7.2-x64/publish/. /opt/app-root/src/WORKDIR /opt/app-root/src/EXPOSE 5000CMD ["/bin/bash", "-c", "/opt/app-root/src/dotnet_docker_msa"]
最終得到的鏡像大小為257.5MB,這比第一次構建縮小了60%。
下面是各個Dockerfile構建的鏡像大小對比圖:
總結
在探索新技術與新模式時,我們不能將早期的結果與最優做法相混淆。雖然早期的成功會給我們帶來興奮和鼓勵,但它也可能使我們喪失進步的動力。勤奮,然後不斷嘗試,並且始終接受改進的建議,會協助我們走的更遠。
.NET程式在Linux容器中的演變