使用commit理解鏡像構(gòu)成
docker commit 命令除了學(xué)習(xí)之外婉商,還有一些特殊的場(chǎng)合適合使用,比如被入侵后保存現(xiàn)場(chǎng)等。
定制鏡像,應(yīng)該使用 Dockerfile 來完成碗旅,不要使用 docker commit 定制鏡像。
鏡像是容器的基礎(chǔ)镜悉,每次執(zhí)行 docker run 的時(shí)候都會(huì)指定哪個(gè)鏡像作為容器運(yùn)行的基礎(chǔ)祟辟。
直接使用鏡像可以滿足一定的需求,當(dāng)鏡像無法直接滿足的時(shí)候侣肄,就需要定制鏡像旧困。
定制一個(gè) web 應(yīng)用服務(wù)器
[root@ip-10-1-0-142 ~]# docker run --name webserver -itd -p 80:80 nginx:latest
e829ded69fa81c0afddcce54109898e02e15a205cf07e63d101de8c572dc7a54
直接用瀏覽器訪問
定制化web頁面,可以將文字進(jìn)行更改稼锅,使用docker exec 命令進(jìn)入到容器吼具,再進(jìn)行內(nèi)容修改
[root@ip-10-1-0-142 ~]# docker exec -it webserver bash
root@e829ded69fa8:/# echo '<h1>Hello, Word!</h1>' > /usr/share/nginx/html/index.html
修改了容器的文件,也就是改動(dòng)了容器的存儲(chǔ)層缰贝。使用 docker diff 命令查看具體的改動(dòng)
修改之前
[root@ip-10-1-0-142 ~]# docker diff e8
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
C /run
A /run/nginx.pid
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
修改之后
[root@ip-10-1-0-142 ~]# docker diff webserver
C /run
A /run/nginx.pid
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /root
A /root/.bash_history
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
鏡像定制好馍悟,然后進(jìn)行鏡像保存畔濒。
我們運(yùn)行在一個(gè)容器的時(shí)候(不使用卷)剩晴,我們的任何文件修改都會(huì)被記錄于容器存儲(chǔ)層里。而Docker 提供了一個(gè)docker commit 命令侵状,可以將容器的存儲(chǔ)層保存下來成為鏡像赞弥。也就是說,在原有的鏡像基礎(chǔ)上趣兄,再疊加容器的存儲(chǔ)層绽左,構(gòu)建成新的鏡像。
docker commit 的語法格式為:
docker commit [選項(xiàng)] <容器ID或容器名> [<倉(cāng)庫(kù)名>[:<標(biāo)簽>]]
[root@ip-10-1-0-142 ~]# docker commit
--author "BigMay"
--message "modify html"
webserver
nginx:v2
sha256:a09c32d8e04de96e40148839d9fce30f8bee17c5138c2745e6e44199576b0534
- 其中 --author 是指定修改的作者艇潭,而 --message 則是記錄本次修改的內(nèi)容拼窥。這點(diǎn)和 git 版本控制相似,不過這里這些信息可以省略留空蹋凝。
查看定制好的鏡像文件
[root@ip-10-1-0-142 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 a09c32d8e04d About a minute ago 133MB
nginx latest 08b152afcfae 4 days ago 133MB
httpd latest 73b8cfec1155 4 days ago 138MB
centos latest 300e315adb2f 7 months ago 209MB
還可以使用 docker history 具體查看鏡像內(nèi)的歷史記錄鲁纠,對(duì)比nginx:latest 和 nginx:v2的歷史記錄
使用新的鏡像部署容器
[root@ip-10-1-0-142 ~]# docker run -it --name webservr2 -p 8080:80 nginx:v2
慎用 docker commit
使用 docker commit 可以比較直觀的理解鏡像分層存儲(chǔ)的概念,但是在實(shí)際的環(huán)境中不會(huì)這么使用鳍寂。
在修改文件的過程中改含,由于命令的執(zhí)行,可能會(huì)有多個(gè)文件被動(dòng)或添加了迄汛。不僅僅是簡(jiǎn)單的操作捍壤,如果是安裝軟件包骤视、編譯構(gòu)建,就可能會(huì)有大量的無關(guān)內(nèi)容被添加進(jìn)來鹃觉,這樣會(huì)導(dǎo)致鏡像非常臃腫专酗。
另外,使用 docker commit 就是對(duì)所有的鏡像的操作都是黑箱操作盗扇,生成的鏡像被稱為 黑箱鏡像 笼裳。也就是說,除了制作鏡像的人知道執(zhí)行了什么命令粱玲、怎么生成的鏡像躬柬,別人無法知道做過哪些操作。而且抽减,如果制作鏡像的人允青,過一段時(shí)間后無法記清具體的操作。這種黑箱鏡像的維護(hù)工作就非常痛苦卵沉。
回顧之前提及的鏡像所使用的分層存儲(chǔ)的概念颠锉,除了當(dāng)前層外,之前的每一層都是不會(huì)發(fā)生改變的史汗,任何修改的結(jié)果只是在當(dāng)前層進(jìn)行了標(biāo)記琼掠、添加、修改停撞,不會(huì)改動(dòng)上一層瓷蛙。
使用Dockerfile 定制鏡像
Dockerfile 是一個(gè)文本文件,其中包含了一條條的指令戈毒,每一條指令構(gòu)建一層艰猬,因此每一條指令的內(nèi)容,就是描述該層應(yīng)當(dāng)如何構(gòu)建埋市。
對(duì)比 docker commit冠桃,使用Dockerfile 可以吧每一層修改、安裝道宅、構(gòu)建食听、操作的命令都寫入一個(gè)腳本,利用這個(gè)腳本來構(gòu)建污茵、定制鏡像樱报。
以nginx鏡像為例,使用 Dockerfile 來定制省咨。
首先肃弟,在一個(gè)空白目錄中,建立一個(gè)文本文件,命名為 Dockerfile :
[root@ip-10-1-0-142 ~]# mkdir mynginx
[root@ip-10-1-0-142 ~]# cd mynginx/
[root@ip-10-1-0-142 mynginx]# touch Dockerfile
[root@ip-10-1-0-142 mynginx]# vim Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
非常簡(jiǎn)單笤受,只有兩行穷缤,只涉及到兩條指令,F(xiàn)ROM 和 RUN
FROM 指定基礎(chǔ)鏡像
定制鏡像就是以一個(gè)鏡像為基礎(chǔ)箩兽,在其上進(jìn)行定制津肛。
FROM 就是指定的 基礎(chǔ)鏡像,所以在一個(gè)Dockerfile 中 FROM的指令是必備的汗贫,并且必須是第一條指令身坐。
在 Docker Hub 上有非常多的高質(zhì)量的官方鏡像,有可以直接拿來使用的服務(wù)類的鏡像落包,如 nginx
部蛇、redis
、mongo
咐蝇、mysql
涯鲁、httpd
、php
有序、tomcat
等抹腿;也有一些方便開發(fā)、構(gòu)建旭寿、運(yùn)行各種語言應(yīng)用的鏡像警绩,如 node
、openjdk
盅称、python
肩祥、ruby
、golang
等微渠〈罨茫可以在其中尋找一個(gè)最符合我們最終目標(biāo)的鏡像為基礎(chǔ)鏡像進(jìn)行定制。
如果沒有找到對(duì)應(yīng)服務(wù)的鏡像逞盆,官方鏡像中還提供了一些更為基礎(chǔ)的操作系統(tǒng)鏡像,如 ubuntu
松申、debian
云芦、centos
、fedora
贸桶、alpine
等舅逸,這些操作系統(tǒng)的軟件庫(kù)為我們提供了更廣闊的擴(kuò)展空間。
除了選擇現(xiàn)有鏡像為基礎(chǔ)鏡像外皇筛,Docker 還存在一個(gè)特殊的鏡像琉历,名為 scratch
。這個(gè)鏡像是虛擬的概念,并不實(shí)際存在旗笔,它表示一個(gè)空白的鏡像彪置。
FROM scratch
...
如果你以 scratch
為基礎(chǔ)鏡像的話,意味著你不以任何鏡像為基礎(chǔ)蝇恶,接下來所寫的指令將作為鏡像第一層開始存在拳魁。
不以任何系統(tǒng)為基礎(chǔ),直接將可執(zhí)行文件復(fù)制進(jìn)鏡像的做法并不罕見撮弧,對(duì)于 Linux 下靜態(tài)編譯的程序來說潘懊,并不需要有操作系統(tǒng)提供運(yùn)行時(shí)支持,所需的一切庫(kù)都已經(jīng)在可執(zhí)行文件里了贿衍,因此直接 FROM scratch
會(huì)讓鏡像體積更加小巧授舟。使用 Go 語言 開發(fā)的應(yīng)用很多會(huì)使用這種方式來制作鏡像,這也是為什么有人認(rèn)為 Go 是特別適合容器微服務(wù)架構(gòu)的語言的原因之一贸辈。
RUN 執(zhí)行命令
RUN 指令是用來執(zhí)行命令行命令的岂却。由于命令行的強(qiáng)大能力,RUN 指令在指定鏡像時(shí)是最常用的指令之一裙椭。其格式有兩種:
shell 格式:RUN <命令>躏哩,就像直接在命令行中輸入的命令一樣。剛才寫的 Dockerfile 中的 RUN 指令就是這種格式揉燃。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
exec 格式:RUN ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2"]扫尺,這更像是函數(shù)調(diào)用中的格式。
既然 RUN 就像shell 腳本一樣可以執(zhí)行命令炊汤,那么我們是否就可以像 Shell 腳本一樣把每個(gè)命令對(duì)應(yīng)一個(gè)RUN呢正驻?比如:
FROM debian:stretch
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
其實(shí)這樣也是可以的,只是創(chuàng)建了7層抢腐。
Dockerfile 中每一個(gè)指令都會(huì)建立一層姑曙, RUN 也不例外。每一個(gè) RUN 的行為迈倍,都會(huì)新建立一層伤靠,在其上執(zhí)行這些命令,待執(zhí)行結(jié)束后啼染,commit 這一層的修改宴合,構(gòu)建新的鏡像。
再部署一個(gè)應(yīng)用或一個(gè)環(huán)境的時(shí)候迹鹅,把每一個(gè)步驟的執(zhí)行建立一層是沒有必要的卦洽,很多運(yùn)行時(shí)不需要的東西都單獨(dú)封裝在一層,這樣會(huì)導(dǎo)致image 非常臃腫斜棚。比如編譯環(huán)境阀蒂、更新的軟件包等等该窗。不僅讓image產(chǎn)生了臃腫和多層,而且還非常耗時(shí)蚤霞。
Union FS是有最大層數(shù)限制的酗失,比如AUFS,曾經(jīng)是最大不超過42層争便,現(xiàn)在是不超過127層
上面的Dockerfile 正確的寫法是:
FROM debian:stretch
RUN set -x; buildDeps='gcc libc6-dev make wget'
&& apt-get update
&& apt-get install -y $buildDeps
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
&& mkdir -p /usr/src/redis
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
&& make -C /usr/src/redis
&& make -C /usr/src/redis install
&& rm -rf /var/lib/apt/lists/*
&& rm redis.tar.gz
&& rm -r /usr/src/redis
&& apt-get purge -y --auto-remove $buildDeps
首先级零,之前所有的命令只有一個(gè)目的,就是編譯安裝redis可執(zhí)行文件滞乙。只是創(chuàng)建一層的需求奏纪,只使用一個(gè) RUN 指令,并使用 && 將各個(gè)所需命令串聯(lián)起來斩启。將7個(gè) RUN 序调,簡(jiǎn)化為一個(gè) RUN,1層兔簇。
所以发绢,在撰寫 Dockerfile 的時(shí)候,要經(jīng)常提醒自己垄琐,不是在寫 shell 腳本边酒,而是在定義每一層要如何構(gòu)建。
并且狸窘,這里為了格式化海進(jìn)行了換行墩朦。Dockerfile 支持 shell 類的行尾添加 \ 的命令換行方式,以及可以使用 # 進(jìn)行注釋的格式翻擒。
良好的格式氓涣,比如換行、縮緊陋气、注釋等劳吠,會(huì)讓維護(hù)、排障更為容易巩趁,是一個(gè)比較良好的習(xí)慣痒玩。
構(gòu)建鏡像
使用定制的 nginx 鏡像的 Dockerfile來構(gòu)建鏡像。
在 Dockerfile 文件所在的目錄執(zhí)行:
[root@ip-10-1-0-142 mynginx]# docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 08b152afcfae
Step 2/2 : RUN echo '<h1>Hello, Word!</h1>' > /usr/share/nginx/html/index.html
---> Running in c71a877f386f
Removing intermediate container c71a877f386f
---> 31aa55b35c46
Successfully built 31aa55b35c46
Successfully tagged nginx:v3
從命令輸出的結(jié)果晶渠,可以清晰的看到鏡像構(gòu)建的過程凰荚。
在 Step 2 中,RUN 指令啟動(dòng)了一個(gè)容器 c71a877f386f 褒脯,執(zhí)行了所要求的命令,并最后提交了這一層 31aa55b35c46 缆毁,隨后刪除了所用到的這個(gè)容器 c71a877f386f 番川。
使用 docker build 命令進(jìn)行鏡像構(gòu)建。格式為:
docker build [選項(xiàng)] <上下文路徑/URL/->
在這里我們指定了最終鏡像的名稱 -t nginx:v3,構(gòu)建成功后颁督,我們可以像之前運(yùn)行 nginx:v2 那樣來運(yùn)行這個(gè)鏡像践啄,其結(jié)果會(huì)和 nginx:v2 一樣。
鏡像構(gòu)建上下文(Context)
在運(yùn)行 docker build 命令最后有一個(gè) . 沉御。. 表示當(dāng)前目錄屿讽,而 Dockerfile 就在當(dāng)前目錄,這是指定上下文路徑吠裆。上下文是什么伐谈?
首先我們要理解 docker build 的工作原理。Docker 在運(yùn)行時(shí)分為Docker 引擎(也就是服務(wù)端守護(hù)進(jìn)程)和客戶端工具试疙。Docker 的引擎提供了一組 REST API诵棵,被稱為 Docker Remote API,如 docker 命令這樣的客戶端工具祝旷,則是通過這組API 與 Docker 引擎交互來完成各種功能履澳。
所以,看似我們是在本機(jī)執(zhí)行各種 docker 功能命令怀跛,但實(shí)際上距贷,一切都是使用的遠(yuǎn)程調(diào)用形式在服務(wù)端(Docker 引擎)完成。也因?yàn)檫@種 C/S 架構(gòu)設(shè)計(jì)吻谋,讓我們操作遠(yuǎn)程服務(wù)器的Docker 引擎變得簡(jiǎn)單忠蝗。
當(dāng)我們進(jìn)行鏡像構(gòu)建的時(shí)候,并非所有定制都會(huì)通過 RUN 指令完成滨溉,經(jīng)常會(huì)需要將一些本地文件復(fù)制到鏡像什湘,比如通過 copy 指令、add 指令等等晦攒。而docker build 命令構(gòu)建鏡像闽撤,是在服務(wù)端進(jìn)行的,不是在本地進(jìn)行的脯颜,也就是在 docker engine 中構(gòu)建的哟旗。那么,如何才能讓服務(wù)器端獲得本地的文件呢栋操?
這就引入了上下文的概念闸餐,當(dāng)構(gòu)建的時(shí)候,用戶會(huì)指定構(gòu)建鏡像上下文的路徑矾芙, docker build 命令得知這個(gè)路徑后舍沙,會(huì)將路徑下的所有內(nèi)容打包,然后上傳到 Docker 引擎剔宪。Docker 引擎收到這個(gè)上下文包后拂铡,展開就會(huì)獲得構(gòu)建鏡像所需的一切文件壹无。
如果在 Dockerfile 中這么寫:
COPY ./package.json /app/
這不是要復(fù)制執(zhí)行 docker build 命令所在目錄下的 package.json文件,也不是復(fù)制 Dockerfile 所在目錄下的 package.json感帅,而是復(fù)制 上下文(context)目錄下的 package.json 文件斗锭。
因此,COPY 這類指令中的源文件的路徑都是相對(duì)路徑失球。這也是初學(xué)者經(jīng)常會(huì)問的為什么 COPY ../package.json /app 或者 COPY /opt/xxxx /app 無法工作的原因岖是,因?yàn)檫@些路徑已經(jīng)超出了上下文的范圍,Docker 引擎無法獲得這些位置的文件实苞。如果真的需要那些文件豺撑,應(yīng)該將它們復(fù)制到上下文目錄中去。
現(xiàn)在就可以理解剛才的命令 docker build -t nginx:v3 . 中的這個(gè) .硬梁,實(shí)際上是在指定上下文的目錄前硫,docker build 命令會(huì)將該目錄下的內(nèi)容打包交給 Docker 引擎以幫助構(gòu)建鏡像。
如果觀察 docker build 輸出荧止,我們其實(shí)已經(jīng)看到了這個(gè)發(fā)送上下文的過程:
[root@ip-10-1-0-142 mynginx]# docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048kB
理解構(gòu)建上下文對(duì)于鏡像構(gòu)建是很重要的屹电,避免犯一些不應(yīng)該的錯(cuò)誤。比如有些初學(xué)者在發(fā)現(xiàn) COPY /opt/xxxx /app 不工作后跃巡,于是干脆將 Dockerfile 放到了硬盤根目錄去構(gòu)建危号,結(jié)果發(fā)現(xiàn) docker build 執(zhí)行后,在發(fā)送一個(gè)幾十 GB 的東西素邪,極為緩慢而且很容易構(gòu)建失敗外莲。那是因?yàn)檫@種做法是在讓 docker build 打包整個(gè)硬盤,這顯然是使用錯(cuò)誤兔朦。
一般來說偷线,應(yīng)該會(huì)將 Dockerfile 置于一個(gè)空目錄下,或者項(xiàng)目根目錄下沽甥。如果該目錄下沒有所需文件声邦,那么應(yīng)該把所需文件復(fù)制一份過來。如果目錄下有些東西確實(shí)不希望構(gòu)建時(shí)傳給 Docker 引擎摆舟,那么可以用 .gitignore 一樣的語法寫一個(gè) .dockerignore亥曹,該文件是用于剔除不需要作為上下文傳遞給 Docker 引擎的。
那么為什么會(huì)有人誤以為 . 是指定 Dockerfile 所在目錄呢恨诱?這是因?yàn)樵谀J(rèn)情況下媳瞪,如果不額外指定 Dockerfile 的話,會(huì)將上下文目錄下的名為 Dockerfile 的文件作為 Dockerfile照宝。
[root@ip-10-1-0-142 mynginx]# docker build -t nginx:v5 -f demo .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 08b152afcfae
Step 2/2 : RUN echo '<h1>Hello, Word!</h1>' > /usr/share/nginx/html/index.html
---> Using cache
---> 31aa55b35c46
Successfully built 31aa55b35c46
Successfully tagged nginx:v5
一般情況下都會(huì)使用默認(rèn)的文件名 Dockerfile蛇受,以及會(huì)將其放置于鏡像構(gòu)建上下文目錄中。
其他 docker build 的用法
直接用 Git repo 進(jìn)行構(gòu)建
[root@ip-10-1-0-142 mynginx]# docker build --help
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Options:
--add-host list Add a custom host-to-IP mapping (host:ip)
--build-arg list Set build-time variables
--cache-from strings Images to consider as cache sources
--cgroup-parent string Optional parent cgroup for the container
--compress Compress the build context using gzip
--cpu-period int Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit the CPU CFS (Completely Fair Scheduler) quota
-c, --cpu-shares int CPU shares (relative weight)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
--disable-content-trust Skip image verification (default true)
-f, --file string Name of the Dockerfile (Default is 'PATH/Dockerfile')
--force-rm Always remove intermediate containers
--iidfile string Write the image ID to the file
--isolation string Container isolation technology
--label list Set metadata for an image
-m, --memory bytes Memory limit
--memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--network string Set the networking mode for the RUN instructions during build (default
"default")
--no-cache Do not use cache when building the image
--pull Always attempt to pull a newer version of the image
-q, --quiet Suppress the build output and print image ID on success
--rm Remove intermediate containers after a successful build (default true)
--security-opt strings Security options
--shm-size bytes Size of /dev/shm
-t, --tag list Name and optionally a tag in the 'name:tag' format
--target string Set the target build stage to build.
--ulimit ulimit Ulimit options (default [])
[root@ip-10-1-0-142 mynginx]# docker build -f nginx:v4 ./dem
docker build 還支持從 URL 構(gòu)建厕鹃,比如可以直接從 Git repo 中構(gòu)建:
[root@ip-10-1-0-142 mynginx]# !229
docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
Sending build context to Docker daemon 19.46kB
Step 1/3 : FROM scratch
--->
Step 2/3 : COPY hello /
---> 73f19933b2d9
Step 3/3 : CMD ["/hello"]
---> Running in 0c6155341ab9
Removing intermediate container 0c6155341ab9
---> dd3f92cd2824
Successfully built dd3f92cd2824
Successfully tagged hello-world:latest
如果出現(xiàn)錯(cuò)誤信息龙巨,如下:
[root@ip-10-1-0-142 mynginx]# docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
unable to prepare context: unable to find 'git': exec: "git": executable file not found in $PATH
先在系統(tǒng)安裝git笼呆,如 yum install -y git ,然后再進(jìn)行鏡像 build
用給定的 tar 壓縮包構(gòu)建
docker build http://<server-001>/context.tar.gz
如果所給出的 URL 不是個(gè) Git repo熊响,而是個(gè) tar 壓縮包旨别,那么 Docker 引擎會(huì)下載這個(gè)包,并自動(dòng)解壓縮汗茄,以其作為上下文秸弛,開始構(gòu)建。
從標(biāo)準(zhǔn)輸入中讀取 Dockerfile 進(jìn)行構(gòu)建
docker build -t nginx:v1 - < Dockerfile
[root@ip-10-1-0-142 mynginx]# docker build -t nginx:v1 - < demo
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 08b152afcfae
Step 2/2 : RUN echo '<h1>Hello, Word!</h1>' > /usr/share/nginx/html/index.html
---> Running in 4a04eff723cd
Removing intermediate container 4a04eff723cd
---> a772a8d3759e
Successfully built a772a8d3759e
Successfully tagged nginx:v1
或
cat Dockerfile | docker build -
[root@ip-10-1-0-142 mynginx]# cat demo | docker build -t nginx:v2 -
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 08b152afcfae
Step 2/2 : RUN echo '<h1>Hello, Word!</h1>' > /usr/share/nginx/html/index.html
---> Using cache
---> a772a8d3759e
Successfully built a772a8d3759e
Successfully tagged nginx:v2