docker 學習路線
參考資料
- 知乎 docker 的學習路線
 - Docker — 從入門到實踐
 - Docker 核心技術與實現原理
 - Docker 入門
 - 《Kubernetes in Action》,想要學習 Kubernetes 的讀者一定不要錯過。
 - 編程能力影響最大的兩本書就是: 
          
- 《計算機程序的構造和解釋》(Structure and Interpertation of Computer Programming,SICP)
 - 《計算機程序的概念、技術和模型》(Concepts, Techniques, and Models of Computer Programming,CTMCP)
 
 
理解 docker 的核心技術(core tech)
- docker 的核心技術有 namespace, control groups, union filesystem
 
Namespaces
- 命名空間 (namespaces) 是 Linux 為我們提供的用於分離進程樹、網絡接口、掛載點以及進程間通信等資源的方法。
 - Docker 其實就通過 Linux 的 Namespaces 對不同的容器實現了隔離。
 - Linux 的命名空間機制提供了以下七種不同的命名空間,包括 CLONE_NEWCGROUP、CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER 和 CLONE_NEWUTS,通過這七個選項我們能在創建新的進程時設置新進程應該在哪些資源上與宿主機器進行隔離。
 - Docker 通過命名空間成功完成了與宿主機進程和網絡的隔離。
 
進程
- 一個是 pid 為 1 的 /sbin/init 進程 
          
- 負責執行內核的一部分初始化工作和系統配置,也會創建一些類似 getty 的注冊進程。
 
 - 另一個是 pid 為 2 的 kthreadd 進程
 - 這兩個進程都是被 Linux 中的上帝進程 idle 創建出來的。 
          
- 負責管理和調度其他的內核進程。
 
 - Docker 容器內部的任意進程都對宿主機器的進程一無所知。
 - 在 setNamespaces 方法中不僅會設置進程相關的命名空間,還會設置與用戶、網絡、IPC 以及 UTS 相關的命名空間。
 
網絡
- Docker 為我們提供了四種不同的網絡模式,Host、Container、None 和 Bridge 模式。
 - Docker 默認的網絡設置模式:網橋模式。 
          
- 除了分配隔離的網絡命名空間之外,Docker 還會為所有的容器設置 IP 地址。
 - 當 Docker 服務器在主機上啟動之后會創建新的虛擬網橋 docker0,隨后在該主機上啟動的全部服務在默認情況下都與該網橋相連。
 - 在默認情況下,每一個容器在創建時都會創建一對虛擬網卡,兩個虛擬網卡組成了數據的通道,其中一個會放在創建的容器中,會加入到名為 docker0 網橋中。
 
 - libnetwork: 
          
- 提供了一個連接不同容器的實現,同時也能夠為應用給出一個能夠提供一致的編程接口和網絡層抽象的容器網絡模型。
 
 
掛載點
- 新的進程中創建隔離的掛載點命名空間需要在 clone 函數中傳入 CLONE_NEWNS,這樣子進程就能得到父進程掛載點的拷貝,如果不傳入這個參數子進程對文件系統的讀寫都會同步回父進程以及整個主機的文件系統。
 - 如果一個容器需要啟動,那么它一定需要提供一個根文件系統(rootfs),容器需要使用這個文件系統來創建一個新的進程,所有二進制的執行都必須在這個根文件系統中。
 - 為了保證當前的容器進程沒有辦法訪問宿主機器上其他目錄,我們在這里還需要通過 libcontainer 提供的 pivot_root 或者 chroot 函數改變進程能夠訪問文件目錄的根節點。
 - chroot 的使用能夠改變當前的系統根目錄結構,通過改變當前系統的根目錄,我們能夠限制用戶的權利,在新的根目錄下並不能夠訪問舊系統根目錄的結構個文件,也就建立了一個與原系統完全隔離的目錄結構。
 
