docker快速入門6-dockerfile和registry

docker快速入門6-dockerfile和registry

dockerfile是構造Docker images的一行行命令的集合,是一個純文本文件。html

語法格式

# 註釋信息node

INSTRUCTION 指令,指令不區分大小寫,但約定使用大寫linux

非註釋行的第一行必須是FROM指令nginx

工做目錄

使用Dockerfile製做鏡像時須要一個乾淨的工做目錄,該目錄結構以下:git

Dockerfile文件
可選的 .dockerignore,用於存放要打包進鏡像的文件目錄中須要排除的文件
文件1,文件2,...
目錄1,目錄2,...

要打包進鏡像的文件或目錄都存放在與Dockerfile文件同級。github

Dockerfile指令

更多的dockerfile指令相關信息請參考:https://docs.docker.com/engine/reference/builderweb

FROM docker

Dockerfile文件開篇的第一個非註釋行,用於爲鏡像文件構建過程指定基準鏡像,後續的指令運行於此基準鏡像所提供的運行環境。shell

語法
FROM <repository>[:<tag>]或
FROM <repository>@<digest>

<repository>: 基礎鏡像名稱
<tag>: 基礎鏡像的標籤,省略時默認爲latest
<digest>: 能夠不指定鏡像的名稱而使用鏡像的惟一識別hash碼

LABLE json

爲Dockerfile提供key,value對的源數據信息,是MAINTAINER的替代指令

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

COPY

從Docker主機複製文件至建立的新鏡像文件中

有兩種方式
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

--chow只適用於類linux系統的鏡像
<src>: 要複製的源文件或目錄,支持通配符
<dest>: 目標路徑,即正在建立的image的文件系統路徑,使用絕對路徑,不然是以WORKDIR爲其起始路徑

文件複製準則:
<src> 必須是Dockerfile文件所在目錄中的文件,不能是其父目錄中的文件
若是<src>是目錄,則其內部的文件或子目錄會被遞歸複製,但<src>目錄自身不會被複制
若是指定了多個<src>,或使用了通配符,則<dest>必須是一個目錄,且以「/」結尾
若是<dest>事先不存在,會被遞歸建立

ADD

相似COPY指令,ADD支持使用tar文件和url路徑

兩種語法格式
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

--chow只適用於類linux系統的鏡像

操做準則
1. 同COPY指令
2. 若是<src>爲URL且<dest>不以/結尾,則<src>指定的文件將被下載而且直接被建立爲<dest>;若是<des>以/結尾,則文件名URL指定的文件將被直接下載並保存爲<des>/<filename>
3. 若是<src>是一個本地系統上的壓縮格式的tar文件,它將被展開爲一個目錄,其行爲相似於「tar -x」命令;然而,經過URL獲取到的tar文件將不會自動展開;
4. 若是<src>有多個,或其間接或直接使用了通配符,則<dest>必須爲一個以/結尾的目錄路徑;若是<dest>不以/結尾,其被視爲一個普通文件,<src>的內容將被直接寫入到<des>;

WORKDIR

用於爲Dockerfile中全部的RUN、CMD、ENTRYPOINT、COPY和ADD指定設定的工做目錄。

語法
WORKDIR /path/to/workdir

在Dockerfile文件中,WORKDIR指令能夠出現屢次,其路徑也能夠爲相對路徑,不過,其是相對此前一個WORKDIR指令指定的路徑。另外,WORKDIR也可調用由ENV指令指定的變量。
如:
ENV DIRPATH /path
WORKDIR $DIRPATH/

VOLUME

用於在image中建立一個掛載點目錄,以掛載Docker host上的卷或其它容器上的卷,該卷屬於Docker managed volume類型的卷,即宿主機上要掛載的目錄由dockerd管理。

語法
VOLUME ["/data"]

若是掛載點目錄路徑下此前有文件存在,docker run命令會在卷掛載完成後將此前的全部文件複製到新掛載的卷中。

