2.1 創(chuàng)建瓮床、運行及共享容器鏡像

2.1.1 安裝Docker并運行Hello World容器

基本內容基于原書,代碼部分稍有修改,以適應最新版本

CentOS一鍵安裝docker
curl -fsSL https://get.docker.com | bash -s docker --mirror aliyun

開啟docker并設置自啟動

sudo systemctl start docker
systemctl enable docker

VirtualBox 動態(tài)磁盤擴容 vboxmanage modifyhd "/home/matrix/VirtualBox VMs/ubuntu/ubuntu.vdi" --resize 10240

參考連接 https://www.cnblogs.com/xueweihan/p/5923937.html#1

運行Hello World容器

busybox是一個單一可執(zhí)行文件丑掺,包含多種標準UNIX命令行工具兼丰,如:echo黍翎、ls氮双、gzip 等砰粹。除了包含 echo 命令的 busybox 命令唧躲,也可以使用如Fedora造挽、Ubuntu等功能完備的鏡像。

如何才能運行 busybox 鏡像呢弄痹?無須下載或者安裝任何東西饭入。使用 docker run 命令然后指定需要運行的鏡像的名字肛真,以及需要執(zhí)行的命令(可選)谐丢,如下面這段代碼。

代碼清單2.1 使用Docker運行一個Hello world容器

[root@localhost test]# docker run busybox echo 'Hello world'
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
b71f96345d44: Pull complete 
Digest: sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d
Status: Downloaded newer image for busybox:latest
Hello world

背后的原理

首先蚓让,Docker會檢查busybox:latest 鏡像是否已經(jīng)存在于本機乾忱。如果沒有,Docker會從http://docker.io的Docker鏡像中心拉取鏡像历极。鏡像下載到本機之后窄瘟,Docker基于這個鏡像創(chuàng)建一個容器并在容器中運行命令。echo 命令打印文字到標準輸出流趟卸,然后進程終止蹄葱,容器停止運行。

運行其他鏡像

運行其他的容器鏡像和運行busybox鏡像是一樣的锄列,甚至可能更簡單图云,因為你可以不需要指定執(zhí)行命令。就像例子中的 echo "Hello world"邻邮,被執(zhí)行的命令通常都會被包含在鏡像中竣况,但也可以根據(jù)需要進行覆蓋。在瀏覽器中搜索http://hub.docker.com或其他公開的鏡像中心的可用鏡像之后筒严,可以像這樣在Docker中運行鏡像:

$ docker run <image>

容器鏡像的版本管理

當然帕翻,所有的軟件包都會更新鸠补,所以通常每個包都不止一個版本。Docker支持同一鏡像的多個版本嘀掸。每一個版本必須有唯一的tag名紫岩。當引用鏡像沒有顯式地指定tag時,Docker會默認指定tag為latest睬塌。如果想要運行別的版本的鏡像泉蝌,需要像這樣指定鏡像的版本:

$ docker run <image>:<tag>

2.1.2 創(chuàng)建一個簡單的 Node.js 應用

現(xiàn)在有了一個可以工作的Docker環(huán)境來創(chuàng)建應用。接下來會構建一個簡單的Node.js Web應用揩晴,并把它打包到容器鏡像中勋陪。這個應用會接收HTTP請求并響應應用運行的主機名。這樣硫兰,應用運行在容器中诅愚,看到的是自己的主機名而不是宿主機名,即使它也像其他進程一樣運行在宿主機上劫映。這在后面會非常有用违孝,當應用部署在Kubernetes上并進行伸縮時(水平伸縮,復制應用到多個節(jié)點)泳赋,你會發(fā)現(xiàn)HTTP請求切換到了應用的不同實例上雌桑。

應用包含一個名為app.js的文件,詳見下面的代碼清單祖今。

代碼清單2.2 一個簡單的Node.js應用:app.js

const http = require('http');
const os = require('os');
const hostname = '0.0.0.0';
const port = 888;

const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end("You've hit " + os.hostname() + "\n");
});

server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
});

代碼清晰地說明了實現(xiàn)的功能校坑。這里在8080端口啟動了一個HTTP服務器。服務器會以狀態(tài)碼 200 OK 和文字 "You've hit <hostname>" 來響應每個請求千诬。請求handler會把客戶端的IP打印到標準輸出耍目,以便日后查看。注意 返回的主機名是服務器真實的主機名徐绑,不是客戶端發(fā)出的HTTP請求中頭的 Host 字段邪驮。

