1. 程式人生 > >Dokcer入門及其Docker file的製作指令

Dokcer入門及其Docker file的製作指令

Docker借鑑了kvm中應用映象的方式,使得Docker的出現方便了容器的實現和使用,從此docker就佔據了容器的市場。

docker:引擎:建立、執行容器,採用C/S架構
客戶端:docker
服務端:dockerd,dockerd負責接收docker客戶端的請求,客戶端傳送指令,dockerd通過映象倉庫,把映象拖到本地,執行執行容器
容器是基於映象啟動的,如果本地沒有映象,dockerd會去遠端拉取映象。

IT行業的部署異構化程度越來越大。不同的開發平臺,不同的執行平臺,各個服務不同的需求環境。此時我們不必再根據不同的底層執行平臺部署不同的執行環境。但是有了docker之後,只需保證能在docker上執行就可以,而不同的環境只要能執行docker就可以。
docker後來把lxc換成了libcontainer。
docker並沒有解決容器之間的編排工具,google的kubernetes解決了這個問題。
容器提供的映象包含了應用的所有依賴項,因而從開發到測試、生產環境中都有可移植性。
容器技術起源於FreeBSD jail,jail 的目的是讓程序在經過修改的 chroot 環境中建立,而不會脫離和影響整個系統 — 在 chroot 環境中,對檔案系統、網路和使用者的訪問都實現了虛擬化。儘管 Jail 在實施方面存在侷限性,但最終人們找到了脫離這種隔離環境的方法。
映象檔案儲存於Registry倉庫中,映象檔案是分層構建的,所以其檔案系統必需為分層檔案系統(aufs,overlafs)
docker可以通過一個映象檔案啟動多個容器,映象是隻讀的,每一個容器都在映象上層建立了一層內部可寫的專用層,所有讀寫都僅在自己的專用層上實現。
Registry:一個映象倉庫伺服器,可以通過一個套接字接受映象的搜尋和下載請求。映象儲存於Registry後面的儲存空間中,可以有很多倉庫,每一個倉庫只放一種映象,其中的每一個映象都有其對應的tag(標籤)。Registry對每一個倉庫和映象有一個索引,還有使用者的賬戶密碼,對倉庫進行認證和管理。
每一個容器內可以允許多個程序、執行緒,但docker中每一個容器內部只執行一個程序及其子程序,只要次程序停止,則該容器也停止了。容器內程序執行的日誌被送到控制檯,這樣檢視日誌的時候就不需要進入容器內部,只需在控制檯檢視。容器管理被簡化。
Registry:通過一個httpd伺服器提供服務,https為Registry,http為insecure Registyry
Registry可以自定義,也可以使用官方提供的

docker image

採用分層構建機制,最底層為bootfs,其之為rootfs
    bootfs:用於系統引導的檔案系統,包括BootLoader和kernel,容器啟動完成後會被解除安裝以節約記憶體資源;
    rootfs:位於bootfs之上,表現為docker容器的根檔案系統;
        傳統模式中,系統啟動之時,核心掛載rootf時會首先將其掛載為只讀,完整性自檢完成後將其重新掛載為讀寫
        docker中,rootfs由核心掛載為只讀模式,而後通過聯合掛載技術額外掛載一個“可寫”層。
位於下層的映象稱為父映象,最底層的稱為基礎映象
最上層為“可讀寫”層,其下的為“只讀”層
automated builds:docker hub可以根據使用者上傳的指令製作docker映象
webhooks:docker hub可以根據git伺服器上程式碼的變化而自動製作映象

製作映象

製作映象的時候只需要把最上面的可寫層修改後儲存。後續呼叫此映象的時候,分層掛載系統會自動把基礎映象給掛載上去
執行為容器之後因為只有一個程序,所以就不可能通過systemd來管理各個程序了。

docker save  httpd:v0.1 centos7:v0.1 /data/centos-httpd.tar  通過docker save把本機的image儲存至一個tar檔案,通過scp等命令把tar檔案傳輸到目標主機上
docker load -i centos-httpd.tar   根據tar檔案解壓映象到本地

