本篇文章是關于Dockerfiles的,這是Docker系列文章的第三部分,如果您還沒有讀過第一部分,請先閱讀它,您可以從全新的角度了解Docker容器概念, 第二部分是Docker生態系統的簡要介紹,在以后的文章中,我將研究精簡Docker映像、Docker CLI命令以及使用Docker的資料,
現在,讓我們跳進這十幾個Dockerfile說明中去吧!

圖:跳進來
Docker映像
Docker容器是栩栩如生的Docker映像,它是一個獨立的、最小的作業系統,帶有應用程式代碼,
Docker映像在構建時創建的,而Docker容器是在運行時創建,
Dockerfile是Docker的核心,Dockerfile告訴Docker如何構建用于制作容器的映像,
每個Docker映像都包含一個名為Dockerfile的檔案,沒有擴展名,呼叫Dockerfile docker build 創建映像時,假定該Dockerfile位于當前作業目錄中,可以使用檔案標志( -f )指定其他位置,
容器是由一系列層構建而成的,除位于最后一層之上的最終容器層外,每一層都是只讀的,Dockerfile告訴Docker添加哪些層以及添加順序,
每一層實際上只是一個檔案,其中包含自上一層以來的更改,在Unix中,幾乎所有內容都是檔案,
基礎影像提供了初始層,基本影像也稱為父影像,
當影像從遠程存盤庫拉到本地計算機時,只下載本地計算機上尚未存在的層,Docker就是通過重用現有層來節省空間和時間,

圖:基本(跳躍)影像
Dockerfile指令是一行開頭的大寫單詞,后跟其引數,Dockerfile中的每一行都可以包含一條指令,構建影像時,說明從上到下進行處理,說明如下:
FROM ubuntu:18.04
COPY . /app
只有指令FROM,RUN,COPY和ADD才能在最終影像中創建圖層,其他的指令可配置事物,添加元資料或告訴Docker在運行時執行某些操作,例如公開埠或運行命令, 在本文中,我假設您正在使用基于Unix的Docker映像,您也可以使用基于Windows的映像,但這是一個較慢,較不愉快,較不常見的程序,因此,如果可以,請使用Unix,
讓我們快速瀏覽一下我們將探索的十二個Dockerfile指令吧,
Dockerfile指令
FROM —指定基本(父)影像,
LABEL —提供元資料,包括維護者資訊,
ENV —設定持久性環境變數,
RUN —運行命令并創建影像層,用于將軟體包安裝到容器中,
COPY -將檔案和目錄復制到容器,
ADD -將檔案和目錄復制到容器,可以支持本地.tar檔案,
CMD —為執行中的容器提供命令和引數,可以覆寫引數,只能有一個CMD,
WORKDIR —為以下說明設定作業目錄,
ARG —定義在構建時傳遞給Docker的變數,
ENTRYPOINT —為執行中的容器提供命令和引數,爭論依然存在,
EXPOSE —暴露埠,
VOLUME —創建目錄安裝點以訪問和存盤持久資料,
讓我們開始吧!
說明和示例
Dockerfile可以像下面這樣簡單:
FROM ubuntu:18.04
FROM
Dockerfile必須以FROM指令或ARG指令開頭,后跟FROM指令,
FROM 關鍵字告訴Docker使用與提供的存盤庫和標簽匹配的基礎映像,基本影像也稱為父影像,
在此示例中,ubuntu是映像存盤庫,Ubuntu是 官方Docker存盤庫的名稱,該存盤庫提供了流行的Linux作業系統的Ubuntu版本的基本版本,

圖:Linux吉祥物Tux
請注意,此Dockerfile包含基礎映像的標記:18.04,這個標簽告訴Docker在ubuntu倉庫中鏡像的哪個版本,如果不包含標簽,則默認情況下,Docker將采用最新標簽,為了使您的意圖清晰明了,最好指定一個基本影像標簽,
當上述Dockerfile首次用于在本地構建映像時,Docker下載ubuntu映像中指定的層,可以將這些層視為彼此堆疊,每一層都是一個檔案,具有與前一層不同的一組檔案,
創建容器時,可以在只讀層的頂部添加可寫層,

