標籤:

【DockerCon2017最新技術解讀】Docker最新特性介紹

摘要:在雲棲TechDay34期:DockerCon2017最新的技術解讀中,阿里巴巴技術專家譚林華為大家介紹了Docker的最新特性以及與傳統場景相比,這些新特性所具有的優勢和所能夠解決的問題。

以下內容根據演講嘉賓現場視頻以及速記整理而成。

演講嘉賓介紹:

譚林華(花名:霖華),阿里雲容器服務團隊技術專家,具有多年PaaS產品研發經驗,在平台設計、基礎架構等方面具有深厚的功底,Docker技術實踐者,目前負責阿里雲容器服務鏡像構建等功能。

本次將分享關於Docker新特性如下的幾個點:

  • 多階段構建
  • 資源管理
  • Docker secrets
  • swarm mode
  • 健康檢查

首先介紹Docker新推出的多階段構建;其次介紹一下Docker在資源管理方面新加的一些命令,這些命令可以方便開發者來做資源管理;還有就是介紹一下Docker secret跟之前那些密碼管理的方式有什麼不同;還有就是swarm mode裡面的一些新特性;最後再介紹一下swarm mode下面的健康檢查。

首先看一下多階段構建,構建鏡像了解Docker的同學應該比較熟悉。現在想像一個在Java語言下構建鏡像的場景,這個場景下開發者提交代碼,然後一個構建模塊,之後就去拉取GitHub或者其他源代碼倉庫的代碼,最後執行構建。像對這種靜態語言的構建而言,其實過程會稍微麻煩一點,比如說要有編譯器對它進行編譯,然後跑單元測試,然後打包,打包到最後就生成了War包或者Jar包,最後推到Registry中去。這個過程有一個問題就是如果把所有的內容都放在一個Dockerfile裡面,源代碼就會包含在鏡像裡面,所以這裡有源代碼泄露的風險。還有就是具體的生產環境其實是不需要那些編譯器源代碼以及測試框架或者打包框架的,最終可能只需要一個簡單的運行環境就可以了,這樣會導致鏡像變得特別大,所以這個方案不是特別好。

再來看一下Docker在5月份出來的一個最新的17.05版本,這個版本中引入了multi-stage build,也就是多階段構建。它的思路就是把剛剛提到的在構建鏡像的過程拆成兩個階段,這兩個階段都會產生鏡像,第一個階段就是去執行編譯、測試然後打包,得到一個鏡像,對於第一階段得到的鏡像,並不會使用這個鏡像的全部內容;在第二階段,可以把第一個階段的Jar包拷貝到第二個階段,這樣的好處就是沒有源代碼泄露的風險,因為最終打包到生產環境的只有最終編譯的位元組碼文件。同時整個鏡像也變得很小,因為它裡面沒有包含源代碼也沒有包含一些編譯器的軟體、測試框架和打包工具,所以這個方案是比較完美的。

然後看一下它最終的實現,上圖展現的主要是設計思路,最終實現是通過加入一些簡單的語法來支持這個功能的。下圖顯示的就是一個Dockerfile,它分為兩個構建階段,兩個構建階段都會生成鏡像,然後第二個構建鏡像是通過引用第一個構建鏡像的方式,把第一個構建鏡像裡面的Jar包打到第二個鏡像裡面。主要使用了copy命令,這裡面有個from參數,from參數引用了第一個構建鏡像的名稱,Dockerfile增加了一個新的語法就是AS命令,上面這個紅框中from指令就相當於給這個構建階段取了一個名字叫build-env,然後在第二個構建階段裡面就引用它,相當於把第一個構建鏡像裡面target目錄下面的app.jar拷貝到當前鏡像的工作目錄中,這樣的好處就是最終只包含了運行環境和部署到生產環境的Jar包,所以整個鏡像也變小了,也沒有代碼泄露的風險。