現(xiàn)在可以直接下載安裝Node.js來測試代碼了,但是這不是必需的泵三,因為可以直接用Docker把應用打包成鏡像耕捞,這樣在需要運行的主機上就無須下載和安裝其他的東西(當然不包括安裝Docker來運行鏡像)。

2.1.3 為鏡像創(chuàng)建Dockerfile

為了把應用打包成鏡像烫幕,首先需要創(chuàng)建一個叫Dockerfile的文件俺抽,它包含了一系列構建鏡像時會執(zhí)行的指令。Dockerfile文件需要和app.js文件在同一目錄较曼,并包含下面代碼清單中的命令磷斧。

代碼清單2.3 構建應用容器鏡像的Dockerfile

FROM node:12
ADD app.js /app.js
ENTRYPOINT ["node","app.js"]

From 行定義了鏡像的起始內容(構建所基于的基礎鏡像)。這個例子中使用的是 node 鏡像的tag 7 版本。第二行中把app.js文件從本地文件夾添加到鏡像的根目錄弛饭,保持app.js這個文件名冕末。最后一行定義了當鏡像被運行時需要被執(zhí)行的命令,這個例子中侣颂,命令是 node app.js档桃。

選擇基礎鏡像

你或許在想虽画,為什么要選擇這個鏡像作為基礎鏡像撒犀。因為這個應用是Node.js應用,鏡像需要包含可執(zhí)行的 node 二進制文件來運行應用间学。你也可以使用任何包含這個二進制文件的鏡像拒担,或者甚至可以使用Linux發(fā)行版的基礎鏡像嘹屯,如 fedora或ubuntu,然后在鏡像構建的時候安裝Node.js从撼。但是由于 node鏡像是專門用來運行Node.js應用的州弟,并且包含了運行應用所需的一切,所以把它當作基礎鏡像低零。

2.1.4 構建容器鏡像

現(xiàn)在有了Dockerfile和app.js文件,這是用來構建鏡像的所有文件毁兆。運行下面的Docker命令來構建鏡像:

$ docker build -t kubia .

刪除鏡像必須刪除容器

//查詢容器
#docker ps -a
//刪除容器
#docker rm 67jhgf***

//查詢鏡像
#docker images
//刪除鏡像
#docker rmi 99fkjh***

用戶告訴Docker需要基于當前目錄(注意命令結尾的點)構建一個叫kubia的鏡像宿百,Docker會在目錄中尋找Dockerfile,然后基于其中的指令構建鏡像洪添。

鏡像是如何構建的

構建過程不是由Docker客戶端進行的垦页,而是將整個目錄的文件上傳到Docker守護進程并在那里進行的。Docker客戶端和守護進程不要求在同一臺機器上干奢。如果你在一臺非Linux操作系統(tǒng)中使用Docker痊焊,客戶端就運行在你的宿主操作系統(tǒng)上,但是守護進程運行在一個虛擬機內。由于構建目錄中的文件都被上傳到了守護進程中薄啥,如果包含了大量的大文件而且守護進程不在本地運行辕羽,上傳過程會花費更多的時間。

提示 不要在構建目錄中包含任何不需要的文件垄惧,這樣會減慢構建的速度——尤其當Docker守護進程運行在一個遠端機器的時候刁愿。

在構建過程中,Docker首次會從公開的鏡像倉庫(Docker Hub)拉取基礎鏡像(node:12)到逊,除非已經(jīng)拉取過鏡像并存儲在本機上了酌毡。

鏡像分層

鏡像不是一個大的二進制塊,而是由多層組成的蕾管,在運行busybox例子時你可能已經(jīng)注意到(每一層有一行Pull complete)枷踏,不同鏡像可能會共享分層,這會讓存儲和傳輸變得更加高效掰曾。比如旭蠕,如果創(chuàng)建了多個基于相同基礎鏡像(比如例子中的 node:7)的鏡像,所有組成基礎鏡像的分層只會被存儲一次旷坦。拉取鏡像的時候掏熬,Docker會獨立下載每一層。一些分層可能已經(jīng)存儲在機器上了秒梅,所以Docker只會下載未被存儲的分層旗芬。

