10分鐘瞭解Docker,運維和開發視角有什麼不一樣?

attachments-2020-07-ZFK1GvHR5f0ec2ec122b2.png

本文從下面兩部份內容講解Docker。node

  • 運維(Ops)視角。
  • 開發(Dev)視角。

在運維視角中,主要包括下載鏡像、運行新的容器、登陸新容器、在容器內運行命令,以及銷燬容器。linux

在開發視角中,更多關注與應用相關的內容。《深刻淺出Docker內》會從GitHub拉取一些應用代碼,解釋其中的Dockerfile,將應用容器化,並在容器中運行它們。nginx

經過上面兩部份內容,你能夠從總體上理解Docker到底是什麼,以及主要組件之間是如何相互配合的。推薦讀者對開發和運維兩部份內容都要閱讀。web

1.1 運維視角

當讀者安裝Docker的時候,會涉及兩個主要組件:Docker客戶端和Docker daemon(有時也被稱爲「服務端」或者「引擎」)。docker

daemon實現了Docker引擎的API。shell

使用Linux默認安裝時,客戶端與daemon之間的通訊是經過本地IPC/UNIX Socket完成的(/var/run/docker.sock);在Windows上是經過名爲npipe:////./pipe/docker_engine的管道(pipe)完成的。讀者可使用docker version命令來檢測客戶端和服務端是否都已經成功運行,而且能夠互相通訊。npm

1> docker version
 2Client:
 3 Version:       18.01.0-ce
 4 API version:   1.35
 5 Go version:    go1.9.2
 6 Git commit:    03596f5
 7 Built: Wed Jan 10 20:11:05 2018
 8 OS/Arch:       linux/amd64
 9 Experimental:  false
10 Orchestrator:  swarm
11
12Server:
13 Engine:
14  Version:      18.01.0-ce
15  API version:  1.35 (minimum version 1.12)
16  Go version:   go1.9.2
17  Git commit:   03596f5
18  Built:        Wed Jan 10 20:09:37 2018
19  OS/Arch:      linux/amd64
20  Experimental: false

若是讀者能成功獲取來自客戶端和服務端的響應,那麼能夠繼續後面的操做。若是讀者正在使用 Linux,而且服務端返回了異常響應,則可嘗試在命令的前面加上 sudo——sudo docker version。若是加上sudo以後命令正常運行,那麼讀者須要將當前用戶加入到docker用戶組,或者給本書後面的命令都加上sudo前綴。json

1.1.1 鏡像ubuntu

將Docker鏡像理解爲一個包含了OS文件系統和應用的對象會頗有幫助。若是讀者實際操做過,就會認爲與虛擬機模板相似。虛擬機模板本質上是處於關機狀態的虛擬機。在Docker世界中,鏡像實際上等價於未運行的容器。若是讀者是一名開發者,能夠將鏡像比做類(Class)。瀏覽器

在Docker主機上運行docker image ls命令。

1$ docker image ls
2REPOSITORY    TAG     IMAGE ID     CREATED     SIZE

若是讀者運行命令環境是剛完成Docker安裝的主機,或者是Play With Docker,那麼Docker主機中應當沒有任何鏡像,命令輸出內容會如上所示。

在Docker主機上獲取鏡像的操做被稱爲拉取(pulling)。若是使用Linux,那麼會拉取ubuntu:latest鏡像;若是使用Windows,則會拉取microsoft/powershell:nanoserver鏡像。

1latest: Pulling from library/ubuntu
250aff78429b1: Pull complete
3f6d82e297bce: Pull complete
4275abb2c8a6f: Pull complete
59f15a39356d6: Pull complete
6fc0342a94c89: Pull complete
7Digest: sha256:fbaf303...c0ea5d1212
8Status: Downloaded newer image for ubuntu:latest

再次運行docker image ls命令來查看剛剛拉取的鏡像。

1$ docker images
2REPOSITORY       TAG      IMAGE ID       CREATED       SIZE
3ubuntu           latest   00fd29ccc6f1   3 weeks ago   111MB

