第四章Docker鏡像

base 鏡像有兩層含義:
    不依賴其他鏡像,從FROM構建
    其他鏡像可以之爲基礎進行擴展

hello-world 是Docker官方提供的一個鏡像,通常用來驗證Docker是否安裝成功,不到2KB
在docker中centos鏡像不到200MB,而官網鏡像好幾個G,因爲
Linux 操作系統由內核空間和用戶空間組成如下圖

rootfs
內核空間是kernel,Linux剛啓動時會加載bootfs文件系統,之後bootfs會被卸載掉;用戶空間的文件系統是rootfs,包含我們熟悉的/dev, /proc, /bin等目錄,對於base鏡像來說,底層直接用Host的kernel,自己只需要提供rootfs就行了;而對於一個精簡的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序庫就可以了;相比其他 Linux 發行版,CentOS的rootfs已經算臃腫的了,alpine還不到10MB;平時安裝的CentOS除了rootfs還會選裝很多軟件、服務、圖形桌面等,需要好幾個GB就不足爲奇了

base鏡像提供的是最小安裝的Linux發行版(內容如下)
FROM cbb
ADD centos7-docker.tar.bz2 /
CMD ["/bin/bash"]
第二行ADD指令添加到鏡像的tar包就是CentOS 7的rootfs;在製作鏡像時,這個tar包會自動解壓到/目錄下,生成/dev、/proc、/bin等目錄

    不同Linux發行版的區別主要就是rootfs;比如Ubuntu 14.04使用upstart管理服務,apt管理軟件包;而CentOS 7使用systemd和yum;這些都是用戶空間上的區別,Linux kernel差別不大,所以Docker可以同時支持多種Linux鏡像,模擬出多種操作系統環境
Debian和BusyBox(一種嵌入式 Linux)上層提供各自的rootfs,底層共用Docker Host的kernel

base鏡像只是在用戶空間與發行版一致,kernel版本與發行版是不同的
所有容器都共用host的kernel,在容器中沒辦法對kernel升級、修改;如果容器對kernel版本有要求(比如應用只能在某個kernel版本下運行)則不建議用容器,這種場景虛擬機可能更合適


某鏡像構建過程


    新鏡像是從base鏡像一層一層疊加生成的;每安裝一個軟件,就在現有鏡像的基礎上增加一層,最大的一個好處就是共享資源;有多個鏡像都從相同的base鏡像構建而來,那麼DockerHost只需在磁盤上保存一份base鏡像;同時內存中也只需加載一份base鏡像,就可以爲所有容器服務了;而且鏡像的每一層都可以被共享,當容器啓動時,一個新的可寫層被加載到鏡像的頂部;這一層通常被稱作"容器層","容器層"之下的都叫"鏡像層";所有對容器的改動,無論添加、刪除、還是修改文件都只會發生在容器層中;只有容器層是可寫的,容器層下面的所有鏡像層都是隻讀的;鏡像層數量可能會很多,所有鏡像層會聯合在一起組成一個統一的文件系統;如果不同層中有一個相同路徑的文件,在容器層中,用戶看到的就是一個疊加之後的文件系統

    1 添加文件
    2 在容器中創建文件時,新文件被添加到容器層中
    3 讀取文件在容器中讀取某個文件時,Docker會從上往下依次在各鏡像層中查找此文件;一旦找到,立即將其複製到容器層,然後打開並讀入內存
    4 修改文件在容器中修改已存在的文件時,Docker會從上往下依次在各鏡像層中查找此文件;一旦找到,立即將其複製到容器層,然後修改
    5 刪除文件在容器中刪除文件時,Docker也是從上往下依次在鏡像層中查找此文件;找到後,會在容器層中記錄下此刪除操作

    只有當需要修改時才複製一份數據,這種特性被稱作Copy-on-Write;可見容器層保存的是鏡像變化的部分,不會對鏡像本身進行任何修改;容器層記錄對鏡像的修改,所有鏡像層都是隻讀的,不會被容器修改,所以鏡像可以被多個容器共享


Docker 提供了兩種構建鏡像的方法
    docker commit 命令
    Dockerfile 構建文件


docker commit命令是創建新鏡像最直觀的方法,其過程包含三個步驟:
    1 運行容器
    2 修改容器
    3 將容器保存爲新的鏡像
然而Docker並不建議用戶通過這種方式構建鏡像,因爲:
    這是一種手工創建鏡像的方式,容易出錯,效率低且可重複性弱;比如要在debian base鏡像中也加入vi,還得重複前面的所有步驟
    使用者並不知道鏡像是如何創建出來的,裏面是否有惡意程序;也就是說無法對鏡像進行審計,存在安全隱患


Dockerfile創建鏡像
docker層不要超過127層,超過報錯,層越多查詢越慢
第一行必須指定基礎鏡像(如果在同一個Dockerfile中創建多個鏡像,可以指定多個FROM)
FROM 鏡像
維護者信息
MAINTAINER 信息
鏡像的操作指令(可以爲多條,但儘量用&&來執行多條命令)
RUN 命令
啓動容器時執行的命令(每個dockerfile只能有一條CMD命令,如果指定多條,只執行最後一條,如果啓動容器時用戶指定了運行命令,則覆蓋CMD指定的命令)
CMD 指令
指定容器暴露的端口(可以指定多個以空格隔開)
EXPOSE 端口
指定一個環境變量,會被後續RUN指令使用
ENV 環境變量
複製本地指定的文件或目錄到容器中,tar文件自動解壓
ADD 源 目標
複製本地指定文件到容器中,與ADD功能一樣,但不會自動解壓文件
COPY 源 目標
容器啓動後執行的命令(每個dockerfile中只能有一個,指定多個買最後一個生效)
ENTRYPOINT 命令
創建一個從本地或其他容器的掛載點(用來存放數據)
VOLUME 掛載點
指定運行容器的用戶名或UID(後續的RUN也會使用指定的用戶)
USER 用戶
爲後續的RUN、CMD、ENTRYPOINT指令配置工作目錄(可以多個)
WORKDIR 路徑
配置當所創建的鏡像爲其他新鏡像的基礎鏡像是所執行的操作命令
ONBUILD ADD\RUN\……
Dockerfile編寫完成後可以通過docker bulid命令來創建鏡像

例如
FROM centos
MAINTAINER CBB
RUN yum -y install httpd
ADD start.sh /usr/local/bin/start.sh
ADD index.html /var/www/html/index.html
echo "/usr/sbin/httpd -DFOREGROUND" > start.sh    (/usr/sbin/httpd -DFOREGROUND 相當於執行了 systemctl start httpd)
chmod a+x start.sh
echo "docker image build test" > index.html
docker build -t 鏡像名:TAG .

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章