docker入門(3)--創(chuàng)建和管理鏡像

有三種創(chuàng)建自定義鏡像的方式

一、交互式創(chuàng)建

  1. 選取基礎(chǔ)鏡像瞳别,運(yùn)行容器征候,并進(jìn)入交互窗口
    docker container run -it --name sample alpine /bin/sh
  2. 進(jìn)行你所需要的修改,變更祟敛。這里假設(shè)需要安裝ping命令所需的相關(guān)軟件疤坝。
    / # apk update && apk add iputils
  3. 核實(shí)ping是否可用了,退出容器馆铁,查看容器狀態(tài)
    / # ping 114.114.114.114
    / # exit
    docker container ls -a | grep sample
  4. 查看我們的容器與基礎(chǔ)鏡像有什么不同
    docker container diff sample

    圖片中跑揉,首字母含義:
  • A代表新增文件
  • C代表修改過的文件
  • D代表被刪除的文件
  1. 將修改過的容器導(dǎo)出為自己的鏡像
    docker container commit sample my-alpine
  2. 查看鏡像
    docker image ls
  3. 查看自定義的鏡像的創(chuàng)建過程
    docker image history my-alpine

    通過IMAGE的id可以看到最后的一層是我們添加的,并且是在alpine這個(gè)鏡像的基礎(chǔ)上埠巨。
    這種方式創(chuàng)建鏡像的優(yōu)缺點(diǎn):

Manually creating custom images as shown in the previous section of this chapter is very helpful when doing exploration, creating prototypes, or making feasibility studies. But it has a serious drawback: it is a manual process and thus is not repeatable or scalable. It is also as error-prone as any task executed manually by humans.

二历谍、通過Dockerfile創(chuàng)建鏡像

一個(gè)簡(jiǎn)單的Dockerfile示例如下:

FROM python:2.7
RUN mkdir -p /app
WORKDIR /app
COPY ./requirements.txt /app/
RUN pip install -r requirements.txt
CMD ["python", "main.py"]

Dockerfile與鏡像層級(jí)的關(guān)系


關(guān)鍵字詳解:

  • FROM
    每一個(gè)Dockerfile文件都從這個(gè)關(guān)鍵字開始,它指明從哪個(gè)基礎(chǔ)鏡像開始進(jìn)行你的鏡像構(gòu)建辣垒。通常望侈,我們將docker hub里面提供的官方鏡像作為基礎(chǔ)鏡像,例如:FROM centos:7或者FROM python:2.7勋桶,如果你想從空白鏡像開始脱衙,可以使用FROM scratch
  • RUN
    RUN后面可以跟隨任意有效的linux命令哥遮,一般用來進(jìn)行我們?cè)诨A(chǔ)鏡像上的變更操作岂丘,由于每個(gè)RUN命令都會(huì)在鏡像上增加一層,因此眠饮,建議將多個(gè)linux命令整合成一個(gè)命令奥帘。可使用類似如下方式:
  • COPY 和 ADD
    COPYADD都是用于將主機(jī)中的文件拷貝到鏡像中的仪召,不同之處在于寨蹋,ADD可以拷貝和解壓tar文件松蒜,還可以通過URL來拷貝網(wǎng)絡(luò)上的文件到容器中。
    一些示例如下:
COPY . /app        #將上下文目錄中所有文件或目錄遞歸拷貝到容器的/app目錄下
COPY ./web /app/web        #將上下文目錄中的web目錄下的內(nèi)容拷貝到容器的/app/web目錄下
COPY sample.txt /data/my-sample.txt        #拷貝單個(gè)文件并重命名
ADD sample.tar /app/bin/        #解壓tar包內(nèi)的文件到指定目錄
ADD http://example.com/sample.txt /data/        #拷貝遠(yuǎn)程文件到指定目錄
COPY ./sample* /mydir/        #支持源路徑中使用通配符

默認(rèn)已旧,通過COPYADD拷貝到鏡像內(nèi)的文件的UID和GID都為0秸苗,如果你需要改變,可以使用如下命令:
ADD --chown=11:22 ./data/files* /app/data/
除了指定UID和GID运褪,你也可以指定用戶的用戶名稱組名稱惊楼,但是這些名稱必須存在與鏡像的/etc/passwd 和 /etc/group中,否則Dockerfile構(gòu)建過程會(huì)失敗秸讹。

  • WORKDIR
    WORKDIR用來定義工作目錄或者上下文目錄檀咙。常見的問題:
RUN cd /app/bin
RUN touch sample.txt

