衆所周知,Docker能打通開發和運維的任督二脈,所謂DevOps是也。有朋友說,這符合王陽明的"知行合一"之教。
而Windows Server 2016 TP4内置的Windows Docker亦已經出來一段時間,這裡就來和諸公彙報一下測試結果。
Linux和Windows,容器裡各有多少程序?
在安裝配置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容器裡的程序比較少,可以參考以下截圖:
<a href="http://s3.51cto.com/wyfs02/M00/7F/10/wKiom1cRsyni1FpzAAGIn1uLX6I926.jpg" target="_blank"></a>
而Windows容器,則情況略有不同。
在Windows主機上啟動Process Explorer,可以看到這個Windows容器的程序相對多一些:
<a href="http://s4.51cto.com/wyfs02/M00/7F/10/wKiom1cRtKnR3oFwAAlFKM7xgug817.jpg" target="_blank"></a>
這是因為在Windows系統中,需要給應用提供一些使用者模式的系統服務,例如DNS、DHCP、RPC等服務,這樣從容器的角度來看,容器獲得了自己獨有的服務(一般是在各自的svchost裡運作),構成了所謂的Container OS。
我們可以用PowerShell指令檢視容器内部啟動的Windows服務,大概有27個,參考附圖。
<a href="http://s2.51cto.com/wyfs02/M01/7F/10/wKiom1cRtHnByIlNAAYaMLnowqM505.jpg" target="_blank"></a>
很可惜,這個版本的Windows docker裡,雖然有遠端桌面服務,但是目前還不支援遠端桌面到容器,是以無法使用容器應用的圖形化界面。
容器裡的應用,到底應該啟動多少Windows服務?由于Windows服務的具體作用是非文檔化的,是以不像Linux可以做到最精簡。但是由于這些服務幾乎不占用什麼額外的資源,對于容器性能沒有影響。
Windows容器的程序間怎麼隔離的?
在最新的測試版本裡,容器對象的權限設定有了改變,隻有SYSTEM權限才能檢視。是以要檢視Windows容器的程序隔離,需要用SYSTEM權限啟動Winobj。這可以借助Psexec來實作:
Psexec -i -d -s winobj.exe
可以看到Windows對象空間裡多了一個Containers的節點,其下有若幹個GUID分支,這些GUID代表系統裡的容器。其下每個容器有自己獨立的BaseNamedObjects等命名空間,包括互斥信号量、記憶體Section、事件等。
<a href="http://s3.51cto.com/wyfs02/M00/7F/0D/wKioL1cRtbrCFQCmAAI57gSAY04674.jpg" target="_blank"></a>
可以用PowerShell檢視容器的GUID,參考附圖。
<a href="http://s2.51cto.com/wyfs02/M01/7F/0D/wKioL1cRtcqCJbM9AADLBoPrV-Y451.jpg" target="_blank"></a>
每個容器節點下,有自己的Session分支,例如該容器,占據了Windows系統的Session 2。如附圖所示。
<a href="http://s5.51cto.com/wyfs02/M02/7F/10/wKiom1cRtSij3wS5AAIIFTqQfbY289.jpg" target="_blank"></a>
這就是為什麼,不管用任務管理器,還是PowerShell,抑或是Process Explorer等工具,我們都在Windows主機裡看到容器裡的所有程序都會标記Session為2。
借助Process Explorer,我們可以看到容器裡的程序,所打開的Handle,其中就指向先前所看到的Windows容器對象命名空間。
<a href="http://s4.51cto.com/wyfs02/M02/7F/0D/wKioL1cRtgGBIeV3AAW-b5eUvNA537.jpg" target="_blank"></a>
同時還能看到,容器程序所在的WindowStation并不是WinSta0,而是Service-0x0-3e7$,3e7的10進制等于999,等于九五之尊,這是SYSTEM服務所在的視窗站。是以容器程序無法在Windows桌面上擁有圖形化界面。
<a href="http://s3.51cto.com/wyfs02/M00/7F/0D/wKioL1cRtoXwICZTAAgeP4-gpYQ626.jpg" target="_blank"></a>
還可以檢視一個有意義的對象,Windows容器所挂載的主機目錄,類似于Linux容器的Volume。
<a href="http://s4.51cto.com/wyfs02/M01/7F/0D/wKioL1cRtqWDy3dVAAPkQ73bwEc496.jpg" target="_blank"></a>
Windows容器的檔案系統怎麼隔離的?
和Linux一樣,Windows容器映像采用分層的檔案系統,基于映像建立容器後,相當于在隻讀的分層檔案系統上再覆寫一層可讀寫的檔案系統層。如果要修改的檔案在最上層的可讀寫層裡沒有,則沿着分層的Layer找到目标檔案後,将其用COW(Copy on write:寫時複制)複制到可讀寫層再修改。
讓我們進入到Windows主機的以下目錄:
C:\ProgramData\Microsoft\Windows\Hyper-V\Containers
該目錄下列出所有通過PowerShell指令建立的容器檔案。其下有檔案夾和檔案,都以容器的GUID來命名。
<a href="http://s3.51cto.com/wyfs02/M02/7F/10/wKiom1cRtjbxAYwnAAUYGvvyu-s712.jpg" target="_blank"></a>
其中的926A300B-ACB7-4B28-9D86-45BF82C1211C.vhdx就是該容器的最上層的可讀寫層,是一個VHDX檔案。
記住該可讀寫層并不是一個完整的檔案系統,它需要和Image的現有檔案系統組成Union File System。如果嘗試輕按兩下該VHDX(隻能嘗試挂載停止狀态的容器VHDX),試圖挂載到Windows系統,會彈出以下報錯資訊,提示該虛拟硬碟無法挂載。
<a href="http://s3.51cto.com/wyfs02/M00/7F/10/wKiom1cRtubhxEuLAAFNljQwIqo295.jpg" target="_blank"></a>
Image的檔案系統位于以下路徑(Windows Server Core的Container OS檔案):
C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Files
如果用Process Explorer檢視容器程序通路的Dll,可以看到其通路的路徑為Container OS檔案。
<a href="http://s5.51cto.com/wyfs02/M01/7F/10/wKiom1cRtxLj6lHVAAZEqSe8sdI014.jpg" target="_blank"></a>
如果是用docker指令建立的程序,道理類似,但是其可讀寫層檔案系統位于以下路徑:
C:\ProgramData\docker\windowsfilter
<a href="http://s3.51cto.com/wyfs02/M01/7F/10/wKiom1cRt2_A3PvuAAWn7RWf7to967.jpg" target="_blank"></a>
Windows容器還有系統資料庫
和Linux不一樣,Windows容器需要考慮系統資料庫的隔離問題。
下面讓我們進入PowerShell指令建立的Windows容器檔案夾内部。
C:\ProgramData\Microsoft\Windows\Hyper-V\Containers\926A300B-ACB7-4B28-9D86-45BF82C1211C\Hives
<a href="http://s4.51cto.com/wyfs02/M00/7F/10/wKiom1cRt_yRpi7OAAHsULkQsQ4385.jpg" target="_blank"></a>
在這個Hives檔案夾下方,有很多命名為*_Delta的檔案,這是容器所通路的系統資料庫配置單元檔案。
從命名方式中可以看到,容器的系統資料庫和檔案系統一樣,也采用分層架構,最上層的是可讀寫的系統資料庫命名空間。而Image映像也有隻讀部分的系統資料庫空間,路徑如下。
C:\ProgramData\Microsoft\Windows\Images\CN=Microsoft_WindowsServerCore_10.0.10586.0\Hives
<a href="http://s2.51cto.com/wyfs02/M01/7F/10/wKiom1cRuIGRwgEiAAH5S8IPJg8906.jpg" target="_blank"></a>
在Process Explorer裡可以看到可讀寫層、隻讀層系統資料庫合并後所加載的内容。
<a href="http://s4.51cto.com/wyfs02/M01/7F/10/wKiom1cRuKzwAxo8AAoVotGDato324.jpg" target="_blank"></a>
Docker指令所建立的容器,方法類似,位于類似以下路徑:
<a href="http://s3.51cto.com/wyfs02/M02/7F/10/wKiom1cRuQGj3cx9AAHqs4aJq44117.jpg" target="_blank"></a>
Windows容器的資源限制
大家知道,Docker可以調用CGroup技術來限制Linux容器的CPU、記憶體等資源占用。而在Windows容器裡,記憶體資源的限制,則是通過Windows的JO(作業對象)技術來實作。
可以參考以下技術來限定Windows容器的CPU、記憶體和磁盤IO。例如可以将容器的記憶體限定為最大占用為5GB。
https://msdn.microsoft.com/en-us/virtualization/windowscontainers/management/manage_resources?f=255&MSPPError=-2147217396
然後用Process Explorer打開任意一個容器程序的屬性對話框,切換到Job标簽頁。
<a href="http://s4.51cto.com/wyfs02/M02/7F/10/wKiom1cRuTGDIcNsAAFNRGAkCYw791.jpg" target="_blank"></a>
可以看到所有容器程序共享一個作業對象,而且該作業對象的記憶體限額(Job Memory Limit)為5GB。
寫到現在,手都酸了,這次就到這裡吧,下次有空再一起讨論容器的網絡隔離,和Azure container service整合等高大上的技術吧。
本文轉自 ahpeng 51CTO部落格,原文連結:http://blog.51cto.com/markwin/1764383,如需轉載請自行聯系原作者