圖:從 Docker檔案
為了提高效率,Docker使用了一種寫時拷貝策略,如果一個層存在于影像的前一層,而另一層需要對其進行讀訪問,Docker將使用現有檔案,不需要下載任何內容,
當一個影像正在運行時,如果一個層需要被容器修改,那么該檔案將被復制到頂部的可寫層中,
更具實質性的Dockerfile
雖然我們的單線圖很簡潔,但它也很慢,提供的資訊很少,并且在容器運行時什么也不做,讓我們看一個較長的Dockerfile,它構建一個小得多的影像,并在容器運行時執行腳本,
FROM python:3.7.2-alpine3.8
LABEL maintainer="[email protected]"
ENV ADMIN="jeff"
RUN apk update && apk upgrade && apk add bash
COPY . ./app
ADD https://raw.githubusercontent.com/discdiver/pachy-vid/master/sample_vids/vid1.mp4 \
/my_app_directory
RUN ["mkdir", "/a_directory"]
CMD ["python", "./my_script.py"]
這是怎么回事能?讓我們逐步了解并揭開神秘面紗, 基本映像是帶有標簽3.7.2-alpine3.8的正式Python映像,從 源代碼中可以看到,該映像包含Linux、Python和其他一些內容,高山影像之所以受歡迎,是因為它們體積小,速度快且安全,但是,Alpine映像并沒有很多作業系統優點,如果需要,您必須自己安裝這樣的軟體包,
LABEL
下一條指令是LABEL,LABEL將元資料添加到影像中,在本例中,它提供影像維護者的聯系資訊, Labels不會減慢構建速度或占用空間,它們提供了有關Docker映像的有用資訊,因此一定要使用它們,有關LABEL元資料的更多資訊,請參見 此處,

ENV
ENV設定在容器運行時可用的持久環境變數,在上面的例子中,您可以在創建Docker容器時使用ADMIN變數,
ENV非常適合設定常量,如果您在Dockerfile中的多個位置使用常量,并且想在以后更改其值,則可以在一個位置進行更改,

圖:環境
對于Dockerfiles,通常可以通過多種方式完成同一件事,針對您的案例,最好的方法是平衡Docker約定、透明性和速度,例如,RUN、CMD和ENTRYPOINT具有不同的用途,并且均可用于執行命令,
RUN
RUN在構建時創建一個層,每次運行后,Docker都會提交映像的狀態,
RUN通常用于將軟體包安裝到映像中 , 在上面的示例中, RUN apk update && apk upgrade 告訴Docker從基礎映像更新軟體包 , && apk add bash 告訴Docker將bash安裝到映像中,
apk代表Alpine Linux軟體包管理器,如果您使用的是Alpine以外的其他版本的Linux基礎映像,則應使用RUN apt-get而不是apk安裝軟體包,apt代表高級包工具,在后面的示例中,我將討論安裝包的其他方法,

圖:跑
RUN及其同級命令CMD和ENTRYPOINT可以在exec表單或shell表單中使用,Exec form使用的JSON陣列語法如下:
例如: RUN ["my_executable", "my_first_param1", "my_second_param2"] ,
在上面的示例中,我們使用格式為的shell形式 RUN apk update && apk upgrade && apk add bash ,
稍后在Dockerfile中,我們使用首選的exec形式 RUN ["mkdir", "/a_directory"] 創建目錄,別忘了對exec form使用JSON語法的字串使用雙引號!
COPY
該 COPY . ./app 指令告訴Docker在本地構建背景關系中獲取檔案和檔案夾,并將它們添加到Docker映像的當前作業目錄中,如果不存在,復制將創建目標目錄,

圖:復制
ADD
ADD與COPY執行相同的操作,但有兩個以上的用例,ADD可用于將檔案從遠程URL移動到容器,ADD可以提取本地TAR檔案,
我在上面的示例中使用ADD將檔案從遠程URL復制到容器的 my_app_directory中 ,Docker檔案不建議以這種方式使用遠程URL,因為您無法洗掉這些檔案,額外的檔案會增加最終影像的大小,
Docker檔案還建議盡可能使用COPY而不是ADD來提高清晰度,Docker沒有將ADD和COPY合并到一個命令中,以減少Dockerfile指令的數量來保持直線,這太糟糕了,
注意,ADD指令包含 \ 換行符,使用它可以通過將一條長指令拆分成幾行來提高可讀性,
CMD
CMD向Docker提供了一個在容器啟動時運行的命令,它不會在構建時將命令的結果提交給映像,在上面的示例中,CMD將使Docker容器在運行時運行my_ script.py 檔案,

