深入淺出Docker( 讀書筆記1)

容器

之前的文章中已經介紹了用Docker或者說用容器的好處了,這裡將先討論容器現狀 1. Linux容器

Linux容器工具的英文名稱是LXC。現代容器技術就是起源於Linux。

  1. Windows容器

Windows上已經是能夠支持docker了。

  1. Mac容器 可以在Mac系統上使用Docker for Mac來運行Linux容器。這是通過在Mac 上啟動一個輕量級Linux VM,然後在其中無縫地運行linux容器來實現的
  2. Kubernetes(K8s) Kubernetes 是一個自動化部署,伸縮和操作應用程序容器的開源平台。

使用K8s,你可以快速,高效地滿足用戶以下的需求: 1. 快速精準地部署應用程序 2. 即時伸縮你的應用程序 3. 無縫展現新特徵 4. 限制硬體用量僅為所需資源

K8s採用Docker作為其默認容器運行時(container runtime),包括K8s啟動和停止容器,以及鏡像的拉取等。

可理解為K8s是在Docker之上的平台。

縱觀Docker

運維視角

安裝Docker時,會涉及兩個主要組件:Docker客戶端和Docker daemon(引擎,或服務端)

使用Linux默認安裝時,客戶端與daemon之間的通信是通過本地IPC/UNIX Socket完成的

可以通過Docker version命令來檢查客戶端和服務端是否都已經成功運行,並且可以互相通信。(客戶端與Docker daemon之間的通信)

鏡像(image)可以視為未運行的模版,或是處於關機狀態的虛擬機一樣的存在,也有人把鏡像比作是容器的類(class)。

容器是(Container)是鏡像的實例。工作在進程上。

開發視角

容器即應用

每個倉庫中都會包含一個名為Dockerfile的文件。Dockerfile是一個純文本文件,其中描述了如何將應用構建到Docker鏡像當中。 使用docker image build命令,根據Dockerfile中的指令來構建新的鏡像。

Docker引擎

Docker引擎是用來運行和管理容器的核心軟體。通常人們會簡單地將其代指為Docker或Docker平台。

Docker引擎是模塊化的。 其由許多專用的工具協同工作,從而可以創建和運行容器。

Docker引擎由如下主要組件構成:

  1. Docker 客戶端(Docker Client)
  2. Docker 守護進程(Docker daemon)
  3. containerd
  4. runc

共同負責容器的創建和運行

Docker引擎詳解

Docker首次發布,兩個核心組件: 1. LXC(提供對諸如命名空間(Namespace)和控制組(CGroup)等基礎工具的操作能力,基於Linux內核的容器虛擬化技術)

  1. Docker daemon(單一的二進位文件,包含諸如Docker客戶端,Docker API,容器運行時,鏡像構建等)

擺脫LXC

LXC是基於Linux的,這對於立志於跨平台的項目來說是個問題。

Docker公司開發的Libcontainer的自研工具,用於替代LXC。

擯棄大而全的Docker daemon

Docker daemon的整體性帶來很多問題

  • 難以變更
  • 運行越來越慢
  • 這並非生態(或Docker公司)所期望的

因此Docker公司開始努力拆解這個大而全的Docker daemon進程,並將其模塊化。這項任務的目標是儘可能拆解出其中的功能特性,並用小而專的工具來實現他。即模塊化。

runc

runc本質上是一個輕量級的,針對Libcontainer(就是那個取代了LXC的)進行包裝的命令行交互工具。

runc生來只有一個作用——創建容器,速度很快,但它只是一個基礎工具,並不提供類似Docker引擎所擁有的豐富功能。

containerd

在對Docker daemon的功能進行拆解後,所有的容器執行邏輯被重構到一個新的名為containerd的工具中。其主要任務是容器的生命周期管理——start | stop | pause | rm ......

最初containerd被設計為輕量級的小型工具,僅用於容器的生命周期管理。然而隨著時間的推移,它被賦予了更多的功能,比如鏡像管理。這樣便於在其他項目中使用它,比如K8s中containerd就是一個很受歡迎的容器運行時。

啟動容器

啟動容器的整個過程: 1. Docker client:向Docker API發出docker container run命令

  1. Docker daemon: 在API斷點接收指令,指示containerd啟動新容器
  2. Containerd:給runc傳遞OCI bundle(鏡像)指示runc創建容器
  3. shim和runc:創建容器

這樣的優勢是容器運行時與Docker daemon是解耦的,有時稱之為「無守護進程的容器」,如此對Docker daemon的維護和升級工作不會影響到運行中的容器。

shim

shim實現無daemon的容器以便進行daemon升級等操作。

前面提到,containerd會指揮runc來創建容器。事實上,每次創建容器時它都會fork一個新的runc實例。不過一旦容器創建完畢,對應的runc進程就會退出。因此,即使運行上百上千個容器,也無須上百上千個runc實例。

