Docker的基本概念

zyhmz發表於2018-06-15

Docker和傳統虛擬化的區別
我們首先來比較一下 Docker 和傳統虛擬化方式的不同之處。傳統虛擬機器技術是虛擬出一套硬體後,在其上執行一個完整作業系統,在該系統上再執行所需應用程式;而容器內的應用程式直接執行於宿主的核心,容器內沒有自己的核心,而且也沒有進行硬體虛擬。因此容器要比傳統虛擬機器更為輕便。

使用docker的理由

  1. 更高效的利用系統資源
    由於容器不需要進行硬體虛擬以及執行完整作業系統等額外開銷,Docker 對系統資源的利用率更高。無論是應用執行速度、記憶體損耗或者檔案儲存速度,都要比傳統虛擬機器技術更高效。因此,相比虛擬機器技術,一個相同配置的主機,往往可以執行更多數量的應用。

  2. 更快速的啟動時間
    傳統的虛擬機器技術啟動應用服務往往需要數分鐘,而 Docker 容器應用,由於直接執行於宿主核心,無需啟動完整的作業系統,因此可以做到秒級、甚至毫秒級的啟動時間。大大的節約了開發、測試、部署的時間。

  3. 一致的執行環境
    開發過程中一個常見的問題是環境一致性問題。由於開發環境、測試環境、生產環境不一致,導致有些 bug 並未在開發過程中被發現。而 Docker 的映象提供了除核心外完整的執行時環境,確保了應用執行環境一致性,從而不會再出現 “這段程式碼在我機器上沒問題啊” 這類問題。

  4. 持續交付和部署
    對開發和運維(DevOps)人員來說,最希望的就是一次建立或配置,可以在任意地方正常執行。

Docker映象

我們都知道,作業系統分為核心和使用者空間。對於 Linux 而言,核心啟動後,會掛載 root 檔案系統為其提供使用者空間支援。而 Docker 映象(Image),就相當於是一個 root 檔案系統。比如官方映象 ubuntu:16.04 就包含了完整的一套 Ubuntu 16.04 最小系統的 root 檔案系統。

Docker 映象是一個特殊的檔案系統,除了提供容器執行時所需的程式、庫、資源、配置等檔案外,還包含了一些為執行時準備的一些配置引數(如匿名卷、環境變數、使用者等)。映象不包含任何動態資料,其內容在構建之後也不會被改變。

容器

映象(Image)和容器(Container)的關係,就像是物件導向程式設計中的類和例項一樣,映象是靜態的定義,容器是映象執行時的實體。容器可以被建立、啟動、停止、刪除、暫停等。

容器的實質是程式,但與直接在宿主執行的程式不同,容器程式執行於屬於自己的獨立的名稱空間。因此容器可以擁有自己的 root 檔案系統、自己的網路配置、自己的程式空間,甚至自己的使用者 ID 空間。容器內的程式是執行在一個隔離的環境裡,使用起來,就好像是在一個獨立於宿主的系統下操作一樣。這種特性使得容器封裝的應用比直接在宿主執行更加安全。也因為這種隔離的特性,很多人初學 Docker 時常常會混淆容器和虛擬機器。

在這裡提一下,映象使用的是分層儲存的技術,容器也是如此。每一個容器執行時,是以映象為基礎層,在其上建立一個當前容器的儲存層,我們可以稱這個為容器執行時讀寫而準備的儲存層為容器儲存層。

容器儲存層的生存週期和容器一樣,容器消亡時,容器儲存層也隨之消亡。因此,任何儲存於容器儲存層的資訊都會隨容器刪除而丟失。

按照 Docker 最佳實踐的要求,容器不應該向其儲存層內寫入任何資料,容器儲存層要保持無狀態化。所有的檔案寫入操作,都應該使用資料卷(Volume),或者繫結宿主目錄,在這些位置的讀寫會跳過容器儲存層,直接對宿主(或網路儲存)發生讀寫,其效能和穩定性更高。

