Docker 學習筆記(二):Dockerfile 定製鏡像

鏡像的定製實際上就是定製每一層所添加的配置、文件。
若是咱們能夠把每一層修改、安裝、構建、操做的命令都寫入一個腳本,用這個腳原本構建、定製鏡像,那麼以前說起的沒法重複的問題、鏡像構建透明性的問題、體積的問題就都會解決。
這個腳本就是 Dockerfile。php

  1. Dockerfile 是一個文本文件,其內包含了一條條的 指令(Instruction),每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建。前端

  2. 由於每一條指令構建一層,並且每一層構建好後,就不會再變化。爲了使鏡像儘量地小並且層次清晰,每一層都應該圍繞一個特定的目標進行構建,而且在構建結束前,要清理掉全部緩存和其餘無關的東西!node

  3. Docker 如今最多隻能支持 127 層,儘可能讓每一條命令都完成一個完整的目標,不要每條 shell 命令都對應一個 RUN,這是至關糟糕的作法。python

在撰寫 Dockerfile 的時候,要常常提醒本身,這並非在寫 Shell 腳本,而是在定義每一層該如何構建。mysql

1、commit 命令

docker commit 用法相似 git commit,用於將當前容器層的修改,固化成一個新的鏡像層。linux

# 1. 首先啓動了一個容器
# 2. 經過 exec 命令登入該容器作一些修改
# 3. 可使用下列命令查看容器層的具體改動
docker diff <container id> 

# 4. 使用 commit 命令提交容器層的改動
docker commit [選項] <容器ID或容器名> [<倉庫名>[:<標籤>]]  # 模板
docker commit \
    --author "Tao Wang <twang2218@gmail.com>" \
    --message "修改了默認網頁" \
    webserver \
    nginx:v2

# 5. 使用 history 命令查看鏡像的構建歷史
docker history nginx:v2

利用 Dockerfile 定製鏡像,其實就是在基礎鏡像上啓動一個臨時容器,而後在該容器上一條條地運行 Dockerfile 內的指令。android

每跑完一個指令,就將當前的修改固化層一個新的鏡像層(這就相似在此時執行 docker commit)。nginx

指令跑完了,一個分層的鏡像也就生成了,這時再清除掉構建用的臨時容器。git

二 、Dockerfile 指令詳解

Dockerfile 經常使用的有十多個指令:github

  1. FROM:指定基礎鏡像
  2. LABEL:鏡像的一些標籤,如 maintainer/licence
  3. USER:能用普通用戶,就不要用 root 來作。建議使用普通用戶來運行不須要 root 權限的服務。
  4. ENV:設置環境變量,可用於設置 PATH 或者其餘環境變量。
    • 運行容器時,能夠經過 --env XXX=xxx 來設置或者修改環境變量。--env可屢次重複使用
    • 密碼/密鑰等參數的默認值可設置在這裏,在運行時自行修改。
  5. ARG:構建時的參數,只在構建期有用。(而 ENV 就至關於運行期參數)
    • 可經過docker build -build-arg <varname>=<value> xxx 來修改構建參數。
    • 通常用於設置一些依賴的版本號、鏡像源的地址等。構建時根據這些參數從鏡像源下載對應的依賴。
  6. WORKDIR:用於制定下一個鏡像層的工做目錄(容器內部的),類比 cd xxx
    • 可屢次使用,這樣每個鏡像層均可以用不一樣的工做目錄。
    • 若是路徑不存在,會直接建立該路徑
  7. ADD/COPY:都是添加文件的命令,更推薦使用 COPY,ADD 最好只用在 tar.gz/tar.xz等文件的添加上(會自動解壓)。
    • 須要下載的文件,建議使用 curl/wget
    • COPY 能夠用於從別的鏡像複製文件(經常使用於多階段構建)
  8. RUN:最經常使用的構建指令,會建立新的鏡像層,因此最好讓每條 RUN 命令都完成一個目標的構建,減小層數。
  9. VOLUME:指定數據層掛載點。
    • 經常使用:VOLUME ["/data", "/var/log/"]
  10. EXPOSE:暴露端口。
    • 該指令只制定了容器須要暴露的端口。在 run 時還須要用 -p xx:xx 作端口映射,才能和本機的端口綁定!
  11. ENTRYPOINT:鏡像的「入口」,也就是啓動鏡像時會執行的命令。
    • 格式:ENTRYPOINT ["executable", "param1", "param2"]
    • docker run 命令的全部其餘參數,都會被看成 "入口"命令的參數傳入!
  12. CMD:在不使用 ENTRYPOINT 的狀況下,它就是鏡像的默認命令。
    • 格式:CMD ["executable","param1","param2"]
    • 在使用 ENTRYPOINT 的狀況下,CMD 建議設置爲 CMD ["--help"],而且緊跟在 ENTRYPOINT 命令以後。
  13. ONBUILD:該指令適合用在基礎鏡像的構建中。
    • 若是 FROM 一個使用了 ONBUILD 指令的鏡像,會先執行該指令,而後才執行 Dockerfile 裏面的指令。