下圖展現了在Docker 1.13中引入的一些資源管理命令,比如docker system df,它可以查看整個容器集群裡面資源的使用情況,包括鏡像的使用情況以及數據卷的使用情況。還有就是以前要刪除鏡像或者刪除容器可能都比較麻煩,需要指定鏡像ID或容器ID,現在它提供了docker system prune的命令,可以很方便地一鍵清理所有沒有被使用或者沒有被引用的資源,這些資源包括所有停止的容器,還有就是所有沒有被引用的鏡像,以及數據卷和網路資源對象。沒有被引用的鏡像是什麼意思呢?這裡用了dangling這個英文單詞,稍後會具體介紹。還有就是在一鍵清理這些資源的同時,可以針對某個特定的資源進行清理,也就是第三條命令,可以清理所有沒有被使用的容器鏡像、網路或者數據卷。

我們來了解一下dangling的含義,在17.05的時候,其實dangling的含義發生了一點點變化。之前dangling的含義指的是同時沒有版本和名稱的鏡像,這個鏡像版本指的是就是鏡像tag,像這種情況它會認為是dangling的鏡像,所以在使用prune的時候會把它刪掉。現在dangling的含義也包括有鏡像名稱,但是沒有鏡像版本的鏡像。這種情況最常見於要構建相同tag的鏡像時,新構建的鏡像會把老的覆蓋掉,最後它的鏡像tag會變為none,所以這種情況在prune中刪掉也是合理的。

接下來介紹一下Docker Secrets,Secrets這個特性的引進還算比較早,在1.13版本就引入了。大家可以理解一下在引入Docker Secrets之前是怎麼樣傳入一些密碼這樣的敏感信息的,比如下圖這裡就是一個簡單的compose文件,這個文件裡面就是通過環境變數的方式把密碼傳進去,而這樣的方式有一個問題就是不是很安全,還有就是也不適合許可權管理,因為有些程序員可能不需要知道密碼裡面具體的內容,只需要去部署這個compose文件,所以這裡有這樣的兩個缺點。

Docker Secrets試圖解決這兩個問題,首先它的整個密碼傳輸的過程都是通過TLS加密的,就是用戶如果要把它密文通過Docker Secrets的方式保存的話,它最後會保存到中心化的存儲上,然後當某個服務要引用Docker Secrets的時候,它會通過TLS的方式傳輸到各個節點上,並且已經是以內存文件系統的形式掛載到容器上。

下圖展示的是具體的Compose模板的例子。在這個Compose模板裡邊其實並沒有Secrets密碼的明文保存,例如這個地方定義了Secrets,聲明Secrets的引用是來自於外部,包括這個wp_db_password和root_db_password,並且聲明了它的使用,還有就是它具體的使用方法,最後所有的Docker Secrets對象都會掛載到容器裡面的run/secrets目錄下面,這個目錄是固定的,後邊還要加上Secrets的名稱。

Docker 17.05還加入了Docker Service Logs。之前在查看容器的日誌或者任務的日誌的時候,比如在排查問題時,除非用了別的工具,要不然經常是需要挨個任務或者挨個容器進行查看,Docker Service Logs就試圖解決這個問題。這個 Service Logs通過服務維度把所有任務的日誌列出來,例如下圖中就表明了Redis服務的很多任務。然後將它整個日誌會按時間排序聚合起來,這樣的好處就是聚合該服務下所有日誌後,當進行調試時就可以方便地查找這些日誌。還有就是當需要把這些日誌保存到一個集中的地方的時候,通過這個介面也可以直接導到別的地方,而不用把每個容器的日誌再收集一遍。

再來看一下swarm mode下Service的另外一個特性,就是Service Create和Service Update這兩個命令。之前使用的Docker Create和Docker Update都是非同步的,就是創建或者更新完資源之後,這個命令調用完之後會立馬返回。只有通過Service ls或者Service ps的方式來察看這個任務是處於運行狀態還是失敗狀態。但是現在它加了一個參數叫detach,detach等於false就表明這個命令是在同步的狀態下執行的,所以它會同步地返回,這指的是它創建的所有任務會顯示狀態,然後一直等到它們處於Running狀態或者運行失敗狀態時,才會最終返回停止。下圖是兩個示例,就是跑了一個Redis服務,它會等所有任務返回之後再停止。

