DockerFile

通常來講,通用的Docker image無法知足公司的業務需求,須要根據公司的實際需求製做特定image,方法主要有兩個:
1.基於容器建立
2. DockerFile
html

DockerFile Format

1. # 註釋
2. INSTRUCTION 參數 (INSCTRUCTION最好用大寫)
3. 順序執行INSTRUCTION
4. 第一個非註釋行的INSTRUCTION必須以FROM開始,去指定基礎image
5. 必須以一個專用目錄,Dockerfile文件必須存在,首字母必須大寫,引用文件的路徑必須是專用目錄爲開始,也能夠用子目錄來包含全部文件,必定不能是父目錄。也能夠用.dockerignore來指定文件路徑,打包時全部在此文件中指定的文件都不包含,相似黑名單,起文件排除的做用。
6. 製做image的指令是docker build,docker build會隱式啓動一個容器,同時在Dockerfile中能執行的命令必須是基礎image中包含的。
7. 能夠用環境變量Environment variables,Dockerfile中的變量和shell的變量很是相似
    ${variable:-word}:indicates that if variable is set then the result will be that value. If variable is not set then word will be the result.
    ${variable:+word} :indicates that if variable is set then word will be the result, otherwise the result is the empty string.

DockerFile INSTRUCTION

FROM

1:定義
指令是最重的一個且必須爲Dockerfile文件開篇的第一個非註釋行,用於爲映像文件構建過程指定基準鏡像,後續的指令運行於此基準鏡像所提供的運行環境。實踐中,基準鏡像能夠是任何可用鏡像文件,默認狀況下,docker build會在docker主機上查找指定的鏡像文件,在其不存在時,則會從Docker Hub Registry或指定的Registry上拉取所需的鏡像文件。
2:語法
    • FROM <repository>[:<tag>] 或
    • FROM <resository>@<digest>
        • <reposotiry>:指定做爲base image的名稱;
        • <tag>:base image的標籤,爲可選項,省略時默認爲latest;

LABEL

1.:定義
    用於讓Dockerfile製做者提供本人的詳細信息
    Dockerfile並不限制LABEL指令可在出現的位置,但推薦將其放置於FROM指令以後
2:語法
    - LABEL <key>=<value> <key>=<value> <key>=<value>
    - LABEL 是鍵值類型
    - 一個image能夠有多個label
    - 能夠在一行中指定多個label

COPY

1:定義
    用於從Docker主機複製文件至建立的新映像文件
2:語法
    - COPY <src> ... <dest> 或
    - COPY ["<src>",... "<dest>"]
        • <src>:要複製的源文件或目錄,支持使用通配符
        • <dest>:目標路徑,即正在建立的image的文件系統路徑;建議爲<dest>使用絕對路徑,不然,COPY指定則以WORKDIR爲其起始路徑;
3:文件複製準則
    - <src>必須是build上下文中的路徑,不能是其父目錄中的文件
    - 若是<src>是目錄,則其內部文件或子目錄會被遞歸複製,但<src>目錄自身不會被複制
    - 若是指定了多個<src>,或在<src>中使用了通配符,則<dest>必須是一個目錄,且必須以結尾
    - 若是<dest>事先不存在,它將會被自動建立,這包括其父目錄路徑
4:實例
    # vim Dockerfile
        #Description: test image
        FROM busybox
        LABEL maintainer="Evan <liangjindong0@qq.com>" app="httpd"
        COPY index.html /data/web/html/
    # 當前目錄下,建立index.html: echo hello > index.html
    # docker build -t tinyhttpd:v0.1-1 ./
    # docker run --name tinyweb1 --rm tinyhttpd:v0.1-1 cat /data/web/html/index.html
    # cp -r /etc/yum.repos.d/ ./
    # vim Dockerfile
        #Description: test image
        FROM busybox
        LABEL maintainer="Evan <liangjindong0@qq.com>" app="httpd"
        COPY index.html /data/web/html/
        COPY yum.repos.d /etc/yum.repos.d/ (會把yum.repos.d下的全部文件copy到/etc/yum.repos.d/目錄下,必須以/結尾)
    # docker build -t tinyhttpd:v0.1-2 ./
    # docker run --name tinyweb1 --rm tinyhttpd:v0.1-2 ls /etc/yum.repos.d/

ADD