EXPOSE

用於爲容器打開指定要監聽的端口以實現與外部通訊

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

<protocol> 用於指定傳輸層協議,可爲tcp或udp兩者之一,默認爲tcp協議
可一次指定多個端口,如:
EXPOSE 80/tcp 8080/udp

EXPOSE指令並不會真正把相應的端口暴露到宿主機上,而是說明以該鏡像運行的容器具備該種能力,須要在`docker run`命令時使用`-P`(大寫的字母p)選項就可把EXPOSE指定的端口進行暴露,宿主機使用的隨機端口,也可使用`-p <hostPort>:<containerPort>`來指定宿主機上使用的端口。

ENV

用於爲鏡像定義所須要的環境變量,並可被Dockerfile文件中位於其後的其它指令(如ENV、ADD、COPY等)所調用。

語法
ENV <key> <value>
ENV <key>=<value> ...

第一種格式中,<key>以後的全部內容均會被視做其<value>的組成部分,所以,一次只能設置一個變量;
第二種格式中可一次設置多個變量,每個變量爲一個「<key>=<value>」鍵值對,若是<value>有空格,使用反斜線(\)進行轉義,可經過對<value>加引號進行標識;另外反斜線也可用於續行;
如:
ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy
引用時使用「$myName」或「${myName}」

定義多個變量時,建議使用第二種方式。

RUN

用於指定docker build過程當中運行的程序,其能夠是任何命令

語法
RUN <command>
RUN ["executable", "param1", "param2", ...]

第一種格式中,<command>一般是一個shell命令,且以「/bin/sh -c」來運行它,這意味着此進程在容器中的PID不爲1,不能接收Unix信號,所以,當使用「docker stop <container>」命令中止容器時,此進程接收不到SIGTERM信息;
第二種格式中的參數是一個JSON格式的數組,其中<executable>爲要運行的命令,後面的<paramN>爲傳遞給命令的選項或參數;然而,此種格式指定的命令不會以「/bin/sh -c」來發起,所以常見的shell操做如變量替換以及通配符(?,*等)替換將不會進行;不過,若是要運行的命令依賴此shell特性話,能夠將其替換爲相似下面的格式。
RUN ["/bin/bash", "-c", "<executable>", "param1"]
JSON數組中必定要使用雙引號

CMD

相似RUN指令,CMD指令也可用於運行任何命令或程序,不過兩者的運行時間點不一樣。

RUN指令運行於鏡像文件構建過程當中,而CMD指令運行於基於Dockerfile構建出的新鏡像文件啓動一個容器時;
CMD指令的首要目的在於爲啓動的容器指定默認要運行的程序,且其運行結束後,容器也將終止;不過,CMD指定的命令能夠被「docker run」的命令行選項所覆蓋;

在Dockerfile中能夠存在多個CMD指令,但僅最後一個會生效。

語法
CMD ["executable","param1","param2"] (exec的形式, 首選使用這種)
CMD ["param1","param2"] (爲ENTRYPOINT指代默認參數)
CMD command param1 param2 (同RUN同樣)

ENTRYPOINT

相似CMD指令的功能,用於爲容器指定默認運行程序,從而使得容器像是一個單獨的可執行程序。與CMD不一樣的是,由ENTRYPOINT啓動的程序不會被docker run命令行指定的參數所覆蓋,並且,這些命令行參數會被看成參數傳遞給ENTRYPOINT指定的程序。不過,docker run命令的--entrypoint選項的參數能夠覆蓋ENTRYPOINT指令指定的程序。

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

docker run命令傳入的命令參數會覆蓋CMD指令的內容,而且附加到ENTRYPOINT命令最後作爲其參數使用,若是docker run命令行未傳入命令參數,那ENTRYPOINT會以CMD指令中的內容做爲其默認參數
Dockerfile文件中也能夠存在多個ENTRYPOINT指令,但僅有最後一個會生效