17.05版本的另一個比較有亮點的特性就是拓撲結構感知的調度。關於調度這塊,先來看一下swarm mode之前的調度方式。假設在兩個可用區下面一共有三個節點,可用區1有兩個節點,可用區2有一個節點,如果使用Service Create命令創建一個Web APP的時候,指定下面有六個任務,所以Service Create默認使用的是spread的調度策略,它會在每個節點上平均分配容器,所以最終導致的結果就是可用區1有四個容器,可用區2有兩個容器。但是事實上為保證可用性,通常會傾向於每個可用區都有一半的容器,也就是可用區1和可用區2各有三個,這樣當可用區1壞掉之後,可用區2能有三個容器來提供服務和支持,特別是在一些流量比較高的場景下,三個容器比兩個容器會有更高的可用性支持。所以在這種情況下用傳統的swarm調度方式是比較麻煩的,如果默認用spread調度方式就只能夠每個節點兩個容器分配,還有一種方式就是用Constrain,Constrain存在一個問題就是必須標識每個節點,比如說指定把三個容器部署到node 3,然後再把剩下的三個容器部署到node 1和node 2,這種方式其實跟按照可用區調度是不符合的。

那麼引入的新特性是怎麼做這件事情的呢?在Service Create的時候增加了一個placement-pref參數,這個參數有spread等於後面的label,這裡的意思是什麼呢?就是說採用的調度策略還是跟之前一樣用spread,由於均分的調度策略,但是具體調度是按照某個label表示的可用區來調度。這個集群會對於下面所有具有labels.az的節點,查看它們的label有幾個值,比如說現在有兩個值az1和az2,會按照這兩個值來均分整個的調度策略,最終的結果就會在az1上調度三個容器,然後az2也調度三個容器,就達到了按照可用區域來均分容器的目的。

最後來看一下Docker在健康檢查這塊引入的改動,健康檢查其實是已經存在比較久了,在1.12中就引入了。先來了解一下健康檢查使用的命令,健康檢查有兩種設置的方式,可以在Dockerfile中就是構建鏡像的過程中設置默認的健康檢查,然後通過健康檢查的命令來執行,所以通過Shell命令支持的方式,就可以通過各種方式來檢測應用程序和容器的健康性。還有就是在Compose file裡面可以對一些檢查的參數進行細粒度的調整,例如健康檢查的間隔時間以及超時時間,還有就是連續出現多少次失敗才認為是不健康的。在17.05加了一個參數Start Period,舉個例子解釋這個啟動參數的意義所在,就是比如配置好MySQL資料庫啟動起來大概要個二、三十秒,它的健康檢查間隔時間可能需要5秒或3秒,這種場景就比較適合用Start Period,這樣的健康檢查比較符合剛剛說的MySQL啟動的特性,當然還有一些其他類似的程序。

接下來看一個具體的例子,下圖展示的是對Redis做健康檢查,就是有一個文件叫docker-healthcheck,是用這個文件來檢查Redis。Redis的客戶端發一個ping的命令,當伺服器端返回PONG時健康檢查就通過了,否則健康檢查失敗。下面是健康檢查涉及的Dockerfile,就是最下面這一行。

健康檢查有什麼用呢,之前提到可以通過docker ps來查看任務或者容器是否處於健康狀態,但是現在比如這裡的Redis它後面會有一個狀態告訴你這個容器是否健康。同時這個健康檢查還會跟swarm mode調度結合在一起,這是什麼意思呢?就是說如果swarm根據你設置的健康檢查指令發現任務失敗了,它就會認為這個任務健康檢查不通過,但是這個任務還在運行中,它會主動地把運行中的這個任務退出,然後再新起一個任務,比如你的任務指定了一定要始終保持三個拷貝,然後它就始終會有三個拷貝在運行狀態,還有就是它在啟動時會保證去檢查健康狀況。


推薦閱讀:

Egg.js+Antd 擼個簡易版阿里雲CS控制台?
Docker Remote API 如何使用?
基於OSS搭建私有(跨區域)Docker鏡像倉庫
把docker鏡像當作桌面系統來用
Docker 重要更新: 原生支持多階段構建(multi-stage build)

TAG:Docker |