淺嘗docker

作者:拔劍少年

簡書地址:http://www.itdecent.cn/u/dad4d9675892
博客地址:https://it18monkey.github.io
轉(zhuǎn)載請注明出處

什么是docker

? 我們先來看下官方給出的說法

Package Software into Standardized Units for Development, Shipment and Deployment

? docker是一個工具,一個用于軟件打包的工具。那這個打包工具有什么特殊的呢,他能將運行一個應用所需要的所有東西,包括程序代碼、系統(tǒng)工具、系統(tǒng)庫和系統(tǒng)設(shè)置都打成一個包。這個包被稱之為容器。

我個人更傾向于將他描述為一個輕量級的虛擬機,因為它和虛擬機有著很多相似之處。

docker與虛擬機的區(qū)別

虛擬機結(jié)構(gòu)示意
Docker結(jié)構(gòu)示意

上面兩幅圖展示了用虛擬機和docker運行程序的大體結(jié)構(gòu)。讓我們從下往上來對比。

先看虛擬機這邊:

最底層是某種類型的基礎(chǔ)設(shè)施,可能是一臺個人電腦,或者是服務(wù)器。往上,是一個名為hypervisor的虛擬機管理程序,在這之上運行客戶操作系統(tǒng),也就是虛擬系統(tǒng),每個虛擬系統(tǒng)都是相互隔離的。然后,所有的應用程序都運行在虛擬系統(tǒng)上。這里提下,虛擬機也是可以運行在操作系統(tǒng)上的。它分為兩種,一種直接運行在系統(tǒng)硬件上,創(chuàng)建硬件全仿真實例,被稱為裸機型。一種運行在傳統(tǒng)操作系統(tǒng)上,同樣創(chuàng)建的是硬件全仿真實例,被稱為“托管(宿主)”型。

再看docker這邊:

最底層和虛擬機一樣,是某種類型的基礎(chǔ)設(shè)施,可能是一臺個人電腦,或者是服務(wù)器。往上是一個宿主操作系統(tǒng),可能是windows或者是linux。也就是說docker不能直接運行在系統(tǒng)硬件上。目前來說支持linux和windows。在這個宿主操作系統(tǒng)上,我們安裝一個docker,而我們的應用程序全部都運行在docker上,由docker來統(tǒng)一管理。每個應用程序都是相互隔離的。

docker和虛擬機最大的區(qū)別就是他們的隔離級別不同。虛擬機是硬件級別的隔離,而docker只到進程級別。這一點也比較影響我們選擇使用docker或是虛擬機。當然他們也不是互斥的,完全可以根據(jù)實際需要相互結(jié)合。

為什么要用docker

作為一種新興的虛擬化方式,Docker 跟傳統(tǒng)的虛擬化方式相比具有眾多的優(yōu)勢。

  • 更高效的利用系統(tǒng)資源
  • 更快速的啟動時間
  • 一致的運行環(huán)境
  • 持續(xù)交付和部署
  • 更輕松的遷移
  • 更輕松的維護和擴展

docker基本概念

  1. 鏡像

我們都知道,操作系統(tǒng)分為內(nèi)核和用戶空間。對于 Linux 而言,內(nèi)核啟動后,會掛載 root 文件系統(tǒng)為其提供用戶空間支持。而 Docker 鏡像(Image),就相當于是一個 root 文件系統(tǒng)。比如官方鏡像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系統(tǒng)的 root 文件系統(tǒng)。

Docker 鏡像是一個特殊的文件系統(tǒng),除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(shù)(如匿名卷、環(huán)境變量、用戶等)。鏡像不包含任何動態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會被改變。

  1. 容器

鏡像( Image )和容器( Container )的關(guān)系,就像是面向?qū)ο蟪绦蛟O(shè)計中的類 和 實例 一樣,鏡像是靜態(tài)的定義,容器是鏡像運行時的實體。容器可以被創(chuàng)建、啟動、停止、刪除、暫停等。

  1. 倉庫

鏡像構(gòu)建完成后,可以很容易的在當前宿主機上運行,但是,如果需要在其它服務(wù)器上使用這個鏡像,我們就需要一個集中的存儲、分發(fā)鏡像的服務(wù),DockerRegistry 就是這樣的服務(wù)。一個 Docker Registry 中可以包含多個倉庫( Repository );每個倉庫可以包含多個標簽( Tag );每個標簽對應一個鏡像。

通常,一個倉庫會包含同一個軟件不同版本的鏡像,而標簽就常用于對應該軟件的各個版本。我們可以通過 <倉庫名>:<標簽> 的格式來指定具體是這個軟件哪個版本的鏡像。如果不給出標簽,將以 latest 作為默認標簽。