docker container commit -a "zhanghw" -c 'CMD ["/bin/sh","-c","/bin/httpd -h var/www/html -f"]' -p b1 tiny-httpd:v5 
以正在執行的image為基礎,用命令修改映象啟動後的首個程序。

docker 啟動時顯示:bridge-nf-iptables is disabled 解決方法

vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1 
讓docker可以自動設定iptables  

docker network

三種內建虛擬網路:none,bridge,host
四種網路型別
closed container:沒有外網介面,只要lo網絡卡
bridged container:一個lo網絡卡,一個橋接網絡卡
united container:網絡卡由兩塊網絡卡共用,共用同一個TCP/IP 協議棧
open container:直接使用host的物理網絡卡  

docker run --name a1 -it --network none httpd:2.4   
--network none        設定其網路為:closed container 
--network bridge        設定其網路為:bridged container
--network container:a1   設定其網路為:united container
--network host            設定其網路為:open container

docker -p 釋出服務,暴露服務

把一個容器內的網路暴露到外部,讓外部網路可以訪問容器內的服務 
hostIP:hostPort --->  conIP:conPort   PNAT機制實現
在建立容器的時候使用-p選項指定
-p conPort  主機埠隨機指派
-p conPort:hostPort  指定主機埠
-p hostIP::conPort  指定主機IP,::之間為主機埠,不指定為隨機獲取
-p hostIP:hostPort:conPort  指定主機的IP和埠
docker port continer 檢視容器暴露埠的情況

docker network create

docker network create -d bridge --gateway 192.168.1.1 --subnet 192.168.1.0/24  vmnet1  
docker run --network     create container 通過--network指定多個網路時,只有最後一個生效
docker network connect bridge vmnet1  c1 把c1連線至vmnet1
docker network disconnect vmnet1 c1  剝離網路  
docker network rm vmnet1 刪除網路  

docker inspect host 檢視網路定義
docker network inpect -t 

create:根據指定資訊建立網路
docker network create -h  檢視幫助
docker network create -d bridge --gateway 192.168.1.1 --subnet 192.168.1.0/24 vmnet1
docker container run --name a1 --network vmnet1 -it --rm busybox:latest  啟動容器時指定其網路
docker network connect bridge a1   吧container a1 連線到bridge網路上

Data volume

可寫層依存於下一層映象,docker commit 是根據最上層映象的變化來建立映象的,其底層的映象通過聯合掛載技術實現。
Docker映象由多個只讀層疊加而成,啟動容器時,Docker會載入只讀映象層並在映象棧頂部新增一個讀寫層。
寫時複製(cow):如果一個檔案需要修改,則會把在底層中的檔案複製到最上面的可寫層,聯合掛載系統此時會遮蔽最下面只讀層中的檔案,只顯示可寫層中的檔案。
大量業務資料不建議直接儲存在容器映象中:
    1.多層映象讀寫效能差。
    2.容器一刪除,其儲存的檔案也被刪除
    3.磁碟的IO讀寫一直是伺服器整體效能的瓶頸

卷:容器上的一個或多個目錄,此類目錄可繞過聯合檔案系統,與宿主機上的某個目錄關聯。獨立於容器的生命週期實現資料持久化,實現資料和執行程式分離。
    •Volume於容器初始化之時即會建立,由base image提供的卷中的資料會於此期間完成複製
    • Data volumes can be shared and reused among containers
    • Changes to a data volume are made directly
    • Changes to a data volume will not be included when you update an image
    • Data volumes persist even if the container itself is deleted
    •Volume的初衷是獨立於容器的生命週期實現資料持久化,因此刪除容器之時既不會刪除卷,也不會對哪怕未被引用的卷做垃圾回收操作

Docker支援兩種型別的儲存卷
    1.動態:container上指定儲存卷,但至於對應的宿主機中的檔案路徑則是docker-daemon隨機產生的,也稱之為docker管理的卷。
    2.靜態:container上指定、宿主機上對應的卷也由使用者手動指定。