USER

用於指定運行image時的或運行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序時的用戶名或UID

默認狀況下,container的運行身份爲root用戶

語法
USER <user>[:<group>]
USER <UID>[:<GID>]

UDI,GID必須爲鏡像系統中有效用戶的UID,GID,不然,docker run命令將運行失敗。

HEALTHCHECK

用於Docker如何測試容器是否仍在正常工做。

語法
HEALTHCHECK [OPTIONS] CMD command (經過在容器內部運行命令來檢查容器的運行情況)
HEALTHCHECK NONE (禁用從基本映像繼承的任何運行情況檢查)

[OPTIONS]:
--interval=DURATION(默認值:30s) 表示檢查間隔時間
--timeout=DURATION(默認值:30s)  表示檢查超時時間
--start-period=DURATION(默認值:0s) 表示container運行後等待主進程起動程序,開始健康檢查前的等待時長
--retries=N(默認值:3) 當檢查失敗時,須要連續檢查多少次才斷定該服務處於不健康狀態

檢查命令的退出狀態,可能的值爲:
0:成功-容器健康且可使用
1:不健康-容器沒法正常工做
2:保留-請勿使用此退出代碼

事例
HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

SHELL

用於覆蓋RUN,CMD,ENTRYPOINT等指令運行的默認shell。

語法
SHELL ["executable", "parameters"]

linux默認使用["/bin/sh", "-c"],windows默認使用["cmd", "/S", "/C"]

STOPSIGNAL

向容器發送退出的信號

語法
STOPSIGNAL signal

signal爲系統合法的無符號的信號數字,如9

ARG

用於給docker build時傳遞變量

語法
ARG <name>[=<default value>]

在「docker build」時使用「--build-arg <varname>=<value>」傳遞參數
如:
FROM busybox
ARG user
USER ${user:-some_user}
USER $user

在build時使用
$ docker build --build-arg user=what_user ./

ONBUILD

用於在Dockerfile中定義一個觸發器

Dockerfile用於build映像文件,此映像文件亦可做爲base image被另外一個Dockerfile用做FROM指令的參數,並以之構建新的映像文件,在後面的這個Dockerfile中的FROM指令在build過程當中被執行時,將會「觸發」建立其base image的Dockerfile文件中的ONBUILD指令定義的觸發器。

語法
ONBUILD <INSTRUCTION>

儘管任何指令均可註冊爲觸發器指令,但ONBUILD不能自我嵌套,且不會觸發FROM和MAINTAINER指令。
使用包含ONBUILD指令的Dockerfile構建的鏡像應該使用特殊的標籤,如 ruby:2.0-onbuild,來告訴用戶會觸發ONBUILD
在ONBUILD指令中使用ADD或COPY指令應該格外當心,由於新構建過程的上下文在缺乏指定的源文件時會失敗

Dockerfile事例

root@node01:~/img01# pwd
/root/img01
root@node01:~/img01# ls -al
total 20
drwxr-xr-x 2 root root 4096 Jul 20 09:58 .
drwx------ 5 root root 4096 Jul 20 09:58 ..
-rw-r--r-- 1 root root  513 Jul 20 09:32 Dockerfile
-rwxr-xr-x 1 root root  195 Jul 20 09:58 entrypoint.sh
-rw-r--r-- 1 root root   35 Jul 20 09:22 index.html
root@node01:~/img01# cat Dockerfile
FROM nginx:1.14-alpine

# ARG定義的變量能夠在build時經過--build-arg 傳遞參數替換
ARG author="Jack <jack@qq.com>"
LABEL maintainer="${author}"

ENV NGX_DOC_ROOT="/data/web/html/"

ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/

EXPOSE 80/TCP 8080/TCP

# 健康檢查
HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/

# 觸發器
ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt

CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]

