看完這篇,Docker 你就入門了!
公眾號關(guān)注“杰哥的IT之旅”,
選擇“星標(biāo)”,重磅干貨,第一時(shí)間送達(dá)!

在計(jì)算機(jī)技術(shù)日新月異的今天, Docker在國內(nèi)發(fā)展的如火如荼,特別是在一線互聯(lián)網(wǎng)公司,Docker的使用是十分普遍的,在理解docker之前,我們先熟悉兩個(gè)概念,容器和虛擬機(jī)。
一、容器與虛擬機(jī)
傳統(tǒng)的虛擬機(jī)有VMware, VirtualBox ,它們需要模擬整臺機(jī)器包括硬件,每臺虛擬機(jī)都需要有自己的操作系統(tǒng),虛擬機(jī)一旦開啟,預(yù)分配給它們的資源將全部被占用。每一臺虛擬機(jī)包括應(yīng)用,必要的二進(jìn)制和庫,以及一個(gè)完整的用戶操作系統(tǒng)。
而容器技術(shù)是和我們的宿主機(jī)共享硬件資源及操作系統(tǒng),可以實(shí)現(xiàn)資源的動(dòng)態(tài)分配。容器包含應(yīng)用和其所有的依賴包,但是與其他容器共享內(nèi)核。容器在宿主機(jī)操作系統(tǒng)中,在用戶控件以分離的進(jìn)程運(yùn)行。
容器技術(shù)是實(shí)現(xiàn)操作系統(tǒng)虛擬化的一種途徑,可以讓您在資源受到隔離的進(jìn)程中運(yùn)行應(yīng)用程序及其依賴關(guān)系。通過使用容器,我們可以輕松打包應(yīng)用程序的代碼、配置和依賴關(guān)系,將其編程容易使用的構(gòu)建塊,從而實(shí)現(xiàn)環(huán)境一致性、運(yùn)營效率、開發(fā)人員生產(chǎn)力和版本控制等諸多目標(biāo)。容器幫助保證應(yīng)用程序快速、可靠、一致性部署,其間不受部署環(huán)境的影響。容器還賦予我們對資源更多的精細(xì)化控制能力,讓我們的基礎(chǔ)設(shè)施效率更高、通過下面這張圖我們可以很直觀的反映出二者的區(qū)別。

Docker屬于Linux容器的一種封裝,提供簡單易用的容器使用接口。它是目前最流行的Linux容器解決方案。
Linux容器不是模擬一個(gè)完整的操作系統(tǒng),而是對進(jìn)程進(jìn)行隔離,相當(dāng)于在正常進(jìn)程的外面套了一個(gè)保護(hù)層。對于容器里面的進(jìn)程來說,它接觸到的各種資源都是虛擬的,從而實(shí)現(xiàn)與底層系統(tǒng)的隔離。
Docker將應(yīng)用程序與該程序的依賴,打包在一個(gè)文件里。運(yùn)行這個(gè)文件,就會(huì)生成一個(gè)虛擬容器,程序在這個(gè)虛擬容器里運(yùn)行,就好像在真實(shí)的物理機(jī)上運(yùn)行一樣,有了Docker,就不用擔(dān)心環(huán)境問題。
總體來說,Docker的接口相當(dāng)簡單,用戶可以方便的創(chuàng)建和使用容器,把自己的應(yīng)用放入容器,容器還可以進(jìn)行版本管理,復(fù)制,分享,修改,就像管理代碼一樣。
二、Docker的優(yōu)勢
1、Docker啟動(dòng)快速,屬于秒級別。虛擬機(jī)通常需要幾分鐘去啟動(dòng)。
2、Docker需要的資源更少,Docker在操作系統(tǒng)級別進(jìn)行虛擬化,Docker容器和內(nèi)核交互,幾乎沒有性能損耗,性能優(yōu)于通過 Hypervisor 層與內(nèi)核層的虛擬化
3、Docker更輕量,Docker的架構(gòu)可以共用一個(gè)內(nèi)核與共享應(yīng)用程序庫,所占內(nèi)存極小。同樣的硬件環(huán)境,Docker運(yùn)行的鏡像數(shù)遠(yuǎn)低于虛擬機(jī)數(shù)量,對系統(tǒng)的利用率非常高
4、安全性, Docker的安全性也更弱。Docker的租戶root和宿主機(jī)root等同,一旦容器內(nèi)的用戶從普通用戶權(quán)限提升為root權(quán)限,它就直接具備了宿主機(jī)的root權(quán)限,進(jìn)而可進(jìn)行無限制的操作。虛擬機(jī)租戶root權(quán)限和宿主機(jī)的root虛擬機(jī)權(quán)限是分離的,并且虛擬機(jī)利用如intel的vt-d和vt-x的ring-1硬件隔離技術(shù),這種隔離技術(shù)可以防止虛擬機(jī)突破和彼此交互,而容器至今還沒有任何形式的硬件隔離,這使得容器容易受到攻擊
5、可管理性:Docker的集中化管理工具還不算成熟。各種虛擬化技術(shù)都有成熟的管理工具,例如VMware Vcentor提供完備的虛擬機(jī)管理能力
6、高可用和可恢復(fù)性:Docker對業(yè)務(wù)的高可用支持是通過快速重新部署實(shí)現(xiàn)的。虛擬化具備負(fù)載均衡,高可用,容錯(cuò),遷移和數(shù)據(jù)保護(hù)等經(jīng)過生產(chǎn)實(shí)踐檢驗(yàn)的成熟保障機(jī)制,VMware可承諾虛擬機(jī)99.9999%高可用,保證業(yè)務(wù)連續(xù)性
7、 交付、部署:虛擬機(jī)可以通過鏡像實(shí)現(xiàn)環(huán)境交付的一致性,但鏡像分發(fā)無法體系化。Docker在Dockerfile中記錄了容器構(gòu)建過程,可在集群中實(shí)現(xiàn)快速分發(fā)和快速部署
三、Docker的三個(gè)基本概念

