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

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

std 存儲空間 應用程序 man period 數據持久化 adb chroot not work

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才會執行。
    所以任何來路不明的鏡像都不應該被運行。

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