root@node01:~/img01# cat entrypoint.sh
#!/bin/sh
cat > /etc/nginx/conf.d/www.conf << EOF
server {
    server_name ${HOSTNAME};
    listen ${IP:-0.0.0.0}:${PORT:-10080};
    root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
}
EOF
exec "$@"

root@node01:~/img01# cat index.html
<h1>This is a nginx test page</h1>

entrypoint.sh文件中末尾的exec "$@"尤其重要,因爲Dockerfile中同時定義了ENTRYPOINT和CMD指令,因此容器運行時執行的程序爲/bin/entrypoint.sh "/usr/sbin/nginx" "-g" "daemon off;" 然後邊的參數都會entrypoint.sh腳本末尾的「$@」收集,即成了exec "/usr/sbin/nginx" "-g" "daemon off;",因使用了exec來執行,因此啓動nginx的進程ID會替代運行/bin/entrypoint.sh腳本時的sh進程的ID。

build生成鏡像

root@node01:~/img01# docker build --build-arg 'author="Tom <tom@163.com>"' -t mynginx:v0.1-1 ./
Sending build context to Docker daemon  4.608kB
Step 1/11 : FROM nginx:1.14-alpine
 ---> 8a2fb25a19f5
Step 2/11 : ARG author="Jack <jack@qq.com>"
 ---> Running in ffe97dc263b2
Removing intermediate container ffe97dc263b2
 ---> 48cccb2b3ac2
Step 3/11 : LABEL maintainer="${author}"
 ---> Running in e31958e5d9eb
Removing intermediate container e31958e5d9eb
 ---> b2c494b442d5
Step 4/11 : ENV NGX_DOC_ROOT="/data/web/html/"
 ---> Running in 1aabf04d1295
Removing intermediate container 1aabf04d1295
 ---> 4fdb24fa67f2
Step 5/11 : ADD index.html ${NGX_DOC_ROOT}
 ---> e334aa452daa
Step 6/11 : ADD entrypoint.sh /bin/
 ---> ad5488c7c47c
Step 7/11 : EXPOSE 80/TCP 8080/TCP
 ---> Running in 773ae947ecd7
Removing intermediate container 773ae947ecd7
 ---> 23c16ae625fe
Step 8/11 : HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/
 ---> Running in 7be92e4c77a7
Removing intermediate container 7be92e4c77a7
 ---> 544097889172
Step 9/11 : ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt
 ---> Running in 3f121c8e23d0
Removing intermediate container 3f121c8e23d0
 ---> 6d80a88f95ee
Step 10/11 : CMD ["/usr/sbin/nginx","-g","daemon off;"]
 ---> Running in b5dbfb4a6c46
Removing intermediate container b5dbfb4a6c46
 ---> 7eaa7434d331
Step 11/11 : ENTRYPOINT ["/bin/entrypoint.sh"]
 ---> Running in f3d78245e25a
Removing intermediate container f3d78245e25a
 ---> 3a250eefa3a7
Successfully built 3a250eefa3a7
Successfully tagged mynginx:v0.1-1

查看鏡像詳細信息

root@node01:~/img01# docker image inspect mynginx:v0.1-1
...
           "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.14.2",
                "NGX_DOC_ROOT=/data/web/html/"
            ],
            "Cmd": [
                "/usr/sbin/nginx",
                "-g",
                "daemon off;"
            ],
            "Healthcheck": {
                "Test": [
                    "CMD-SHELL",
                    "wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/"
                ],
                "StartPeriod": 3000000000
            },
            "Image": "sha256:7eaa7434d331cfc56db82b03ee9472eca1dd4ee3411252fb0155d86debb5fa78",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/bin/entrypoint.sh"
            ],
            "OnBuild": [
                "RUN echo \"Hello Word!\" > /tmp/readme.txt"
            ],
            "Labels": {
                "maintainer": "\"Tom <tom@163.com>\""
            },
  ...

