Docker的鏡像和容器

什么是Image?

廢話不多說,先上圖


image.png

最底層的Linux Kernel就是宿主機(jī)的操作系統(tǒng)內(nèi)核浮还,這一部分是共享的,稱之為boot filesystem闽巩。在這之上钧舌,是我們的Base Image,是文件和meta data的集合涎跨,也稱為root filesystem洼冻,這一層就是我們的系統(tǒng)鏡像,比如Ubuntu隅很,CentOS等撞牢,這個(gè)鏡像只包含操作系統(tǒng),不包含其它軟件叔营。我們?cè)赽ase image之上可以安裝一些軟件屋彪,比如Nginx,PHP等绒尊,這會(huì)產(chǎn)生新的一層image畜挥,如圖中image123,都是在系統(tǒng)之上裝了一些軟件婴谱,而image4是在image2的基礎(chǔ)上蟹但,又裝了一些軟件躯泰,則會(huì)產(chǎn)生新一層image。每一層image都是read only的矮湘,生成以后就不能改變斟冕。

Image獲取

那么Image是怎么獲取的口糕?在Docker中有個(gè)Dockerfile缅阳,這個(gè)Dockerfile就定義了一個(gè)Docker的Image。Dockerfile有自己的語法景描,后面我們會(huì)說到十办。先來看看一個(gè)基本的Dockerfile

FROM ubuntu:16.04 #選擇BaseImage
LABEL maintainer="Heheda <heheda@gamil.com>" #作者標(biāo)識(shí)
RUN apt-get update && apt-get install -y redis-server #在BaseImage上運(yùn)行某個(gè)命令
EXPOSE 6379 #暴露端口
ENTRYPOINT [ "/usr/bin/redis-server" ] #程序入口,此處是redis啟動(dòng)入口

通過命令docker build -t your-directory/xxx:latest .build當(dāng)前目錄下的Dockerfile超棺,你會(huì)看到每執(zhí)行一步向族,都會(huì)生成一個(gè)id,一共五個(gè)id棠绘,對(duì)應(yīng)Dockerfile里的五條語句件相,每一步都是image的一層(layer)狭吼,層是可以共享的疙赠。以上是手動(dòng)創(chuàng)建Image的方式。

另一種獲取Image的方式是從Docker的Registry中獲取酣难。Registry類似docker的github让虐,里面有許許多多的Image供選擇紊撕。
docker pull targetImageName來獲取

小提示,如果需要在虛擬機(jī)中執(zhí)行docker命令是不輸入sudo赡突,那么需要把當(dāng)前用戶加到docker用戶組里对扶。具體命令如下

sudo groupadd docker
sudo gpasswd -a vagrant docker
sudo service docker restart

最后退出賬戶重新登錄,再執(zhí)行docker命令就不需要sudo了

創(chuàng)建一個(gè)簡(jiǎn)單的BaseImage

  • 創(chuàng)建一個(gè)目錄惭缰,里面可以編寫一段簡(jiǎn)單的程序浪南,俗套來了,這里用C語言寫個(gè)HelloWorld
mkdir hello-world
vim hello.c
image.png
  • 用gcc將c文件編譯好漱受,得到hello這個(gè)二進(jìn)制可執(zhí)行文件
    gcc -static hello.c -o hello

  • 編寫Dockerfile

FROM scratch #因?yàn)槲覀兪莿?chuàng)建BaseImage逞泄,不是安裝軟件,所以用scratch
ADD hello / #將hello這個(gè)可執(zhí)行文件放在根目錄
CMD ["/hello"] #執(zhí)行根目錄下的hello程序
  • build image
docker build -t guojh/hello-world .

這條命令 -t是指定image的tag拜效,后面跟的參數(shù)就是tag的名字喷众,最后的點(diǎn)表示Dockerfile在當(dāng)前目錄。不加-t也是可以的
可以看到創(chuàng)建過程一共執(zhí)行了3步紧憾,也就是3層到千,對(duì)應(yīng)Dockerfile里的三條語句。