圖:那是CMD!
有關CMD的其他幾件事:
- 每個Dockerfile僅一個CMD指令,否則,除最后一個以外的所有內容都將被忽略,
- CMD可以包含一個可執行檔案,如果存在沒有可執行檔案的CMD,則必須存在ENTRYPOINT指令,在這種情況下,CMD和ENTRYPOINT指令都應為JSON格式,
-
命令列引數將
docker run覆寫Dockerfile中提供給CMD的引數,準備好了嗎?
讓我們在另一個Dockerfile示例中介紹更多說明,
FROM python:3.7.2-alpine3.8
LABEL maintainer="[email protected]"
# Install dependencies
RUN apk add --update git
# Set current working directory
WORKDIR /usr/src/my_app_directory
# Copy code from your local context to the image working directory
COPY . .
# Set default value for a variable
ARG my_var=my_default_value
# Set code to run at container run time
ENTRYPOINT ["python", "./app/my_script.py", "my_var"]
# Expose our port to the world
EXPOSE 8000
# Create a volume for data storage
VOLUME /my_volume
請注意,您可以在Dockerfiles中使用注釋,注釋以 # 開頭, 軟體包安裝是Dockerfiles的主要作業,如前所述,有幾種方法可以使用RUN安裝軟體包,
您可以使用apk在Alpine Docker映像中安裝軟體包,apk就像常規Linux構建中的apt-get,例如,帶有基本Ubuntu映像的Dockerfile中的軟體包可以像這樣更新和安裝: RUN apt-get update && apt-get install my_package ,
除了apk和apt-get 之外 ,還可以通過pip,wheel和conda安裝Python軟體包,其他語言可以使用各種安裝程式,
基礎層需要向安裝層提供相關的軟體包管理器,如果您在安裝軟體包時遇到問題,請在安裝軟體包管理器之前嘗試使用它們,
您可以將RUN與pip一起使用,并在Dockerfile中直接列出要安裝的軟體包,如果這樣做,則將您的軟體包安裝到一條指令中,并用換行符(\)將其分開,與多個RUN指令相比,此方法提供了清晰度和更少的層數,
或者,您可以在檔案中列出軟體包要求,然后在該檔案上運行軟體包管理器,人們通常將檔案命名為 requirements.txt ,我將在下一篇文章中分享一個推薦的模式,以利用build.ca快取與 requirements.txt 一起使用,
WORKDIR
WORKDIR會更改容器中的作業目錄,以供后面的COPY、ADD、RUN、CMD和ENTRYPOINT指令使用,幾點注意事項:
- 最好使用WORKDIR設定絕對路徑,而不是使用Dockerfile中的
cd命令在檔案系統中導航, - 如果該目錄不存在,則WORKDIR會自動創建該目錄,
- 您可以使用多個WORKDIR指令,如果提供了相對路徑,則每個WORKDIR指令都會更改當前作業目錄,

圖:某種作業目錄
ARG
ARG定義了一個在構建時從命令列傳遞到映像的變數,可以在Dockerfile中為ARG提供默認值,如示例所示: ARG my_var=my_default_value ,
與ENV變數不同,ARG變數不適用于運行中的容器,但是,在生成映像時,可以使用ARG值在命令列中為ENV變數設定默認值,然后,ENV變數在容器運行期間一直存在,
ENTRYPOINT
ENTRYPOINT指令還允許您在容器啟動時提供默認命令和引數,它看起來與CMD相似,但是如果使用命令列引數運行容器,則ENTRYPOINT引數不會被覆寫,
而是將傳遞給的命令列引數 docker run my_image_name 附加到ENTRYPOINT指令的引數中,例如, docker run my_image bash 將引數 bash 添加到ENTRYPOINT指令的現有引數的末尾,

圖:進入某處
Dockerfile應該至少具有一個CMD或ENTRYPOINT指令,
Docker檔案中有一些關于在CMD和ENTRYPOINT之間選擇初始容器命令的建議:
- 當您 需要每次運行 相 同 的 命令時,請 選擇 ENTRYPOINT,
- 當 容器 將 用作可執行程式時, 首選入口點 ,
- 當您 需要提供 額外的默認引數, 可以從命令列 重寫 時, 使用 CMD,
在上面的示例中, ENTRYPOINT ["python", "my_script.py", "my_var"] 讓容器在容器開始運行時運行帶有引數 my_var 的python腳本 my_script.py , 然后, my_script可以 通過argparse使用 my_var ,請注意, my_var 具有ARG先前在Dockerfile中提供的默認值,因此,如果未從命令列傳遞引數,則將使用默認引數,
Docker建議您通常使用ENTRYPOINT:的exec形式 ENTRYPOINT ["executable", "param1", "param2"] ,這種形式是使用JSON陣列語法的形式,
EXPOSE
EXPOSE指令顯示要發布哪個埠以提供對正在運行的容器的訪問,EXPOSE實際上不會發布埠,相反,它充當構建映像的人員與運行容器的人員之間的檔案,

圖:暴露
docker run 與 -p 標志一起使用,以在運行時發布和映射一個或多個埠,大寫 -P 標志將發布所有公開的埠,
VOLUME
VOLUME指定您的容器將在哪里存盤和/或訪問持久資料,

圖:卷
總結
Dockerfile也許是Docker掌握的關鍵組件,我希望本文能幫助到你們,
原文作者:Jeff Hale
原文地址:https://towardsdatascience.com/learn-enough-docker-to-be-useful-1c40ea269fa8
翻譯:豬齒魚技術團隊
本文由豬齒魚技術團隊原創,轉載請注明出處:豬齒魚官網
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/302418.html
標籤:其他
