.NET開發者啟程Docker之路

jopen 8年前發布 | 16K 次閱讀 Docker .NET

經常聽到很多企業說,我們還沒用Docker,還在觀望中,以后會用的。其實Docker通過將近三年的發展,它已經成熟了,能夠為企業帶來巨大的商業價值。

未來普及是必然趨勢,使用還是要趁早才好。所以還在觀望中的朋友們,不要再猶豫了,Dokcer不只是別人的玩具,更是屬于我們每個技術人員。

為此,希云特意為大家分享微軟Azure MVP專家Elton Stoneman的經驗之談:“如何在Docker里運行.NET應用”。

Elton Stoneman

.NET開發者啟程Docker之路

Elton是軟件架構師、微軟MVP,自2000年以來在Pluralsight Author上帶來很多成功的解決方案。他主要開發環境是在Azure和微軟軟件棧上,但也意識到跨平臺的發展帶來了很多機遇,他在Pluralsight上最新的課程也是如此,涵蓋了Azure上的大數據應用和Ubuntu基礎。

Docer容器

Docker讓我們能用更少的資源,更快的速度來構建運行應用程序,所以應用容器技術(Docker就是其中一種)在當今那么受歡迎。我們可以在只能跑幾個虛擬機的物理機器上跑上百個容器,容器的部署效率非常高,而且能用版本管理。

如果你在微軟的環境下工作,那你可能以為容器只是其他平臺的開發者能用的技術(例如LAMP,NodeJs或者Java),但是實際上你已經能在Docker里運行.NET應用了。下面,將詳細介紹如何操作。

應用容器

應用容器是一種快捷且輕量的計算單元,能讓你在一個物理(或虛擬)服務器上承載大量計算任務。一個已被容器化的應用,會被部署在一個包含了所有依賴的鏡像上,這里據說的依賴,包括了最小化安裝的操作系統。這些鏡像非常輕量,通常只有幾百兆,而且啟動只需要數秒。

Docker已經引領了容器技術的發展,讓構建、分發和使用都更加簡單,容器技術在過去幾年是一個熱門話題。原因很簡單:這種技術不僅能讓你在單個節點上運行成千上百個容器,而且,它的分發和運行速度讓人欲罷不能。所以到現在,它已經成為很多團隊開發、測試和構建流程的核心。另外,它的出現也讓人們加速轉向更易于擴展的無狀態架構。

如果按目前的發展趨勢,很可能再過幾年應用容器就會成為我們默認的部署方式,容器技術即將正式應用在Windows平臺上。但其實現在你就可以用Docker來運行.NET核心的應用,下面我們來提前體驗一下這種激動人心的技術吧。

不只是別人的玩具

容器技術使用了Linux內核的特性,使容器內的應用能像運行在原生系統上那樣調用系統指令。所以你既需要在容器中運行Linux系統,也需要Linux系統來運行容器。

但實際上Linux也可以作為虛擬機運行在Windows或者OS/X上, Docker Toolbox 把所有相關的都打成了一個包,讓我們能輕松上手在Windows上使用容器,只需要花幾分鐘下載安裝好,它帶有一個Linux虛擬機,底層使用的是 VirtualBox

微軟正在大力推進Docker在非Linux下運行的開發工作,在Windows Server 2016上,我們將能在Windows原生系統上運行Docker容器;而在容器中,我們將能運行Windows Nano Server系統,所以屆時我們將把.NET應用運行在原生系統上。

.NET Core

而現在,我們可以使用跨平臺的.NET Core去在Linux容器中打包應用,Docker有公共鏡像倉庫,我已經把一個示例鏡像推到上邊了,你安裝好Docker之后,可以通過以下命令來體驗一個基礎版的.NET內核應用:

sh
docker run sixeyed/coracle-hello-world

第一次運行這個命令,會從Docker Hub下載容器的鏡像,這會花費一段時間,但你下次運行時,由于這個鏡像已經存在于你本地,所以將會立即運行,這個簡單的應用會輸出當前時間和日期:

雖然功能很簡單,但它是使用了.NET中的Console.WriteLine(),而這個容器中的系統是Ubuntu Server。也就是說,我們現在有了一個運行在Linux上的.NET應用容器鏡像,這樣相當于我們可以在任何地方運行.NET應用了。

.NET Core 是一個開源版的.NET,它與原來的.NET關注點并不一樣,它是一個模塊化的框架,也就是說你可以只引入你需要的依賴,這個框架本身是由NuGet包組成。

在你要運行.NET Core應用在Linux(或OS/X或Windows)上,你需要安裝DNX運行時組件,這不是官方的.NET運行,而是一個瘦身版的.NET運行環境(DNX)。

