天天看點

DockerFile建構鏡像

DockerFile建構鏡像

首先通過一張圖來了解Docker鏡像,容器和DockerFile三者之間的關系

DockerFile建構鏡像

DockerFile概念

Docker 鏡像是一個特殊的檔案系統,除了提供容器運作時所需的程式、庫、資源、配置等檔案外,還包含了一些為運作時準備的一些配置參數(如匿名卷、環境變量、使用者等)。鏡像不包含任何動态資料,其内容在建構之後也不會被改變。

鏡像的定制實際上就是定制每一層所添加的配置、檔案。如果我們可以把每一層修改、安裝、建構、操作的指令都寫入一個腳本,用這個腳本來建構、定制鏡像,那麼之前提及的無法重複的問題、鏡像建構透明性的問題、體積的問題就都會解決。這個腳本就是 Dockerfile。

Dockerfile 是一個文本檔案,其内包含了一條條的指令(Instruction),每一條指令建構一層,是以每一條指令的内容,就是描述該層應當如何建構。有了 Dockerfile,當我們需要定制自己額外的需求時,隻需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲指令的麻煩。

DockerFile的指令

1、FROM 指定基礎鏡像

FROM 指令用于指定其後建構新鏡像所使用的基礎鏡像。FROM 指令必是 Dockerfile 檔案中的首條指令,啟動建構流程後,Docker 将會基于該鏡像建構新鏡像,FROM 後的指令也會基于這個基礎鏡像。

FROM文法格式為:

FROM <image>

FROM <image>:<tag>

FROM <image>:<digest>

通過 FROM 指定的鏡像,可以是任何有效的基礎鏡像。FROM 有以下限制:

FROM 必須 是 Dockerfile 中第一條非注釋指令

在一個 Dockerfile 檔案中建立多個鏡像時,FROM 可以多次出現。隻需在每個新指令 FROM 之前,記錄送出上次的鏡像 ID。

tag 或 digest 是可選的,如果不使用這兩個值時,會使用 latest 版本的基礎鏡像

2、RUN 執行指令

在鏡像的建構過程中執行特定的指令,并生成一個中間鏡像。

shell格式

RUN <command>

exec格式

RUN ["executable", "param1", "param2"]

RUN 指令将在目前 image 中執行任意合法指令并送出執行結果。指令執行送出後,就會自動執行 Dockerfile 中的下一個指令。

層級 RUN 指令和生成送出是符合 Docker 核心理念的做法。它允許像版本控制那樣,在任意一個點,對 image 鏡像進行定制化建構。

RUN 指令建立的中間鏡像會被緩存,并會在下次建構中使用。如果不想使用這些緩存鏡像,可以在建構時指定 --no-cache 參數,如:docker build --no-cache。

3、COPY 複制檔案

COPY <源路徑>... <目标路徑>

COPY ["<源路徑1>",... "<目标路徑>"]

和 RUN 指令一樣,也有兩種格式,一種類似于指令行,一種類似于函數調用。COPY 指令将從建構上下文目錄中 <源路徑> 的檔案/目錄複制到新的一層的鏡像内的<目标路徑>位置。比如:

COPY package.json /usr/src/app/

<源路徑>可以是多個,甚至可以是通配符,其通配符規則要滿足 Go 的 filepath.Match 規則,如:

COPY hom* /mydir/

COPY hom?.txt /mydir/

<目标路徑>可以是容器内的絕對路徑,也可以是相對于工作目錄的相對路徑(工作目錄可以用 WORKDIR 指令來指定)。目标路徑不需要事先建立,如果目錄不存在會在複制檔案前先行建立缺失目錄。

此外,還需要注意一點,使用 COPY 指令,源檔案的各種中繼資料都會保留。比如讀、寫、執行權限、檔案變更時間等。這個特性對于鏡像定制很有用。特别是建構相關檔案都在使用 Git 進行管理的時候。

4、ADD 更進階的複制檔案

ADD 指令和 COPY 的格式和性質基本一緻。

在 Docker 官方的 Dockerfile 最佳實踐文檔 中要求,盡可能的使用 COPY,因為 COPY 的語義很明确,就是複制檔案而已,而 ADD 則包含了更複雜的功能,其行為也不一定很清晰。最适合使用 ADD 的場合,就是所提及的需要自動解壓縮的場合。

另外需要注意的是,ADD 指令會令鏡像建構緩存失效,進而可能會令鏡像建構變得比較緩慢。

是以在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的檔案複制均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD。

在建構鏡像時,複制上下文中的檔案到鏡像内,格式:

ADD <源路徑>... <目标路徑>

ADD ["<源路徑>",... "<目标路徑>"]

5、ENV 設定環境變量

格式有兩種:

ENV <key> <value>

ENV <key1>=<value1> <key2>=<value2>...

這個指令很簡單,就是設定環境變量而已,無論是後面的其它指令,如 RUN,還是運作時的應用,都可以直接使用這裡定義的環境變量。