1:定義
    ADD指令相似於COPY指令,ADD支持使用TAR文件和URL路徑
2:語法
    • ADD <src> ... <dest> 或
    • ADD ["<src>",... "<dest>"]
3:操做準則
    - 同COPY指令
    - 若是<src>爲URL且<dest>不以/結尾,則<src>指定的文件將被下載並直接被建立爲<dest>;若是<dest>以/結尾,則文件名URL指定的文件將被直接下載並保存爲<dest>/<filename>
    - 若是<src>是一個本地系統上的壓縮格式的tar文件,它將被展開爲一個目錄,其行爲相似於「tar -x」命令;然而,經過URL獲取到的tar文件將不會自動展開;
    - 若是<src>有多個,或其間接或直接使用了通配符,則<dest>必須是一個以/結尾的目錄路徑;若是<dest>不以/結尾,則其被視做一個普通文件,<src>的內容將被直接寫入到<dest>;
4:實例
    # vim Dockerfile
        ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/
    # docker build -t tinyhttpd:v0.1-3 ./
    # docker run --name tinyweb1 --rm tinyhttpd:v0.1-3 ls /usr/local/src/  (只會上傳,不會解壓)
    # 若是nginx-1.15.2.tar.gz是本地文件,會在目標上解壓

WORKDIR

1:定義
      用於爲Dockerfile中全部的RUN、CMD、ENTRYPOINT、COPY和ADD指定設定工做目錄
2: 語法
WORKDIR <dirpath>
    • 在Dockerfile文件中,WORKDIR指令可出現屢次,其路徑也能夠爲相對路徑,不過,其是相對此前一個WORKDIR指令指定的路徑
    • 另外,WORKDIR也可調用由ENV指定定義的變量
例如
    • WORKDIR /var/log
    • WORKDIR $STATEPATH

VOLUME

1: 定義
    用於在image中建立一個掛載點目錄,以掛載Docker host上的卷或其它容器上的卷
2:語法
    • VOLUME <mountpoint> 或
    • VOLUME ["<mountpoint>"]
    若是掛載點目錄路徑下此前在文件存在,docker run命令會在卷掛載完成後將此前的全部文件複製到新掛載的卷中
3:實例
    # vim Dockerfile
        VOLUME /data/mysql/
        此volume是docker自動管理的類型
    # docker build -t tinyhttpd:v0.1-4 ./
    # docker run --name tinyweb1 --rm tinyhttpd:v0.1-4 sleep 60
    # docker inspect tinyweb1

EXPOSE

1:定義
    用於爲容器打開指定要監聽的端口以實現與外部通訊
2:語法
    EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...]
        • <protocol>用於指定傳輸層協議,可爲tcp或udp兩者之一,默認爲TCP協議
        • EXPOSE指令可一次指定多個端口,例如
            EXPOSE 11211/udp 11211/tcp (只是能夠暴露,須要在docker run -P纔會暴露在Dockerfile中定義的EXPOSE端口)
3:實例
# vim Dockerfile
    EXPOSE 80/tcp
# docker build -t tinyhttpd:v0.1-5 ./
# docker run --name tinyweb1 --rm tinyhttpd:v0.1-5 /bin/httpd -h /data/web/html
    只能夠訪問Docker IP的網頁
# docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-5 /bin/httpd -h /data/web/html
# docker port tinyweb1
    能夠訪問Docker宿主機IP的網頁

ENV

1:定義
    用於爲鏡像定義所需的環境變量,並可被Dockerfile文件中位於其後的其它指令(如ENV、ADD、COPY等)所調用,調用格式爲$variable_name或${variable_name}
2:語法
    • ENV <key> <value> 或
    • ENV <key>=<value> ...
    • 第一種格式中,<key>以後的全部內容均會被視做其<value>的組成部分,所以,一次只能設置一個變量
    • 第二種格式可用一次設置多個變量,每一個變量爲一個"<key>=<value>"的鍵值對,若是<value>中包含空格,能夠以反斜線(\)進行轉義,也可經過對<value>加引號進行標識;另外,反斜線也可用於續行
    • 定義多個變量時,建議使用第二種方式,以便在同一層中完成全部功能