關於鏡像的存儲位置以及鏡像內部構成,本書會在後續的章節中詳細介紹。如今,讀者只需知道鏡像包含了基礎操做系統,以及應用程序運行所需的代碼和依賴包。剛纔拉取的ubuntu鏡像有一個精簡版的Ubuntu Linux文件系統,其中包含部分Ubuntu經常使用工具。而Windows示例中拉取的microsoft/powershell鏡像,則包含了帶有PowerShell的Windows Nano Server操做系統。

若是拉取了如nginx或者microsoft/iis這樣的應用容器,則讀者會獲得一個包含操做系統的鏡像,而且在鏡像中還包括了運行Nginx或IIS所需的代碼。

重要的是,Docker的每一個鏡像都有本身的惟一ID。用戶能夠經過引用鏡像的ID或名稱來使用鏡像。若是用戶選擇使用鏡像ID,一般只須要輸入ID開頭的幾個字符便可——由於ID是惟一的,Docker知道用戶想引用的具體鏡像是哪一個。

1.1.2 容器

到目前爲止,讀者已經擁有一個拉取到本地的鏡像,可使用docker container run命令從鏡像來啓動容器。

在Linux中啓動容器的命令以下。

1$ docker container run -it ubuntu:latest /bin/bash
2root@6dc20d508db0:/#

在Windows中啓動容器的命令以下。

1> docker container run -it microsoft/powershell:nanoserver pwsh.exe
2
3Windows PowerShell
4Copyright (C) 2016 Microsoft Corporation. All rights reserved.
5PS C:\>

仔細觀察上面命令的輸出內容,會注意到每一個實例中的提示符都發生了變化。這是由於-it參數會將Shell切換到容器終端——如今已經位於容器內部了!

接下來分析一下docker container run命令。docker container run告訴Docker daemon啓動新的容器。其中-it參數告訴Docker開啓容器的交互模式並將讀者當前的Shell鏈接到容器終端(在容器章節中會詳細介紹)。接下來,命令告訴Docker,用戶想基於ubuntu:latest鏡像啓動容器(若是用戶使用Windows,則是基於microsoft/powershell:nanoserver鏡像)。最後,命令告訴Docker,用戶想要在容器內部運行哪一個進程。對於Linux示例來講是運行Bash Shell,對於Windows示例來講則是運行PowerShell。

在容器內部運行ps命令查看當前正在運行的所有進程。

Linux示例以下。

1root@6dc20d508db0:/# ps -elf
2F S UID    PID  PPID   NI ADDR SZ WCHAN  STIME TTY  TIME CMD
34 S root     1     0    0 -  4560 wait   13:38 ?    00:00:00 /bin/bash
40 R root     9     1    0 -  8606 -      13:38 ?    00:00:00 ps -elf

Windows示例以下。

1PS C:\> ps
 2
 3Handles   NPM(K)   PM(K)   WS(K)   CPU(s)     Id   SI ProcessName
 4-------   ------   -----   -----   ------     --   -- -----------
 5      0        5     964    1292     0.00   4716    4 CExecSvc
 6      0        5     592     956     0.00   4524    4 csrss
 7      0        0       0       4               0    0 Idle
 8      0       18    3984    8624     0.13    700    4 lsass
 9      0       52   26624   19400     1.64   2100    4 powershell
10      0       38   28324   49616     1.69   4464    4 powershell
11      0        8    1488    3032     0.06   2488    4 services
12      0        2     288     504     0.00   4508    0 smss
13      0        8    1600    3004     0.03    908    4 svchost
14      0       12    1492    3504     0.06   4572    4 svchost
15      0       15   20284   23428     5.64   4628    4 svchost
16      0       15    3704    7536     0.09   4688    4 svchost
17      0       28    5708    6588     0.45   4712    4 svchost
18      0       10    2028    4736     0.03   4840    4 svchost
19      0       11    5364    4824     0.08   4928    4 svchost
20      0        0     128     136    37.02      4    0 System
21      0        7     920    1832     0.02   3752    4 wininit
22      0        8    5472   11124     0.77   5568    4 WmiPrvSE