ENV VERSION=1.0 DEBUG=on \NAME="Happy Feet"

這個例子中示範了如何換行,以及對含有空格的值用雙引号括起來的辦法,這和 Shell 下的行為是一緻的。

6、EXPOSE

為建構的鏡像設定監聽端口,使容器在運作時監聽。格式:

EXPOSE <port> [<port>...]

EXPOSE 指令并不會讓容器監聽 host 的端口,如果需要,需要在 docker run 時使用 -p、-P 參數來釋出容器端口到 host 的某個端口上。

7、VOLUME 定義匿名卷

VOLUME用于建立挂載點,即向基于所建構鏡像創始的容器添加卷:

VOLUME ["/data"]

一個卷可以存在于一個或多個容器的指定目錄,該目錄可以繞過聯合檔案系統,并具有以下功能:

卷可以容器間共享和重用

容器并不一定要和其它容器共享卷

修改卷後會立即生效

對卷的修改不會對鏡像産生影響

卷會一直存在,直到沒有任何容器在使用它

VOLUME 讓我們可以将源代碼、資料或其它内容添加到鏡像中,而又不并送出到鏡像中,并使我們可以多個容器間共享這些内容。

8、CMD容器啟動指令

CMD用于指定在容器啟動時所要執行的指令。CMD 有以下三種格式:

CMD ["executable","param1","param2"]

CMD ["param1","param2"]

CMD command param1 param2

省略可執行檔案的 exec 格式,這種寫法使 CMD 中的參數當做 ENTRYPOINT 的預設參數,此時 ENTRYPOINT 也應該是 exec 格式,具體與 ENTRYPOINT 的組合使用,參考 ENTRYPOINT。

注意 與 RUN 指令的差別:RUN 在建構的時候執行,并生成一個新的鏡像,CMD 在容器運作的時候執行,在建構時不進行任何操作。

9、ENTRYPOINT入口點

ENTRYPOINT 指定這個容器啟動的時候要運作的指令,可以追加指令。

ENTRYPOINT 用于給容器配置一個可執行程式。也就是說,每次使用鏡像建立容器時,通過 ENTRYPOINT 指定的程式都會被設定為預設程式。ENTRYPOINT 有以下兩種形式:

ENTRYPOINT ["executable", "param1", "param2"]

ENTRYPOINT command param1 param2

ENTRYPOINT 與 CMD 非常類似,不同的是通過docker run執行的指令不會覆寫 ENTRYPOINT,而docker run指令中指定的任何參數,都會被當做參數再次傳遞給 ENTRYPOINT。Dockerfile 中隻允許有一個 ENTRYPOINT 指令,多指定時會覆寫前面的設定,而隻執行最後的 ENTRYPOINT 指令。

docker run運作容器時指定的參數都會被傳遞給 ENTRYPOINT ,且會覆寫 CMD 指令指定的參數。如,執行docker run

-d時,-d 參數将被傳遞給入口點。

也可以通過docker run --entrypoint重寫 ENTRYPOINT 入口點。如:可以像下面這樣指定一個容器執行程式:

ENTRYPOINT ["/usr/bin/nginx"]

10、USER 指定目前使用者

USER 用于指定運作鏡像所使用的使用者:

USER daemon

使用USER指定使用者時,可以使用使用者名、UID 或 GID,或是兩者的組合。以下都是合法的指定試:

USER user

USER user:group

USER uid

USER uid:gid

USER user:gid

USER uid:group

使用USER指定使用者後,Dockerfile 中其後的指令 RUN、CMD、ENTRYPOINT 都将使用該使用者。鏡像建構完成後,通過 docker run 運作容器時,可以通過 -u 參數來覆寫所指定的使用者。

11、WORKDIR 指定工作目錄

WORKDIR用于在容器内設定一個工作目錄:

WORKDIR /path/to/workdir

通過WORKDIR設定工作目錄後,Dockerfile 中其後的指令 RUN、CMD、ENTRYPOINT、ADD、COPY 等指令都會在該目錄下執行。 如,使用WORKDIR設定工作目錄:

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

在以上示例中,pwd 最終将會在 /a/b/c 目錄中執行。在使用 docker run 運作容器時,可以通過-w參數覆寫建構時所設定的工作目錄。

12、LABEL為鏡像添加中繼資料

LABEL用于為鏡像添加中繼資料,元數以鍵值對的形式指定:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

使用LABEL指定中繼資料時,一條LABEL指定可以指定一或多條中繼資料,指定多條中繼資料時不同中繼資料之間通過空格分隔。推薦将所有的中繼資料通過一條LABEL指令指定,以免生成過多的中間鏡像。 如,通過LABEL指定一些中繼資料:

LABEL version="1.0" description="這是一個Web伺服器" by="Docker筆錄"

指定後可以通過docker inspect檢視:

docker inspect itbilu/test

"Labels": {

"version": "1.0",

"description": "這是一個Web伺服器",

"by": "Docker筆錄"

},

13、ARG建構參數

