1. 程式人生 > >Kubernetes-基於Dockerfile構建docker映象最佳實踐

Kubernetes-基於Dockerfile構建docker映象最佳實踐

1、Dockerfile檔案和核心指令
在Kubernetes中執行容器的前提是已存在構建好的映象檔案,而通過Dockerfile檔案構建映象是最好方式。Dockerfile是一個文字檔案,在此檔案中的可以設定各種指令,以通過docker build命令自動構建出需要的映象。Dockerfile檔案必需以FROM命令開始,然後按照檔案中的命令順序逐條進行執行。在檔案以#開始的內容會被看做是對相關命令的註釋。

Comment

INSTRUCTION arguments
下面是一個典型的Dockerfile檔案,此Dockerfile用於構建一個docker映象倉庫的映象。Dockerfile檔案的格式如下,在檔案中對於大小寫是不敏感的。但是為了方便的區分命令和引數,一般以大寫的方式編寫命令。此映象的基礎映象為alpine:3.4,構建一個docker映象倉庫的映象:

Build a minimal distribution container

FROM alpine:3.4
RUN set -ex \
&& apk add --no-cache ca-certificates apache2-utils
COPY ./registry/registry /bin/registry
COPY ./registry/config-example.yml /etc/docker/registry/config.yml
VOLUME ["/var/lib/registry"]
EXPOSE 5000
COPY docker-entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

CMD ["/etc/docker/registry/config.yml"]
1.1 FROM:設定基礎映象
FROM命令為後續的命令設定基礎映象,它是Dockerfile檔案的第一條命令,FROM命令的格式如下:
FROM <image>[:<tag>] [AS <name>]
1.2 RUN:設定構建映象時執行的命令
RUN命令有兩種格式,下面是shell格式的RUN命令,在Linux中RUN的預設命令是/bin/sh;在Windows中預設命令為cmd /S /C:
RUN <command>
下面是exec格式的RUN命令:
RUN ["executable", "param1", "param2"]

RUN指令將會在當前映象頂部的新層中執行任何命令,並提交結果。提交的結果映象將用於Dockerfile檔案的下一步。分層RUN指令和生成提交符合Docker的核心概念,容器可以從映象歷史中的任何點映象建立,非常類似於原始碼管理。
1.3 CMD:設定容器的預設執行命令
CMD指令的主要目的是為容器提供一個預設的執行命令,在一個Dockerfile只能有一條CMD指令,如果設定多條CMD指令,只有最後一條CMD指令會生效。The CMD指令有如下三種格式:
exec格式,這是推薦的格式:
CMD ["executable","param1","param2"]
為ENTRYPOINT提供引數:
CMD ["param1","param2"]
shell格式:
CMD command param1 param2
如果在Dockerfile中,CMD被用來為ENTRYPOINT指令提供引數,則CMD和ENTRYPOINT指令都應該使用exec格式。當基於映象的容器執行時,將會自動執行CMD指令。如果在docker run命令中指定了引數,這些引數將會覆蓋在CMD指令中設定的引數。
1.4 ENTRYPOINT:設定容器為可執行檔案
通過ENTRYPOINT指令可以將容器設定作為可執行的檔案,ENTRYPOINT 有兩種格式:
exec格式,這是推薦的格式:
ENTRYPOINT ["executable", "param1", "param2"]
shell格式:
ENTRYPOINT command param1 param2
下面是是啟動一個nginx的例子,埠為80:
docker run -i -t --rm -p 80:80 nginx
docker run <image>命令列引數將會被追加到exec格式的ENTRYPOINT所有元素之後,並將會覆蓋使用CMD指定的所有元素。這就允許江參數傳遞到入口點,例如,docker run <Image> -d 將通過-d 引數傳遞到入口點。可以使用docker run --entrypoint 欄位覆蓋“ENTRYPOINT ”指令。如果在Dockerfile檔案設定了多條ENTRYPOINT指令,則只會生效最後的一條指令。
1.4.1 ENTRYPOINT指令exec格式示例:
可以使用ENTRYPOINT 的exec形式來設定相對穩定的預設命令和引數,然後使用任何形式的CMD指令來設定可能發生變化的引數。
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
當執行容器是,可以看到只有一個top程序在執行:
$ docker run -it --rm --name test top -H
top - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05
Threads: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 2056668 total, 1616832 used, 439836 free, 99352 buffers
KiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top
通過docker exec命令,能夠參考容器的更多資訊。
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.6 0.1 19752 2352 ? Ss+ 08:24 0:00 top -b -H
root 7 0.0 0.1 15572 2164 ? R+ 08:25 0:00 ps aux
下面的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"]
1.4.2 ENTRYPOINT指令的shell格式
通過為ENTRYPOINT指定文字格式的引數,此引數將在/bin /sh -c 中進行執行。這個形式將使用shell處理,而不是shell環境變數,並且將忽略任何的CMD或docker run執行命令列引數。
FROM ubuntu
ENTRYPOINT exec top -b
1.4.3 CMD和ENTRYPOINT互動
CMD和ENTRYPOINT指令都可以定義容器執行時所執行的命令,下面是它們之間協調的一些規則:
1)在Dockerfile至少需要設定一條CMD或者ENTRYPOINT指令;
2)當將容器作為可執行檔案使用時,建議定義ENTRYPOINT指令;
3)CMD作為為ENTRYPOINT命令定義預設引數的一種方式;
4)當使用帶有引數的命令執行容器時,CMD將會被覆蓋。
下表是顯示了不同的ENTRYPOINT / CMD指令組合的命令執行情況:
No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“exec_entry”, “p1_entry”]
No CMD 報錯,這種情況不執行出現 /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