Linux容器中僅包含兩個進程。

  • PID 1:表明/bin/bash進程,該進程是經過docker container run命令來通知容器運行的。
  • PID 9:表明ps -elf進程,查看當前運行中進程所使用的命令/程序。

命令輸出中展現的ps -elf進程存在必定的誤導,由於這個程序在ps命令退出後就結束了。這意味着容器內長期運行的進程其實只有/bin/bash。

Windows 容器運行中的進程會更多,這是由 Windows 操做系統工做方式決定的。雖然Windows容器中的進程比Linux容器要多,但與常見的Windows服務器相比,其進程數量倒是明顯偏少的。

按Ctrl-PQ組合鍵,能夠在退出容器的同時還保持容器運行。這樣Shell就會返回到Docker主機終端。能夠經過查看Shell提示符來確認。

如今讀者已經返回到Docker主機的Shell提示符,再次運行ps命令。

Linux示例以下。

1$ ps -elf
2F S UID       PID  PPID    NI ADDR SZ WCHAN  TIME CMD
34 S root        1     0     0 -  9407 -      00:00:03 /sbin/init
41 S root        2     0     0 -     0 -      00:00:00 [kthreadd]
51 S root        3     2     0 -     0 -      00:00:00 [ksoftirqd/0]
61 S root        5     2     -20     0 -      00:00:00 [kworker/0:0H]
71 S root        7     2    -0 -     0 -      00:00:00 [rcu_sched]
8<Snip>
90 R ubuntu  22783 22475     0 -  9021 -      00:00:00 ps -elf

Windows示例以下。

1> ps
 2Handles   NPM(K)    PM(K)    WS(K)    CPU(s)     Id  SI ProcessName
 3-------   ------    -----    -----    ------     --  -- -----------
 4    220       11     7396     7872      0.33   1732   0 amazon-ssm-agen
 5     84        5      908     2096      0.00   2428   3 CExecSvc
 6     87        5      936     1336      0.00   4716   4 CExecSvc
 7    203       13     3600    13132      2.53   3192   2 conhost
 8    210       13     3768    22948      0.08   5260   2 conhost
 9    257       11     1808      992      0.64    524   0 csrss
10    116        8     1348       580     0.08    592   1 csrss
11     85        5      532      1136     0.23   2440   3 csrss
12    242       11     1848       952     0.42   2708   2 csrss
13     95        5      592       980     0.00   4524   4 csrss
14    137        9     7784      6776     0.05   5080   2 docker
15    401       17    22744     14016    28.59   1748   0 dockerd
16    307       18    13344      1628     0.17    936   1 dwm
17    <SNIP>
18   1888        0      128       136    37.17      4   0 System
19    272       15     3372      2452     0.23   3340   2 TabTip
20     72        7     1184         8     0.00   3400   2 TabTip32
21    244       16     2676      3148     0.06   1880   2 taskhostw
22    142        7     6172      6680     0.78   4952   3 WmiPrvSE
23    148        8     5620     11028     0.77   5568   4 WmiPrvSE

能夠看到與容器相比,Docker主機中運行的進程數要多不少。Windows容器中運行的進程要遠少於Windows主機,Linux容器中的進程數也遠少於Linux主機。

在以前的步驟當中,是使用Ctrl-PQ組合鍵來退出容器的。在容器內部使用該操做能夠退出當前容器,但不會殺死容器進程。讀者能夠經過docker container ls命令查看系統內所有處於運行狀態的容器。

1$ docker container ls
2CONTAINER ID   IMAGE          COMMAND      CREATED  STATUS    NAMES
3e2b69eeb55cb   ubuntu:latest  "/bin/bash"  7 mins   Up 7 min  vigilant_borg

