八一八Windows Docker的有趣事實

FrancesStil 8年前發布 | 14K 次閱讀 Windows Docker

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

作者 彭愛華

作者按:本文涉及的是Windows Server Container技術,可以通過Docker客戶端直接管理。

眾所周知,Docker能打通開發和運維的任督二脈,所謂DevOps是也。有朋友說,這符合王陽明的"知行合一"之教。

而Windows Server 2016內置的Windows Docker亦已經出來一段時間,這里就來和諸公匯報一下測試結果。

Linux和Windows,容器里各有多少進程?

在安裝配置Windows Server Container Host的時候,經常報錯Container OS Image下載失敗(沒辦法,墻內的緣故)。

什么是Container OS?顧名思義,是從容器角度看到的OS。

Container OS實際是應用所依賴的用戶模式(User mode)OS組件,對于Windows容器來說,例如ntdll.dll、kernel32.dll或者coresystem.dll之類的System DLL。主機上的所有容器共享內核模式(Kernel mode)OS組件,對于Windows,就是ntoskrnl.exe,還有驅動等。

例如對于以下命令,意味著Windows系統從docker映像中獲取Windows Server Core的用戶模式OS組件,并啟動cmd獲得Shell。

docker run -it windowsservercore cmd

Linux也是一理,如果運行以下命令,意味著從docker映像中獲取Ubuntu的用戶模式組件,并且啟動Bash Shell。

docker run -it ubuntu /bin/bash

對于以上兩個容器,Linux容器里的進程比較少,可以參考以下截圖:

而Windows容器,則情況略有不同。

在Windows主機上啟動Process Explorer,可以看到這個Windows容器的進程相對多一些:

這是因為在Windows系統中,需要給應用提供一些用戶模式的系統服務,例如DNS、DHCP、RPC等服務,這樣從容器的角度來看,容器獲得了自己獨有的服務(一般是在各自的svchost里運行),構成了所謂的Container OS。

我們可以用PowerShell命令查看容器內部啟動的Windows服務,大概有27個,參考附圖。

很可惜,當前測試版本的Windows docker里,雖然容器里開啟遠程桌面服務,但是卻并不支持遠程桌面到容器,所以無法使用容器應用的圖形化界面,前一個版本倒是支持。

容器里的應用,到底應該啟動多少Windows服務?由于Windows服務的具體作用是非文檔化的,所以不像Linux可以做到最精簡。但是由于這些服務幾乎不占用什么額外的資源,對于容器性能沒有影響。

Windows容器的進程間怎么隔離的?

在最新的測試版本里,容器對象的權限設置有了改變,只有SYSTEM權限才能查看。所以要查看Windows容器的進程隔離,需要用SYSTEM權限啟動Winobj。這可以借助Psexec來實現:

Psexec -i -d -s winobj.exe

可以看到Windows對象空間里多了一個Containers的節點,其下有若干個GUID分支,這些GUID代表系統里的容器。其下每個容器有自己獨立的BaseNamedObjects等命名空間,包括互斥信號量、內存Section、事件等。

可以用PowerShell查看容器的GUID,參考附圖。

每個容器節點下,有自己的Session分支,例如該容器,占據了Windows系統的Session 2。如附圖所示。

這就是為什么,不管用任務管理器,還是PowerShell,抑或是Process Explorer等工具,我們都在Windows主機里看到該容器里的所有進程都會標記Session為2(容器會占據系統中可用的最新Session)。

借助Process Explorer,我們可以看到容器里的進程,所打開的Handle,其中就指向先前所看到的Windows容器對象命名空間。

同時還能看到,容器進程所在的WindowStation并不是WinSta0,而是Service-0x0-3e7$,3e7的10進制等于999,等于九五之尊,這是SYSTEM服務所在的窗口站。所以容器進程無法在Windows桌面上擁有圖形化界面。

還可以查看一個有意義的對象,Windows容器所掛載的主機目錄,類似于Linux容器的Volume,看上去像是符號鏈接。

Windows容器的文件系統怎么隔離的?

和Linux一樣,Windows容器映像采用分層的文件系統,基于映像創建容器后,相當于在只讀的分層文件系統上再覆蓋一層可讀寫的文件系統層。如果要修改的文件在最上層的可讀寫層里沒有,則沿著分層的Layer找到目標文件后,將其用COW(Copy on write:寫時復制)復制到可讀寫層再修改。

讓我們進入到Windows主機的以下目錄:C:\ProgramData\Microsoft\Windows\Hyper-V\Containers

該目錄下列出所有通過PowerShell命令創建的容器文件。其下有文件夾和文件,都以容器的GUID來命名。

其中的926A300B-ACB7-4B28-9D86-45BF82C1211C.vhdx就是該容器的最上層的可讀寫層,是一個VHDX文件。

記住該可讀寫層并不是一個完整的文件系統,它需要和Image的現有文件系統組成Union File System。如果嘗試雙擊該VHDX(只能嘗試掛載停止狀態的容器VHDX),試圖掛載到Windows系統,會彈出報錯信息,提示該虛擬硬盤無法掛載。

Image的文件系統位于以下路徑(Windows Server Core的Container OS文件):

C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Files

如果用Process Explorer查看容器進程所加載的Dll,可以看到其訪問的路徑為Container OS Image文件。

如果是用docker命令創建的進程,道理類似,但是其可讀寫層文件系統位于以下路徑:C:\ProgramData\docker\windowsfilter

Windows容器還有注冊表

和Linux不一樣,Windows容器需要考慮注冊表的隔離問題。

下面讓我們進入PowerShell命令創建的Windows容器文件夾內部。

C:\ProgramData\Microsoft\Windows\Hyper-V\Containers\926A300B-ACB7-4B28-9D86-45BF82C1211C\Hives

在這個Hives文件夾下方,有很多命名為*_Delta的文件,這是容器所訪問的注冊表配置單元文件。

從命名方式中可以看到,容器的注冊表和文件系統一樣,也采用分層架構,最上層的是可讀寫的注冊表命名空間。而Image映像也有只讀部分的注冊表空間,路徑如下。

C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Hives

在Process Explorer里可以看到可讀寫層、只讀層注冊表合并后所加載的內容。

Docker命令所創建的容器,方法類似,位于類似以下路徑:

Windows容器的資源限制

大家知道,Docker可以調用CGroup技術來限制Linux容器的CPU、內存等資源占用。而在Windows容器里,內存資源的限制,則是通過Windows的JO(作業對象)技術來實現。

可以參考以下技術來限定Windows容器的CPU、內存和磁盤IO。例如可以將容器的內存限定為最大占用為5GB。

https://msdn.microsoft.com/en- ... 17396

然后用Process Explorer打開任意一個容器進程的屬性對話框,切換到Job標簽頁。

可以看到所有容器進程共享一個作業對象,而且該作業對象的內存限額(Job Memory Limit)為5GB。

</div>

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