資料卷的生存週期獨立於容器,容器消亡,資料卷不會消亡。因此,使用資料卷後,容器刪除或者重新執行之後,資料卻不會丟失。

Docker Registry(倉庫)

映象構建完成後,可以很容易的在當前宿主機上執行,但是,如果需要在其它伺服器上使用這個映象,我們就需要一個集中的儲存、分發映象的服務,Docker Registry 就是這樣的服務。

Docker Registry 公開服務是開放給使用者使用、允許使用者管理映象的 Registry 服務。一般這類公開服務允許使用者免費上傳、下載公開的映象,並可能提供收費服務供使用者管理私有映象。最常使用的 Registry 公開服務是官方的 Docker Hub,這也是預設的 Registry,並擁有大量的高質量的官方映象。

在MacOS中安裝Docker

當我們安裝好Docker之後,可以在終端中執行以下指令測試Docker是否安裝成功:

$ docker --version
Docker version 17.10.0-ce, build f4ffd25
$ docker-compose --version
docker-compose version 1.17.0-rc1, build a0f95af
$ docker-machine --version
docker-machine version 0.13.0, build 9ba6da9

如果 docker version、docker info 都正常的話,可以在docker裡面嘗試執行一個 Nginx 伺服器,雖然我們還不知道-d,-p 引數所代表的具體含義,我們後面會講到。

docker run -d -p 80:80 --name webserver nginx

要停止 Nginx 伺服器並刪除執行下面的命令:

$ docker stop webserver
$ docker rm webserver

獲取映象
我們一般使用以下指令獲取映象,這裡的Docker Registry一般是指官方映象庫:

docker pull [選項] [Docker Registry 地址[:埠號]/]倉庫名[:標籤]

所以上面的指令一般可以簡化為:

$ docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
bf5d46315322: Pull complete
9f13e0ac480c: Pull complete
e8988b5b3097: Pull complete
40af181810e7: Pull complete
e6f7c7e5c03e: Pull complete
Digest: sha256:147913621d9cdea08853f6ba9116c2e27a3ceffecf3b492983ae97c3d643fbbe
Status: Downloaded newer image for ubuntu:16.04

前面提到過分層儲存的概念,所以下載也是分層下載的,下載也是一層層的去下載,並非單一檔案。下載過程中給出了每一層的 ID 的前 12 位。並且下載結束後,給出該映象完整的 sha256 的摘要,以確保下載一致性。

在使用上面命令的時候,你可能會發現,你所看到的層 ID 以及 sha256 的摘要和這裡的不一樣。這是因為官方映象是一直在維護的,有任何新的 bug,或者版本更新,都會進行修復再以原來的標籤釋出,這樣可以確保任何使用這個標籤的使用者可以獲得更安全,更穩定的映象。

下載之後我們來執行一下這個映象:

$ docker run -it --rm \
    ubuntu:16.04 \
    bash

root@e7009c6ce357:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.4 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

這裡我們來簡單地解釋一下上面一些引數的作用:

-it:這是兩個引數,一個是 -i:互動式操作,一個是 -t 終端。我們這裡打算進入 bash 執行一些命令並檢視返回結果,因此我們需要互動式終端。
--rm:這個引數是說容器退出後隨之將其刪除。預設情況下,為了排障需求,退出的容器並不會立即刪除,除非手動 docker rm。我們這裡只是隨便執行個命令,看看結果,不需要排障和保留結果,因此使用 --rm 可以避免浪費空間。
ubuntu:16.04:這是指用 ubuntu:16.04 映象為基礎來啟動容器。
bash:放在映象名後的是命令,這裡我們希望有個互動式 Shell,因此用的是 bash。

列出映象和刪除映象
要想列出已經下載下來的映象,可以使用 docker image ls 命令。
我們還有使用 docker image ls ubuntu 命令,列出部分映象。

相關文章