方槍槍的java世界

          不要因為風雨飄落就停止了你的腳步,真正的得失就在你的心中。 做喜歡做的事,不輕言放棄!

          Docker學習筆記(五)Dockerfile

          七、Dockerfile

          Docker 可以通過 Dockerfile 的內容來自動構建鏡像。Dockerfile 是一個包含創建鏡像所有命令的文本文件,通過docker build命令可以根據 Dockerfile 的內容構建鏡像,在介紹如何構建之前先介紹下 Dockerfile 的基本語法結構。

          Dockerfile 有以下指令選項:

          • FROM
          • MAINTAINER
          • RUN
          • CMD
          • EXPOSE
          • ENV
          • ADD
          • COPY
          • ENTRYPOINT
          • VOLUME
          • USER
          • WORKDIR
          • ONBUILD

          7.1 FROM

          用法:

          FROM <image>

          或者

          FROM <image>
          • FROM指定構建鏡像的基礎源鏡像,如果本地沒有指定的鏡像,則會自動從 Docker 的公共庫 pull 鏡像下來。
          • FROM必須是 Dockerfile 中非注釋行的第一個指令,即一個 Dockerfile 從FROM語句開始。
          • FROM可以在一個 Dockerfile 中出現多次,如果有需求在一個 Dockerfile 中創建多個鏡像。
          • 如果FROM語句沒有指定鏡像標簽,則默認使用latest標簽。

          7.2 MAINTAINER

          用法:

          MAINTAINER <name>

          指定創建鏡像的用戶

          RUN 有兩種使用方式

          • RUN
          • RUN

          每條RUN指令將在當前鏡像基礎上執行指定命令,并提交為新的鏡像,后續的RUN都在之前RUN提交后的鏡像為基礎,鏡像是分層的,可以通過一個鏡像的任何一個歷史提交點來創建,類似源碼的版本控制。

          exec 方式會被解析為一個 JSON 數組,所以必須使用雙引號而不是單引號。exec 方式不會調用一個命令 shell,所以也就不會繼承相應的變量,如:

          RUN [ "echo", "$HOME" ]

          這種方式是不會達到輸出 HOME 變量的,正確的方式應該是這樣的

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

          RUN產生的緩存在下一次構建的時候是不會失效的,會被重用,可以使用--no-cache選項,即docker build --no-cache,如此便不會緩存。

          7.3 CMD

          CMD有三種使用方式:

          CMD指定在 Dockerfile 中只能使用一次,如果有多個,則只有最后一個會生效。

          CMD的目的是為了在啟動容器時提供一個默認的命令執行選項。如果用戶啟動容器時指定了運行的命令,則會覆蓋掉CMD指定的命令。

          CMD會在啟動容器的時候執行,build 時不執行,而RUN只是在構建鏡像的時候執行,后續鏡像構建完成之后,啟動容器就與RUN無關了,這個初學者容易弄混這個概念,這里簡單注解一下。

          7.4 EXPOSE

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

          告訴 Docker 服務端容器對外映射的本地端口,需要在 docker run 的時候使用-p或者-P選項生效。

          7.5 ENV

          ENV <key> <value>       # 只能設置一個變量
          ENV <key>=<value> ...   # 允許一次設置多個變量

          指定一個環節變量,會被后續RUN指令使用,并在容器運行時保留。

          例子:

          ENV myName="John Doe" myDog=Rex\ The\ Dog \
              myCat=fluffy

          等同于

          ENV myName John Doe
          ENV myDog Rex The Dog
          ENV myCat fluffy

          7.6 ADD

          ADD <src>... <dest>

          ADD復制本地主機文件、目錄或者遠程文件 URLS 從 并且添加到容器指定路徑中 。

          支持通過 GO 的正則模糊匹配,具體規則可參見 Go filepath.Match

          ADD hom* /mydir/        # adds all files starting with "hom"
          ADD hom?.txt /mydir/    # ? is replaced with any single character
          • 路徑必須是絕對路徑,如果 不存在,會自動創建對應目錄
          • 路徑必須是 Dockerfile 所在路徑的相對路徑
          • 如果是一個目錄,只會復制目錄下的內容,而目錄本身則不會被復制

          7.7 COPY

          COPY <src>... <dest>

          COPY復制新文件或者目錄從 并且添加到容器指定路徑中 。用法同ADD,唯一的不同是不能指定遠程文件 URLS。

          7.8 ENTRYPOINT

          配置容器啟動后執行的命令,并且不可被 docker run 提供的參數覆蓋,而CMD是可以被覆蓋的。如果需要覆蓋,則可以使用docker run --entrypoint選項。

          每個 Dockerfile 中只能有一個ENTRYPOINT,當指定多個時,只有最后一個生效。

          Exec form ENTRYPOINT 例子

          通過ENTRYPOINT使用 exec form 方式設置穩定的默認命令和選項,而使用CMD添加默認之外經常被改動的選項。

          FROM ubuntu
          ENTRYPOINT ["top", "-b"]
          CMD ["-c"]

          通過 Dockerfile 使用ENTRYPOINT展示前臺運行 Apache 服務

          FROM debian:stable
          RUN apt-get update && apt-get install -y --force-yes apache2
          EXPOSE 80 443
          VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
          ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

          Shell form ENTRYPOINT 例子

          這種方式會在/bin/sh -c中執行,會忽略任何CMD或者docker run命令行選項,為了確保docker stop能夠停止長時間運行ENTRYPOINT的容器,確保執行的時候使用exec選項。

          FROM ubuntu
          ENTRYPOINT exec top -b

          如果在ENTRYPOINT忘記使用exec選項,則可以使用CMD補上:

          FROM ubuntu
          ENTRYPOINT top -b
          CMD --ignored-param1 # --ignored-param2 ... --ignored-param3 ... 依此類推

          7.9 VOLUME

          VOLUME ["/data"]

          創建一個可以從本地主機或其他容器掛載的掛載點,后續具體介紹。

          7.10 USER

          USER daemon

          指定運行容器時的用戶名或 UID,后續的RUN、CMD、ENTRYPOINT也會使用指定用戶。

          7.11 WORKDIR

          WORKDIR /path/to/workdir

          為后續的RUN、CMD、ENTRYPOINT指令配置工作目錄。可以使用多個WORKDIR指令,后續命令如果參數是相對路徑,則會基于之前命令指定的路徑。

          WORKDIR /a
          WORKDIR b
          WORKDIR c
          RUN pwd

          最終路徑是/a/b/c。

          WORKDIR指令可以在ENV設置變量之后調用環境變量:

          ENV DIRPATH /path
          WORKDIR $DIRPATH/$DIRNAME

          最終路徑則為 /path/$DIRNAME。

          7.12 ONBUILD

          ONBUILD [INSTRUCTION]

          配置當所創建的鏡像作為其它新創建鏡像的基礎鏡像時,所執行的操作指令。

          例如,Dockerfile 使用如下的內容創建了鏡像 image-A:

          [...]
          ONBUILD ADD . /app/src
          ONBUILD RUN /usr/local/bin/python-build --dir /app/src
          [...]

          如果基于 image-A 創建新的鏡像時,新的 Dockerfile 中使用 FROM image-A 指定基礎鏡像時,會自動執行 ONBUILD 指令內容,等價于在后面添加了兩條指令。

          # Automatically run the following
          ADD . /app/src
          RUN /usr/local/bin/python-build --dir /app/src

          使用ONBUILD指令的鏡像,推薦在標簽中注明,例如 ruby:1.9-onbuild。

          7.13 Dockerfile Examples

          # Nginx
          #
          # VERSION               0.0.1
          
          FROM      ubuntu
          MAINTAINER Victor Vieux <victor@docker.com>
          
          RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
          
          # Firefox over VNC
          #
          # VERSION               0.3
          
          FROM ubuntu
          
          # Install vnc, xvfb in order to create a 'fake' display and firefox
          RUN apt-get update && apt-get install -y x11vnc xvfb firefox
          RUN mkdir ~/.vnc
          # Setup a password
          RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
          # Autostart firefox (might not be the best way, but it does the trick)
          RUN bash -c 'echo "firefox" >> /.bashrc'
          
          EXPOSE 5900
          CMD    ["x11vnc", "-forever", "-usepw", "-create"]
          
          # Multiple images example
          #
          # VERSION               0.1
          
          FROM ubuntu
          RUN echo foo > bar
          # Will output something like ===> 907ad6c2736f
          
          FROM ubuntu
          RUN echo moo > oink
          # Will output something like ===> 695d7793cbe4
          
          # You?ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
          # /oink.

          7.14 docker build

          $ docker build --help
          
          Usage: docker build [OPTIONS] PATH | URL | -
          
          Build a new image from the source code at PATH
          
            --force-rm=false     Always remove intermediate containers, even after unsuccessful builds # 移除過渡容器,即使構建失敗
            --no-cache=false     Do not use cache when building the image                              # 不實用 cache        
            -q, --quiet=false    Suppress the verbose output generated by the containers               
            --rm=true            Remove intermediate containers after a successful build               # 構建成功后移除過渡層容器
            -t, --tag=""         Repository name (and optionally a tag) to be applied to the resulting image in case of success

          參考文檔:Dockerfile Reference

          7.15 dockerfile 最佳實踐

          • 使用.dockerignore文件

          為了在docker build過程中更快上傳和更加高效,應該使用一個.dockerignore文件用來排除構建鏡像時不需要的文件或目錄。例如,除非.git在構建過程中需要用到,否則你應該將它添加到.dockerignore文件中,這樣可以節省很多時間。

          • 避免安裝不必要的軟件包

          為了降低復雜性、依賴性、文件大小以及構建時間,應該避免安裝額外的或不必要的包。例如,不需要在一個數據庫鏡像中安裝一個文本編輯器。

          • 每個容器都跑一個進程

          在大多數情況下,一個容器應該只單獨跑一個程序。解耦應用到多個容器使其更容易橫向擴展和重用。如果一個服務依賴另外一個服務,可以參考 Linking Containers Together

          • 最小化層

          我們知道每執行一個指令,都會有一次鏡像的提交,鏡像是分層的結構,對于Dockerfile,應該找到可讀性和最小化層之間的平衡。

          • 多行參數排序

          如果可能,通過字母順序來排序,這樣可以避免安裝包的重復并且更容易更新列表,另外可讀性也會更強,添加一個空行使用\換行:

          RUN apt-get update && apt-get install -y \
            bzr \
            cvs \
            git \
            mercurial \
            subversion
          • 創建緩存

          鏡像構建過程中會按照Dockerfile的順序依次執行,每執行一次指令 Docker 會尋找是否有存在的鏡像緩存可復用,如果沒有則創建新的鏡像。如果不想使用緩存,則可以在docker build時添加--no-cache=true選項。

          從基礎鏡像開始就已經在緩存中了,下一個指令會對比所有的子鏡像尋找是否執行相同的指令,如果沒有則緩存失效。在大多數情況下只對比Dockerfile指令和子鏡像就足夠了。ADD和COPY指令除外,執行ADD和COPY時存放到鏡像的文件也是需要檢查的,完成一個文件的校驗之后再利用這個校驗在緩存中查找,如果檢測的文件改變則緩存失效。RUN apt-get -y update命令只檢查命令是否匹配,如果匹配就不會再執行更新了。

          為了有效地利用緩存,你需要保持你的 Dockerfile 一致,并且盡量在末尾修改。

          Dockerfile 指令

          • FROM: 只要可能就使用官方鏡像庫作為基礎鏡像
          • RUN: 為保持可讀性、方便理解、可維護性,把長或者復雜的RUN語句使用\分隔符分成多行
            • 不建議RUN apt-get update獨立成行,否則如果后續包有更新,那么也不會再執行更新
            • 避免使用RUN apt-get upgrade或者dist-upgrade,很多必要的包在一個非privileged權限的容器里是無法升級的。如果知道某個包更新,使用apt-get install -y xxx
            • 標準寫法
              • RUN apt-get update && apt-get install -y package-bar package-foo

          例子:

          RUN apt-get update && apt-get install -y \
              aufs-tools \
              automake \
              btrfs-tools \
              build-essential \
              curl \
              dpkg-sig \
              git \
              iptables \
              libapparmor-dev \
              libcap-dev \
              libsqlite3-dev \
              lxc=1.0* \
              mercurial \
              parallel \
              reprepro \
              ruby1.9.1 \
              ruby1.9.1-dev \
              s3cmd=1.1.0*
          • CMD: 推薦使用CMD [“executable”, “param1”, “param2”…]這種格式,CMD [“param”, “param”]則配合ENTRYPOINT使用
          • EXPOSE: Dockerfile 指定要公開的端口,使用docker run時指定映射到宿主機的端口即可
          • ENV: 為了使新的軟件更容易運行,可以使用ENV更新PATH變量。如ENV PATH /usr/local/nginx/bin:$PATH確保CMD ["nginx"]即可運行

          ENV也可以這樣定義變量:

          ENV PG_MAJOR 9.3
          ENV PG_VERSION 9.3.4
          RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
          ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
          • ADDorCOPY:ADD比COPY多一些特性「tar 文件自動解包和支持遠程 URL」,不推薦添加遠程 URL

          如不推薦這種方式:

          ADD http://example.com/big.tar.xz /usr/src/things/
          RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
          RUN make -C /usr/src/things all

          推薦使用 curl 或者 wget 替換,使用如下方式:

          RUN mkdir -p /usr/src/things \
              && curl -SL http://example.com/big.tar.gz \
              | tar -xJC /usr/src/things \
              && make -C /usr/src/things all

          如果不需要添加 tar 文件,推薦使用COPY。

          參考文檔:

          posted on 2016-12-27 21:35 做強大的自己 閱讀(132) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 新泰市| 资源县| 德安县| 兴隆县| 白银市| 略阳县| 玉环县| 营山县| 磐石市| 察雅县| 营口市| 广汉市| 双鸭山市| 屏东县| 仪征市| 荆门市| 西和县| 平谷区| 万荣县| 吉林省| 云和县| 读书| 甘洛县| 灵山县| 阿拉善盟| 七台河市| 吴旗县| 平南县| 东至县| 松潘县| 抚松县| 平武县| 彰化县| 定安县| 门头沟区| 四会市| 兰州市| 正定县| 庆云县| 郁南县| 翁源县|