image.png

docker image ls 查看創(chuàng)建的guojh/hello-world鏡像

image.png

使用docker history imageID可以查看image的創(chuàng)建記錄赴穗°舅模可以看到膀息,我們FROM指定的是scratch,在執(zhí)行過程中這并不算一層了赵,因?yàn)槲覀儎?chuàng)建的是BaseImage潜支。

image.png

最后使用docker run guojh/hello-world執(zhí)行我們的image

image.png

Container

Container是通過Image創(chuàng)建的,會(huì)拷貝一份Image柿汛。之后會(huì)在Image上創(chuàng)建一個(gè)Container層冗酿,負(fù)責(zé)讀寫操作÷缍希可以將Image和Container類比成類和實(shí)例裁替,Image描述了一個(gè)鏡像該有的樣子,Container根據(jù)Image的描述實(shí)例化一個(gè)鏡像貌笨。Image在職責(zé)上負(fù)責(zé)存儲(chǔ)和分發(fā)弱判,Container負(fù)責(zé)運(yùn)行。


image.png

通過docker run xxx就是最快的根據(jù)Image創(chuàng)建Container的方式锥惋。
docker container ls或者docker ps可以查看當(dāng)前Container昌腰,執(zhí)行命令后我們發(fā)現(xiàn)沒有任何Container,這是因?yàn)槲覀兊膆ello-world鏡像打印出hello, my docker后就退出了膀跌,我們可以通過-a參數(shù)查看正在運(yùn)行及已經(jīng)退出的Container

image.png

如何不讓Container退出呢遭商?我們需要運(yùn)行一個(gè)有不會(huì)退出的進(jìn)程的image,比如操作系統(tǒng)Image淹父,centos
如果我們直接docker run centos:7株婴,那么Container依舊會(huì)退出。如果不希望推出暑认,可以加-t參數(shù)困介,采用交互式運(yùn)行
docker run -it centos:7

image.png

查詢現(xiàn)有Container,可以看到up的Container是centos


image.png

如果要?jiǎng)h除容器蘸际,使用docker container rm ContainerID或者docker rm ContainerID
如果刪除多個(gè)鏡像座哩,使用docker container rm $(docker container ls -aq),-ap是列出所有鏡像ID粮彤。
如果想刪除退出狀態(tài)的Container根穷,使用docker rm $(docker container ls -f "status=exited" -q)

構(gòu)建自己的Docker鏡像

第一個(gè)需要了解的命令docker container commit,將當(dāng)前運(yùn)行的Container變成一個(gè)鏡像导坟。

首先我們運(yùn)行前面的centos這個(gè)baseImage屿良,運(yùn)行docker run -it centos:7
這個(gè)centos7是不包含vim軟件的,我們就在baseImage的基礎(chǔ)上惫周,安裝一個(gè)尘惧,運(yùn)行命令sudo yum install vim進(jìn)行安裝。

安裝完成后递递,退出centos喷橙,運(yùn)行docker container ls -a查看當(dāng)前container啥么。

image.png

我們可以看到,紅線標(biāo)出的就是剛才我們退出的container贰逾,這個(gè)container包含了vim悬荣。我們使用docker container commit命令來創(chuàng)建Image。這個(gè)命令需要兩個(gè)參數(shù)疙剑,一個(gè)是container的名字氯迂,一個(gè)是Image的tag,tag默認(rèn)是latest的核芽,所以我們不用加latest了囚戚。最終命令是這樣docker container commit epic_stonebraker guojh/centos7-vim

創(chuàng)建完成后酵熙,查看image轧简,你會(huì)發(fā)現(xiàn)多了個(gè)我們剛才創(chuàng)建的帶VIM的鏡像,比baseImage大了100MB+匾二。


image.png

這種創(chuàng)建鏡像的方式不是特別推薦哮独,因?yàn)楫?dāng)發(fā)布鏡像的時(shí)候,只提供了一個(gè)image察藐,但具體有沒有多加什么其它軟件皮璧,你并不知道,所以接下來我們說第二種創(chuàng)建Image的方式分飞,用Dockerfile悴务。