上述的輸出顯示只有一個運行中的容器。這就是前面示例中建立的那個容器。輸出中有該容器,證實了容器在退出後依然是運行的。讀者能夠看到這個進程是7min以前建立的,而且一直在運行。

1.1.3 鏈接到運行中的容器

執行docker container exec命令,能夠將Shell鏈接到一個運行中的容器終端。由於以前示例中的容器仍在運行,因此下面的示例會建立到該容器的新鏈接。

Linux示例以下。

1$ docker container exec -it vigilant_borg bash
2root@e2b69eeb55cb:/#

示例中的容器名爲「vigilant_brog」。讀者環境中的容器名稱會不一樣,因此請記得將「vigilant_brog」替換爲本身Docker主機上運行中的容器名稱或者ID。

Windows示例以下。

1> docker container exec -it pensive_hamilton pwsh.exe
2
3Windows PowerShell
4Copyright (C) 2016 Microsoft Corporation. All rights reserved.
5PS C:\>

本例中使用的容器爲「pensive_hamilton」。一樣,讀者環境中的容器名稱會不一樣,因此請記得將「pensive_hamilton」替換爲本身Docker主機上運行中的容器名稱或者ID。

注意,Shell提示符又發生了變化。此時已登陸到了容器內部。

docker container exec命令的格式是docker container exec <options><container-name or container-id> <command/app>。在示例中,將本地Shell鏈接到容器是經過-it參數實現的。本例中使用名稱引用容器,而且告訴Docker運行Bash Shell(在Windows示例中是PowerShell)。使用十六進制ID的方式也能夠很容易地引用具體容器。

再次使用Ctrl-PQ組合鍵退出容器。

Shell提示符應當退回到Docker主機中。

再次運行docker container ls命令來確認容器仍處於運行狀態。

1$ docker container ls
2CONTAINER ID   IMAGE          COMMAND      CREATED  STATUS    NAMES
3e2b69eeb55cb   ubuntu:latest  "/bin/bash"  9 mins   Up 9 min  vigilant_borg

經過docker container stop和docker container rm命令來中止並殺死容器。切記須要將示例中的名稱/ID替換爲讀者本身的容器對應的名稱和ID。

1$ docker container stop vigilant_borg
2vigilant_borg
3
4$ docker container rm vigilant_borg
5vigilant_borg

經過運行docker container ls命令,並指定-a參數來確認容器已經被成功刪除。添加-a的做用是讓Docker列出全部容器,甚至包括那些處於中止狀態的。

1$ docker container ls -a
2CONTAINER ID    IMAGE    COMMAND    CREATED    STATUS    PORTS    NAMES

1.2 開發視角

容器即應用!

在本節中,會分析一份應用代碼中的Dockerfile並將其容器化,最終以容器的方式運行。相關代碼可從本書配套資源或個人Github主頁中獲取。

本節接下來的內容會基於 Linux 示例進行演示。但其實兩個示例中都容器化了相同的Web 應用代碼,因此步驟也是同樣的。

進入到倉庫文件目錄之下,查看其內容。

1$ cd psweb
 2$ ls -l
 3total 28
 4-rw-rw-r-- 1 ubuntu ubuntu  341 Sep 29 12:15 app.js
 5-rw-rw-r-- 1 ubuntu ubuntu  216 Sep 29 12:15 circle.yml
 6-rw-rw-r-- 1 ubuntu ubuntu  338 Sep 29 12:15 Dockerfile
 7-rw-rw-r-- 1 ubuntu ubuntu  421 Sep 29 12:15 package.json
 8-rw-rw-r-- 1 ubuntu ubuntu  370 Sep 29 12:15 README.md
 9drwxrwxr-x 2 ubuntu ubuntu 4096 Sep 29 12:15 test
10drwxrwxr-x 2 ubuntu ubuntu 4096 Sep 29 12:15 views

對於Windows示例,讀者須要cd到dotnet-docker-samples\aspnetapp目錄當中。