由于每執(zhí)行一次RUN,都是在原有鏡像上添加一個(gè)新層璃诀,因此上面的命令只是在root目錄下新建了sample.txt文件弧可。
正確的切換至一個(gè)目錄下,并新建文件劣欢,命令如下:

WORKDIR /app/bin
RUN touch sample.txt
  • CMD 和 ENTRYPOINT
    CMDENTRYPOINT命令比較特殊棕诵,因?yàn)槌诉@兩個(gè)命令以外的其他命令,都是在構(gòu)建鏡像時(shí)就會(huì)運(yùn)行并生效凿将,而這兩個(gè)命令是在使用鏡像啟動(dòng)容器時(shí)校套,才會(huì)執(zhí)行的命令。這兩個(gè)命令用于告訴Docker在啟動(dòng)容器時(shí)丸相,應(yīng)該執(zhí)行什么命令搔确,并以何種方式去執(zhí)行(指定一些參數(shù))彼棍。
    兩者的區(qū)別
    先來看一個(gè)典型的Dockerfile示例
FROM alpine:latest
ENTRYPOINT ["ping"]
CMD ["8.8.8.8", "-c", "3"]

ENTRYPOINT來指定需要執(zhí)行的命令灭忠,用CMD來指定該命令所需的參數(shù)。
這是首選的推薦用法,也被稱為exec格式。我們使用這個(gè)Dockerfile來構(gòu)建一個(gè)鏡像川蒙,命名為pinger洽故,并使用該鏡像運(yùn)行一個(gè)容器,然后刪除牙咏。


通過這種方式創(chuàng)建的鏡像,我們還可以按照如下方式運(yùn)行,可以實(shí)現(xiàn)修改Dockerfile中ENTRYPOINT的命令萨西,也可以修改Dockerfile中CMD的參數(shù),非常靈活旭旭。
如下:
修改命令

修改參數(shù)

再來看一個(gè)使用CMD谎脯,并且沒有ENTRYPOINT的Dockerfile示例:

FROM alpine:latest
CMD wget -O - http://www.baidu.com

當(dāng)沒有明確定義ENTRYPOINT參數(shù)時(shí),其默認(rèn)參數(shù)為/bin/sh -c持寄,而CMD內(nèi)的參數(shù)將以字符串形式源梭,傳遞給該命令娱俺,因此以上Dockerfile最終執(zhí)行的就是:
/bin/sh -c "wget -O - http://www.baidu.com"

一個(gè)Dockerfile文檔示例

FROM node:9.4        #指定基礎(chǔ)鏡像
RUN mkdir -p /app        #在鏡像的文件系統(tǒng)內(nèi),創(chuàng)建一個(gè)/app目錄
WORKDIR /app        #切換上下文(工作目錄)至/app目錄下
COPY package.json /app/        #從主機(jī)上Dockerfile文件所在目錄下废麻,將package.json文件拷貝到鏡像中的/app目錄下
RUN npm install        #npm會(huì)安裝package.json內(nèi)Node.js所需的依賴包
COPY . /app        #與第四步一樣荠卷,拷貝主機(jī)內(nèi)文件(這里是應(yīng)用程序文件)到鏡像的/app目錄下
ENTRYPOINT ["npm"]        #與最后一行的命令結(jié)合,啟動(dòng)Node.js服務(wù)
CMD ["start"]

通過Dockerfile構(gòu)造鏡像的過程及相關(guān)解釋

常用的通過Dockerfile構(gòu)造鏡像的過程:

  1. 創(chuàng)建一個(gè)空目錄cmd_entrypoint烛愧。
  2. 進(jìn)入目錄中油宜,創(chuàng)建一個(gè)Dockerfile文件,寫入如下內(nèi)容:
FROM alpine:latest
ENTRYPOINT ["ping"]
CMD ["8.8.8.8", "-c", "3"]
  1. 在目錄下執(zhí)行命令:
    docker image build -t pinger .
    當(dāng)你的配置文件不是默認(rèn)的名字時(shí)怜姿,可以使用-f參數(shù)指定:
    docker image build -t pinger -f my-Dockerfile .
    構(gòu)造過程如下:

以上過程解釋如下:

  1. 拉取基礎(chǔ)鏡像alpine验庙,它的id為196d
  2. 執(zhí)行ENTRYPOINT,會(huì)通過第一步的基礎(chǔ)鏡像生成一個(gè)容器9ad9社牲,在容器內(nèi)執(zhí)行ENTRYPOINT所需的修改或變更操作等粪薛,操作完成后刪除容器9ad9,然后新加一層成為新的鏡像0669搏恤。
  3. 這個(gè)鏡像將作為下一個(gè)操作的基礎(chǔ)鏡像违寿,然后重復(fù)上面的過程,直至最后成為一個(gè)你所需的鏡像熟空。
    流程也可以參考:


多階段構(gòu)建

示例如下:
C程序源文件hello.c:

#include <stdio.h>
int main (void)
{
printf ("Hello, world!\n");
return 0;
}

常用的Dockerfile編寫方式如下:

FROM alpine:3.7
RUN apk update &&
    apk add --update alpine-sdk
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN mkdir bin
RUN gcc -Wall hello.c -o bin/hello
CMD /app/bin/hello

這種方式構(gòu)造的鏡像文件如下:

$ docker image ls | grep hello-world
hello-world latest e9b... 2 minutes ago 176MB

多階段構(gòu)建Dockerfile如下:

FROM alpine:3.7 AS build
RUN apk update && \
    apk add --update alpine-sdk
RUN mkdir /app
WORKDIR /app
COPY . /app
RUN mkdir bin
RUN gcc hello.c -o bin/hello

FROM alpine:3.7
COPY --from=build /app/bin/hello /app/hello
CMD /app/hello

得到的鏡像文件如下:

$ docker image ls | grep hello-world
hello-world-small latest f98... 20 seconds ago 4.16MB
hello-world       latest 469... 10 minutes ago 176MB

多階段構(gòu)建優(yōu)點(diǎn):減少黑客可攻擊的范圍藤巢、節(jié)省內(nèi)存和磁盤空間、更少的啟動(dòng)容器時(shí)間息罗、減少下載鏡像所需的帶寬掂咒。

Dockerfile編寫最佳實(shí)踐

一些建議:

  • 首先,我們要意識(shí)到容器的生命周期是短暫的迈喉。短暫的绍刮,意味著一個(gè)運(yùn)行著的容器可能很快就會(huì)被停止以及銷毀,而一個(gè)增加了新功能的容器挨摸,需要我們能夠快速的構(gòu)建和啟用孩革。我們需要盡可能的保證能夠快速的啟動(dòng)、停止容器內(nèi)的應(yīng)用得运。
  • 我們可能會(huì)針對(duì)同一個(gè)Dockerfile不停的構(gòu)建自己的鏡像膝蜈。我們應(yīng)該合理的組織Dockerfile內(nèi)的每個(gè)命令,以盡可能的利用容器構(gòu)建過程中的緩存功能熔掺。例如:
FROM node:9.4
RUN mkdir -p /app
WORKIR /app
COPY . /app
RUN npm install
CMD ["npm", "start"]

修改為:

FROM node:9.4
RUN mkdir -p /app
WORKIR /app
COPY package.json /app/
RUN npm install
COPY . /app
CMD ["npm", "start"]

以上兩個(gè)Dockerfile一般來說饱搏,都會(huì)在通過npm install安裝依賴包的時(shí)候花費(fèi)大量時(shí)間,而針對(duì)一個(gè)開發(fā)項(xiàng)目來說置逻,依賴包的變動(dòng)的情況是比較少的推沸,大部分時(shí)間都是應(yīng)用程序的變動(dòng)而導(dǎo)致重新構(gòu)建鏡像,因此將安裝依賴包的過程獨(dú)立出來诽偷,利用緩存的功能坤学,可以加速下一次的構(gòu)建過程疯坤。

  • 另一個(gè)最佳實(shí)踐就是盡可能減少你鏡像的layer數(shù)。通常來說深浮,layer越少压怠,鏡像越小,啟動(dòng)速度越快飞苇。而最好的減少layer數(shù)量的辦法就是整合你的命令菌瘫,因?yàn)椋赿okcerfile中布卡,每一個(gè)以FROM雨让、COPY、RUN這樣的關(guān)鍵字開頭的行忿等,就意味著一個(gè)新的layer栖忠。最常見的辦法就是整合多個(gè)RUN行為一行。例如:
RUN apt-get update
RUN apt-get install -y ca-certificates
RUN rm -rf /var/lib/apt/lists/*

整合為:

RUN apt-get update \
    && apt-get install -y ca-certificates \
    && rm -rf /var/lib/apt/lists/*
  • 通過.dockerignore文件贸街,除去那些不需要拷貝到鏡像內(nèi)的文件庵寞,達(dá)到減小鏡像體積的作用。用法與git中.gitignore一樣薛匪。
  • 在鏡像的文件系統(tǒng)內(nèi)捐川,減少安裝不必要的軟件。
  • 合理利用多階段構(gòu)建逸尖。

三古沥、保存和加載鏡像

第三種制作一個(gè)容器鏡像的方法是,通過一個(gè)文件進(jìn)行導(dǎo)入或加載娇跟。因?yàn)檠页荩粋€(gè)容器鏡像本質(zhì)上就是一個(gè)tar包的文件。請(qǐng)看以下示例:
docker image save -o ./backup/my-alpine.tar my-alpine
上面的命令逞频,將一個(gè)鏡像保存為指定的tar包纯衍。
docker image load -i ./backup/my-alpine.tar
上面的命令,將一個(gè)tar包加載為可用的鏡像苗胀。

管理鏡像(分享和運(yùn)送鏡像)

為了能夠把我們自定義的鏡像運(yùn)送到我們的生產(chǎn)環(huán)境中,我們需要給鏡像一個(gè)全球唯一的名稱瓦堵,通常這個(gè)動(dòng)作稱為:tagging基协。通常,我們把鏡像存放在一個(gè)集中管理的地方菇用,以方便他人獲取澜驮,這個(gè)地方稱為:倉庫(image registries)。

鏡像的標(biāo)簽

每個(gè)鏡像都有一個(gè)標(biāo)簽惋鸥,通常用來指定鏡像的版本號(hào)杂穷。

docker image pull alpine        #沒有指定tag時(shí)悍缠,默認(rèn)為lates
docker image pull alpine:3.5        #指定tag

鏡像的命名空間

一個(gè)完整的鏡像命名如下:

<registry URL>/<User or Org>/<name>:<tag>
  • <registry URL>
    鏡像存放的倉庫的名字,通常是一些公用的鏡像存儲(chǔ)及管理服務(wù)器耐量,例如docker hub飞蚓。
  • <User or Org>
    在前面的倉庫中定義的一個(gè)用戶或者組織。
  • <name>:<tag>
    上面已經(jīng)介紹過廊蜒,就是你的鏡像名以及標(biāo)簽趴拧。
    一些特殊的約定:
  • 如果忽略<registry URL>,那么默認(rèn)是使用docker hub倉庫山叮。
  • 如果忽略<tag>名稱著榴,那么默認(rèn)是latest。
  • 如果是docker hub上的官方鏡像屁倔,那么鏡像名不需要<User or Org>脑又。

常見鏡像名稱解釋:

Image Description
alpine Official alpine image on Docker Hub with the latest tag.
ubuntu:16.04 Official ubuntu image on Docker Hub with the 16.04 tag or version.
microsoft/nanoserver nanoserver image of Microsoft on Docker Hub with the latest tag.
acme/web-api:12.0 web-api image version 12.0 associated with the acme org.The image is on Docker Hub.
gcr.io/gnschenker/sampleapp:1.1 sample-app image with the 1.1 tag belonging to an individual with the gnschenker ID on Google's container registry.

推送鏡像到一個(gè)倉庫

  1. 將需要推送的鏡像取一個(gè)自定義的tag
    docker image tag alpine:latest gnschenker/alpine:1.0
  2. 登錄到你的倉庫
    docker login -u gnschenker -p <my secret password>
  3. 推送鏡像
    docker image push gnschenker/alpine:1.0
    以上是默認(rèn)使用docker hub倉庫,你需要有相關(guān)的賬號(hào)密碼锐借。

相關(guān)參考:Docker鏡像上傳到阿里云

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挂谍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞎饲,更是在濱河造成了極大的恐慌口叙,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗅战,死亡現(xiàn)場(chǎng)離奇詭異妄田,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驮捍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門疟呐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人东且,你說我怎么就攤上這事启具。” “怎么了珊泳?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鲁冯,是天一觀的道長。 經(jīng)常有香客問我色查,道長薯演,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任秧了,我火速辦了婚禮跨扮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己衡创,他們只是感情好帝嗡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著璃氢,像睡著了一般哟玷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拔莱,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天碗降,我揣著相機(jī)與錄音,去河邊找鬼塘秦。 笑死讼渊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尊剔。 我是一名探鬼主播爪幻,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼须误!你這毒婦竟也來了挨稿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤京痢,失蹤者是張志新(化名)和其女友劉穎奶甘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祭椰,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡臭家,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了方淤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钉赁。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖携茂,靈堂內(nèi)的尸體忽然破棺而出你踩,到底是詐尸還是另有隱情,我是刑警寧澤讳苦,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布带膜,位于F島的核電站,受9級(jí)特大地震影響医吊,放射性物質(zhì)發(fā)生泄漏钱慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一卿堂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦草描、人聲如沸览绿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饿敲。三九已至,卻和暖如春逛绵,著一層夾襖步出監(jiān)牢的瞬間怀各,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工术浪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓢对,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓胰苏,卻偏偏與公主長得像硕蛹,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硕并,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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