3:實例
    # vim Dockerfile
        ENV DOC_ROOT=/data/web/html/ \
                WEB_SERVER_PACKAGE="nginx-1.15.2"
        COPY index.html ${DOC_ROOT:-/data/web/html/}
        ADD ${WEB_SERVER_PACKAGE}.tar.gz ./src/
    # image構建和啓動是兩個不一樣的過程,兩個不一樣的階段,Dockerfile中定義的EVN在啓動時會注入到容器中
    # docker build -t tinyhttpd:v0.1-6 ./
    # docker run --name tinyweb1 --rm -e WEB_SERVER_PACKAGE="nginx-1.15.1" tinyhttpd:v0.1-6 printenv

RUN

1:定義
    用於指定docker build過程當中運行的程序,其能夠是任何命令
2:語法
    • 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操做如變量替換以及通配符(?,*等)替換將不會進行;不過,若是要運行的命令依賴於此shell特性的話,能夠將其替換爲相似下面的格式。
            RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
    • 注意:JSON數組中,要使用雙引號
3:實例
# vim Dockerfile
    RUN    yum makecache &&\
                yum install nginx -y && \
                yum clean all
#

CMD

1:定義
    相似於RUN指令,CMD指令也可用於運行任何命令或應用程序,不過,兩者的運行時間點不一樣
        • RUN指令運行於映像文件構建過程當中,而CMD指令運行於基於Dockerfile構建出的新映像文件啓動一個容器時
        • CMD指令的首要目的在於爲啓動的容器指定默認要運行的程序,且其運行結束後,容器也將終止;不過,CMD指定的命令其能夠被docker run的命令行選項所覆蓋
        • 在Dockerfile中能夠存在多個CMD指令,但僅最後一個會生效
2:語法
    • CMD <command> 或
    • CMD [「<executable>」, 「<param1>」, 「<param2>」] 或
    • CMD ["<param1>","<param2>"]
    • 前兩種語法格式的意義同RUN
    • 第三種則用於爲ENTRYPOINT指令提供默認參數
3:實例
    - 第一種格式:以shell啓動

    # vim Dockerfile
        FROM busybox
        LABEL maintainer="Evan <liangjindong0@qq.com>" app="httpd"

        ENV WEB_DOC_ROOT="/data/web/html/"
        RUN mkdir -p ${WEB_DOC_ROOT} && \
        echo '<h1>Busybox httpd server.</h1>' > ${WEB_DOC_ROOT}/index.html

        CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
    # docker build -t tinyhttpd:v0.1-7 ./
    # docker run --name tinyweb1 --rm -it tinyhttpd:v0.1-7 ()
    # docker ps (啓動爲/bin/sh的子進程)
         "/bin/sh -c '/bin/ht…" 
    #  docker exec -it tinyweb1 /bin/sh (shell中exec COMMAND,exec取代shell爲1的進程,shell退出)
         / # ps
            PID   USER     TIME  COMMAND
            1 root      0:00 /bin/httpd -f -h /data/web/html/ ()
            6 root      0:00 /bin/sh
           11 root      0:00 ps
    - 第二種格式:不是以shell啓動,能夠指定用shell
    # vim Dockerfile
        CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
    # docker build -t tinyhttpd:v0.1-8 ./
    # docker run --name tinyweb1 --rm -it tinyhttpd:v0.1-8 
        httpd: can't change directory to ' ${WEB_DOC_ROOT}': No such file or directory (不是以shell啓動,因此沒法識別${WEB_DOC_ROOT}'變量)
    指定用shell啓動
    # vim Dockerfile
        CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
    # docker build -t tinyhttpd:v0.1-9 ./
    
    - 第三種格式: 帶ENTRYPOINT
       # vim Dockerfile
        CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
        ENTRYPOINT /bin/sh
        (CMD的命令會做爲ENTRYPOINT的參數傳遞)
        #  docker run --name tinyweb1 --rm -it tinyhttpd:v1.4
        # docker inspect tinyweb1
            "Cmd": [
            "/bin/httpd",
            "-f",
            "-h ${WEB_DOC_ROOT}"
            ],
        "ArgsEscaped": true,
        "Image": "tinyhttpd:v1.4",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": [
            "/bin/sh",
            "-c",
            "/bin/sh"
            ],
        解釋:用/bin/sh -c運行/bin/sh

        ENTRYPOINT ["/bin/sh","-c"]
         "Cmd": [
            "/bin/httpd",
            "-f",
            "-h ${WEB_DOC_ROOT}"
        ],
        "ArgsEscaped": true,
        "Image": "sha256:ba8350e53c013997d443f1f5ee68083a906b76a35e771fe89cf9426947ebc015",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": [
            "/bin/sh",
            "-c"
        ],

    # docker run --name tinyweb1 --rm -it tinyhttpd:v1.6 "ls /data" (能執行,CMD做爲默認參數時傳給ENTRYPOINT,可是docker run運行時傳的參數會傳給ENTRYPOINT,ls命令做爲shell的子進程運行,此時docker run傳的參數覆蓋的是CMD參數)