Linux的示例是一個簡單的Node.js Web應用。Windows示例是一個簡單的[http://ASP.NET]Web應用。

每一個倉庫中都包含一個名爲Dockerfile的文件。Dockerfile是一個純文本文件,其中描述瞭如何將應用構建到Docker鏡像當中。

查看Dockerfile的所有內容。

1$ cat Dockerfile
 2
 3FROM alpine
 4LABEL maintainer="nigelpoulton@hotmail.com"
 5RUN apk add --update nodejs nodejs-npm
 6COPY . /src
 7WORKDIR /src
 8RUN  npm install
 9EXPOSE  8080
10ENTRYPOINT ["node", "./app.js"]

Windows示例中的Dockerfile內容會有所不一樣。可是,這些區別在現階段並不重要。關於Dockerfile的更多細節本書會在接下來的章節中進行詳細介紹。如今,只須要知道Dockerfile的每一行都表明一個用於構建鏡像的指令便可。

使用docker image build命令,根據Dockerfile中的指令來建立新的鏡像。示例中新建的Docker鏡像名爲test:latest。

必定要在包含應用代碼和Dockerfile的目錄下執行這些命令。

1$ docker image build -t test:latest .
 2
 3Sending build context to Docker daemon 74.75kB
 4Step 1/8 : FROM alpine
 5latest: Pulling from library/alpine
 688286f41530e: Pull complete
 7Digest: sha256:f006ecbb824...0c103f4820a417d
 8Status: Downloaded newer image for alpine:latest
 9 ---> 76da55c8019d
10<Snip>
11Successfully built f154cb3ddbd4
12Successfully tagged test:latest
{注:} 
Windows示例構建可能花費比較長的時間。構建時間長短是由構建過程當中要拉取的鏡像大小和複雜度決定的。

一旦構建完成,就能夠確認主機上是否存在test:latest鏡像。

1$ docker image ls
2REPO     TAG        IMAGE ID         CREATED         SIZE
3Test     latest     f154cb3ddbd4     1 minute ago    55.6MB
4...

讀者如今已經擁有一個新的Docker鏡像,其中包含了應用程序。

從鏡像啓動容器,並測試應用。

Linux代碼以下。

1$ docker container run -d \
2  --name web1 \
3  --publish 8080:8080 \
4  test:latest

打開Web瀏覽器,在地址欄中輸入容器運行所在的Docker主機的DNS名稱或者IP地址,並在後面加上端口號8080。而後就能看到圖4.1的Web頁面。

若是讀者使用的是Windows示例或者Mac版Docker,則須要將地址替換爲localhost:8080或者127.0.0.1:8080;若是讀者使用的是Play with Docker,須要單擊終端界面上的8080超連接。

v2-8a94976c061b1528d16f96eaef990369_720w.jpg

圖1.1 Linux系統測試應用Web界面

Windows代碼以下。

1> docker container run -d \
2  --name web1 \
3  --publish 8080:80 \
4  test:latest

打開Web瀏覽器,在地址欄中輸入容器運行所在的Docker主機的DNS名稱或者IP地址,並在後面加上端口號8080,而後就能看到圖4.2的Web頁面。

v2-df684d5c63f1d00cfd67ec31c9b720e4_720w.jpg

圖1.2 Windows系統測試應用Web界面

若是讀者使用的是Windows示例或者Mac版Docker,則可參考上面的規則。

讀者已經成功將應用代碼構建到了Docker鏡像當中,而後以容器的方式啓動該鏡像,這個過程叫做「應用容器化」。

1.3 本文小結

在運維部分,咱們下載了Docker鏡像,啓動容器而且登陸到容器內部執行相應的命令,最後中止容器並刪除。

在開發部分,咱們完成了簡單應用的容器化過程:從GitHub拉取應用源代碼,而且經過Dockerfile中的指令,將應用代碼構建到鏡像之中。接着運行了該容器化應用。

attachments-2020-07-PJNV9wbl5f0ec3d45ea3f.jpg

相關文章
相關標籤/搜索