從上圖我們可以看到,Docker中包括三個(gè)基本的概念:
Image(鏡像)
Container(容器)
Repository(倉庫)
1、鏡像是Docker運(yùn)行容器的前提,倉庫是存放鏡像的場所,可見鏡像是Docker的核心。
那么鏡像到底是什么呢?
Docker鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。
2、Container (容器)
容器的定義和鏡像幾乎一模一樣,也是一堆層的統(tǒng)一視角,唯一區(qū)別在于容器的最上面那一層是可讀可寫的。

由于容器的定義并沒有提及是否要運(yùn)行容器,所以實(shí)際上,容器 = 鏡像 + 讀寫層。
3、Repository(倉庫)
Docker倉庫是集中存放鏡像文件的場所,鏡像構(gòu)建完成后,可以很容易在當(dāng)前宿主上運(yùn)行,但是,如果需要在其他服務(wù)器上使用這個(gè)鏡像,我們需要一個(gè)集中的存儲(chǔ)、分發(fā)鏡像的服務(wù),Docker Registry(倉庫注冊服務(wù)器)就是這樣的服務(wù)。有時(shí)候會(huì)把倉庫(Repository)和倉庫注冊服務(wù)器(Registry)混為一談,并不嚴(yán)格區(qū)分。實(shí)際上,一個(gè)Docker Registry中可以包含多個(gè)倉庫(Repository),每個(gè)倉庫可以包含多個(gè)標(biāo)簽 ,每個(gè)標(biāo)簽對應(yīng)著一個(gè)鏡像。所以說,鏡像倉庫是Docker用來集中存放鏡像文件的地方類似于我們之前常用的代碼倉庫。
倉庫又可以分為兩種形式:
(1)public(共有倉庫)
Docker Registry公有倉庫是開放給用戶使用、允許用戶管理鏡像的 Registry 服務(wù)。一般這類公開服務(wù)允許用戶免費(fèi)上傳、下載公開的鏡像,并可能提供收費(fèi)服務(wù)供用戶管理私有鏡像。
(2)private(私有倉庫)
Docker官方提供了Docker Registry鏡像,可以直接使用做為私有Registry服務(wù)。當(dāng)用戶創(chuàng)建了自己的鏡像之后就可以使用push命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺機(jī)器上使用這個(gè)鏡像時(shí)候,只需要從倉庫上 pull下來就可以了。
四、Docker的架構(gòu)

