1.從零開始來創建一個新的鏡像、
什么是 Dockerfile 文件?
Dockerfile是用來構建Docker鏡像的構建文件,是由一系列命令和參數構成的腳本
主要作用:
1、找一個鏡像: centos
2、創建一個容器: docker run centos
3、進入容器: docker exec -it 容器 命令
4、操作: 各種應用配置
....
5、構造新鏡像: docker commit
Dockerfile 使用准則
1、大: 首字母必須大寫D
2、空: 盡量將Dockerfile放在空目錄中。
3、單: 每個容器盡量只有一個功能。
4、少: 執行的命令越少越好。
Dockerfile 基礎四指令:
基礎鏡像信息 從哪來?
維護者信息 我是誰?
鏡像操作指令 怎么干?
容器啟動時執行指令 嗨!!!
Dockerfile使用命令:
構建鏡像命令格式:
docker build -t [鏡像名]:[版本號] [Dockerfile所在目錄]
構建樣例:
docker build -t nginx:v0.2 /opt/dockerfile/nginx/
參數詳解:
-t 指定構建后的鏡像信息,
/opt/dockerfile/nginx/ 則代表Dockerfile存放位置,如果是當前目錄,則用 .(點)表示
1.1編寫Dockerfile文件、
$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
$ cat Dockerfile
FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
說明:
每一個指令都會在鏡像上創建一個新的層,每一個指令的前綴都必須是大寫的
第一條FROM,指定使用哪個鏡像源,基礎鏡像
FROM scratch (表示空白的鏡像,是一個虛擬的概念,實際不存在)
RUN
指令是用來執行命令行命令的(兩種格式)
shell 格式:RUN <命令>
exec 格式:RUN ["可執行文件", "參數1", "參數2"]
如:# RUN ["./test.php", "dev", "offline"] 等價於 RUN ./test.php dev offline
最好不要寫多個指令,每一個指令代表一層,則會創建了很多層鏡像,如果需要寫多個指令可以用連接符 && 連接起來,在同一層上面創建即可。
1.2 構建鏡像
在 Dockerfile
文件所在目錄執行:
$ docker build -t nginx:2.0 .
發現其執行了兩步,查看鏡像列表已經存在創建的鏡像了
-t:指定要創建的鏡像名
.:Dockerfile 文件所在目錄,可以指定Dockerfile 的絕對路徑