•為docker run命令使用-v選項即可使用Volume
• Docker-managed volume 
    •  docker run -it -name bbox1 –v /data busybox 
    •  docker inspect -f {{.Mounts}} bbox1 
        • 檢視bbox1容器的卷、卷識別符號及掛載的主機目錄
• Bind-mount Volume  
    •  docker run -it -v HOSTDIR:VOLUMEDIR --name bbox2 busybox 
    •  docker inspect -f {{.Mounts}} bbox2

docker volume ls 檢視已存在的volume
docker volume inspect filename  檢視卷的詳細資訊
兩個容器共用一個儲存卷,就可以共享資料
•多個容器的卷使用同一個主機目錄,例如
    • docker run –it --name c1 -v /docker/volumes/v1:/data busybox 
    • docker run –it --name c2 -v /docker/volumes/v1:/data busybox
•複製使用其它容器的卷,為docker run命令使用--volumes-from選項
    • docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox 
    • docker run -it --name bbox2 --volumes-from bbox1 busybox

配置容器化應用

• MariaDB:
    • 命令列選項:使程式執行特性和程式解耦
    • 配置檔案
• 容器化方式執行MariaDB
    • 啟動容器
    • exec -it 
• 配置容器化應用
    • docker run 
        • 通過自定義要執行的命令,並向傳遞命令列引數;
    • 自定義映象,將修改好的配置檔案直接焙進映象。不同環境不同的映象
    • 環境變數,應用程式支援變數配置,容器啟動時通過載入使用者傳入的變數值,實現同一個映象,不同的執行環境。但傳統意義上的應用大部分都不支援次方法
        • docker run -e
    • 儲存卷:把配置檔案在本地編輯好,啟動時載入特定的volume
    但這些配置方式都需要一個docker額外的平臺,通過這個平臺去管理docker,而不是直接通過docker
容器化時代靜態已不是主流,動態才是,動態化是容器時代的一大特徵。

容器和程序

• 容器:一個程序;
    • 程序終止,必將導致容器終止;
        • 傳遞終止訊號:SIGTERM,SIGKILL
    • 程序沒終止:running
        • 健康狀態檢測
        • 通過重啟自愈,映象內部應該有自愈機制

配置中心:專門的鍵值儲存系統,Redis、etcd
    程式通過watch監測,當配置中心的配置檔案發生變化時從配置中心載入配置,reload配置。此時就可以達到以一應百。
    註冊中心,配置中心

Docker file

Dockerfile:Dockerfile is nothing but the source code for building,製作docker映象的指令、原始碼。
    • docker build:根據docker file裡的指令根據指定的某一個基礎映象來製作docker image
    • Dokcerfile必須放在workdir目錄下,build把workdir作為根,所以所有build用到的檔案必須放在workdir下
    • docker build必須基於一個基礎映象製作新的映象,不可能完全製作一個新映象
    • 一個docker file中一條指令就一層映象,所以映象層次越少越好
    • docker build在製作過程中會基於base image啟動一個容器  
    • dockerfile所支援的命令和製作環境都是基於基礎映象的,不是基於宿主機的
    • 指令全大寫,易於區分引數和指令,第一個指令必須是FROM
    • dockerignore file:指定要排除的檔案