ARG用于指定傳遞給建構運作時的變量:

ARG <name>[=<default value>]

如,通過ARG指定兩個變量:

ARG site

ARG build_user=IT筆錄

以上我們指定了 site 和 build_user 兩個變量,其中 build_user 指定了預設值。在使用 docker build 建構鏡像時,可以通過 --build-arg = 參數來指定或重設定這些變量的值。

docker build --build-arg site=itiblu.com -t itbilu/test .

這樣我們建構了 itbilu/test 鏡像,其中site會被設定為 itbilu.com,由于沒有指定 build_user,其值将是預設值 IT 筆錄。

14、ONBUILD

ONBUILD用于設定鏡像觸發器:

ONBUILD [INSTRUCTION]

當所建構的鏡像被用做其它鏡像的基礎鏡像,該鏡像中的觸發器将會被觸發。 如,當鏡像被使用時,可能需要做一些處理:

[...]

ONBUILD ADD . /app/src

ONBUILD RUN /usr/local/bin/python-build --dir /app/src

15、STOPSIGNAL

STOPSIGNAL用于設定停止容器所要發送的系統調用信号:

STOPSIGNAL signal

所使用的信号必須是核心系統調用表中的合法的值,如:SIGKILL。

16、SHELL指令

SHELL用于設定執行指令(shell式)所使用的的預設 shell 類型:

SHELL ["executable", "parameters"]

SHELL在Windows環境下比較有用,Windows 下通常會有 cmd 和 powershell 兩種 shell,可能還會有 sh。這時就可以通過 SHELL 來指定所使用的 shell 類型:

FROM microsoft/windowsservercore

Executed as cmd /S /C echo default

RUN echo default

Executed as cmd /S /C powershell -command Write-Host default

RUN powershell -command Write-Host default

Executed as powershell -command Write-Host hello

SHELL ["powershell", "-command"]

RUN Write-Host hello

Executed as cmd /S /C echo hello

SHELL ["cmd", "/S"", "/C"]

RUN echo hello

DockerFile檔案格式

Dockerfile檔案格式

This dockerfile uses the ubuntu image

VERSION 2 - EDITION 1

Author: docker_user

Command format: Instruction [arguments / command] ..

1、第一行必須指定 基礎鏡像資訊

FROM ubuntu

2、維護者資訊

MAINTAINER docker_user [email protected]

3、鏡像操作指令

RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list

RUN apt-get update && apt-get install -y nginx

RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

4、容器啟動執行指令

CMD /usr/sbin/nginx

Dockerfile 分為四部分:基礎鏡像資訊、維護者資訊、鏡像操作指令、容器啟動執行指令。一開始必須要指明所基于的鏡像名稱,接下來一般會說明維護者資訊;後面則是鏡像操作指令,例如 RUN 指令。每執行一條RUN 指令,鏡像添加新的一層,并送出;最後是 CMD 指令,來指明運作容器時的操作指令。

DockerFile執行個體

[root@localhost ~]# cd /opt/

[root@localhost opt]# mkdir nginx ##建立Nginx目錄

[root@localhost opt]# cd nginx/

[root@localhost nginx]# vim Dockerfile

FROM centos:7

MAINTAINER The is nginx

RUN yum install -y proc-devel gcc gcc-c++ zlib zlib-devel make openssl-devel wget && wget http://nginx.org/download/nginx-1.21.1.tar.gz

ADD nginx-1.21.1.tar.gz /usr/local

WORKDIR /usr/local/nginx-1.21.1/

RUN ./configure --prefix=/usr/local/nginx && make && make install

EXPOSE 80

EXPOSE 443

RUN echo "daemon off;">>/usr/local/nginx/conf/nginx.conf

WORKDIR /root/nginx

ADD run.sh /run.sh

RUN chmod 755 /run.sh

CMD ["/run.sh"]

[root@localhost nginx]# vim run.sh

!/bin/bash

/usr/local/nginx/sbin/nginx ##開啟Nginx服務

[root@localhost nginx]# mount.cifs //192.168.100.3/LNMP-C7 /mnt/ ##挂載鏡像

Password for root@//192.168.100.3/LNMP-C7:

[root@localhost nginx]# cp /mnt/nginx-1.12.2.tar.gz ./ ##複制到目前目錄下

[root@localhost nginx]# docker build -t nginx:new . ##建立鏡像

[root@localhost nginx]# docker run -d -P nginx:new ##建立容器

228c1f5b8070d52c6f19d03159ad93a60d682a586c0b1f944dc651ee40576a3e

[root@localhost nginx]# docker ps -a ##檢視容器

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

228c1f5b8070 nginx:new "/run.sh" 9 seconds ago Up 8 seconds 0.0.0.0:32770->80/tcp, 0.0.0.0:32769->443/tcp busy_booth

用浏覽器通路網頁

越是無知的人越是覺得自己無所不知(之前的自己)

越是學習的人越是覺得自己會的太少了(現在的自己)

共勉