摘要:本文引用至之所以這么牛逼一是在于他強(qiáng)大的生態(tài)環(huán)境以及他和的新穎的概念鏡像的簡(jiǎn)單剖析的我們可以理解為積木一層一層往上搭最后完成一個(gè)工程化的大項(xiàng)目在最初實(shí)際上只有一個(gè)靜態(tài)的相當(dāng)于只能讀所以你所有的改動(dòng)并不會(huì)影響到原來(lái)的上只會(huì)一層一層的疊加比如
本文引用至: dockerfile
docker 之所以這么牛逼, 一是在于他強(qiáng)大的生態(tài)環(huán)境, 以及,他container和writable layer 的新穎的概念.
docker鏡像的簡(jiǎn)單剖析docker的images,我們可以理解為積木, 一層一層往上搭, 最后完成一個(gè)工程化的大項(xiàng)目.
在最初,docker實(shí)際上,只有一個(gè)靜態(tài)的image(Ps: read-only). 相當(dāng)于只能讀, 所以, 你所有的改動(dòng)并不會(huì)影響到原來(lái)的image上, 只會(huì)一層一層的疊加, 比如, 你在Ubuntu的image上面, 再接一層nodeJS的image. 實(shí)際上的結(jié)果是, 兩個(gè)image疊加起來(lái).
這里放一張 the Docker book的說(shuō)明圖:
(Ps: 算啦,估計(jì)大家也沒(méi)聽(tīng)懂,還是在下面根據(jù)實(shí)例,來(lái)進(jìn)行細(xì)致的區(qū)分吧)
docker 在下載image的時(shí)候,會(huì)在/var/lib/docker目錄下創(chuàng)建相關(guān)的image 目錄. 而運(yùn)行的container則會(huì)放在/var/lib/docker/containers中.
另外,docker中的image,是存儲(chǔ)在docker倉(cāng)庫(kù). 現(xiàn)在,我們通過(guò)快速創(chuàng)建自已的倉(cāng)庫(kù)來(lái)仔細(xì)了解一下docker是怎樣擁有這樣一個(gè)完善的生態(tài)的.
docker 倉(cāng)庫(kù)首先, 要想擁有自己的docker 倉(cāng)庫(kù), 你得有一個(gè)自己的docker賬號(hào).so, 那就想apply 一個(gè)唄. 在docker hub上面注冊(cè)一下自己的賬號(hào)就行.
登錄指令在docker中,不僅支持web查看docker中的內(nèi)容, 而且還支持使用命令行登錄.
// 登錄到docker docker login // 然后輸入賬戶密碼就ok了 // 使用完畢,想要登出 docker logout
實(shí)際上,docker會(huì)將你的認(rèn)證信息存放在. ~/.docker/config.json當(dāng)中。
images 常用命令如果瀏覽了上面的docker倉(cāng)庫(kù), 會(huì)發(fā)現(xiàn)在一個(gè)repository里面會(huì)存在很多images, 比如ubuntu的repository.不同的images發(fā)布,代表的都是特定的版本系統(tǒng). 所以,在拉取的時(shí)候,需要額外注意一下你需要的指定docker images.
images的拉取在container中,我們講過(guò),使用docker run的時(shí)候, 你會(huì)發(fā)現(xiàn)如果你的images里面沒(méi)有存在指定的image時(shí), docker會(huì)主動(dòng)去docker hub里面找,然后下載,并且自動(dòng)運(yùn)行.
// 運(yùn)行最新版的ubuntu image docker run -t -i ubuntu:latest
如果,你想自己手動(dòng)下載images的話,可以直接pull
// 手動(dòng)拉取images docker pull ubuntu:latest // 拉取12.04版本的ubuntu images docker pull ubuntu:12.04
如果在拉取的時(shí)候,想知道這個(gè)image是否是真正存在的話,就可以使用.docker 提供的搜索指令.
搜索指定docker在docker中,可以使用自帶的search命令,搜索所有含有指定term的image. 相當(dāng)于js中的search 方法.
// 搜索name中含有demo的image docker search demo // 結(jié)果為: 名字. 通常為: author/image_name . 通常搜索的就是這個(gè) // 描述: 就是一段文字描述 NAME DESCRIPTION STARS OFFICIAL AUTOMATED
查到之后,我們就可以使用pull將指定的庫(kù),拉下來(lái)了.
創(chuàng)建自己的image上面說(shuō)過(guò), contianer是copy image運(yùn)行的進(jìn)程容器,image是不會(huì)變的read-only 塊. 但是,如果我們?cè)赾ontainer里面, 改動(dòng)了一些設(shè)置,比如,下載了node, 而且,我想要保存我這次改動(dòng), 以至于,下次我想重新,啟動(dòng)該image時(shí), 他已經(jīng)具備了node.
// 現(xiàn)在我再ubuntu:latest上面安裝了node // 偽代碼 npm install node -g
docker提供了一個(gè)非常快捷的方式就是創(chuàng)建自己的docker image. 使用docker commit.
// 查看剛才改動(dòng)的container ID docker ps -a -q -l // 得到 docker_id, 提交到自己的庫(kù)中 docker commit docker_id villainHR/node // 之后會(huì)返回新的image id
需要注意,docker commit提交的并不是一個(gè)整體的100+MB的ubuntu+node. 他只會(huì)將兩個(gè)倉(cāng)庫(kù)的差異提交,比如原來(lái)image和新的image比起來(lái),就是多了一個(gè)npm install node -g命令.
使用DockerfileDockerfile是為了迅速的構(gòu)建image而出現(xiàn)的. 他與docker commit 的區(qū)別在于. 能夠迅速的更替歷史image 命令. 比如,我們以前下載的npm是version 2, 現(xiàn)在想要更換為npm@3的話,則難度就不是一般的了. 但是,如果我們能夠像寫(xiě)命令一樣將下載的配置命令下載Dockerfile里面, 那么以后我們想要更換版本,就是很方便的啦.
ok, 現(xiàn)在我們來(lái)了解一下Dockerfile是怎樣的運(yùn)行的.
這里,我們利用dockerfile 來(lái)搭建一個(gè)簡(jiǎn)單的webServer. 首先創(chuàng)建一個(gè)你自己的dockerfile目錄
mkdir first_docker cd first_docker touch Dockerfile
然后, 確保你有ubuntu:latest image.因?yàn)? 接下來(lái)我們就是基于它,來(lái)搭建我們的server.
# first dockerfile demo FROM ubuntu:latest # 設(shè)置該dockerfile的作者和聯(lián)系郵箱 MAINTAINER Jimmy "villainhr@gmail.com" # 開(kāi)始配置環(huán)境, 下載apt-get,生成index.html的文件 RUN apt-get update && apt-get install -y nginx RUN echo "first demo" > /usr/share/nginx/html/index.html # 暴露server的port EXPOSE 80
說(shuō)一下上面的命令內(nèi)涵.
FROM: 用來(lái)指定第一層image, 這是必須有的. 并且指定的image是存在在你的computer中. 相當(dāng)于是 docker run.
RUN: 這是用來(lái)在container中,做出相應(yīng)的修改. 相當(dāng)于 修改+docker commit xxx. 給原來(lái)的image加上一層layer. 然后, docker會(huì)在你commit新一層之后,重新docker run你最新改動(dòng)過(guò)的image
MAINTAINER: 設(shè)置作者和聯(lián)系郵箱.其實(shí)就是docker commit 后面的Name參數(shù). 而且加上了聯(lián)系郵箱. 這是在dockerfile 運(yùn)行完后,會(huì)自動(dòng)添加到image上的.
EXPOSE: 用來(lái)給最新的container 設(shè)置與外部交流的port
上面簡(jiǎn)單的介紹了基本的dockerfile的命令. 不過(guò), 這尼瑪太簡(jiǎn)單了,不符合我們一貫追求到底的風(fēng)格.
這里, 我們?cè)趤?lái)細(xì)說(shuō)一下RUN這個(gè)命令. 實(shí)際上, 這應(yīng)該是dockerfile的關(guān)鍵. RUN的原理很簡(jiǎn)單, 就是commit + run. 先創(chuàng)建一個(gè)新的image 然后 在這個(gè)基礎(chǔ)上將原有的container替換為新的,如果某一步的RUN發(fā)生錯(cuò)誤,則container會(huì)停在那個(gè)階段, 這樣,你可以直接進(jìn)入該container去查看,你那一步的RUN發(fā)生了什么BUG。 另外, 使用RUN的時(shí)候, 需要注意, 由于,dockerfile是由上到下解析的, 比如你一開(kāi)始FROM ubuntu的image, 那么此時(shí)的環(huán)境是停留在ubuntu的shell中的.
比如:
RUN touch demo.js // 等同于 /bin/sh -c touch demo.js
所以, 如果你調(diào)用的image 并沒(méi)有shell的話, 那么久需要使用exec調(diào)用系統(tǒng)shell 來(lái)執(zhí)行命令.
// 調(diào)用系統(tǒng)的shell來(lái)運(yùn)行, 實(shí)際上就是 exec xxx xxx xxx. RUN ["npm","install","node"]運(yùn)行dockerfile
上面的dockerfile文件配置好了之后,就輪到我們運(yùn)行dockerfile.直接運(yùn)行docker build即可.
// 注意后面的".", 用來(lái)指定搜索dockerfile文件的路徑. docker build -t="jimmy/first_dockerfile" .
說(shuō)一下docker build的指令吧.
// 基本格式為: docker build -t="repository/name:tag" directory // -t用來(lái)指定生成的image的name,比如倉(cāng)庫(kù),image的名字以及他的tag,如果你不指定tag, 那么docker會(huì)自動(dòng)添加latest代替。 // directory 用來(lái)相對(duì)于當(dāng)前運(yùn)行build的目錄, 搜索指定的dockerfile.當(dāng)然,你也可以使用絕對(duì)路徑了
順利的話,應(yīng)該就會(huì)有, 下列的信息出來(lái).
Sending build context to Docker daemon 2.048 kB Step 1 : FROM ubuntu:latest ---> c5f1cf30c96b Step 2 : MAINTAINER jimmy "villainhr@gmai.com" ---> Running in 078148a5086a ---> 11b061f665d1 Removing intermediate container 078148a5086a Step 3 : RUN cd /var ---> Running in ffd3141e64c8 ---> a4d7c5303b60 Removing intermediate container ffd3141e64c8 Step 4 : RUN touch demo.js ---> Running in c8393a6fcc98 ---> 109b402b9adc Removing intermediate container c8393a6fcc98 Step 5 : EXPOSE 80 ---> Running in 2c064f4bac57 ---> ff7ad58a5d8a Removing intermediate container 2c064f4bac57 Successfully built ff7ad58a5d8a
然后, 你可以使用docker images查看.就會(huì)發(fā)現(xiàn)多出來(lái)一個(gè)image.
dockerfile cache上面已經(jīng)提到過(guò),使用docker build的時(shí)候,如果你的dockerfile中的某一步出現(xiàn)問(wèn)題的話,你生成的image會(huì)停留在那一步.當(dāng)你fix errors時(shí), 重新運(yùn)行docker build, 此時(shí),docker是不會(huì)真的重頭來(lái)建一遍的,他會(huì)使用你改動(dòng)line的前一個(gè)image,然后以此為基點(diǎn)繼續(xù)向下構(gòu)建.
不過(guò),如果你使用緩存的話,他前面的版本id是不會(huì)發(fā)生改變的.如果你想完整的得到一個(gè)新的ID的話,就可以在build的時(shí)候,禁用掉cache.
docker build --no-cache -t="jimmy/first_dockerfile" .
不過(guò),該方法是不推薦的. 因?yàn)橐粋€(gè)非常棒的cache機(jī)制,就被你硬生生的cancel. 而且,這也極力不推薦使用該方法進(jìn)行cache的取消.以為,有些地方,我們完全可以利用cache來(lái)加快速度.這就需要使用到ENV關(guān)鍵字.來(lái)幫助我們,另外利用cache.
在講解ENV之前,先給大家講解一下docker cache的運(yùn)行機(jī)理.
(是不是感覺(jué)很激動(dòng)~)
實(shí)際上,機(jī)理就一句話:ID命中. 因?yàn)閐ocker在你每次運(yùn)行一行命令的時(shí)候,會(huì)自動(dòng)生成一個(gè)id值.
Sending build context to Docker daemon 2.048 kB Step 1 : FROM ubuntu:latest ---> c5f1cf30c96b // 這就是ID值
docker借由這個(gè)ID值,來(lái)判斷是否有cache鏡像.所以,這里就需要借一下ENV這個(gè)比較費(fèi)的指令,來(lái)靈活的幫助我們使用cache.
配置化cacheENV的就是給docker來(lái)設(shè)置變量的. 基本格式為:
# 一個(gè)一個(gè)的賦值 ENV key value // demo: ENV name jimmy ENV age 18 # 另外,還可以一起賦值 ENV key=value[...] // demo: ENV name=jimmy age=18
而通過(guò)ENV我們就可以完美的告訴docker 從這里開(kāi)始,你就不能使用cache,自己的重新來(lái).(因?yàn)?每條指令都會(huì)生成layer并且有獨(dú)立的id,一旦你更改的ENV,那么從該指令開(kāi)始id都會(huì)發(fā)生改變,也就匹配不到緩存了)
看個(gè)demo:
# 第一個(gè)dockerfile FROM ubuntu:latest MAINTAINER jimmy "villainhr@gmai.com" ENV REFRESH first # 這里設(shè)置的是refresh=first RUN cd /var RUN touch demo.js EXPOSE 80 // 使用docker build ... 后面就會(huì)生成一系列新的id和images // 現(xiàn)在修改dockerfile # 第二個(gè)dockerfile FROM ubuntu:latest MAINTAINER jimmy "villainhr@gmai.com" ENV REFRESH second # 這里設(shè)置的是refresh=second RUN cd /var RUN touch demo.js EXPOSE 80 // 開(kāi)始運(yùn)行docker build... 你會(huì)發(fā)現(xiàn),從下面語(yǔ)句開(kāi)始. ENV REFRESH second // 其docker id就已經(jīng)發(fā)生了改變,并且docker 沒(méi)有了use cache的提示.說(shuō)明,下面就沒(méi)有命中緩存了. 所以,如果你想在某一段不使用緩存,只需要將ENV后面的value改變即可.
創(chuàng)建完后, 我們可以使用docker history,查看一下剛才創(chuàng)建的image的整個(gè)流程.
// 查看image創(chuàng)建的過(guò)程 docker history jimmy/first_dockerfile // 輸出的結(jié)果為: 2322ddc85cc3 10 hours ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B b39397abc7aa 10 hours ago /bin/sh -c touch demo.js 0 B 3c9a4daf4c42 10 hours ago /bin/sh -c cd /var 0 B b1c2f890a262 10 hours ago /bin/sh -c #(nop) ENV REFRESH=second 0 B 2cf0ee3c373c 10 hours ago /bin/sh -c #(nop) MAINTAINER jimmy "villainhr 0 B
俺的目的,其實(shí)是想讓你們看看,docker在每一層是怎么執(zhí)行的--/bin/sh. 了解了之后,我們就繼續(xù)了.
docker container的接口暴露上面通過(guò)dockerfile 已經(jīng)暴露了一個(gè)80接口,用來(lái)和外部通信。 不過(guò),如果我們沒(méi)有使用EXPOSE暴露接口的話, 那應(yīng)該怎么做呢?
我們可以直接在外部運(yùn)行docker image, 手動(dòng)指定暴露的端口.
# 同樣,暴露80端口給外部交互 docker run -d -p 80 --name demo jimmy/node node -jimmy app.js # -d是daemon的意思 # -p 80 表示暴露80的port給外部 # node -jimmy app.js 表示在jimmy/node image里面運(yùn)行的指令
這里, 我們需要額外了解一下80端口的開(kāi)啟. docker 其實(shí)是在底層上面,虛擬化了存儲(chǔ). 并且,docker在運(yùn)行的時(shí)候,會(huì)自動(dòng)向主機(jī)要一個(gè)ip(假的), 相當(dāng)于,有了自己的host. (這不就一個(gè)主機(jī)嗎?)
這里我們開(kāi)啟的80端口,是docker在內(nèi)部虛擬開(kāi)啟的, 他會(huì)從32768 到 61000端口之間,隨機(jī)抽一個(gè)映射到docker開(kāi)啟的80端口上, 依此來(lái)和外部進(jìn)行真正的交互(膜拜///).
# 使用docker ps -l 來(lái)查看開(kāi)啟情況 docker ps -l # 得到: 只截取了一部分. 0.0.0.0:49154->80 tcp # 或者指定查看docker端口開(kāi)啟情況 docker port c96f2c18bb64 80 // ID也可以使用name代替 # 返回: 0.0.0.0:49154手動(dòng)指定端口
如果你不想讓docker決定的綁定的接口是哪一個(gè),ok, 你可以自己指定.
# 手動(dòng)指定端口 # 指定docker的8080連接到container暴露的80端口 docker run -d -p 8080:80 --name demo jimmy/node node -jimmy app.js # 甚至你也可以指定ip+port # 指定docker的127.0.0.1:8080連接container的80 docker run -d -p 127.0.0.1:8080:80 --name demo jimmy/node node -jimmy app.js利用EXPOSE
在寫(xiě)dockerfile的時(shí)候,我們已經(jīng)了解了,使用EXPOSE可以完美的實(shí)現(xiàn)端口的暴露. 但如果,我們?cè)赿ockerfile里面暴露多個(gè)port的話,那么-p的參數(shù),感覺(jué)有點(diǎn)雞肋啊喂~
不過(guò),現(xiàn)在我們可以使用-P(注意是大寫(xiě)). 來(lái)手動(dòng)開(kāi)啟所有在dockerfile中,通過(guò)EXPOSE暴露的端口.
docker run -d -P --name demo jimmy/node node -jimmy app.js外部訪問(wèn)
通過(guò)端口開(kāi)啟之后,我們就可以間接的訪問(wèn)docker的路由, 來(lái)訪問(wèn)在docker里面開(kāi)啟的端口了.
# 假如上面我們通過(guò)dockre暴露的端口是34251的話,就可以在docker環(huán)境外訪問(wèn)了. ping localhost:34251dockerfile常用指令 自動(dòng)化運(yùn)行CMD
你是不是已經(jīng)厭煩了使用docker run 來(lái)運(yùn)行命令了呢? 你是不是已經(jīng)討厭重復(fù)的copy命令運(yùn)行了呢?
那么請(qǐng)使用CMD吧.
CMD的作用是,用來(lái)指定當(dāng)你調(diào)其對(duì)應(yīng)的container時(shí), 運(yùn)行的命令.
比如在dockerfile中,指定/bin/bash.
# 當(dāng)調(diào)起container時(shí),運(yùn)行/bin/bash docker run -t -i jimmy/ubuntu:latest /bin/bash # 等同于在dockerfile中指定CMD CMD ["/bin/bash"] // 運(yùn)行docker run docker run -t -i jimmy/ubuntu:latest
不過(guò),如果你在run后面手動(dòng)指定指令運(yùn)行的話,會(huì)默認(rèn)覆蓋掉CMD提供的命令.
熟悉了CMD,感覺(jué)有種RUN的感覺(jué). 但,這兩者的區(qū)別還是很大的
RUN: 一般是用來(lái)給image增加layer來(lái)完善image, 他一旦執(zhí)行完,就和后面的運(yùn)行沒(méi)有關(guān)系了
CMD: 這個(gè)在docker build過(guò)程中,是沒(méi)有半毛錢關(guān)系的. 他只和在調(diào)用image時(shí),關(guān)系比較大
強(qiáng)制運(yùn)行ENTRYPOINT這里的ENTRYPOINT和CMD很相似. 可以說(shuō),在一定程度上兩者可以互相替代,但,兩者的實(shí)際意義相差還是挺大的.
ENTRYPOINT的主要功能是強(qiáng)制執(zhí)行的環(huán)境.
# 指定ENTRYPOINT為/bin/sh ENTRYPOINT ["/bin/sh"] // 然后在build之后,調(diào)起container # 我們嘗試在run后面加上參數(shù): docker run -t -i jimmy/demo /bin/bash/ // 不出意外的話,會(huì)得到一個(gè)bug提示: >> /bin/sh: 0: Can"t open /bin/bash/
所以, ENTRYPOINT的主要功能實(shí)際上是,指定了內(nèi)部運(yùn)行命令的解析器. 而使用docker run添加的命令,會(huì)被當(dāng)做參數(shù)添加給ENTRYPOINT.
# 已經(jīng)指定了ENTRYPOINT ["/bin/sh"] # 運(yùn)行docker run docker run -t -i jimmy/demo /bin/bash/ # 實(shí)際上相當(dāng)于(不出錯(cuò)才怪嘞...) /bin/sh /bin/bash/
另外,我們還可以使用CMD配合ENTRYPOINT寫(xiě)成默認(rèn)參數(shù)的效果.
# 默認(rèn)執(zhí)行 /bin/bash default.sh ENTRYPOINT ["/bin/bash"] CMD ["default.sh"] # 如果你在docker run中指定了參數(shù)的話,則CMD會(huì)默認(rèn)被代替 docker run jimmy/demo sam.sh
不過(guò),CMD和ENTRYPOINT都只能在dockerfile里面出現(xiàn)一次.
指定運(yùn)行目錄WORKDIR既然,我們能夠在dockerfile里面運(yùn)行指定的命令。 但,有時(shí),我們僅僅是想在不同的目錄中執(zhí)行不同的命令. 那,在dockerfile中,如何做到靈活的目錄切換呢?
那就得使用docker提供的WORKDIR命令了.
# 在/var/data里面創(chuàng)建data.js WORKDIR /var/data RUN touch data.js # 然后在/etc 下創(chuàng)建data.conf文件 WORKDIR /etc RUN touch data.conf
并且當(dāng)你在使用docker run時(shí),他也會(huì)停留在使用WORKDIR指定的目錄中.
環(huán)境變量的設(shè)置ENVENV在dockerfile里面的用處,應(yīng)該算是灰常大的. 什么靈活更新,什么變量設(shè)置,什么更改全局變量等. 都是so easy.
那ENV到底是用來(lái)干嘛的?
答: 就是用來(lái)設(shè)置變量的啊喂. 只是他是設(shè)置全局變量.
比如像PATH神馬的之類的.
# 設(shè)置一個(gè)DATA的全局變量. ENV DATA=jimmy
ENV最獨(dú)特之處在于,他所設(shè)置的變量,會(huì)在你運(yùn)行的時(shí)候生效.即,如果你修改了PATH,他也會(huì)在container中立即生效.
# 修改環(huán)境變量 ENV PATH=$PATH:/user/bin // 現(xiàn)在進(jìn)入到運(yùn)行的container中 echo $PATH >> /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/data掛載通用盤VOLUME
在說(shuō)里面正式的內(nèi)容之前,我們先來(lái)說(shuō)一下,什么叫做VOLUME. 說(shuō)人話吧,VOLUME叫做數(shù)據(jù)卷, 相當(dāng)于通用盤一樣的東西. 他其實(shí)也是一個(gè)存儲(chǔ)裝置,我們就把他叫做硬盤吧. 這個(gè)硬盤不普通,有>1的外接口.(說(shuō)人話) 每一個(gè)外接口,都可以接入到一個(gè)操作系統(tǒng)里面. 即,實(shí)現(xiàn)了多個(gè)系統(tǒng)的數(shù)據(jù)共享.
一句話:
VOLUME就是一個(gè)數(shù)據(jù)共享盤
而,docker秉承著,虛擬儲(chǔ)存idea, 想下面idea踐行到底.
wirte once, run anywhere
(感覺(jué),在哪見(jiàn)過(guò))
所以, dockerfile提供了一個(gè)VOLUME的指令,能夠讓我們指定數(shù)據(jù)卷的位置.
# 指定/opt/data為數(shù)據(jù)卷 VOLUME ["/opt/data"] # 指定多個(gè)目錄為數(shù)據(jù)卷/opt/data, /opt/project VOLUME ["/opt/data","/opt/project"]
當(dāng)然,關(guān)于數(shù)據(jù)卷的操作,肯定不止掛載這一點(diǎn),還有遷移,備份等等,相關(guān)操作. 具體,可以參考: Docker VOLUME
添加外部文件ADD有時(shí),我們僅僅是想將外部文件copy到container中,docker有辦法嗎?
nonsense
docker 提供了ADD命令,來(lái)幫助我們完成文件的添加. 不過(guò),這里ADD有點(diǎn)限制, 即, 你添加的文件或者目錄,只能在docker build運(yùn)行的目錄下, 因?yàn)?這是docker在調(diào)起container的時(shí)候,只將該目錄放進(jìn)了daemon(尷尬~)
# 現(xiàn)假設(shè),docker build運(yùn)行的目錄為: /data // 只能添加指定目錄下 // 將/data/sam.js 添加到image中的/opt/node/sam.js // 如果存在該文件,則不會(huì)被覆蓋 ADD sam.js /opt/node/ # 添加文件,還可以使用通配符 // 將所有的js文件,添加到node目錄下 ADD *.js /opt/node/ # 如果destination不是絕對(duì)路徑,則相對(duì)于最近的WORKDIR // 如果最近的WORKDIR為/var // 則下列添加的路徑為/var/opt/node ADD *.js opt/node/
當(dāng)文件被添加到指定目錄中時(shí),該文件的權(quán)限是755,并且UID和GID都是0.
ADD 還支持url添加,以及文件自動(dòng)解壓.
# 使用url添加 // 將指定路由的文件放到根目錄當(dāng)中 ADD http://example.com/foobar / # 自動(dòng)解壓tar.gz文件 // 將文件解壓過(guò)后放在指定目錄中 ADD latest.tar.gz /var/www/wordpress/純粹的COPY
COPY和ADD非常類似. 我們可以做個(gè)類比:
ADD 包含 COPY
COPY做的事情比不上ADD, 他比ADD少了解壓縮和URL下載的功能. 不過(guò),他耗費(fèi)的性能比較少,他只做純粹的添加和下載.他的結(jié)構(gòu)和ADD一毛一樣. 不過(guò), 有一點(diǎn),COPY的時(shí)候,如果遇到目錄不存在的情況下,COPY會(huì)自動(dòng)創(chuàng)建
COPY file.js /opt/data/添加個(gè)人信息LABEL
顧名思義,使用LABEL就是給你的image打上獨(dú)一無(wú)二的標(biāo)簽.讓別人能夠了解,這個(gè)Image是屬于你的. 又或是,用來(lái)提醒你自己,這個(gè)image現(xiàn)在處于哪一個(gè)版本狀態(tài).
# 設(shè)置自己的label LABEL owner="jimmy" version="0.0.1"
在創(chuàng)建完image之后, 我們可以使用docker inspect來(lái)查看我們已經(jīng)打的LABEL
docker inspect jimmy/node ... labels:{ owner:"jimmy", version:"0.0.1" } ...
本人覺(jué)得, 這個(gè)指令其實(shí)真的,有時(shí), 母雞用到什么地方去...
并且,書(shū)寫(xiě)的時(shí)候,最好多個(gè)連著寫(xiě),因?yàn)檫@樣只會(huì)增加一層image.(image的層數(shù)是有限制的)
這是docker提供的另外一個(gè),讓我有點(diǎn)懵逼的命令. 他的實(shí)際效果和ENV的區(qū)別可以趨近于無(wú)。
# 使用ARG定義變量 ARG buildno # 設(shè)置默認(rèn)值 ARG user1=someuser
當(dāng)然,我們可以在命令中,手動(dòng)指定替換.
# 在dockerfile定義了默認(rèn)變量 ARG user=jimy # 在運(yùn)行時(shí),進(jìn)行手動(dòng)替換 docker build --build-arg user=sam -t jimmy/demo .
上面說(shuō)了ARG和ENV比較類似,不過(guò),里面的區(qū)別還是有的. 即, ARG只能用在docker build的階段, 并且不會(huì)被保存在image中,這就是和ENV的區(qū)別.
模板image之ONBUILD因?yàn)閐ockerfile的構(gòu)建的層數(shù)有限制,所以,這也帶給了我們一些麻煩, 如果搭建的環(huán)境過(guò)多,則會(huì)造成寫(xiě)到一半,發(fā)現(xiàn)dockerfile已經(jīng)full. 這時(shí)候, 就輪到ONBUILD出場(chǎng)了. ONBUILD的作用在于,他可以完美的實(shí)現(xiàn)模板image的搭建.
ONBUILD的主要作用在于,他定義的命令,可以在子dockerfile中使用.(md... 好繞口)
# 使用ONBUILD 默認(rèn)下載Apache ONBUILD RUN apt-get update && apt-get install -y apache2 // 然后運(yùn)行docker file 會(huì)得到下列結(jié)果 Step 3 : ONBUILD RUN apt-get update && apt-get install -y apache2 ---> Running in 0e117f6ea4ba ---> a79983575b8 //然后生成一個(gè)新的image,我們這里暫且叫他jimmy/demo
接下來(lái),我們?cè)賮?lái)寫(xiě)一個(gè)dockerfile
# 這里繼承上面的jimmy/demo FROM jimmy/demo:latest ENV SEX=001 // 運(yùn)行上面的dockerfile,得到: Step 0 : FROM jimmy/demo # Executing 1 build triggers Step onbuild-0 : ADD . /var/www/ ---> 1a018213a59d ---> 1a018213a59d Step 1: ENV SEX=001 ...
細(xì)心的童鞋可以發(fā)現(xiàn)這一條命令:
Step onbuild-0 : RUN apt-get update && apt-get install -y apache2 ---> 1a018213a59d ---> 1a018213a59d
他居然在這里自動(dòng)運(yùn)行了. 所以,我們可以將ONBUILD命令理解為模板命令. 即,子dockerfile里面運(yùn)行時(shí)同樣生效(這里,我沒(méi)有說(shuō)grandchildren的事).
但ONBUILD只能往下延伸一級(jí). 相當(dāng)于你用ONBUILD定義的命令,有兩次有效次數(shù),一次在build原來(lái)Image時(shí),已經(jīng)用掉了. 所以, 另外一次(在子dockerfile中使用)用掉了之后就無(wú)效了. grandchildren dockerfile就沒(méi)法使用了.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26676.html
摘要:和區(qū)別讓用戶可以進(jìn)入查看輸出等等操作,但是并不會(huì)另外啟動(dòng)一個(gè)進(jìn)程如果你用來(lái)退出,同時(shí)這個(gè)信號(hào)會(huì)默認(rèn)情況會(huì)啟動(dòng)另外一個(gè)進(jìn)程來(lái)進(jìn)入,這里的操作是在這個(gè)進(jìn)程下的。 走在通往docker的大道上——docker基礎(chǔ)知識(shí)匯總 最后編輯時(shí)間:2017年03月09日 1.Docker是什么 Docker是一種新的容器化技術(shù),為應(yīng)用開(kāi)發(fā)和部署提供一站式容器解決方案,能幫助開(kāi)發(fā)者高效快速的構(gòu)建應(yīng)用,實(shí)...
摘要:源碼解讀系列一好難都跑不起來(lái)怎么破了解一下唄閱讀框架源碼第一步搞定環(huán)境小伙伴剛接觸的時(shí)候會(huì)感覺(jué)壓力有點(diǎn)大更直觀的說(shuō)法是難開(kāi)發(fā)組是不贊成難這個(gè)說(shuō)法的的代碼都是實(shí)現(xiàn)的而又是世界上最好的語(yǔ)言的代碼閱讀起來(lái)是很輕松的開(kāi)發(fā)組會(huì)用源碼解讀系列博客深 date: 2018-8-01 14:22:17title: swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? doc...
摘要:源碼解讀系列一好難都跑不起來(lái)怎么破了解一下唄閱讀框架源碼第一步搞定環(huán)境小伙伴剛接觸的時(shí)候會(huì)感覺(jué)壓力有點(diǎn)大更直觀的說(shuō)法是難開(kāi)發(fā)組是不贊成難這個(gè)說(shuō)法的的代碼都是實(shí)現(xiàn)的而又是世界上最好的語(yǔ)言的代碼閱讀起來(lái)是很輕松的開(kāi)發(fā)組會(huì)用源碼解讀系列博客深 date: 2018-8-01 14:22:17title: swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? doc...
摘要:將安裝與模塊安裝放在一起的話,則每次修改源代碼,都需要重新安裝,這顯然不合適。使用設(shè)置鏡像元數(shù)據(jù)使用指令,可以為鏡像設(shè)置元數(shù)據(jù),例如鏡像創(chuàng)建者或者鏡像說(shuō)明。自從年雙十一正式上線,累計(jì)處理了億錯(cuò)誤事件,付費(fèi)客戶有金山軟件百姓網(wǎng)等眾多品牌企業(yè)。 譯者按: Dockerfile 的語(yǔ)法非常簡(jiǎn)單,然而如何加快鏡像構(gòu)建速度,如何減少 Docker 鏡像的大小卻不是那么直觀,需要積累實(shí)踐經(jīng)驗(yàn)。這篇...
摘要:安裝完成后,可以用以下命令查看下版本信息。另外,如果要?jiǎng)h除剛運(yùn)行的兩個(gè)容器,可以總結(jié)本文從數(shù)據(jù)持久化開(kāi)始說(shuō)起,淺談了和并附送如何用這兩種方式分別搭建環(huán)境,并在對(duì)比中展示了它們各自的特點(diǎn)。 上一文中提到,每次對(duì)容器做了改動(dòng),如果不把它 commit 成新的鏡像,在刪除容器后,數(shù)據(jù)也會(huì)丟失,有沒(méi)有什么更好的辦法來(lái)保存數(shù)據(jù)呢?使用數(shù)據(jù)卷就可以解決這個(gè)問(wèn)題。 另外,相對(duì)于用 commit 容器...
閱讀 832·2023-04-26 00:13
閱讀 2826·2021-11-23 10:08
閱讀 2450·2021-09-01 10:41
閱讀 2118·2021-08-27 16:25
閱讀 4200·2021-07-30 15:14
閱讀 2365·2019-08-30 15:54
閱讀 864·2019-08-29 16:22
閱讀 2742·2019-08-26 12:13