當你定義了一個Docker鏡像,你可以從一個基鏡像開始構建, sixeyed/coreclr-base 這個鏡像發布在Hub上,在它里邊DNX已經安裝配置好了,要把你的應用容器化的話,只需要在這個基鏡像中加入你的代碼,下一部分,我們看看應該怎么做。

The Uptimer App

在GitHub上有一個.NET Core應用,它會去ping一個URL,然后記錄一些關鍵字段,例如響應碼和響應時間,把結果寫到Azure blob上。代碼在 coreclr-uptimer 倉庫。

它是一個.NET Core 應用,所以它和典型的Visual Studio solution應用結構不同,它沒有solution文件,它的Sixeyed.Uptimer相當于solution,還有一個project.json定義了應用運行的配置和相關依賴:

    ```json
</p>
<p>
    “frameworks”: {
</p>
<p>
    “dnxcore50″: {
</p>
<p>
    “dependencies”: {
</p>
<p>
    “Microsoft.CSharp”: “4.0.1-beta-23516″,
</p>
<p>
    “WindowsAzure.Storage”: “6.1.1-preview”,
</p>
<p>
    “System.Net.Http”: “4.0.1-beta-23516″
</p>
<p>
    …
</p>
<p>
    ```
</p>
<p>
    這里我定義了應用運行在dnxcore50上,這是DNX最新的版本。還有那些依賴全部都是NuGet的包,.NET Core應用像普通應用那樣使用NuGet,但你可以只引用用于構建.NET Core的包,這里使用了WindowsAzure.Storage和System.Net.Http 。
</p>
<p>
    以下這段代碼使用了標準C#,包括timer,disposables 和 AAT (Async, Await and Tasks):
</p>
<p>
    ```java
</p>
<p>
    var request = new HttpRequestMessage(HttpMethod.Get, url);
</p>
<p>
    using (var client = new HttpClient())
</p>
<p>
    {
</p>
<p>
    return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
</p>
<p>
    }
</p>
<p>
    ```
</p>
<p>
    然后這樣把輸出寫到Azure中:
</p>
<p>
    ```java
</p>
<p>
    var blockId = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
</p>
<p>
    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
</p>
<p>
    {
</p>
<p>
    stream.Position = 0;
</p>
<p>
    await blockBlob.PutBlockAsync(blockId, stream, md5, access, options, context);
</p>
<p>
    }
</p>
<p>
    ```
</p>
<p>
    project.json文件能從任何機器上用源碼構建,而不需要指定平臺,所以這應用的代碼能運行于Windows,OS/X和Linux,也就是說能把它打包到Docker容器中。
</p>
<p>
    容器通過Dockerfile來定義,這個文件中包含了構建和運行鏡像的所有程序。通常來說,需要創建一個目錄用于容器的定義,這個目錄包含了Dockerfile和所有用到的文件,例如Sixeyed.Uptimer的代碼目錄。
</p>
<p>
    <img alt=".NET開發者啟程Docker之路" src="https://simg.open-open.com/show/b875efe12470905b7941fd179a7909bf.gif" width="670" height="359" /> 
</p>
<p>
    構建這個容器后,會得到一個包含編譯后應用的鏡像。所以在容器的定義中,需要告訴Docker去使用.NET Core基鏡像,并且把應用的代碼復制進去。Dockerfile的語法是自解釋的, <a href="/misc/goto?guid=4958977246128699270" target="_blank">整個流程</a> 只需要7行代碼 :
</p>
<p>
    ```sh
</p>
<p>
    FROM sixeyed/coreclr-base:1.0.0-rc1-final
</p>
<p>
    MAINTAINER Elton Stoneman < <a href="/misc/goto?guid=4958977246223483451" target="_blank">elton@sixeyed.com</a> >
</p>
<h2>
    deploy the app code
</h2>
<p>
    COPY /Sixeyed.Uptimer /opt/sixeyed-uptimer
</p>
<p>
    ```
</p>
<p>
    Docker剛剛構建鏡像時,只有一個裝有.NET Core的Ubuntu Server鏡像,應用的代碼文件都復制進容器中了,但是還沒有構建。要構建一個.NET Core 應用,首先要運行dnu,這會從NuGet獲取全部依賴包,可以用<code>RUN</code>指令:
</p>
<p>
    ```sh
</p>
<p>
    WORKDIR opt/sixeyed-uptimer
</p>
<p>
    RUN dnu restore
</p>
<p>
    ```
</p>
<p>
    <code>WORKDIR</code>指令設置了當前目錄,所以dnu命令會讀取應用目錄下的project.json文件去獲取依賴。