1.5 ENV:設定環境變數
Env指令通過<鍵>和<值>對設定環境變數。此值將在環境中用於生成階段中的所有後續指令,並且也可以在許多情況下被替換為內聯。
“Env”指令有兩種形式。第一種形式,即ENV <Key> < value >,將一個變數設定為一個值。第一個空間之後的整個字串將被處理為“<值>”,包括空白字元。
ENV <key> <value>
第二種形式,即ENV <Key>=Value>…,允許一次設定多個變數。注意,第二個表單在語法中使用等號(=),而第一個表單則不使用。與命令列解析一樣,引用和反斜槓可用於在值內包含空格。
ENV <key>=<value> ...
例如:
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy
和:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
1.6 ADD:新增內容到容器中
ADD指令用於從當前機器或遠端URL中的<src>中拷貝檔案、目錄,並將它們新增到映象檔案系統的<dest>中。在指令中能夠設定多個<src>,--chown僅僅在構建Linux容器映象時起作用,ADD指令有兩種格式:
ADD [--chown=<user>:<group>] <src>... <dest>
下面的ADD指令格式可以執行源和目標路徑包含空格。
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
<src>可以包含萬用字元,例如:
ADD hom* /mydir/ # 新增所有以"hom"開頭的檔案到映象中的/mydir目錄下。
ADD hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"
<dest>是容器一個絕對路徑,或者是一個相對於WORKDIR的相對路徑,
ADD test relativeDir/ # 新增"test"到容器中WORKDIR/relativeDir/
ADD test /absoluteDir/ # 新增"test"到容器中的/absoluteDir/
ADD指令遵循下面的規則:
• <src>路徑必需在構建的上下文中;不能使用 ADD ../someting /someting,這是因為docker build的第一步就是傳送上下文目錄給docker daemon。
• 如果<src>是一個URL,並且<dest>不是以斜線結束的情況,則會從URL中下載一個檔案,並將其拷貝到<dest>;
• 如果<src>是一個URL,並且<dest>以斜線結束,則會然後從URL中匯出檔名,並將檔案下載到<dest>/<filename>中。例如:ADD http://example.com/foobar /,則會在容器的/目錄下建立foobar檔案,並將URL中foobar檔案中的內容複製到容器中/foobar檔案中。
• 如果<src>是一個目錄,那麼將會拷貝整個目錄下的內容,幷包括檔案系統的元資料。需要注意的時,拷貝時,並不會拷貝目錄本身,而只是拷貝目錄下內容。
• 如果<src>是本地的一個壓縮(例如:gzip、bzip2、xz等格式)檔案,則會對其進行解壓縮。對於來自於遠端的URL,則不會進行解壓縮。
• 如果<src>是一個普通檔案,將會直接將檔案和它的元資料拷貝到映象的<dest>目錄下。
• 如果指定了多個<src>,如果這些<src>中存在目錄或使用了萬用字元,則<Dest>必須是一個目錄,並且必須以斜槓/結尾。
• 如果<dest>不是以斜槓/結尾,它將被認為是一個檔案,那麼<src>的內容將被寫到<dest>中。
1.7 COPY:拷貝內容到映象中
COPY指令用於從<src>中拷貝檔案或目錄,並將其新增到映象檔案系統的<path>目錄下。在指令中可以指定多個< src>資源,但是檔案和目錄的路徑將被解釋為相對於當前構建上下文的資源。COPY指令與ADD指令的功能基本上相似,但ADD能夠從遠端拷貝,以及解壓縮檔案。COPY指令有兩種格式:
COPY [--chown=<user>:<group>] <src>... <dest>
當目錄中存在空格時,請使用下面的格式:
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
1.8 WORKDIR:設定當前工作目錄
WORKDIR指令用於為RUN、CMD、ENTRYPOINT、COPY和ADD指令設定當前的工作目錄。如果WORKDIR不存在,則會自動建立一個,即使後續不使用。
WORKDIR /path/to/workdir
在Dockerfile檔案中,可以設定多個WORKDIR指令。如果給定了一個相對路徑,則後續WORKDIR設定的路徑是相對於上一個相對路徑的路徑:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
在Dockerfile中,最後的pwd命令輸出的為:/a/b/c
1.9 EXPOSE:設定暴露的埠
EXPOSE指令告知docker,容器在執行時將監聽指定哪個指定的網路埠。並可以指定埠的協議是TCP或UDP,如果沒有指定協議,則預設為TCP協議。EXPOSE指令的格式如下:
EXPOSE <port> [<port>/<protocol>...]
“EXPOSE”指令實際上並不釋出埠,它在構建映象的人員和執行容器的人員之間起著文件告知的作用。要在執行容器時實際釋出埠,則需要通過在docker run命令使用-p和-P來發布和對映一個或者多個埠。
1.10 LABEL:設定映象的元資料資訊
LABEL指令擁有為映象新增一些描述的元資料。LABEL是一系列的鍵值對,它的格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
下面是LABEL指令的示例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
通過docker inspect命令,可以檢視映象中的標籤資訊:
"Labels": {
"com.example.vendor": "ACME Incorporated"
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple lines.",
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
},
1.12 VOLUME:設定儲存卷
VOLUME指令用於建立一個帶有指定名稱的掛載點,並將其標記為來自於本地主機或其他容器的儲存卷。該值可以是JSON陣列、VOLUME ["/var/log/“],或者是具有多個引數的普通字串,例如VOLUME /var/log 或 VOLUME /var/log /var/db。
VOLUME ["/data"]
2、構建映象
在定義後Dockerfile檔案,並準備好相關的內容後,就可以通過docker build命令從Dockerfile和上下文構建docker映象。構建的上下文是位於指定路徑或URL中的檔案集合。構建過程可以引用上下文中的任何檔案。例如,您的構建可以使用複製指令來引用上下文中的檔案。
docker build [OPTIONS] PATH | URL | -
2.1 命令選項
名稱 預設值 描述
--ad