其中Labels中的maintainer是docker build使用--build-arg傳遞的值Tom &lt;tom@163.com&gt;,再也不是Docerfile中定義的值Jack &lt;jack@qq.com&gt;

基於鏡像mynginx:v0.1-1運行一個容器

root@node01:~# docker container run --rm --name nginx01 -e "PORT=8080" mynginx:v0.1-1
127.0.0.1 - - [20/Jul/2020:14:43:44 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-"
127.0.0.1 - - [20/Jul/2020:14:44:14 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-"
......

因配置了HEALTHCHECK,在容器運行後,運行進程運行3秒後每隔30秒都會檢查nginx的主頁。

另起終端鏈接到容器中

root@node01:~# docker container exec -i -t nginx01 /bin/sh
/ # cat /etc/nginx/conf.d/www.conf
server {
    server_name eaf2cfb1eece;
    listen 0.0.0.0:8080;
    root /data/web/html/;
}
/ # netstat -tanl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:8080          127.0.0.1:33032         TIME_WAIT
tcp        0      0 127.0.0.1:8080          127.0.0.1:33030         TIME_WAIT
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 nginx: master process /usr/sbin/nginx -g daemon off;
    8 nginx     0:00 nginx: worker process
   44 root      0:00 /bin/sh
   66 root      0:00 ps
/ # ls /tmp/
/ #

生成了配置文件,監聽8080端口是docker run命令行傳遞的PORT變量的值。

再來測試一下ONBUILD指令,以生成的新鏡像mynginx:v0.1-1爲基礎鏡像再來製做一個鏡像

root@node01:~/img02# pwd
/root/img02
root@node01:~/img02# ls
Dockerfile
root@node01:~/img02# cat Dockerfile
FROM mynginx:v0.1-1
RUN /bin/touch /tmp/1.txt

root@node01:~/img02# docker build -t test:v0.1-1 ./
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM mynginx:v0.1-1
# Executing 1 build trigger
 ---> Using cache
 ---> 8fd69355802f
Step 2/2 : RUN /bin/touch /tmp/1.txt
 ---> Running in 2e123d9c7683
Removing intermediate container 2e123d9c7683
 ---> cce488581509
Successfully built cce488581509
Successfully tagged test:v0.1-1

以此鏡像運行一個容器

root@node01:~# docker container run -i -t --rm --name test01 test:v0.1-1 /bin/sh
/ # ls /tmp/
1.txt       readme.txt
/ # cat /tmp/readme.txt
Hello Word!
/ #

/tmp/readme.txt生成了,說明基礎鏡像裏定義的ONBUILD指令被觸發了。

docker官方在github在還有許多Dockerfile事例,能夠參考:https://github.com/docker-library

Docker Registry

Registry用於保存docker鏡像,包括鏡像的層次結構和元數據。用戶能夠自建Registry,也可使用官方的Docker Hub。

分類:

  1. Sponsor Registry: 第三方的registry,供客戶和Docker社區使用
  2. Mirror Registry: 第三方的registry,只讓客戶使用
  3. Vendor Registry: 由發佈Docker鏡像的供應商提供的Registry
  4. Private Registry: 經過設有防火牆和額外的安全層的私有實體提供的registry

私有registry搭建

官方提供了docker-distribution軟件包來搭建一個Private Registry,也提供了一個名爲registry的鏡像,只須要pull該鏡像,啓動容器就能夠搭建起來,若是要提供http的請求,那客戶端須要修改/etc/docker/daemon.json文件,配置insecure-registries這樣一個key

"insecure-registries": ["192.168.101.41/myreposition"]

此key表示訪問192.168.101.41/myreposition這個Private Registry可使用http協議。

官方提供的registry過於簡陋,vmware對該軟件進行了二次開發,名爲Harbor爲其增長了許多特性,還提供了一個web界面,詳細信息請參考:https://github.com/goharbor/harbor

相關文章
相關標籤/搜索