Docker 是一個由 go 語言編寫的,開源的應用容器引擎。
開發者可以打包他們的應用以及依賴包到一個可移植的鏡像[1]中,然後發布到任何流行的Linux[2]或Windows[3]機器上,也可以實現虛擬化[4]。
容器是完全使用沙箱[5]機制,相互之間不會有任何接口。
Docker 背後實現原理是什麼?Docker 架構實現一個完整的容器,需要 Namespace、Cgroups 和聯合文件系統這三項 Linux 技術的支撐。
圖源百度圖片NamespaceNamespace 是 Linux 內核用來隔離內核資源的一種方式。通過 Namespace 可以對某些進程進行限制,使得其只能訪問與自身相關的那部分資源,其他資源不可見。
如此,不同進程之間也是相互無感知的。這種隔離覆蓋面十分廣泛,包括但不限於:隔離進程 ID、主機名、用戶 ID、文件名、網絡訪問和進程間通信等相關資源。在 Docker 的世界中,主要用到以下六種命名空間。
mnt namespace:隔離文件系統掛載點,可在不同進程中看到不同掛載目錄,且不影響主機掛載目錄
ipc namespace:隔離進程間通信(如:信號量,消息隊列和共享內存)
user namespace : 隔離用戶和用戶組,可實現 docker 內擁有 root 權限而在主機上只是普通用戶
正是由於 Docker 使用了 Linux 的這些 Namespace 技術,才實現了 Docker 容器的隔離。
CgroupsCgroups 是控制組群(control groups)的簡寫,可用於限制、控制與分離一個進程組的資源(如 CPU、內存、磁碟輸入輸出等)。
在 Docker 的世界中,Cgroups 通常用來限制容器的 CPU 和內存等資源的使用。
資源限制 : 限制資源的使用量(如通過限制某個業務的內存上限,保護主機其他業務的安全運行)。
優先級控制 : 不同的組可以有不同的資源( CPU 、磁碟 IO 等)使用優先級。
圖源掘金小冊-開發者必備的 Docker 實踐指南聯合文件系統聯合文件系統是一種分層、輕量級並且高性能的文件系統,它支持對文件系統的修改作為一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下。
在 Docker 的世界中,聯合文件系統為容器提供構建層,使得容器可以實現寫時複製以及鏡像的分層構建和存儲。
鏡像本身是只讀的,在運行某個容器的時候,會在鏡像外層附加一個可讀寫層,這也是基於聯合文件系統實現的。
FROM busybox
COPY test /tmp/test
RUN mkdir /tmp/testdir上述每一行命令都會生成一個鏡像層,當不同的鏡像之間有相同的鏡像層時,便可以實現不同的鏡像之間共享鏡像層的效果。(比如基於 base 鏡像擴展的鏡像)
圖源拉鉤教育鏡像層共享這個功能十分強大,每一層都可以共享。
圖源百度圖片作業系統層面的虛擬化以上這種對進程進行封裝隔離的技術,屬於作業系統層面的虛擬化技術[6]。隔離的進程獨立於宿主和其它的隔離的進程,因此也稱其為容器。容器本質是一個受限制的進程,它沒辦法像直接運行在主機上的進程那樣獲取主機上的進程、環境變量、網絡等信息。
該技術最初實現是基於LXC[7](Linux Container),從 0.7 版本以後開始去除 LXC,轉而使用自行開發的libcontainer[8]。從自 1.11 版本開始,進一步演進為使用runC[9]和containerd[10]。
客戶端/服務端模式圖源拉鉤教育docker如上圖所示:Docker 和 MySQL 一樣,也是客戶端-服務端的模式。Docker 客戶端其實是一種泛稱,用戶可通過 docker 命令或者直接請求 REST API 的方式與 Docker 服務端交互。
dockerdDocker 服務端是 Docker 所有後臺服務的統稱。其中 dockerd 是一個非常重要的後臺管理進程,它負責響應和處理來自 Docker 客戶端的請求,然後將客戶端的請求轉化為 Docker 的具體操作。這個過程中 dockerd 會通過 grpc(一個 rpc 框架)與 containerd 通信,containerd 作為 dockerd 的下層服務。
runCrunC 是一個根據 OCI(開放容器標準)規範生成和運行容器的 CLI 工具,可通過命令行的形式控制容器的銷毀與創建。
containedcontainerd 是 dockerd 和 runC 之間的一個中間交流組件,docker 對容器的管理和操作基本都是通過 containerd 完成的。例如:容器生命周期管理、鏡像管理。
containerd-shimcontainerd 通過 containerd-shim 啟動並管理 runC,containerd-shim 主要作用是可以在不中斷容器運行的情況下升級或重啟 dockerd。
Docker 與虛擬化技術虛擬化技術指的是通過隱藏特定計算平臺的實際物理特性,為用戶提供抽象、統一、模擬的計算環境。這種計算環境,也被稱為虛擬機。
Docker 是對 Linux 容器的一種封裝,具有高性能,低開銷,接口簡單易用等特點。真正使其超過其他同類產品,迅速佔領市場,成為目前最流行的 Linux 容器技術解決方案的根本是 Docker 引入了鏡像功能。
與系統級別的虛擬機不同,容器技術的虛擬其實是進程級別的。
圖源極客時間從上圖中可以看出,虛擬機是通過在宿主機上啟動一個虛擬機監視器 HyperVisor 來管理控制虛擬機的,最經典的 HyperVisor 就是 VirtualBox。與容器相比,虛擬機包含了整個客戶作業系統,這也是二者性能差異的主要成因。
從啟動角度來看,進程級別的容器啟動肯定是比系統級別的虛擬機啟動要快得多。從資源佔用角度來看,容器是按需佔用,虛擬機是全量佔用。從資源利用率角度來看,多容器可以共享資源,而虛擬機是獨享資源。從構建角度來看,容器是按需構建,體積小;虛擬機是全量構建,體積大。圖源掘金小冊-開發者必備的 Docker 實踐指南Docker 解決了什麼問題?Docker 是容器技術的一種體現,而容器技術的根本是為了抹平軟體運行的環境差異。
如何抹平?Docker 通過 build 命令將應用程式和其依賴構建成鏡像文件,鏡像是只讀的,這意味著構建完成後,鏡像不會再發生任何變化。如此,基於該鏡像啟動的容器環境必然一致。同理,跑在這個容器中的應用程式所處環境也一致。
此外,容器是完全使用沙箱機制,容器相互之間完全隔離,互不影響。
Docker 有哪些適用場景?作為 Serverless 的底層依賴,動態擴縮容
搭建微服務架構,可通過多容器運行多服務的形式對複雜項目進行拆解
核心概念鏡像Docker 鏡像是一個特殊的文件系統,它包含了容器運行時所需要的所有基礎文件和配置信息,是容器啟動的基礎。這就意味著,必須先有鏡像才能啟動容器。
鏡像可以自己構建也可以從鏡像倉庫[11]拉取。
容器鏡像和容器的關係就好像類和實例的關係。一個類可以有很多實例,一個鏡像也可以有很多容器。
容器不可以脫離鏡像存在。事實上,可以理解為容器=容器層(可寫)+鏡像(只讀)。
圖源拉鉤教育寫時複製
這部分涉及到一個寫時複製(copy-on-write)的技術,能夠有效的提高磁碟的利用率。尤其是對讀操作,十分的友好。
寫時複製會將要修改的內容從鏡像拷貝到容器的可讀寫層,並不會直接修改鏡像的源文件。
這意味著即便是寫的時候有其他容器對同一鏡像資源進行讀取,也不會發生資源不一致的情況。
多容器操作同一個文件也是各自在自己的容器空間創建讀寫層並完成修改,相互隔離,互不影響。
生命周期
每一個容器完整生命周期都具有創建,運行,停止,暫停,刪除這五個狀態。
圖源百度圖片創建:容器被創建,所需資源已就緒,容器中的應用程式尚未運行。暫停:容器中的所有應用程式都處於暫停 ( 非停止 ) 狀態。
停止:容器中的應用程式均已停止,但所佔用資源不會釋放。
值得注意的是:如果要刪除一個鏡像,必須保證沒有容器佔用,停止狀態的容器也不行。
倉庫Docker 的鏡像倉庫(public/private)類似於代碼倉庫,可以用來存儲和分發 Docker 鏡像。
鏡像,容器,代碼倉庫三者關係如下:
安裝官方安裝方式 Docker DesktopDocker Desktop 其本質是藉助 windows 和 macOS 的平臺特性,搭建了一個 Linux 環境,進而運行 docker。
圖源掘金小冊-開發者必備的 Docker 實踐指南鏡像加速為使得在國內從 Docker Hub 拉取鏡像更快,可以配置鏡像加速器。
阿里雲加速器\(控制臺 -> 登錄帳號-> 應用搜索容器鏡像服務 -> 側邊欄選擇鏡像加速器 -> 複製地址\)[14]網易雲加速器https://hub-mirror.c.163.com[15]
百度雲加速器https://mirror.baidubce.com[16]
由於鏡像服務可能出現宕機,建議同時配置多個鏡像。
配置方式
下載安裝官方提供的 Docker Desktop 後,點擊 docker 圖標,選擇 setting(windows)或者 preferences(macOS)面板,切換到 docker engine ,編輯 json 文件,加入鏡像源地址後點擊右下角的 Apply&Restart。
安裝檢測
命令行輸入 docker info 後關注 Registry Mirrors
Hello world本示例將展示一個簡單的 koa server 如何在 docker 中跑起來。
1. 創建項目 koa-server
# 新建文件夾
mkdir koa-server
# 進入
cd koa-server
# 項目初始化,生成package.json
npm init -y
# 安裝koa
npm i koa
# 新建app.js
touch app.js
# 在app.js中寫入如下代碼
const Koa=require('koa')
const app=new Koa()
app.use(ctx=>{
ctx.body='hello koa'
})
app.listen(3000,()=>{
console.log('run server__')
})2. 編寫 Dockerfile 文件,根據其描述構建鏡像
# 新建Dockerfile文件
touch Dockerfile
# 寫入如下內容
FROM node:12.20.1
COPY . /app
WORKDIR /app
RUN npm i
EXPOSE 3000命令解釋
指定基礎鏡像為 node,冒號表示標籤,此處指的是 12.20.1 版本的 node
將當前目錄下的所有(非.dockerignore 排除)文件,都拷貝進入鏡像文件的/app 目錄。
安裝依賴(安裝後所有的依賴,都將打包進入鏡像文件)。
將容器 3000 埠暴露出來, 允許外部連接這個埠。
其他常用命令
圖源拉鉤教育3. 編寫.dockerignore 排除文件
# 新建.dockerignore排除文件
touch .dockerignore
# 寫入如下內容
node_modules4. 構建鏡像
koa-server 根目錄下執行如下命令構建鏡像:
docker image build -t koa-server-image .
-t 用於指定構建的鏡像名,後面可用冒號指定標籤名,默認 latest最後的那個點表示 Dockerfile 文件所在的路徑,因為是進入 koa-server 後執行的構建命令,所以是當前目錄,可以看成是./
鏡像構建完成後可用 docker image ls 命令查看鏡像列表:
5. 啟動容器
Docker 內部環境與主機資源都是隔離的,因此需要定義容器與物理機的埠映射來進行訪問。
此外,容器是在鏡像基礎上啟動,所以要先保證有這個鏡像。如果本地沒有,默認會去公開鏡像倉庫中查找同名鏡像,找到後拉取到本地再執行 docker run 命令。
鏡像,容器,應用程式三者關係是:鏡像是容器啟動的先決條件,容器中運行著真正的應用程式。
docker container run -p 3000:3000 -it koa-server-image /bin/bash-p 參數就是用於指定埠映射,格式為主機埠:容器埠
/bin/bash 相當於在-it 參數返回的交互終端中執行/bin/bash
因為是 node 環境,不加/bin/bash 效果就相當於終端輸入 node 後回車的效果
對於上述-p 參數做一個補充說明,這裡涉及到了 docker 中用於處理埠映射的 docker-proxy 組件。當我們使用帶有-p 參數的 docker run 命令,該組件就會把容器內相應的埠映射到主機上來,這樣主機就可以訪問容器內資源了。
6. 效果驗證
上述命令執行後會返回一個交互終端,此時已經進入容器內部,通過執行 node app.js 啟動 koa-server
瀏覽器訪問地址http://localhost:3000/,頁面顯示 hello koa
如果想退出容器,可以先 ctrl+c 打斷應用程式,然後 ctrl+d 退出。如果安裝了 Docker Desktop,可用圖形化界面形式去管理鏡像和容器,十分方便。更多:Docker run 命令[17]。
容器遷移通過 docker 提供的 export 和 import 命令可以十分方便的實現容器的導入導出,從而完成遷移工作。
導出
docker export 容器名 > xxx.zip
#demo
docker export busybox > busybox.zip執行完後會生成一個壓縮包,可發送到另一臺機子上再導入使用。
導入
導出的容器在被導入後實際會成為一個鏡像,可使用 docker run 命令基於該鏡像啟動容器。
docker import xxx.zip xxx
# demo
docker import busybox.zip busybox:test
docker run -it busybox:test sh
加入我們我們是字節跳動互娛前端安全團隊,是抖音、剪映、輕顏、激萌等現象級產品的守護者。
我們年輕、思維活躍、不拘一格,是一群持續學習和探索的技術極客,每天與Web安全攻防、全棧技術、跨端技術、微前端、微服務、Serverless等各種技術打交道。我們以技術為武裝,為用戶數據安全保駕護航。
點擊閱讀原文,投遞簡歷,來互娛前端一起做優秀事情吧!
關注我們,持續了解最新技術!
參考資料
[1]鏡像: https://baike.baidu.com/item/%E9%95%9C%E5%83%8F/1574
[2]Linux: https://baike.baidu.com/item/Linux
[3]Windows: https://baike.baidu.com/item/Windows/165458
[4]虛擬化: https://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E5%8C%96/547949
[5]沙箱: https://baike.baidu.com/item/%E6%B2%99%E7%AE%B1/393318
[6]作業系統層面的虛擬化技術: https://zh.wikipedia.org/wiki/%E4%BD%9C%E6%A5%AD%E7%B3%BB%E7%B5%B1%E5%B1%A4%E8%99%9B%E6%93%AC%E5%8C%96
[7]LXC: https://linuxcontainers.org/lxc/introduction/
[8]libcontainer: https://github.com/docker/libcontainer
[9]runC: https://github.com/opencontainers/runc
[10]containerd: https://github.com/containerd/containerd
[11]鏡像倉庫: https://hub.docker.com/
[12]mac: https://hub.docker.com/editions/community/docker-ce-desktop-mac/
[13]windows: https://hub.docker.com/editions/community/docker-ce-desktop-windows/
[14]阿里雲加速器(控制臺 -> 登錄帳號-> 應用搜索容器鏡像服務 -> 側邊欄選擇鏡像加速器 -> 複製地址): https://www.aliyun.com/product/acr?source=5176.11533457&userCode=8lx5zmtu
[15]https://hub-mirror.c.163.com: https://www.163yun.com/help/documents/56918246390157312
[16]https://mirror.baidubce.com: https://cloud.baidu.com/doc/CCE/s/Yjxppt74z#%E4%BD%BF%E7%94%A8dockerhub%E5%8A%A0%E9%80%9F%E5%99%A8
[17]Docker run 命令: https://www.runoob.com/docker/docker-run-command.html
[18]Docker —— 從入門到實踐:https://yeasy.gitbook.io/docker_practice/: https://yeasy.gitbook.io/docker_practice/
[19]Docker 入門教程:http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html: http://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html
[20]開發者必備的 Docker 實踐指南:https://juejin.cn/book/6844733746462064654: https://juejin.cn/book/6844733746462064654
[21]由淺入深吃透 Docker:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=455#/content: https://kaiwu.lagou.com/course/courseInfo.htm?courseId=455#/content
[22]Serverless 入門課:https://time.geekbang.org/column/intro/305: https://time.geekbang.org/column/intro/305
[23]Docker 學習筆記之運行和管理容器:https://www.cnblogs.com/JetpropelledSnake/p/10330674.html: https://www.cnblogs.com/JetpropelledSnake/p/10330674.html
[24]Docker 架構中的幾個核心概念:https://www.jianshu.com/p/de3184ad0800: https://www.jianshu.com/p/de3184ad0800
[25]作業系統層面的虛擬化技術:https://zh.wikipedia.org/wiki/%E4%BD%9C%E6%A5%AD%E7%B3%BB%E7%B5%B1%E5%B1%A4%E8%99%9B%E6%93%AC%E5%8C%96: https://zh.wikipedia.org/wiki/%E4%BD%9C%E6%A5%AD%E7%B3%BB%E7%B5%B1%E5%B1%A4%E8%99%9B%E6%93%AC%E5%8C%96
[26]runC:https://github.com/opencontainers/runc: https://github.com/opencontainers/runc
[27]containerd:https://github.com/containerd/containerd: https://github.com/containerd/containerd