Docker Registry 分為公開和私有兩種,用戶可以根據(jù)自己的需要搭配使用。

Docker常用命令

鏡像倉庫操作

  • docker login/logout

    登陸/登出到一個Docker鏡像倉庫,如果未指定鏡像倉庫地址,默認為官方倉庫 Docker Hub。

    格式:docker login [選項][SERVER] ,docker logout [選項][SERVER]。

  • docker pull

    從Docker Registry獲取鏡像。格式:docker pull [選項][Docker Registry 地址[:端口號]/]倉庫名[:標簽]。

  • docker push

    將本地的鏡像上傳到鏡像倉庫,要先登陸到鏡像倉庫。格式:docker push [選項] 倉庫名[:標簽]

  • docker search

    從Docker Hub查找鏡像。格式docker search [選項] 關(guān)鍵字

鏡像操作

  • docker images

    列出本地鏡像。格式:docker images [選項][倉庫名[:標簽]]。

  • docker run

    創(chuàng)建一個新的容器并運行一個命令。格式:docker run [選項] 鏡像名[命令][參數(shù)]。

  • docker rmi

    刪除本地一個或多少鏡像。格式:docker rmi [選項] 鏡像名[鏡像名...]。

  • docker build

    使用 Dockerfile 創(chuàng)建鏡像。格式:docker build [選項] 路徑 | URL | -。

  • docker history
    查看指定鏡像的創(chuàng)建歷史。格式:docker history [選項] 鏡像名。

容器操作

  • docker ps
    列出容器。格式:docker ps [選項]。

  • docker inspect

    獲取容器/鏡像的元數(shù)據(jù)。docker inspect [選項] 名稱|ID。

  • docker start/stop/restart
    docker start :啟動一個或多個已經(jīng)被停止的容器。格式:docker start [選項] 容器名[ [容器名...]]
    docker stop :停止一個運行中的容器。docker stop [選項] 容器名[ [容器名...]]。
    docker restart :重啟容器。docker restart [選項] 容器名[ [容器名...]]

  • docker kill
    殺掉一個運行中的容器。docker kill [選項] 容器名 [容器名...]

  • docker rm
    刪除一個或多個容器。docker rm [選項] 容器名[容器名...]

技術(shù)要點

  1. UnionFS與鏡像分層存儲

    所謂UnionFS就是把不同物理位置的目錄合并mount到同一個目錄中。UnionFS的一個最主要的應用是,把一張CD/DVD和一個硬盤目錄給聯(lián)合mount在一起,然后,你就可以對這個只讀的CD/DVD上的文件進行修改(當然,修改的文件存于硬盤上的目錄里)。

    UnionFS主要有以下幾種實現(xiàn):aufs,overlayfs。下圖展示了overlayfs的基本結(jié)構(gòu)

docker-overlay.jpg

其中l(wèi)ower dirA / lower dirB目錄和upper dir目錄為來自底層文件系統(tǒng)的不同目錄,用戶可以自行指定,內(nèi)部包含了用戶想要合并的文件和目錄,merge dir目錄為掛載點。當文件系統(tǒng)掛載后,在merge目錄下將會同時看到來自各lower和upper目錄下的內(nèi)容,并且用戶也無法(無需)感知這些文件分別哪些來自lower dir,哪些來自upper dir,用戶看見的只是一個普通的文件系統(tǒng)根目錄而已(lower dir可以有多個也可以只有一個)。

雖然overlayfs將不同的各層目錄進行合并,但是upper dir和各lower dir這幾個不同的目錄并不完全等價,存在層次關(guān)系。首先當upper dir和lower dir兩個目錄存在同名文件時,lower dir的文件將會被隱藏,用戶只能看見來自upper dir的文件,然后各個lower dir也存在相同的層次關(guān)系,較上層屏蔽叫下層的同名文件。除此之外,如果存在同名的目錄,那就繼續(xù)合并(lower dir和upper dir合并到掛載點目錄其實就是合并一個典型的例子)。

各層目錄中的upper dir是可讀寫的目錄,當用戶通過merge dir向時其中一個來自upper dir的文件寫入數(shù)據(jù)時,那數(shù)據(jù)將直接寫入upper dir下原來的文件中,刪除文件也是同理;而各lower dir則是只讀的,在overlayfs掛載后無論如何操作merge目錄中對應來自lower dir的文件或目錄,lower dir中的內(nèi)容均不會發(fā)生任何的改變。當用戶想要往來自lower層的文件添加或修改內(nèi)容時,overlayfs首先會的拷貝一份lower dir中的文件副本到upper dir中,后續(xù)的寫入和修改操作將會在upper dir下的copy-up的副本文件中進行,lower dir原文件被隱藏。

以上就是overlayfs最基本的特性,簡單的總結(jié)為以下3點:

(1)上下層同名目錄合并;

(2)上下層同名文件覆蓋;

(3)lower dir文件寫時拷貝。

這三點對用戶都是無感知的。

  1. Linux Namespace

    為了提供更加精細的資源分配管理機制,Linux給出了namespace解決方法。Docker利用這一技術(shù)實現(xiàn)了容器運行環(huán)境的隔離。

    linux內(nèi)核實現(xiàn)了六種namespace。列表如下:

    namespace 引入的相關(guān)內(nèi)核版本 被隔離的全局系統(tǒng)資源 在容器語境下的隔離效果
    Mount namespaces Linux 2.4.19 文件系統(tǒng)掛接點 每個容器能看到不同的文件系統(tǒng)層次結(jié)構(gòu)
    UTS namespaces Linux 2.6.19 主機名和域名 每個容器可以有自己的 主機名和 域名
    IPC namespaces Linux 2.6.19 特定的進程間通信資源,包括System V IPC和 POSIX message queues 每個容器有其自己的 System V IPC 和 POSIX 消息隊列文件系統(tǒng),因此,只有在同一個 IPC namespace 的進程之間才能互相通信
    PID namespaces Linux 2.6.24 進程 ID 數(shù)字空間 每個 PID namespace 中的進程可以有其獨立的 PID; 每個容器可以有其 PID 為 1 的root 進程;也使得容器可以在不同的宿主機之間遷移,因為 namespace 中的進程 ID 和 宿主機無關(guān)了。這也使得容器中的每個進程有兩個PID:容器中的 PID 和宿主機上的 PID。
    Network namespaces 始于Linux 2.6.24 完成于 Linux 2.6.29 網(wǎng)絡(luò)相關(guān)的系統(tǒng)資源 每個容器用有其獨立的網(wǎng)絡(luò)設(shè)備,IP 地址,IP 路由表,/proc/net 目錄,端口號等等。這也使得一個 宿主機 上多個容器內(nèi)的同一個應用都綁定到各自容器的 80 端口上。
    User namespaces 始于 Linux 2.6.23 完成于 Linux 3.8) 用戶和組 ID 空間 在 user namespace 中的進程的用戶和組 ID 可以和在宿主機上不同; 每個 container 可以有不同的 user 和 group id;一個宿主機上的非特權(quán)用戶可以成為 user namespace 中的特權(quán)用戶;

    Linux namespace 的概念說簡單也簡單說復雜也復雜。簡單來說,我們只要知道,處于某個 namespace
    中的進程,能看到獨立的它自己的隔離的某些特定系統(tǒng)資源;復雜來說,可以去看看 Linux 內(nèi)核中實現(xiàn) namespace 的原理。

  2. Linux CGroups

    Docker 容器使用 linux namespace 來隔離其運行環(huán)境,使得容器中的進程看起來就像愛一個獨立環(huán)境中運行一樣。但是,光有運行環(huán)境隔離還不夠,因為這些進程還是可以不受限制地使用系統(tǒng)資源,比如網(wǎng)絡(luò)、磁盤、CPU以及內(nèi)存等。因此,為了讓容器中的進程更加可控,Docker 使用 Linux cgroups 來限制容器中的進程允許使用的系統(tǒng)資源。

    目前 docker 已經(jīng)幾乎支持了所有的 cgroups 資源,可以限制容器對包括 network,device,cpu 和memory 在內(nèi)的資源的使用

    我們可以通過給docker run 命令傳參來控制分配容器的資源。Docker run 命令中 cgroups 相關(guān)命令如下:

    block IO:
    --blkio-weight value          Block IO (relative weight), between 10 and 1000
    --blkio-weight-device value   Block IO weight (relative device weight) (default [])
    --cgroup-parent string        Optional parent cgroup for the container
    CPU:
    --cpu-percent int             CPU percent (Windows only)
    --cpu-period int              Limit CPU CFS (Completely Fair Scheduler)period
    --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
    -c, --cpu-shares int          CPU shares (relative weight)
    --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
    --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
    Device:    
    --device                      Add a host device to the container
    --device-cgroup-rule          Add a rule to the cgroup allowed devices list
    --device-read-bps             Limit read rate (bytes per second) from a device
    --device-read-iops            Limit read rate (IO per second) from a device
    --device-write-bps            Limit write rate (bytes per second) to a device
    --device-write-iops           Limit write rate (IO per second) to a device
    Memory:      
    --kernel-memory string        Kernel memory limit
    --memory , -m                 Memory limit
    --memory-reservation          Memory soft limit
    --memory-swap                 Swap limit equal to memory plus swap: ‘-1’ to enable unlimited swap
    --memory-swappiness           Tune container memory swappiness (0 to 100)
    

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容