dockerfile instruction

    FROM:指定docker build的basic image 
    Syntax 
        • FROM <repository>[:<tag>] 或
        • FROM <resository>@<digest> -->digest:映象的校驗碼,
            • <reposotiry>:指定作為base image的名稱;
            • <tag>:base image的標籤,為可選項,省略時預設為latest;

    MAINTANIER:指定作者資訊(以後會被替代,建議不要用)
    • Syntax 
        • MAINTAINER <authtor's detail>
        • <author's detail>可是任何文字資訊,但約定俗成地使用作者名稱及郵件地址

    LABEL:指定作者資訊
        • Syntax: LABEL <key>=<value> <key>=<value> <key>=<value> ...

    COPY:用於Docker主機複製檔案至建立的新映像檔案
        • Syntax 
            • COPY <src> ... <dest> 或
            • COPY ["<src>",... "<dest>"] • <src>:要複製的原始檔或目錄,支援使用萬用字元
            • <dest>:目標路徑,即正在建立的image的檔案系統路徑;建議為<dest>使用絕對路徑,否則,COPY指定則以WORKDIR為其起始路徑;
        • 注意:在路徑中有空白字元時,通常使用第二種格式
        •檔案複製準則
            • <src>必須是build上下文中的路徑,不能是其父目錄中的檔案
            • 如果<src>是目錄,則其內部檔案或子目錄會被遞迴複製,但<src>目錄自身不會被複制
            • 如果指定了多個<src>,或在<src>中使用了萬用字元,則<dest>必須是一個目錄,且必須以/結尾
            • 如果<dest>事先不存在,它將會被自動建立,這包括其父目錄路徑

    ADD
    •ADD指令類似於COPY指令,ADD支援使用TAR檔案和URL路徑
    • Syntax 
        • ADD <src> ... <dest> 或
        • ADD ["<src>",... "<dest>"]
    •操作準則
        • 同COPY指令
        • 如果<src>為URL且<dest>不以/結尾,則<src>指定的檔案將被下載並直接被建立為<dest>;如果<dest>以/結尾,則檔名URL指定的檔案將被直接下載並儲存為<dest>/<filename>
        • 如果<src>是一個本地系統上的壓縮格式的tar檔案,它將被展開為一個目錄,其行為類似於“tar -x”命令;然而,通過URL獲取到的tar檔案將不會自動展開;
        • 如果<src>有多個,或其間接或直接使用了萬用字元,則<dest>必須是一個以/結尾的目錄路徑;如果<dest>不以/結尾,則其被視作一個普通檔案,<src>的內容將被直接寫入到<dest>;

    WORKDIR
    •用於為Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定設定工作目錄
    • Syntax 
        • WORKDIR <dirpath>
        • 在Dockerfile檔案中,WORKDIR指令可出現多次,其路徑也可以為相對路徑,不過,其是相對此前一個WORKDIR指令指定的路徑
        • 另外,WORKDIR也可呼叫由ENV指定定義的變數
        • 例
            • WORKDIR /var/log 
            • WORKDIR $STATEPATH

    VOLUME
    •用於在image中建立一個掛載點目錄,以掛載Docker host上的卷或其它容器上的卷
    • Syntax 
        • VOLUME <mountpoint> 或
        • VOLUME ["<mountpoint>"] 
    •如果掛載點目錄路徑下此前在檔案存在,docker run命令會在卷掛載完成後將此前的所有檔案複製到新掛載的卷中 

    EXPOSE
    •用於為容器開啟指定要監聽的埠以實現與外部通訊
    • Syntax 
        • EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...] 
            • <protocol>用於指定傳輸層協議,可為tcp或udp二者之一,預設為TCP協議
    • EXPOSE指令可一次指定多個埠,例如
        • EXPOSE 11211/udp 11211/tcp
    docker run --name web1 -it --rm -P tinyweb:v0.1 建立容器的時候,需要通過-P選項來暴露EXPOSE指定的埠

    ENV
    •用於為映象定義所需的環境變數,並可被Dockerfile檔案中位於其後的其它指令如ENV、ADD、COPY等)所呼叫
    •呼叫格式為$variable_name或${variable_name}
    • Syntax 
        • ENV <key> <value> 或
        • ENV <key>=<value> ...
    • 第一種格式中,<key>之後的所有內容均會被視作其<value>的組成部分,因此,一次只能設定一個變數;
    • 第二種格式可用一次設定多個變數,每個變數為一個"<key>=<value>"的鍵值對,如果<value>中包含空格,可以以反斜線(\)進行轉義,也可通過對<value>加引號進行標識;另外,反斜線也可用於續行;
    • 定義多個變數時,建議使用第二種方式,以便在同一層中完成所有功能
    Dockerfile 中指定的變數只能在docker build中使用,docker run指定的變數在docker container中使用。

    RUN
    •用於指定docker build過程中執行的程式,其可以是任何命令
    • Syntax 
        • 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/sh", "-c", "<executable>", "<param1>"]
    •注意:json陣列中,要使用雙引號

    CMD
    •類似於RUN指令,CMD指令也可用於執行任何命令或應用程式,不過,二者的執行時間點不同
        • RUN指令運行於映像檔案構建過程中,而CMD指令運行於基於Dockerfile構建出的新映像檔案啟動一個容器時
        • CMD指令的首要目的在於為啟動的容器指定預設要執行的程式,且其執行結束後,容器也將終止;不過,CMD指定的命令其可以被docker run的命令列選項所覆蓋
        • 在Dockerfile中可以存在多個CMD指令,但僅最後一個會生效
    • Syntax 
        • CMD <command> 或 作為shell的子命令執行
        • CMD [“<executable>”, “<param1>”, “<param2>”] 或
        • CMD ["<param1>","<param2>"]
    •前兩種語法格式的意義同RUN
    •第三種則用於為ENTRYPOINT指令提供預設引數      

    ENTRYPOINT
    •類似CMD指令的功能,用於為容器指定預設執行程式,從而使得容器像是一個單獨的可執行程式
    •與CMD不同的是,由ENTRYPOINT啟動的程式不會被docker run命令列指定的引數所覆蓋,而且,這些命令列引數會被當作引數傳遞給ENTRYPOINT指定指定的程式
        • 不過,docker run命令的--entrypoint選項的引數可覆蓋ENTRYPOINT指令指定的程式
    • Syntax 
        • ENTRYPOINT <command>
        • ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
    • docker run命令傳入的命令引數會覆蓋CMD指令的內容並且附加到ENTRYPOINT命令最後做為其引數使用
    • Dockerfile檔案中也可以存在多個ENTRYPOINT指令,但僅有最後一個會生效
    如果CMD和ENTRYPOINT同時存在,CMD作為ENTRYPOINT的引數執行。
    在docker run時也可以通過docker -e來改變環境變數

    USER
    •用於指定執行image時的或執行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程式時的使用者名稱或UID
    •預設情況下,container的執行身份為root使用者
    • Syntax 
        • USER <UID>|<UserName>
        • 需要注意的是,<UID>可以為任意數字,但實踐中其必須為/etc/passwd中某使用者的有效UID,否則,docker run命令將執行失敗

    HELTHCHECK 
    • 檢測容器的健康狀態
    HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
    HEALTHCHECK NONE (disable any healthcheck inherited from the base image)

    [options]:
        --interval=DURATION (default: 30s)  間隔時長
        --timeout=DURATION (default: 30s)  超時時長
        --start-period=DURATION (default: 0s)  container啟動之後多久開始監測
        --retries=N (default: 3)  重試次數
    退出碼含意
        0: success - the container is healthy and ready for use
        1: unhealthy - the container is not working correctly
        2: reserved - do not use this exit code
    HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1
    如果容器自己沒有健康檢測,則可以在docker run時通過-e 定義  

    SHELL  
    改變系統預設的shell程式,因為基礎映象可能是windows。

    STOPSIGNAL
    指定系統的終止訊號,預設為9

    ARG 
    在build映象的時候,通過 --build-arg 來傳遞引數給ARG定義的變數,而不用事先在Dockerfile中定義好
    Syntax:ARG<name>[=<default value>]

    ONBUILD
    在Dockerfile中定義一個指令,ONBULID後面必須跟一個正常的Dockerfile指令,我們自己build的映象可能被別人作為FROM映象。ONBUILD後面的指令在我們build時不執行,當別人用我們的映象build時ONBUILD才會執行。
    所以任何來路不明的映象都不應該被執行。