我們新建一個(gè)目錄,docker-centos-vim譬猫。進(jìn)入這個(gè)目錄后讯檐,創(chuàng)建一個(gè)Dockerfile,內(nèi)容如下:

FROM centos
RUN yum install -y vim

然后使用docker build -t your-tag完成創(chuàng)建染服。這里有個(gè)問題别洪,image既然是只讀權(quán)限,那么如何在image上安裝vim呢柳刮?docker不會(huì)讓自己陷入這個(gè)困境的挖垛,docker build命令會(huì)運(yùn)行一個(gè)臨時(shí)的container,將baseImage運(yùn)行起來秉颗,然后安裝vim痢毒,最后生成image。以后我們就可以直接分享Dockerfile給其他人蚕甥,保證我們的Image不會(huì)安裝其他惡意軟件了哪替。另外提一點(diǎn),如果希望container在后臺(tái)運(yùn)行梢灭,加上-t即可夷家。

Dockerfile語法

  • FROM
    FROM后面跟scratch是創(chuàng)建baseImage蒸其,F(xiàn)ROM centos是使用已有的baseImage,盡量使用官方的baseImage库快。

  • LABEL
    LABEL標(biāo)簽就是增加對(duì)鏡像的描述摸袁,比如LABLE maintainer=xxx就標(biāo)識(shí)了鏡像的持有者。另外還有version义屏,description這些字段靠汁。對(duì)于LABEL來說,

  • RUN
    RUN是執(zhí)行一些命令闽铐,比如安裝軟件等蝶怔。這里有一點(diǎn)要注意,每執(zhí)行一次RUN兄墅,便會(huì)產(chǎn)生一層Image踢星,為了避免無用分層,盡量用&&連接命令隙咸,如果命令太長(zhǎng)沐悦,用反斜線來?yè)Q行。比如

RUN yum install vim && yum install PHP \
yum install Nginx
  • WORKDIR
    這條命令是設(shè)定當(dāng)前工作目錄五督。類似cd命令藏否,如果WORKDIR一個(gè)不存在的目錄,會(huì)自動(dòng)創(chuàng)建這個(gè)目錄充包。這里需要注意副签,不要使用RUN cd,這會(huì)產(chǎn)生無用層基矮,推薦使用WORKDIR淆储,并且盡量使用絕對(duì)路徑。

  • ADD and COPY
    ADD和COPY都能將本地的文件添加到docker的image中愈捅,比如我們之前創(chuàng)建hello鏡像的時(shí)候遏考。ADD和COPY第一個(gè)區(qū)別是如果拷貝的是壓縮文件,ADD會(huì)將壓縮文件解壓縮后再拷貝蓝谨,而COPY只是單純拷貝壓縮文件而已灌具。如果只是拷貝,不需要解壓縮譬巫,還是用COPY咖楣。如果是添加遠(yuǎn)程文件,比如下載一個(gè)文件芦昔,那么還是RUN來執(zhí)行wget或者crul吧诱贿。

  • ENV
    這個(gè)關(guān)鍵字是聲明常量。比如