你或許會認為每個Dockerfile只創(chuàng)建一個新層,但是并不是這樣的捆蜀。構建鏡像時疮丛,Dockerfile中每一條單獨的指令都會創(chuàng)建一個新層。鏡像構建的過程中辆它,拉取基礎鏡像所有分層之后誊薄,Docker在它們上面創(chuàng)建一個新層并且添加app.js。然后會創(chuàng)建另一層來指定鏡像被運行時所執(zhí)行的命令锰茉。最后一層會被標記為kubia:latest呢蔫。圖2.3 展示了這個過程,同時也展示另外一個叫 other:latest 的鏡像如何與我們構建的鏡像共享同一層Node.js鏡像飒筑。

構建完成時片吊,新的鏡像會存儲在本地。下面的代碼展示了如何通過Docker列出本地存儲的鏡像:

代碼清單2.4 列出本地存儲的鏡像

s docker images
REPOSITORY  TAG         IMAGE ID                CREATED         VIRTUAL SIZE
kubia               latest      d30ecc7419e7        1 minute ago    637.1 MB

比較使用Dockerfile和手動構建鏡像

Dockerfile是使用Docker構建容器鏡像的常用方式协屡,但也可以通過運行已有鏡像容器來手動構建鏡像俏脊,在容器中運行命令,退出容器著瓶,然后把最終狀態(tài)作為新鏡像联予。用Dockerfile構建鏡像是與此相同的啼县,但是是自動化且可重復的,隨時可以通過修改Dockerfile重新構建鏡像而無須手動重新輸入命令沸久。

2.1.5 運行容器鏡像

以下的命令可以用來運行鏡像:

$ docker run --name kube-container -p 888:888 -d kubia

關閉后運行的話

$ docker restart kube-container

這條命令告知Docker基于 kubia 鏡像創(chuàng)建一個叫 kubia-container 的新容器季眷。這個容器與命令行分離(-d 標志),這意味著在后臺運行卷胯。本機上的888端口會被映射到容器內的888端口(-p 888:888 選項)子刮,所以可以通過http://localhost:888 訪問這個應用。

如果沒有在本機上運行Docker守護進程(比如使用的是Mac或Windows系統(tǒng)窑睁,守護進程會運行在VM中)挺峡,需要使用VM的主機名或IP來代替localhost運行守護進程〉Eィ可以通過 DOCKER_HOST 這個環(huán)境變量查看主機名橱赠。

訪問應用

現(xiàn)在試著通過 http://localhost:888 訪問你的應用(確保使用Docker主機名或IP替換localhost):

$ curl localhost:888
You've hit 44d76963e8e1

這是應用的響應。現(xiàn)在應用運行在容器中箫津,與其他東西隔離狭姨。可以看到苏遥,應用把 44d76963e8e1 作為主機名返回饼拍,這并不是宿主機的主機名。這個十六進制數(shù)是Docker容器的ID田炭。

列出所有運行中的容器

下面的代碼清單列出了所有的運行中的容器师抄,可以查看列表(為了更好的可讀性,列表被分成了兩行顯示)教硫。

代碼清單2.5 列出運行中的容器

# docker ps
CONTAINER ID   IMAGE     COMMAND         CREATED         STATUS         PORTS                    NAMES
9d3e6e24ab3c   kubia     "node app.js"   4 minutes ago   Up 4 minutes   0.0.0.0:8080->8080/tcp   kubia-container

有一個容器在運行叨吮。Docker會打印出每一個容器的ID和名稱、容器運行所使用的鏡像栋豫,以及容器中執(zhí)行的命令挤安。

獲取更多的容器信息

docker ps 只會展示容器的大部分基礎信息谚殊∩パ欤可以使用 docker inspect查看更多的信息:

$ docker inspect kubia-container

Docker會打印出包含容器底層信息的長JSON。

2.1.6 探索運行容器的內部

我們來看看容器內部的環(huán)境嫩絮。由于一個容器里可以運行多個進程丛肢,所以總是可以運行新的進程去看看里面發(fā)生了什么。如果鏡像里有可用的shell二進制可執(zhí)行文件剿干,也可以運行一個shell蜂怎。