一旦容器進程的父進程runc退出,相關聯的containerd-shim進程就會成為容器的父進程。(生父走了,養父來了)。

作為容器的父進程,shim的部分職責: 1. 保持所有STDIN和STDOUT流是開啟狀態的,從而當daemon重啟時,不會因為管道(pipe)的關閉而終止 2. 將容器退出的狀態返回給daemon

daemon的作用

當所有的執行邏輯和運行時代碼都從daemon中剝離出來之後,daemon主要功能就是鏡像管理,鏡像構建,REST API,身份驗證,安全,核心網路以及編排。

Docker鏡像

Docker鏡像通常比較小,通常Docker鏡像中只有一個精簡的Shell,甚至沒有Shell。鏡像中還不包含內核——容器都是共享在所在Docker主機的內核。所以有時會說容器僅包含必要的操作系統(通常只有操作系統文件和文件系統對象)

拉取鏡像

常常用的是docker image pull : 的方式,默認的版本號是latest 注意latest不一定比其他版本的新。

過濾docker image ls的輸出內容

$ docker image ls --filter dangling=true

那些沒有標籤的鏡像被成為懸虛鏡像,在列表中展示為:(倉庫名:tag).通常出現這種情況,是因為構建了有一個新鏡像,然後我為該鏡像打了一個已經存在標籤。因為Docker構建新鏡像的時候會發現已有鏡像有相同標籤,這時Docker會移除舊鏡像的標籤,將該標籤打在新鏡像上。

Docker目前支持的過濾器:

  1. dangling:可以指定true或者false,僅返回懸虛鏡像(true),或者非懸虛鏡像(false)
  2. before:需要鏡像名稱或者ID作為參數,返回在之前被創建的全部鏡像
  3. since:與before類似,不過返回的是指定鏡像之後創建的全部鏡像
  4. label:根據標註(label)的名稱或者值,對鏡像進行過濾。docker image ls 命令輸出中不顯示標註內容。
  5. 還有reference的過濾方式

如:

docker image ls --filter=reference="*:latest"

鏡像和分層

Docker鏡像由一些松耦合的只讀鏡像層組成。

Docker負責堆疊這些鏡像層,並且將他們表示為單一統一的對象。

一種查看鏡像分層的方式是通過docker image inspect命令。 如

docker image inspect ubuntu:latest

注意: docker history 命令顯示了鏡像的構建歷史記錄,但其並不是嚴格意義上的鏡像分層。

刪除鏡像

docker image rm 鏡像名

Docker 容器

容器就是鏡像運行時實例。

啟動容器

docker container run <image> <app>

指定了啟動所需的鏡像以及要運行的應用。

如: docker container run -it ubuntu /bin/bash

則會啟動某個ubuntu Linux容器,並運行Bash Shell作為其應用。 其中參數-it表示將當前終端連接到容器的Shell終端上。

容器進程

啟動Ubuntu容器時,讓容器運行Bash Shell。這是的Bash Shell成為容器中運行的且唯一運行的進程。

這意味著一旦輸入exit退出 Bash Shell,那麼容器就會退出(終止)。原因是容器如果不運行任何進程則無法存在——殺死Bash Shell即殺死了容器的唯一運行進程。 殺死容器中的主進程,則容器也會被殺死

而按下Ctrl-PQ組合鍵會退出容器但並不終止容器運行。這樣做會切回到Docker 主機的shell,並保持容器在後台運行。可以用docker container ls命令查看當前系統正在運行的容器列表。

當容器仍在運行,並且可以通過docker container exec命令將終端重新連接到Docker。

優雅地停止容器

docker container stop <容器名>
docker container rm <容器名>

容器生命周期

  1. 創建
  2. 運行
  3. 休眠
  4. 銷毀

利用重啟策略進行容器的自我修復

通常建議在運行容器時配置好重啟策略。這是容器的一種自我修復能力,可以在指定事件或者錯誤後重啟來完成自我修復。

重啟策略應用於每個容器,可以作為參數被強制傳入 docker-container run命令中,

docker container run --name neversaydie -it --restart always alpine sh

如果此時用exit退出

然後用docker container ls觀察一下的話,可以看到容器在輸入退出命令時被殺死了,然後Docker 又重新啟動了該容器

--restart always 策略有一個很有意思的特性,當daemon重啟的時候,停止的容器也會被重啟。

例如,新創建一個容器並指定 --restart always策略,然後通過docker container stop命令停止該容器。現在容器處於Stopped(Exited)狀態。但是,如果重啟Docker daemon,當daemon啟動完成時,該容器也會重新啟動。

還有一個叫restart unless-stopped的,它不會在docker daemon 重啟的時候被重啟。

快速清理Docker主機上的全部運行容器

這種處理方式會強制刪除所有的容器,並且不會給容器完成清理的機會。所以這種操作一定不能在生產環境系統或者運行著重要容器的系統上執行。

docker container rm $(docker container ls -aq) -f

推薦閱讀:

相关文章