CGroups
- Control Groups(簡稱 CGroups)就是能夠隔離宿主機器上的物理資源,例如 CPU、內存、磁盤 I/O 和網絡帶寬。
 - 每一個 CGroup 都是一組被相同的標准和參數限制的進程,不同的 CGroup 之間是有層級關系的,也就是說它們之間可以從父類繼承一些用於限制資源使用的標准和參數。
 - 當我們使用 Docker 關閉掉正在運行的容器時,Docker 的子控制組對應的文件夾也會被 Docker 進程移除,Docker 在使用 CGroup 時其實也只是做了一些創建文件夾改變文件內容的文件操作,不過 CGroup 的使用也確實解決了我們限制子容器資源占用的問題,系統管理員能夠為多個容器合理的分配資源並且不會出現多個容器互相搶占資源的問題。
 - 每一個 CGroup 下面都有一個 tasks 文件,其中存儲着屬於當前控制組的所有進程的 pid,作為負責 cpu 的子系統,cpu.cfs_quota_us 文件中的內容能夠對 CPU 的使用作出限制。
 
UnionFS
- Linux 的命名空間和控制組分別解決了不同資源隔離的問題,前者解決了進程、網絡以及文件系統的隔離,后者實現了 CPU、內存等資源的隔離,但是在 Docker 中還有另一個非常重要的問題需要解決 - 也就是鏡像。
 - 使用 docker run 非常輕松地從遠程下載 Docker 的鏡像並在本地運行。
 - Docker 鏡像其實本質就是一個壓縮包,我們可以使用下面的命令將一個 Docker 鏡像中的文件導出, docker export $(docker create busybox) | tar -C rootfs -xvf -
 - Docker 中的每一個鏡像都是由一系列只讀的層組成的,Dockerfile 中的每一個命令都會在已有的只讀層上創建一個新的層, 當鏡像被 docker run 命令創建時就會在鏡像的最上層添加一個可寫的層,也就是容器層,所有對於運行時容器的修改其實都是對這個容器讀寫層的修改。
 - 容器和鏡像的區別就在於,所有的鏡像都是只讀的,而每一個容器其實等於鏡像加上一個可讀寫的層,也就是同一個鏡像可以對應多個容器。
 - AUFS 作為聯合文件系統,它能夠將不同文件夾中的層聯合(Union)到了同一個文件夾中,這些文件夾在 AUFS 中稱作分支,整個『聯合』的過程被稱為聯合掛載(Union Mount)。
 - 每一個鏡像層或者容器層都是 /var/lib/docker/ 目錄下的一個子文件夾;在 Docker 中,所有鏡像層和容器層的內容都存儲在 /var/lib/docker/aufs/diff/ 目錄中。
 - 而 /var/lib/docker/aufs/layers/ 中存儲着鏡像層的元數據,每一個文件都保存着鏡像層的元數據,最后的 /var/lib/docker/aufs/mnt/ 包含鏡像或者容器層的掛載點,最終會被 Docker 通過聯合的方式進行組裝。
 - Docker 還支持了不同的存儲驅動,包括 aufs、devicemapper、overlay2、zfs 和 vfs 等等,在最新的 Docker 中,overlay2 取代了 aufs 成為了推薦的存儲驅動,但是在沒有 overlay2 驅動的機器上仍然會使用 aufs 作為 Docker 的默認驅動。 
          
- docker info | grep Storage 查看存儲驅動
 
 - Linux 命名空間、控制組和 UnionFS 三大技術支撐了目前 Docker 的實現,也是 Docker 能夠出現的最重要原因。
 
docker 基本組件
基本組件(Docker daemon, Docker client, registry鏡像庫, image鏡像,container容器)
- 容器 = 鏡像 + 讀寫層
 - 一個倉庫會包含同一個軟件不同版本的鏡像,而標簽就常用於對應該軟件的各個版本。
 - Docker daemon 是服務器組件,以 Linux 后台服務的方式運行,是 Docker 最核心的后台進程,我們也把它稱為守護進程。它負責響應來自 Docker Client 的請求,然后將這些請求翻譯成系統調用完成容器管理操作。該進程會在后台啟動一個 API Server ,負責接收由 Docker Client 發送的請求,接收到的請求將通過Docker daemon 內部的一個路由分發調度,由具體的函數來執行請求。
 - Docker Client ,也稱 Docker 客戶端。它其實就是 Docker 提供命令行界面 (CLI) 工具,是許多 Docker 用戶與 Docker 進行交互的主要方式。
 
docker 實踐
- 編寫 Dockerfile 文件,設定 docker 編譯規則
 - docker build -t jianglong/nginx_web:v1 . 編譯時設置倉庫名,鏡像名和版本號
 - 構建完成之后,使用 docker images 命令查看所有鏡像
 - docker run --name nginx_web -d -p 8080:80 jianglong/nginx_web:v1 啟動容器
 