注意:RUN基於基礎image中的命令;RUN能夠運行屢次,一樣屬性的命令用一行描述
            docker run中CMD只能有一個
            運行的時間點不一樣,運行的行爲不一樣

ENTRYPOINT

1:定義
    • 相似CMD指令的功能,用於爲容器指定默認運行程序,從而使得容器像是一個單獨的可執行程序
    • 與CMD不一樣的是,由ENTRYPOINT啓動的程序不會被docker run命令行指定的參數所覆蓋,並且,這些命令行參數會被看成參數傳遞給ENTRYPOINT指定指定的程序
    • 另外,docker run命令的--entrypoint選項的參數可覆蓋ENTRYPOINT指令指定的程序
2:語法
        • ENTRYPOINT <command>
        • ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
        • docker run命令傳入的命令參數會覆蓋CMD指令的內容而且附加到ENTRYPOINT命令最後作爲其參數使用
        • Dockerfile文件中也能夠存在多個ENTRYPOINT指令,但僅有最後一個會生效
3:實例
    # vim DockerfileENTRYPOINT /bin/httpd -f -h ${WEB_DOC_ROOT}
    # docker run --name tinyweb1 --rm -it tinyhttpd:v1.3
    # docker run --name tinyweb1 --rm -it tinyhttpd:v1.3 ls /data/web/html (ls /data/web/html不會覆蓋ENTRYPOINT定義的)
    # docker run --name tinyweb1 --rm -it --entrypoint "ls /data/web/html" tinyhttpd:v1.3 (能夠用--entrypoint來強制覆蓋)
4:應用場景
   多數狀況下,ENTRYPOINT是用來指定一個shell,做爲用來啓動別的進程的父進程,docker run的命令行參數會做爲它的子進程來運行,達到靈活傳遞參數而且被shell解析
    空器接授變量須要經過環境變量
5:實例(Nginx接授變量生成配置文件,並且變量能夠在啓動容器時傳遞)
    # vim entrypoint.sh
        #!/bin/sh
        #
        cat > /etc/nginx/conf.d/www.conf << EOF
        server {
        server_name ${HOSTNAME};
        listen ${IP:-0.0.0.0}:${PORT:-80};
        root ${NGX_DOC_ROOT:-/user/share/nginx/html};
        }
        EOF
        exec "$@"
    # chmod +x entrypoint.sh
    # vim Dockerfile
        FROM nginx:1.14-alpine
        LABEL maintainer="Evan <liangjindong0@qq.com"
        ENV NGX_DOC_ROOT="/data/web/html/"
        ADD entrypoint.sh /bin/
        CMD ["/usr/sbin/nginx","-g","daemon off;"] (前臺運行Nginx)
        ENTRYPOINT  ["/bin/entrypoint.sh"] (首先用此腳本會以shell運行初始化一個配置文件,而後運行CMD,頂替entrypoint.sh,即Nginx進行運行後,shell腳本退出,Nginx成爲容器中的惟一進程,並且是主進程)
    # docker run --name tinyweb1 --rm -P -e "PORT=8080" -h Apache tinyhttpd:v1.8
    # docker run --name tinyweb1 --rm -p 80:80  -h Apache tinyhttpd:v1.8
    # docker exec -it tinyweb1 /bin/sh
    # / # netstat -tnl (port參數被docker run啓動時指定參數8080成功)
        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
    # / # ps
        PID   USER     TIME   COMMAND
        1 root       0:00 nginx: master process /usr/sbin/nginx -g daemon off; (Nginx能以PID爲1的主進程運行,是由於entrypoint.sh腳本中的exec "$@")
        8 nginx      0:00 nginx: worker process
        9 root       0:00 /bin/sh
        總結:ENTRYPOINT腳原本定義參數,在建立image時傳入值,在docker run時接收參數來啓動容器
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息