在已有的容器內部運行shell

鏡像基于的Node.js鏡像包含了bash shell,所以可以像這樣在容器內運行shell:

$ docker exec -it kubia-container bash

這會在已有的kubia-container容器內部運行bash置尔。bash 進程會和主容器進程擁有相同的命名空間杠步。這樣可以從內部探索容器,查看Node.js和應用是如何在容器里運行的。-it 選項是下面兩個選項的簡寫:

  • -i幽歼,確保標準輸入流保持開放朵锣。需要在shell中輸入命令。
  • -t甸私,分配一個偽終端(TTY)诚些。

如果希望像平常一樣使用shell,需要同時使用這兩個選項(如果缺少第一個選項就無法輸入任何命令皇型。如果缺少第二個選項诬烹,那么命令提示符不會顯示,并且一些命令會提示 TERM 變量沒有設置)弃鸦。

從內部探索容器

下面的代碼展示了如何使用shell查看容器內運行的進程绞吁。

代碼清單2.6 從容器內列出進程

# ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.7 565712 30100 ?        Ssl  08:22   0:00 node app.js
root          14  0.1  0.0  18188  3344 pts/0    Ss   08:25   0:00 bash
root          22  0.0  0.0  36640  2764 pts/0    R+   08:25   0:00 ps -aux

只看到了三個進程,宿主機上沒有看到其他進程唬格。

容器內的進程運行在主機操作系統(tǒng)上

如果現(xiàn)在打開另一個終端掀泳,然后列出主機操作系統(tǒng)上的進程,連同其他的主機進程依然會發(fā)現(xiàn)容器內的進程西轩,如代碼清單2.7所示员舵。

注意 如果使用的是Mac或者Windows系統(tǒng),需要登錄到Docker守護進程運行的VM查看這些進程藕畔。

代碼清單2.7 運行在主機操作系統(tǒng)上的容器進程

$ ps aux | grep app.js
USER PID CPU MEM vsz RSS TTY STAT START TIME COMMAND
root 382 0.0 0.1 676380 16504 ? S1 12:31 0:00 node app.js

這證明了運行在容器中的進程是運行在主機操作系統(tǒng)上的马僻。如果你足夠敏銳,會發(fā)現(xiàn)進程的ID在容器中與主機上不同注服。容器使用獨立的PID Linux命名空間并且有著獨立的系列號韭邓,完全獨立于進程樹。

容器的文件系統(tǒng)也是獨立的

正如擁有獨立的進程樹一樣溶弟,每個容器也擁有獨立的文件系統(tǒng)女淑。在容器內列出根目錄的內容,只會展示容器內的文件辜御,包括鏡像內的所有文件鸭你,再加上容器運行時創(chuàng)建的任何文件(類似日志文件),如下面的代碼清單所示擒权。

代碼清單2.8 容器擁有完整的文件系統(tǒng)

root@44d76963e8el:/# 1s
app.js boot etc lib mediabin  dev home 1ib64 mnt
opt root sbin sys usrpros run srv tmp var

其中包含app.js文件和其他系統(tǒng)目錄袱巨,這些目錄是正在使用的 node:7 基礎鏡像的一部分√汲可以使用 exit 命令來退出容器返回宿主機(類似于登出ssh session)愉老。

提示 進入容器對于調試容器內運行的應用來說是非常有用的。出錯時剖效,需要做的第一件事是查看應用運行的系統(tǒng)的真實狀態(tài)嫉入。需要記住的是焰盗,應用不僅擁有獨立的文件系統(tǒng),還有進程咒林、用戶姨谷、主機名和網(wǎng)絡接口。

2.1.7 停止和刪除容器

可以通過告知Docker停止 kubia-container 容器來停止應用:

$ docker stop kubia-container

因為沒有其他的進程在容器內運行映九,這會停止容器內運行的主進程梦湘。容器本身仍然存在并且可以通過 docker ps-a 來查看。-a 選項打印出所有的容器件甥,包括運行中的和已經(jīng)停止的捌议。想要真正地刪除一個容器,需要運行 docker rm :

$ docker rm kubia-container

這會刪除容器引有,所有的內容會被刪除并且無法再次啟動瓣颅。

2.1.8 向鏡像倉庫推送鏡像