須要注意的是,如今只有 RUN/ADD/COPY 這三條指令,纔會建立新的鏡像層。其餘的指令只會在構建過程當中建立臨時鏡像層,它們不會出如今最終的鏡像中。

1. FROM 指定基礎鏡像

所謂定製鏡像,那必定是以一個鏡像爲基礎,在其上進行定製。
Docker Hub 上有很是多的高質量的官方鏡像,有能夠直接拿來使用的服務類的鏡像,如 nginxredismongomysqlhttpdphptomcat 等;也有一些方便開發、構建、運行各類語言應用的鏡像,如 nodeopenjdkpythonrubygolang 等。能夠在其中尋找一個最符合咱們最終目標的鏡像爲基礎鏡像進行定製。

若是沒有找到對應服務的鏡像,官方鏡像中還提供了一些更爲基礎的操做系統鏡像,如 ubuntudebiancentosfedoraalpine 等,這些操做系統的軟件庫爲咱們提供了更廣闊的擴展空間。

除了選擇現有鏡像爲基礎鏡像外,Docker 還存在一個特殊的鏡像,名爲 scratch。這個鏡像是虛擬的概念,並不實際存在,它表示一個空白的鏡像。

FROM scratch
...

若是你以 scratch 爲基礎鏡像的話,意味着你不以任何鏡像爲基礎,接下來所寫的指令將做爲鏡像第一層開始存在。

不以任何系統爲基礎,直接將可執行文件複製進鏡像的作法並不罕見,好比 swarmcoreos/etcd。對於 Linux 下靜態編譯的程序來講,並不須要有操做系統提供運行時支持,所需的一切庫都已經在可執行文件裏了,所以直接 FROM scratch 會讓鏡像體積更加小巧。使用 Go 語言 開發的應用不少會使用這種方式來製做鏡像,這也是爲何有人認爲 Go 是特別適合容器微服務架構的語言的緣由之一。

鏡像構建上下文

docker build --tag <image name>:tag . 中的 . 並不只僅指 Dockerfile 的路徑!

build 命令的最後一個參數,是鏡像構建上下文的路徑,這個路徑能夠是文件夾路徑,能夠是一個 tar 壓縮包,也能夠是一個 url,甚至 git 倉庫地址也是支持的。

Docker 是 Client/Server 模式的程序,build 命令會將該 [文件夾/tar 壓縮包/url] 的內容發送給 Server 端(Docker 引擎)用於構建,
所以後面構建中的 COPY/ADD 指令,只能使用上下文裏面的內容,更不支持 ../xxx 這樣的路徑。

3、多階段構建

多階段構建中,不一樣的階段使用不一樣的基礎鏡像(所以有多個 FROM),前面的階段大都是爲了生成一些須要的文件(先後端編譯等)。
在最後一個階段,使用 COPY 將須要的文件從前幾個階段生成的鏡像中 COPY 過來,這樣就獲得了一個只包含運行時的鏡像。

前端編譯基於前端相關的鏡像,後端用後端的編譯鏡像,最後放到只包含運行時的鏡像裏。

FROM golang:1.9-alpine as builder

RUN apk --no-cache add git

WORKDIR /go/src/github.com/go/helloworld/

RUN go get -d -v github.com/go-sql-driver/mysql

COPY app.go .

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest as prod

RUN apk --no-cache add ca-certificates

WORKDIR /root/

COPY --from=0 /go/src/github.com/go/helloworld/app .

CMD ["./app"]

一些 Jenkins 構建,可供參考/使用的 Dockerfile:

  1. Slave: Jenkins Slave
  2. Python 3.7
  3. Android 構建環境:Docker Android Build Box
  4. 大合集:mritd/dockerfile

參考

相關文章
相關標籤/搜索