Docker使用C/S架構(gòu),即客戶端/服務(wù)器體系結(jié)構(gòu)。Docker客戶端與Docker服務(wù)器進(jìn)行交互,Docker服務(wù)端負(fù)責(zé)構(gòu)建、運(yùn)行和分發(fā)Docker鏡像。Docker客戶端與服務(wù)端可以運(yùn)行在一臺機(jī)器上,也可以通過RESTful、stock或網(wǎng)絡(luò)接口與遠(yuǎn)程Docker服務(wù)端進(jìn)行通信。

這張圖展示了Docker客戶端、服務(wù)端和Docker倉庫(即Docker Hub和Docker Cloud ),默認(rèn)情況下Docker會(huì)在Docker中央倉庫尋找鏡像文件,這種利用倉庫管理鏡像的設(shè)計(jì)理念類似于Git,當(dāng)然這個(gè)倉庫是可以通過修改配置來指定的,甚至我們可以創(chuàng)建我們自己的私有倉庫。
Docker采用的是C/S架構(gòu),客戶端向服務(wù)器發(fā)送請求,服務(wù)器負(fù)責(zé)構(gòu)建、運(yùn)行和分發(fā)容器。客戶端和服務(wù)器可以運(yùn)行在同一個(gè)Host上,客戶端也可以通過socket或REST API與遠(yuǎn)程的服務(wù)器通信。
1、Docker Client
Docker客戶端其實(shí)就是Docker提供命令行界面工具,是許多Docker 用戶與Docker 進(jìn)行交互的主要方式。客戶端可以構(gòu)建、運(yùn)行和停止應(yīng)用程序,還可以遠(yuǎn)程與Docker_HOST進(jìn)行交互。最常用的Docker客戶端就是Docker命令,我們可以通過Docker命令很方便地在host上構(gòu)建和運(yùn)行Docker容器。

2、Docker Daemon
Docker Daemon是服務(wù)器組件,以Linux后臺服務(wù)的方式運(yùn)行,是Docker最核心的后臺進(jìn)程,我們也把它稱為守護(hù)進(jìn)程。它負(fù)責(zé)相應(yīng)來自Docker Client的請求,然后將這些請求翻譯成系統(tǒng)調(diào)用完成容器管理操作。該進(jìn)程會(huì)在后臺啟動(dòng)一個(gè)API Server,負(fù)責(zé)接收由Docker Client發(fā)送的請求,接收到的請求將通過Docker Daemon內(nèi)部的一個(gè)路由分發(fā)調(diào)用,由具體的函數(shù)來執(zhí)行請求。
Docker Daemon的架構(gòu)如下所示:

Docker Daemon可以認(rèn)為是通過Docker Server模塊接受Docker Client的請求,并在Engine中處理請求,然后根據(jù)請求類型,創(chuàng)建出指定的Job并運(yùn)行。Docker Daemon運(yùn)行在Docker Host上,負(fù)責(zé)創(chuàng)建、運(yùn)行、監(jiān)控容器,構(gòu)建、存儲(chǔ)鏡像。
運(yùn)行過程的作用有以下幾種可能:
向Docker Registry獲取鏡像
通過grapthdriver執(zhí)行容器鏡像的本地化操作
通過networkdriver執(zhí)行容器網(wǎng)絡(luò)環(huán)境的配置
通過execdriver執(zhí)行容器內(nèi)部運(yùn)行的執(zhí)行工作
由于Docker Daemon和Docker Client的啟動(dòng)都是通過可執(zhí)行文件Docker來完成的,因此兩者的啟動(dòng)流程非常相似。Docker可執(zhí)行文件運(yùn)行時(shí),運(yùn)行代碼通過不同的命令行flag參數(shù),區(qū)分兩者,并最終運(yùn)行兩者各自相應(yīng)的部分。
啟動(dòng)Docker Daemon時(shí),一般可以使用一下命令來完成
docker --daemon = truedocker –ddocker –d = true
再由docker的main函數(shù)來解析以上命令的相應(yīng)的flag參數(shù),并最終完成Docker Daemon的啟動(dòng)。
Docker Daemon的啟動(dòng)流程:

默認(rèn)配置下, Docker Daemon只能相應(yīng)來自本地host的客戶端請求。如果要允許遠(yuǎn)程客戶端請求,需要在配置文件中打開TCP監(jiān)聽。我們可以照著如下步驟進(jìn)行配置:
(1)編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service ,在環(huán)境變量 ExecStart后面添加 -H tcp://0.0.0.0,允許來自任意 IP 的客戶端連接。

(2)重啟 Docker Daemon
systemctl daemon-reloadsystemctl restart docker.service
(3)我們通過以下命令即可實(shí)現(xiàn)與遠(yuǎn)程服務(wù)器通信
docker -H 服務(wù)器IP地址 info
-H 是用來指定服務(wù)器主機(jī),info子命令用于查看docker服務(wù)器的信息
3、Docker Image
Docker鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如匿名卷、環(huán)境變量、用戶等)。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變。我們可將Docker鏡像看成只讀模板,通過它可以創(chuàng)建Docker容器。
鏡像有多種生成方法:
從無到有開始創(chuàng)建鏡像
下載并使用別人創(chuàng)建好的現(xiàn)成的鏡像
在現(xiàn)有鏡像上創(chuàng)建新的鏡像
我們可以將鏡像的內(nèi)容和創(chuàng)建步驟描述在一個(gè)文本文件中,這個(gè)文本文件稱作Dockerfile,通過執(zhí)行docker build
4、Docker Registry
Docker Registry是存儲(chǔ)Docker Image的倉庫,它在Docker生態(tài)環(huán)境中的位置如下圖所示:

運(yùn)行Docker Push、Docker pull、Docker search時(shí),實(shí)際上是通過 Docker Daemon與 Docker registry通信。
5、Docker Container
Docker容器就是Docker鏡像的運(yùn)行實(shí)例,是真正運(yùn)行項(xiàng)目程序、消耗系統(tǒng)資源、提供服務(wù)的地方。Docker Container提供了系統(tǒng)硬件環(huán)境,我們可以使用Docker Image這些制作好的系統(tǒng)盤,再加上我們編寫好的項(xiàng)目代碼,run一下就可以提供服務(wù)了。
五、Docker組件如何協(xié)作運(yùn)行容器
容器啟動(dòng)過程如下:
Docker客戶端執(zhí)行docker run命令
Docker Daemon發(fā)現(xiàn)本地沒有hello-world鏡像
Daemon從Docker Hub下載鏡像
下載完成,鏡像hello-world被保存到本地
Docker Daemon啟動(dòng)容器
具體過程可以看如下這幅演示圖:

我們可以通過Docker Image可以查看到hello-world已經(jīng)下載到本地

六、Docker常用命令
我們可以通過docker -h去查看命令的詳細(xì)的幫助文檔。在這里我只會(huì)講一些平常日常比賽或者生活中我們可能會(huì)用的比較多的一些命令。

例如,我們需要拉取一個(gè)docker鏡像,我們可以用如下命令:
docker pull image_name
image_name為鏡像的名稱,而如果我們想從Docker Hub上去下載某個(gè)鏡像,我們可以使用以下命令:
docker pull centos:latest
centos:lastest是鏡像的名稱,Docker daemon發(fā)現(xiàn)本地沒有我們需要的鏡像,會(huì)自動(dòng)去Docker Hub上去下載鏡像,下載完成后,該鏡像被默認(rèn)保存到/var/lib/docker目錄下。
接著我們?nèi)绻氩榭聪轮鳈C(jī)下存在多少鏡像,我們可以用如下命令:
docker images
我們要想知道當(dāng)前有哪些容器在運(yùn)行,我們可以用如下命令:
docker ps -a
-a是查看當(dāng)前所有的容器,包括未運(yùn)行的
我們該如何去對一個(gè)容器進(jìn)行啟動(dòng),重啟和停止呢?我們可以用如下命令:
docker start container_name/container_iddocker restart container_name/container_iddocker stop container_name/container_id
這個(gè)時(shí)候我們?nèi)绻脒M(jìn)入到這個(gè)容器中,我們可以使用attach命令:
docker attach container_name/container_id
那如果我們想運(yùn)行這個(gè)容器中的鏡像的話,并且調(diào)用鏡像里面的bash,我們可以使用如下命令:
docker run -t -i container_name/container_id /bin/bash
那如果這個(gè)時(shí)候,我們想刪除指定鏡像的話,由于image被某個(gè)container引用(拿來運(yùn)行),如果不將這個(gè)引用的container銷毀(刪除),那image肯定是不能被刪除。我們首先得先去停止這個(gè)容器:
然后我們用如下命令去刪除這個(gè)容器:
docker psdocker stop container_name/container_id
然后這個(gè)時(shí)候我們再去刪除這個(gè)鏡像:
docker rmi image_name
此時(shí),常用的Docker相關(guān)的命令就講到這里為止了,我們在后續(xù)的文章中還會(huì)反復(fù)地提到這些命令。
七、Dockerfile
Dockerfile是自動(dòng)構(gòu)建docker鏡像的配置文件,用戶可以使用Dockerfile快速創(chuàng)建自定義的鏡像,Dockerfile中的命令非常類似于Linux下的shell命令。
我們可以通過下面這幅圖來直觀地感受下 Docker 鏡像、容器和 Dockerfile 三者之間的關(guān)系。