</p>
<p>
    這時,鏡像中已經具備了所有需要的條件,所以在Dockerfile最后的部分,它告訴容器要運行什么。使用ENV指令添加了DNX的路徑到環境變量中,ENTRYPOINT指定當容器開始運行時,會執行dnx命令。
</p>
<p>
    ```sh
</p>
<p>
    ENV PATH /root/.dnx/runtimes/dnx-coreclr-linux-x64.1.0.0-rc1-final/bin:$PATH
</p>
<p>
    ENTRYPOINT [“dnx”, “run”]
</p>
<p>
    ```
</p>
<p>
    上邊就是定義這個容器的方法,你可以在本地構建,也可以我在Docker Hub上發布的版本<code>sixeyed/coreclr-uptimer</code>:
</p>

sh
docker pull sixeyed/coreclr-uptimer

這個.NET應用需要兩個參數,一個是需要ping的URL,一個是ping的頻率。它還需要配置Azure Storage的賬號用于存放ping的結果,這個配置會讀取環境變量STORAGE_CONNECTION_STRING。

連接字符串是可變的,不能把它放到鏡像構建過程中。為了在運行容器時能傳這個進去,可以使用環境變量或者一個獨立的文件。

運行了這個容器的一個實例,它會每10秒ping 我的博客,并且把結果保存起來:

sh
docker run -e STORAGE_CONNECTION_STRING=’connection-string’ sixeyed/coreclr-uptimer https://blog.sixeyed.com 00:00:10

可以在任何Docker主機運行這個命令,無論是一個開發筆記本,還是虛擬機,或者是云上的容器,無論宿主機的系統是什么,它都會運行同樣的代碼。

Docker的架構方案

上邊介紹的應用只是小兒科,那么到底它有什么用呢?把網站的響應時間記錄下來或許并不是很有用,但是這個項目涉及到一個實際問題,這個問題是我們一直不滿意傳統方式的地方,而在Docker下可以有更好的實現。

想象一下這個場景,把一組REST接口開放給客戶端,其中很多都面臨很大的業務壓力,所以我們希望能每幾秒就ping一下這些接口,來實時檢查接口是否出現了問題。市場上的產品沒有周期性的ping,所以我們寫了自己的工具:

.NET開發者啟程Docker之路

這些任務中的代碼與本文的一樣,但是如果你寫了一個龐大的應用來處理多個URL,那就會添加了很多不必要的復雜性。

需要存儲每個URL,需要一個調度器,需要管理多個并發的任務,需要一個機制來檢測這個應用是否失效....一下子,這個監控的組件就變得大而復雜了,越是穩定,那它就會越龐大復雜。

在Docker的方案中,實現這些就簡單得多了。我把核心的代碼放到一個.NET 應用中,只實現了ping單個URL和記錄返回值 ,這就是全部了,最多就只有100行代碼,而其他需求就可以用其他適當的技術來滿足。

為了ping多個URL,可以啟動多個實例,而Docker會幫你管理資源。而且如果我們用的是云服務,便可以根據需要隨時擴容或縮容,Mesos和Kubernetes提供了集成Docker的管理層。

這段示例代碼啟動了多個后臺實例,每個實例監控不同的域名,會每10秒ping a.com一次,每20秒ping b.com一次,每30秒ping c.com一次。

    ```sh
</p>
<p>
    docker run -i -d –env-file /etc/azure-env.list sixeyed/coreclr-uptimer <a href="/misc/goto?guid=4958977246299322999" target="_blank">http://a.com</a> 00:00:10
</p>
<p>
    docker run -i -d –env-file /etc/azure-env.list sixeyed/coreclr-uptimer <a href="/misc/goto?guid=4958977246389133273" target="_blank">http://b.com</a> 00:00:20
</p>
<p>
    docker run -i -d –env-file /etc/azure-env.list sixeyed/coreclr-uptimer <a href="/misc/goto?guid=4958977246476636767" target="_blank">http://c.com</a> 00:00:30
</p>
<p>
    ```
</p>
<p>
    –env-file參數告訴Docker去指定路徑下找到連接字符串,這樣就可以確保那些文件的安全。-i和-d參數告訴Docker在后臺運行,并且保持輸入通道的打開。
</p>
<p>
    這樣監控單個站點的功能很簡單,也應該保持簡單。而需要監控的站點越多,就需要往這個腳本文件添加越多行。但是每個容器占用的資源是非常少的。
</p>
<p>
    為了看到它能怎樣擴容,我們在Azure上啟動了一個虛擬機,使用了庫里的Ubuntu Server鏡像,上邊已經安裝好了最新的Docker,用了一個D1-spec設備,它主要的配置是單核和3.5GB內存。
