Docker | 第四章:Dockerfile簡單介紹及使用

前言

前一章節,介紹了Docker經常使用的命令。在基本使用上,熟悉這些經常使用的命令基本上就夠了。但在一些場景下,好比在部署SpringBoot應用時,一般咱們都是打成Jar包,而後利用java命令進行運行jar包。這個時候咱們就能經過編寫Dockerfile進行自動化部署了(可能這個比喻不太恰當⊙﹏⊙‖∣)。整體來講,可利用Dockerfile文件自定義鏡像內容,改變原始鏡像的一些行爲,以知足個性化需求。html

Dockerfile介紹

Dockerfile是一個文本文件,裏面包含了若干條指令,每條指令描述了構建鏡像的細節。簡單來講,它就是由一系列指令和參數構成的腳本文件,從而構建出一個新的鏡像文件。java

Dockerfile格式

簡單來講,Dockerfile格式通常以下:linux

# 註釋
  指令 [參數]

這裏以一個修改Nginx鏡像首頁爲示例(此鏡像使用說明詳見:https://hub.docker.com/_/nginx/),簡單說明:nginx

# 注意:非註釋第一行 必須以FROM 開頭。
  # FROM 指定基礎鏡像,即以此鏡像做爲基礎
  FROM nginx
  # 設置元數據,利用 docker inspect [鏡像名稱|鏡像ID],便可查看。
  LABEL author="做者:oKong"
  LABEL version="版本:v0.1"
  LABEL desc="說明:修改nginx首頁提示"
  # 操做執行,這裏直接修改了nginx的html的首頁內容,/usr/share/nginx/html
 # 本來想輸出中文,亂碼了,設置了 ENV LANG C.UTF-8 或者 ENV LANG zh_CN.UTF-8 都不行 放棄了,有知道大神望告知!
  RUN echo 'hello,oKong' > /usr/share/nginx/html/index.html
  # 啓動命令 不寫時 會直接使用基礎鏡像的啓動命令
  CMD ["nginx", "-g", "daemon off;"]

而後利用build命令進行關鍵。docker

docker build -t lqdev.cn/mynginx:v1 .

注意:這裏最後面有個(.),路徑參數,而(.)表示是當前路徑。shell

控制檯會顯示具體每個執行說明windows

[root@izbp16chpwsnff41nrjtfhz docker]# docker build -t lqdev.cn/mynginx:v1 .
Sending build context to Docker daemon   2.56kB
Step 1/6 : FROM nginx
 ---> c82521676580
Step 2/6 : LABEL author="做者:oKong"
 ---> Running in 81eb0dc40699
Removing intermediate container 81eb0dc40699
 ---> 4d2799492a09
Step 3/6 : LABEL version="版本:v0.1"
 ---> Running in e4e0d6097bae
Removing intermediate container e4e0d6097bae
 ---> d47eb89ae7b4
Step 4/6 : LABEL desc="說明:修改nginx首頁提示"
 ---> Running in 36b1bffc8345
Removing intermediate container 36b1bffc8345
 ---> 3e9b63e69b0a
Step 5/6 : RUN echo 'hello,oKong' > /usr/share/nginx/html/index.html
 ---> Running in 1f04dafc3bf6
Removing intermediate container 1f04dafc3bf6
 ---> c9a649422c1d
Step 6/6 : CMD ["nginx", "-g", "daemon off;"]
 ---> Running in f6f41f072643
Removing intermediate container f6f41f072643
 ---> 11e7ca53febd
Successfully built 11e7ca53febd
Successfully tagged lqdev.cn/mynginx:v1

查看鏡像列表,就能看見剛剛構建的鏡像了:bash

[root@izbp16chpwsnff41nrjtfhz docker]# docker images
REPOSITORY             TAG                 IMAGE ID            CREATED              SIZE
lqdev.cn/mynginx       v1                  11e7ca53febd        About a minute ago   109MB
nginx                  latest              c82521676580        7 days ago           109MB
lqdev.cn/hello-world   1                   2cb0d9787c4d        3 weeks ago          1.85kB
hello-world            latest              2cb0d9787c4d        3 weeks ago          1.85kB

而後,咱們運行下:函數

docker run -p 80:80 -d lqdev.cn/mynginx:v1

以後訪問宿主服務地址:http://宿主IP, 便可看見修改後的首頁了:學習

nginx首頁

同時,利用inspect命令,查看鏡像元數據,就能夠看見剛剛指定的值了。

docker inspect 11e7ca53febd

元數據

因此能夠看出Dockerfile主要分爲四個部分基礎鏡像信息元數據信息鏡像操做指令啓動執行指令。下一部分就主要講解下關於Dockerfile的命令說明。

Dockerfile命令說明

FROM 指定基礎鏡像

放在第一行,其格式爲:

#語法:
FROM <image> 
FROM <image>:<tag>
FROM <image>:<digest>

若想構建一個最小的鏡像,不想基於其餘任何鏡像時。可直接

FROM scratch

LABEL 鏡像元數據

能夠設置鏡像的任何元數據,格式爲:

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

例如:

LABEL author="做者:oKong"
  LABEL version="版本:v0.1"
  LABEL desc="說明:修改nginx首頁提示"

而後利用docker inspect命令進行查看。

"Labels": {
                "author": "做者:oKong",
                "desc": "說明:修改nginx首頁提示",
                "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>",
                "version": "版本:v0.1"
            },

ENV 設置環境變量

主要就是設置環境變量,以後的命令均可以用此變量進行賦值,格式以下:

ENV <key> <value>
ENV <key>=<value> ...

VOLUME 定義匿名卷

VOLUME用於建立掛載點,即向基於所構建鏡像創始的容器添加捲:

VOLUME ["/data"]

一個卷能夠存在於一個或多個容器的指定目錄,該目錄能夠繞過聯合文件系統,並具備如下功能:

  • 卷能夠容器間共享和重用
  • 容器並不必定要和其它容器共享卷
  • 修改卷後會當即生效
  • 對卷的修改不會對鏡像產生影響
  • 卷會一直存在,直到沒有任何容器在使用它

VOLUME 讓咱們能夠將源代碼、數據或其它內容添加到鏡像中,而又不併提交到鏡像中,並使咱們能夠多個容器間共享這些內容。

COPY 複製文件

主要就是構建鏡像時,進行拷貝文件到鏡像的指定路徑下,格式爲:

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

ADD 更高級的複製文件

ADD 指令和 COPY 的格式和性質基本一致。可是在 COPY 基礎上增長了一些功能。好比<源路徑>能夠是一個 URL,這種狀況下,Docker 引擎會試圖去下載這個連接的文件放到<目標路徑>去。

EXPOSE 設置監聽端口

爲鏡像設置監聽端口,容器運行時會監聽改端口,格式爲:

EXPOSE <port> [<port>/<protocol>...]

如,nginx鏡像,監聽了80端口

EXPOSE 80

同時,也能指定協議名,如:

EXPOSE 80/udp

ARG 設置構建參數

該命令用於設置構建參數,該參數在容器運行時是獲取不到的,只有在構建時才能獲取。這也是其和ENV的區別。

ARG <name>[=<default value>]

使用舉例:

arg author=okong
# 構建時,也能夠替換了
# docker build --build-arg <varname>=<value>
docker build --build-arg author=okong0123

RUN 執行命令

在鏡像的構建過程當中執行特定的命令,並生成一箇中間鏡像。格式:

RUN <command>
或者
RUN ["executable", "param1", "param2"]

這也是很經常使用的一個功能了。 第一種後邊直接跟shell命令

  • 在linux操做系統上默認 /bin/sh -c
  • 在windows操做系統上默認 cmd /S /C

第二種是相似於函數調用。

可將executable理解成爲可執行文件,後面就是兩個參數。

兩種寫法比對:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", "-c", "echo hello"]

注意:多行命令不要寫多個RUN,緣由是Dockerfile中每個指令都會創建一層.多少個RUN就構建了多少層鏡像,會形成鏡像的臃腫、多層,不只僅增長了構件部署的時間,還容易出錯。

RUN書寫時的換行符是\

CMD 啓動時命令

功能爲容器啓動時要運行的命令, 語法有三種寫法

1. CMD ["executable","param1","param2"]
2. CMD ["param1","param2"]
3. CMD command param1 param2

第三種比較好理解了,就時shell這種執行方式和寫法,第一種和第二種其實都是可執行文件加上參數的形式: 舉例說明兩種寫法:

CMD [ "sh", "-c", "echo $HOME" 
CMD [ "echo", "$HOME" ]

補充細節:這裏邊包括參數的必定要用雙引號,就是雙引號",不能是單引號。千萬不能寫成單引號。緣由是參數傳遞後,docker解析的是一個JSON array

ENTRYPOINT 啓動默認命令

ENTRYPOINT 用於給容器配置一個可執行程序。也就是說,每次使用鏡像建立容器時,經過 ENTRYPOINT 指定的程序都會被設置爲默認程序。ENTRYPOINT 有如下兩種形式:

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

ENTRYPOINTCMD 很是相似,不一樣的是經過docker run執行的命令不會覆蓋 ENTRYPOINT,而docker run命令中指定的任何參數,都會被當作參數再次傳遞給ENTRYPOINTDockerfile只容許有一個 ENTRYPOINT 命令,多指定時會覆蓋前面的設置,而只執行最後的 ENTRYPOINT 指令。 docker run運行容器時指定的參數都會被傳遞給ENTRYPOINT,且會覆蓋 CMD 命令指定的參數。如,執行docker run <image> -d時,-d 參數將被傳遞給入口點。 也能夠通過docker run --entrypoint重寫 ENTRYPOINT 入口點。如:能夠像下面這樣指定一個容器執行程序:

ENTRYPOINT ["/usr/bin/nginx"]

這裏以上面Dockerfile格式章節,做爲例子:

# 注意:第一行 必須以FROM 開頭。
  # FROM 指定基礎鏡像,即以此鏡像做爲基礎
  FROM nginx
  # 設置元數據,利用 docker inspect [鏡像名稱|鏡像ID],便可查看。
  LABEL author="做者:oKong"
  LABEL version="版本:v0.1"
  LABEL desc="說明:修改nginx首頁提示"
  
  # 操做執行,這裏直接修改了nginx的html的首頁內容,/usr/share/nginx/html
 # 本來想輸出中文,亂碼了,設置了 ENV LANG C.UTF-8 或者 ENV LANG zh_CN.UTF-8 都不行 放棄了,有知道大神望告知!
  RUN echo 'hello,oKong' > /usr/share/nginx/html/index.html
  
  # 啓動命令 不寫時 會直接使用基礎鏡像的啓動命令
  # CMD ["nginx", "-g", "daemon off;"]
  # 這裏利用 ENTRYPOINT 改寫
  ENTRYPOINT ["nginx"]

使用docker build構建鏡像,並將鏡像指定爲lqdev.cn/mynginx:v2

docker build -t lqdev.cn/mynginx:v2 .

構建完成後,使用lqdev.cn/mynginx:v2啓動一個容器:

docker run -p 80:80 -d lqdev.cn/mynginx:v2 -g "daemon off;"

在運行容器時,咱們使用了 -g "daemon off;",這個參數將會被傳遞給 ENTRYPOINT,最終在容器中執行的命令爲 nginx -g "daemon off;"。此時,可利用docker ps -a查看下,最後效果是同樣的。

ps -a

WORKDIR 指定工做目錄

用於在容器內設置一個工做目錄:

WORKDIR /opt/docker/workdir

經過WORKDIR設置工做目錄後,Dockerfile 中其後的命令 RUNCMDENTRYPOINTADDCOPY等命令都會在該目錄下執行。

USER 指定當前用戶

用於指定運行鏡像所使用的用戶:

USER okong

使用USER指定用戶後,Dockerfile 中其後的命令RUNCMDENTRYPOINT都將使用該用戶。鏡像構建完成後,經過docker run運行容器時,能夠經過-u參數來覆蓋所指定的用戶。

其餘命令

還有像ONBUILDSTOPSIGNALSHELL及其MAINTAINER(已棄用)等命令,不是十分經常使用或者已經棄用的,這裏不闡述了。主要是沒看懂具體啥意思,⊙﹏⊙‖∣。你們可經過其官網進行查看下:https://docs.docker.com/engine/reference/builder/

總結

本章節主要是介紹了下Dockerfile的一些經常使用命令的說明。學習掌握了Dockerfile命令使用後,咱們就能進行個性化鏡像的構建了。本章節只是簡單演示了下,下一章節,咱們就主要來一步步動手構建一個屬於本身的鏡像文件!

最後

若文中有錯誤或者遺漏之處,還望指出,共同進步!

參考資料

  1. https://docs.docker.com/engine/reference/builder
  2. http://www.ityouknow.com/docker/2018/03/15/docker-dockerfile-command-introduction.html
  3. http://www.javashuo.com/article/p-zpshpgtw-ez.html

老生常談

  • 我的QQ:499452441
  • 公衆號:lqdevOps

公衆號

我的博客:http://blog.lqdev.cn

原文地址:http://blog.lqdev.cn/2018/08/02/docker/docker-four/

相關文章
相關標籤/搜索