我們從上圖中可以看到,Dockerfile可以自定義鏡像,通過Docker命令去運(yùn)行鏡像,從而達(dá)到啟動(dòng)容器的目的。
Dockerfile 是由一行行命令語句組成,并且支持已#開頭的注釋行。
一般來說,我們可以將Dockerfile分為四個(gè)部分:
基礎(chǔ)鏡像(父鏡像)信息指令FROM
維護(hù)者信息指令MAINTAINER
鏡像操作指令RUN、EVN、ADD和WORKER等
容器啟動(dòng)指令CMD、ENTRYPOINT和USER 等
下面是一段簡單的Dockerfile的例子:
1、從Docker Hub上pull下python 2.7的基礎(chǔ)鏡像
2、顯示維護(hù)者的信息
3、copy 當(dāng)前目錄到容器中的/app目錄下 復(fù)制本地主機(jī)的<src>(Dockerfile所在目錄的相對路徑)到容器里<dest>
4、指定工作路徑為/app
5、安裝依賴包
6、暴露5000端口
7、啟動(dòng)app
這個(gè)例子是啟動(dòng)一個(gè)Python flask app的Dockerfile(flask是Python的一個(gè)輕量級的web框架),相信大家從這個(gè)例子中能夠稍微理解了Dockerfile的組成以及指令的編寫過程。
八、構(gòu)建Dockerfile代碼實(shí)例
mkdir static_web
cd static_web
touch Dockerfile
然后 vi Dockerfile 開始編輯該文件
輸入 i 開始編輯
以下是我們構(gòu)建的Dockerfile內(nèi)容``````````FROM nginx
MAINTAINER Angel_Kitty <[email protected]>
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html``````````
編輯完后 按 esc 退出編輯
然后 :wq 寫入 退出
我們在Dockerfile文件所在目錄執(zhí)行:
docker build -t angelkitty/nginx_web:v1 .
我們解釋一下,-t是為新鏡像設(shè)置倉庫和名稱,其中angelkitty為倉庫名,nginx_web為鏡像名,:v1為標(biāo)簽(不添加為默認(rèn)latest)
我們構(gòu)建完成之后,使用docker images命令查看所有鏡像,如果存在REPOSTORY為nginx和TAG是v1的信息,就表示構(gòu)建成功。

接下來使用docker run命令來啟動(dòng)容器
docker run --name nginx_web -d -p 8080:80 angelkitty/nginx_web:v1
這條命令會(huì)用nginx鏡像啟動(dòng)一個(gè)容器,命名為nginx_web,并且映射了 8080 端口,這樣我們可以用瀏覽器去訪問這個(gè)nginx服務(wù)器:http:localhost:8080或者 http://本機(jī)的IP地址:8080/,頁面返回信息:

這樣一個(gè)簡單使用Dockerfile構(gòu)建鏡像,運(yùn)行容器的示例就完成了!
來源:OSC開源社區(qū)
推薦閱讀