現(xiàn)在構建的鏡像只可以在本機使用。為了在任何機器上都可以使用譬正,可以把鏡像推送到一個外部的鏡像倉庫宫补。為了簡單起見,不需要搭建一個私有的鏡像倉庫曾我,而是可以推送鏡像到公開可用的Docker Hub(http://hub.docker.com)鏡像中心粉怕。另外還有其他廣泛使用的鏡像中心,如阿里云鏡像服務

登陸阿里云個人版的鏡像服務
sudo docker login --username={你的郵箱} registry.cn-hangzhou.aliyuncs.com

使用附加標簽標注鏡像

一旦知道了自己的ID抒巢,就可以重命名鏡像贫贝,現(xiàn)在鏡像由 kubia 改為 registry.cn-hangzhou.aliyuncs.com/bernard/kubia(其中bernard是我自己定義的命名空間):

$ docker tag kubia registry.cn-hangzhou.aliyuncs.com/bernard/kubia

這不會重命名標簽,而是給同一個鏡像創(chuàng)建一個額外的標簽蛉谜≈赏恚可以通過docker images 命令列出本機存儲的鏡像來加以確認,如下面的代碼清單所示型诚。

代碼清單2.9 一個容器鏡像可以有多個標簽

# docker images | head
REPOSITORY                          TAG         IMAGE ID       CREATED             SIZE
kubia                               v2          8af4d2d1750a   2 minutes ago       82.7MB

正如所看到的客燕,kubia 和 改為 registry.cn-hangzhou.aliyuncs.com/bernard/kubia 指向同一個鏡像ID,所以實際上是同一個鏡像的兩個標簽狰贯。

向阿里云鏡像服務推送鏡像

$ docker push registry.cn-hangzhou.aliyuncs.com/bernard/kubia

在不同機器上運行鏡像

在推送完成之后也搓,鏡像便可以給任何人使用∧合郑可以在任何機器上運行下面的命令來運行鏡像:

$ docker run -p 888:888 registry.cn-hangzhou.aliyuncs.com/bernard/kubia

這非常簡單还绘。最棒的是應用每次都運行在完全一致的環(huán)境中。如果在你的機器上正常運行栖袋,也會在所有的Linux機器上正常運行。無須擔心主機是否安裝了Node.js抚太。事實上塘幅,就算安裝了昔案,應用也并不會使用,因為它使用的是鏡像內部安裝的电媳。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末踏揣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子匾乓,更是在濱河造成了極大的恐慌捞稿,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拼缝,死亡現(xiàn)場離奇詭異娱局,居然都是意外死亡,警方通過查閱死者的電腦和手機咧七,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門衰齐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人继阻,你說我怎么就攤上這事耻涛。” “怎么了瘟檩?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵抹缕,是天一觀的道長。 經(jīng)常有香客問我墨辛,道長歉嗓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任背蟆,我火速辦了婚禮鉴分,結果婚禮上,老公的妹妹穿的比我還像新娘带膀。我一直安慰自己志珍,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布垛叨。 她就那樣靜靜地躺著伦糯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嗽元。 梳的紋絲不亂的頭發(fā)上敛纲,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音剂癌,去河邊找鬼淤翔。 笑死,一個胖子當著我的面吹牛佩谷,可吹牛的內容都是我干的旁壮。 我是一名探鬼主播监嗜,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼抡谐!你這毒婦竟也來了裁奇?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤麦撵,失蹤者是張志新(化名)和其女友劉穎刽肠,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體免胃,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡音五,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了杜秸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片放仗。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖撬碟,靈堂內的尸體忽然破棺而出诞挨,到底是詐尸還是另有隱情,我是刑警寧澤呢蛤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布惶傻,位于F島的核電站,受9級特大地震影響其障,放射性物質發(fā)生泄漏银室。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一励翼、第九天 我趴在偏房一處隱蔽的房頂上張望蜈敢。 院中可真熱鬧,春花似錦汽抚、人聲如沸抓狭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽否过。三九已至,卻和暖如春惭蟋,著一層夾襖步出監(jiān)牢的瞬間苗桂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工告组, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留煤伟,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像持偏,于是被迫代替她去往敵國和親驼卖。 傳聞我的和親對象是個殘疾皇子氨肌,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內容