</p>
<p>
    然后我們拉取了coreclr-uptimer鏡像,并運行一個腳本監控50個互聯網上最受歡迎的網站。這些容器幾秒就啟動了,但是它用了幾分鐘來運行dnx來構建應用。
</p>
<p>
    當這些容器都準備好了,我們同時監控了50個域名 ,每隔10到30秒ping一次,這時機器資源只占了10-20%。
</p>
<p>
    <img alt=".NET開發者啟程Docker之路" src="https://simg.open-open.com/show/eb553004a266659107bd887a88b77de3.png" width="670" height="380" /> 
</p>
<p>
    這是容器的一個完美用例,當我們有很多獨立的任務要運行時,可以使用這種架構,在同一個節點上運行數百個容器也不會占用太多資源。
</p>
<h2>
    部署 .NET Core 應用
</h2>
<p>
    你可以在Mac和Linux上構建和運行.NET應用,但是你也要在這些平臺上開發,Visual Studio Code是一個Visual Studio的精簡版,可以使用.NET Core的項目結構,并且提供了多種語言的語法高亮,如Node和Dockerfile:
</p>
<p>
    <img alt=".NET開發者啟程Docker之路" src="https://simg.open-open.com/show/67387744b00795f2ef47b483a68fbeb1.png" width="669" height="420" /> 
</p>
<p>
    你甚至可以使用標準的本文編輯器來寫.NET Core代碼 , <a href="/misc/goto?guid=4958866325544103262" target="_blank">OmniSharp</a> 項目添加了.NET項目的格式化特性,還有很受歡迎的跨平臺編輯器Sublime Text:
</p>
<p>
    <img alt=".NET開發者啟程Docker之路" src="https://simg.open-open.com/show/a0da0f390225220a5232a42987175f57.png" width="672" height="418" /> 
</p>
<p>
    但是這些項目都還在初期階段,如果你在Windows上用Visual Studio安裝了ASP.NET 5 ,你可以用VS來構建調試.NET Core的代碼。
</p>
<p>
    Visual Studio 2015可以使用project.json文件來加載源碼到項目中,你能用上所有智能提示,調試和類導航,但是目前NuGet包管理器還不能用在上邊,所以你可以這樣嘗試把標準的.NET添加到一個.NET Core項目,但是會得到一個類似這樣的提示:
</p>

sh
NU1002: The dependency CommonServiceLocator 1.3.0 in project Sixeyed.Uptimer does not support framework DNXCore,Version=v5.0.

所以完整版Visual Studio還是我更常用的.NET Core應用開發IDE,其他替代版雖然輕量,但是功能還不夠完善。

Visual Studio 2015能讓.NET Core應用程序開發起來像.NET原生的應用那樣,設置全都是類似的,在項目的屬性頁,你可以配置開啟調試模式,并且可以使用跨平臺特性來支持DNX運行。

.NET開發者啟程Docker之路

未來的Docker and .NET

Windows Server 2016很快就要發布了,它不需要虛擬機層就能直接支持Docker容器,所以sixeyed/coreclr-uptimer鏡像將能運行在原生的Windows上。

相對Linux基礎鏡像來說,在容器中能運行的Windows系統版本是Nano Server,這個系統也是基于模塊化架構的,目標是要構造非常小的鏡像(目前不到200MB,比1.5GB的Windows Server Core要小得多,但仍然比僅有44MB的Ubuntu鏡像要大很多),所以, .NET Core將仍會引入整個框架,即使容器已經能滿足了。

我們期待的是屆時是否能像這樣子定義一個鏡像:

sh
FROM windowsnanoserver.

Dockerfile現在還不能兼容微軟的鏡像定義,微軟現在在用PowerShell和Desired State配置。同時,Windows Nano Server如果能免費使用,那對基于Windows的鏡像被發布到Docker Hub上來說也是十分便利。

但是如果Dockerfile格式并不能兼容Windows Server,對于把開源社區上的Dockerfile轉換成PowerShell格式的翻譯器項目來說,那將是一個很好的發展機會。

應用容器正在改變軟件的設計、構建和發布方式,現在對于.NET項目來說也該好好利用起來了。未來勢必是Docker的時代,希云,作為Docker私有云領導者!利用Docker技術提供更好的云計算產品和服務。cSphere1.0版本已發布,正式商用!歡迎來電咨詢:400-686-156

如了解更多docker相關知識,請觀看培訓視頻: https://csphere.cn/training

</div>

來自: http://dockone.io/article/949

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!