ENV MYSQL_VERSION 5.6
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/*

盡量使用ENV增加代碼可讀性,減少魔數(shù)的使用珠十。

  • CMD
    CMD是容器啟動(dòng)時(shí)默認(rèn)執(zhí)行的命令料扰,如果定義了多個(gè)CMD,只會(huì)執(zhí)行最后一個(gè)CMD焙蹭,如果docker run指定了其它命令晒杈,則會(huì)忽略CMD。
    對(duì)于最后一種情況解釋一下孔厉,比如我們有這樣一個(gè)Dockerfile:
FROM centos
ENV name Docker
CMD echo "hello, $name"

假設(shè)這個(gè)Dockerfile生成的image名字是testImage拯钻,那么執(zhí)行docker run tetsImage后,默認(rèn)會(huì)執(zhí)行CMD命令撰豺,打印hello, Docker粪般。如果執(zhí)行docker run testImage /bin/bash,那么就不會(huì)打印hello, Docker污桦,因?yàn)槲覀冎付诉\(yùn)行/bin/bash亩歹。

  • ENTRYPOINT
    ENTRYPOINT讓容易以應(yīng)用程序或者服務(wù)的形式啟動(dòng),例如啟動(dòng)Nginx這種守護(hù)進(jìn)程寡润。ENTRYPOINT永遠(yuǎn)不會(huì)被忽略捆憎,一定會(huì)被執(zhí)行舅柜。最好是將要執(zhí)行的命令寫成shell梭纹,用ENTRYPOINT來執(zhí)行這個(gè)shell。比如:
COPY docker-entrypoint.sh /usr/local/bin
ENTRYPOINT ["docker-entrypoint.sh"]
  • EXPOSE
    暴露docker內(nèi)的端口給外部致份。
EXPOSE 5000

更多命令可以參考Dockerfile官方文檔

Dockerfile

Dockerfile中的格式有兩種变抽,一種是Shell格式,一種是Exec格式
Shell:

RUN apt=get install -y vim
CMD echo "finished..."
ENTRYPOINT echo "Hello..."

Exec:

RUN [ "apt-get", "install", "-y", "vim"]
CMD[ "/bin/echo", "finished..."]
ENTRYPOINT ['/bin/echo', "Hello..."]

如果命令中定義了常量氮块,使用常量的時(shí)候绍载,Exec格式不會(huì)識(shí)別常量,CMD可以識(shí)別常量滔蝉。如果必須讓Exec識(shí)別常量击儡,那么第一個(gè)命令應(yīng)該是/bin/bash,后面跟上shell命令即可蝠引。如

ENV name Heheda
ENTRYPOINT ["/bin/bash", "-c", "echo $name"]
  • Dockerfile中執(zhí)行命令時(shí)的動(dòng)態(tài)參數(shù)
    如果Dockerfile中需要執(zhí)行一段shell命令阳谍,但參數(shù)又不確定怎么辦?可以使用ENTRYPOINT搭配CMD螃概,如:
ENTRYPOINT ["/usr/bin/bash/ps"]
CMD[]

在運(yùn)行container的時(shí)候矫夯,直接跟上需要的參數(shù)即可。如:
docker run -it containerID aux | grep parity
這樣aux | grep parity就會(huì)被當(dāng)成ps的參數(shù)

更多Dockerfile例子可以在GitHub上搜索docker-library倉(cāng)庫(kù)吊洼。

搭建自己的Docker鏡像倉(cāng)庫(kù)

搭建很簡(jiǎn)單训貌,官方提供了一個(gè)搭建倉(cāng)庫(kù)的倉(cāng)庫(kù)鏡像,按照教程來就能搭建好。

關(guān)鍵是創(chuàng)建鏡像的時(shí)候递沪,tag需要指定為私有倉(cāng)庫(kù)的ip+端口豺鼻。比如我們的倉(cāng)庫(kù)地址是12.12.12.12:5000,那么build鏡像的時(shí)候款慨,tag為12.12.12.12:5000/imagename拘领。

在push之前,需要在/etc/docker目錄下創(chuàng)建damon.json文件樱调,輸入下面的代碼:

{
    "insecure-registries" : ["12.12.12.12:5000"]
}

把我們的倉(cāng)庫(kù)地址被docker信任约素。

再編輯/lib/systemd/system/docker.service文件,在文件中增加EnviromentFile=-/etc/docker/daemin.json
最后重啟docker

現(xiàn)在我們可以push到私有倉(cāng)庫(kù)了笆凌,docker push 12.12.12.12:5000/imagename

私有倉(cāng)庫(kù)沒有提供web界面圣猎,可以通過API來檢查是否上傳成功。
12.12.12.12:5000/v2/_catalog來查看

容器操作

  • 進(jìn)入container執(zhí)行命令或查看container運(yùn)行的程序
    如果希望進(jìn)入container乞而,可以使用命令docker exec -it containerID shell命令來實(shí)現(xiàn)送悔。比如我想進(jìn)入container的shell里,那就運(yùn)行docker exec -it containerID /bin/bash爪模,這樣就能進(jìn)入container的bash里了欠啤。

  • 給要運(yùn)行的容器起名
    運(yùn)行docker run --name=demo imageID,指定一個(gè)名字即可屋灌,這個(gè)名字是唯一的洁段,不能重復(fù)。

  • 顯示container的詳細(xì)信息
    運(yùn)行docker inspect containerID

  • 查看container運(yùn)行l(wèi)og
    運(yùn)行docker logs containerID

容器資源限制

  • 限制container的內(nèi)存使用量
    使用--memory=200M來限制內(nèi)存使用共郭。這里指定了內(nèi)存是200MB祠丝,但linux還有交換區(qū)內(nèi)存,默認(rèn)是和memory指定的大小一致除嘹,所以實(shí)際的可用內(nèi)存有400MB写半。可以使用--memory-swap來指定交換區(qū)內(nèi)存大小尉咕。查看等多命令使用docker run --help

  • 限制CPU使用
    這里介紹一個(gè)參數(shù)--cpu-shares叠蝇,這是限制CPU使用權(quán)重,以整數(shù)表示年缎。比如我container A限制--cpu-share=10悔捶,另一個(gè)container B限制--cpu-share=5,這意味著A的CPU使用率是B的兩倍晦款。如果這兩個(gè)container占用了宿主機(jī)全部的CPU資源炎功,那么A對(duì)CPU的使用率是B的兩倍。

stress壓力測(cè)試工具

在運(yùn)行的container里安裝好stress后缓溅,第一個(gè)介紹的命令是--vm蛇损,意思是啟動(dòng)進(jìn)程及給進(jìn)程分配內(nèi)存,默認(rèn)內(nèi)存是256MB。如果需要多個(gè)進(jìn)程淤齐,在命令后面空一格股囊,跟上進(jìn)程數(shù)量,如stress --vm 2更啄,這里就會(huì)創(chuàng)建兩個(gè)進(jìn)程稚疹。如果要指定進(jìn)程的內(nèi)存大小,用--vm-bytes祭务,比如stress --vm 2 --vm-bytes 128M内狗。如果要查看log,加上--verbose參數(shù)义锥。

參考資料
慕課網(wǎng)Docker教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柳沙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拌倍,更是在濱河造成了極大的恐慌赂鲤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柱恤,死亡現(xiàn)場(chǎng)離奇詭異数初,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)梗顺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門泡孩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荚守,你說我怎么就攤上這事珍德。” “怎么了矗漾?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)薄料。 經(jīng)常有香客問我敞贡,道長(zhǎng),這世上最難降的妖魔是什么摄职? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任誊役,我火速辦了婚禮,結(jié)果婚禮上谷市,老公的妹妹穿的比我還像新娘蛔垢。我一直安慰自己,他們只是感情好迫悠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布鹏漆。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪艺玲。 梳的紋絲不亂的頭發(fā)上括蝠,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音饭聚,去河邊找鬼忌警。 笑死,一個(gè)胖子當(dāng)著我的面吹牛秒梳,可吹牛的內(nèi)容都是我干的法绵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酪碘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼礼烈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起婆跑,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤此熬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后滑进,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犀忱,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年扶关,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阴汇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡节槐,死狀恐怖搀庶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铜异,我是刑警寧澤哥倔,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站揍庄,受9級(jí)特大地震影響咆蒿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚂子,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一沃测、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧食茎,春花似錦蒂破、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)惧互。三九已至,卻和暖如春挟秤,著一層夾襖步出監(jiān)牢的瞬間壹哺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工艘刚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留管宵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓攀甚,卻偏偏與公主長(zhǎng)得像箩朴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子秋度,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容