運行鏡像:
[root@rbtnode1 mynginx]# docker run -d -p 82:80 nginx:2.0
查看 nginx,運行的頁面如構建的shell腳本更改一致
1.3上下文路徑
最后一個 . 是上下文路徑,怎么理解呢?
是docker在構建鏡像,不一定使用RUN指令完成的,有時候想要使用本機的文件(如復制COPY),docker build命令得知這個路徑后,會將路徑下的所有東西打包。docker是C/S模式,我們使用C,引擎是S。而build是是引擎完成的,則docker不能使用我們本機C的文件,所以需要制定目錄下的文件打包給S使用。如果不說嗎,則為Dockerfile所在的位置。
如果在Dockerfile中寫:
COPY ./package.json /app/
這並不表示要復制docker build命令所在的目錄下的package.json,也不是復制Dockerfile所在目錄下的package.json,而是復制上下文目錄下的package.json。
**COPY
這類指令中的源文件的路徑都是相對路徑。**
docker build -t nginx:2.0 .
中的這個 .
,實際上是在指定上下文的目錄,docker build
命令會將該目錄下的內容打包交給 Docker 引擎以幫助構建鏡像。(輸出的第一行就是其過程)
為了避免犯錯:
-
應該會將
Dockerfile
置於一個空目錄下,或者項目根目錄下。
-
如果該目錄下沒有所需文件,那么應該把所需文件復制一份過來,去copy正常的Linux的路徑如 ../../等是不會工作的。
-
不希望傳有些東西給docker引擎,用.dockerignore文件(似.gitignore)剔除
為什么會誤認為是指定Dockerfile路徑呢?
-
因默認情況且不指定Dockerfile的話,會將上下文目錄下的名為Dockerfile的文件名為Dockerfile
-
不必須命名為Dockerfile,可以用
-f ../Dockerfile.php
參數指定某個文件作為Dockerfile
。 -
當然,一般大家習慣性的會使用默認的文件名
Dockerfile
,以及會將其置於鏡像構建上下文目錄中
2.其它 docker build
的用法
2.1 直接用 Git repo 進行構建
-
docker build支持url構建
$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:11.1
指定默認的 master 分支,構建目錄為 /11.1/,然后 Docker 就會自己去 git clone 這個項目、切換到指定分支、並進入到指定目錄后開始構建。
2.2用給定的 tar 壓縮包構建
$ docker build http://server/context.tar.gz
Docker 引擎會下載這個包,並自動解壓縮,以其作為上下文,開始構建。
2.3從標准輸入中讀取 Dockerfile 進行構建
docker build - < Dockerfile
cat Dockerfile | docker build -
如果標准輸入傳入的是文本文件,則將其視為 Dockerfile
,並開始構建。直接讀取Dockerfile中的內容,沒有上下文
2.4從標准輸入中讀取上下文壓縮包進行構建
$ docker build - < context.tar.gz
3.Dockerfile 指令詳解
3.1 COPY和ADD
COPY復制指令,將從構建上下文目錄中 <源路徑>
的文件/目錄復制到新的一層的鏡像內的 <目標路徑>
位置。ADD是更高級的復制文件,兩種格式兩種(命令行,函數調動型):
COPY [--chown=<user>:<group>] <源路徑1>... <目標路徑>
COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"]
如:COPY package.json /usr/src/app/
加入組的方式:COPY --chown=1 files* /mydir/
[--chown=<user>:<group>]**:可選參數,用戶改變復制到容器內文件的擁有者和屬組。
<源路徑>:源文件或者源目錄,這里可以是通配符表達式,其通配符規則要滿足 Go 的 filepath.Match 規則
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目標路徑>:容器內的指定路徑,該路徑不用事先建好,路徑不存在的話,會自動創建。 可以是容器內的絕對路徑,也可以是相對於工作目錄的相對路徑(工作目錄可以用 WORKDIR
指令來指定。
使用COPY指令,各類元數據都會保留,git時很方便。
ADD源路徑:
-
是一個url,docker引擎會去下載這個路徑,自動設置權限為600,也可以加RUN調整權限。下載到的若是個壓縮包,若解壓則加一層RUN指令,也可以wget或curl下載,處理。
-
<源路徑>
為一個tar
壓縮文件的話,壓縮格式為gzip
,bzip2
以及xz
的情況下,ADD
指令將會自動解壓縮這個壓縮文件到<目標路徑>
去-
使用注意:
-
盡量多用COPY,只是復制沒必要那么復雜,需要自動解壓再用ADD
-
ADD會讓鏡像構建失效,從而鏡像緩慢。
-
--chown=<user>:<group>
ADD --chown=55:mygroup files* /mydir/
修改用戶及所屬組
-
-
3.2 CMD和ENTRYPOINT
-
概念
CMD:指定默認的容器主進程的啟動命令,程序運行結束,容器也就結束。CMD 指令指定的程序可被 docker run 命令行參數中指定要運行的程序所覆蓋。多個CMD時僅最后一個生效。
ENTRYPOINT:類似於 CMD 指令,但其不會被 docker run 的命令行參數指定的指令所覆蓋,而且這些命令行參數會被當作參數送給 ENTRYPOINT 指令指定的程序,存在多個 ENTRYPOINT 指令,僅最后一個生效。需要通過
docker run
的參數--entrypoint
來指定。 -
格式
CMD
指令的格式和 RUN
相似,CMD與ENTRYPOINT類似。也是兩種格式(推薦exec):
-
shell
格式:CMD <命令>
-
exec
格式:CMD ["可執行文件", "參數1", "參數2"...]
-
參數列表格式:
CMD ["參數1", "參數2"...]
。在指定了ENTRYPOINT
指令后,用CMD
指定具體的參數。
-
使用規則
-
CMD
-
使用exec格式,其會被解析成接送數組,一定需要“”雙引號。
-
使用shell格式,實際命令會被包裝是 sh -c 執行。這樣就需要環境變量,環境變量會被shell進行解析。容器中執行的命令需要在前台執行,類似於systemd后台命令無法執行,被迫容器退出,因為容器執行會解讀為sh執行,這樣sh就是這個命令的主進程。那么后台的命令結束則sh結束了就退出了,啟動程序就是容器應用進程,容器就是為了主進程而存在的,主進程結自然容器也退出了。除非CMD要求前台執行。
-
-
ENTRYPOINT
-
指定了
ENTRYPOINT
后,CMD
的含義就發生了改變,不再是直接的運行其命令,而是將CMD
的內容作為參數傳給ENTRYPOINT
指令。<ENTRYPOINT> "<CMD>"。 -
可以讓鏡像變成像命令一樣使用
-
啟動容器就是啟動主進程,但有些時候,啟動主進程前,需要一些准備工作。
-
-
3.3環境指令詳情
1. 環境設置指令
ENV
格式:
ENV <key> <value>
ENV <key>=<value> ...
解釋:
設置環境變量,可以在RUN之前使用,然后RUN命令時調用,容器啟動時這些環境變量都會被指定
WORKDIR
格式:
WORKDIR /path/to/workdir (shell 模式)
解釋:
切換目錄,為后續的RUN、CMD、ENTRYPOINT 指令配置工作目錄。 相當於cd
可以多次切換(相當於cd命令),
也可以使用多個WORKDIR 指令,后續命令如果參數是相對路徑,則會基於之前命令指定的路徑。例如
舉例:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為 /a/b/c。
ENV實踐
修改Dockerfile文件內容:
# 在上一個Dockerfile文件內容基礎上,在RUN下面增加一個ENV
ENV NIHAO=helloworld
WORKDIR實踐
修改Dockerfile文件內容:
# 在上一個Dockerfile文件內容基礎上,在RUN下面增加一個WORKDIR
WORKDIR /nihao/itcast/
RUN ["touch","itcast.txt"]
Dockerfile**構建過程:**
-
從基礎鏡像1運行一個容器A
遇到一條Dockerfile指令,都對容器A做一次修改操作
執行完畢一條命令,提交生成一個新鏡像2
再基於新的鏡像2運行一個容器B
遇到一條Dockerfile指令,都對容器B做一次修改操作
執行完畢一條命令,提交生成一個新鏡像3
...
-
構建過程鏡像介紹**
構建過程中,創建了很多鏡像,這些中間鏡像,我們可以直接使用來啟動容器,通過查看容器效果,從側面能看到我們每次構建的效果。
提供了鏡像調試的能力
我們可以通過docker history <鏡像名> 來查看整個構建過程所產生的鏡像
執行的步驟越多越好呢?還是越少越好?
-
構建緩存**
我們第一次構建很慢,之后的構建都會很快,因為他們用到了構建的緩存。
不適用構建緩存方法常見兩種:
全部不同緩存:
docker build --no-cache -t [鏡像名]:鏡像版本
只要構建的緩存時間不變,那么就用緩存,如果時間一旦改變,就不用緩存了
樣例:
# 構建一個基於ubuntu-base的docker定制鏡像
# 基礎鏡像
FROM ubuntu-base
\ # 鏡像作者
MAINTAINER 郵箱
\ # 創建構建刷新時間
ENV REFRESH_DATE 2019-12-06
# 執行命令
...
構建歷史:
1. 查看構建過程查看
docker history
清理構建緩存:
docker system prune
docker system prune --volumes