docker2-映象原理及建立新的映象

tensor_zhang發表於2021-06-27

1,映象是什麼

映象是一種輕量級、可執行的獨立軟體包,用來打包軟體執行環境和基於執行環境開發的軟體,它包含執行某個軟體所需的所有內容,包括程式碼、執行時、庫、環境變數和配置檔案

在docker中所有應用直接打包為映象,下載下來就可以直接執行。

2,如何獲取映象

  • 從遠端倉庫下載
  • 拷貝
  • 自己製作映象DockerFile

3,Docker映象基本概念

3.1,UnionFS(聯合檔案系統)(Docker映象分層)

一種分層、輕量級並且高效能的檔案系統,支援對檔案系統的修改作為提交併一層層疊加,同時可以將不同目錄掛載到同一虛擬檔案系統下(unite several directories into a single virtual filesystem)。Union檔案系統是Docker映象的基礎,映象可以通過分層進行繼承,基於基礎映象(無父映象),可以製作各種具體的應用映象。

特性:一次同時載入多個檔案系統,但從外面看來,只能看到一個檔案系統;聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄。

docker分層系統0 docker分層系統1 docker分層系統2

3.2,Docker映象底層

在Docker映象的最底層是bootfs(boot file system,主要包含bootloader和kernel,bootloader主要引導載入kernel,linux剛啟動時就會載入bootfs檔案系統),在bootfs載入完成之後整個核心就在記憶體中了,記憶體的使用權已由bootfs轉交給核心,此時系統會解除安裝bootfs。

roofts(root file system/Base Image),在bootfs之上,包含的就是典型linux系統中的/dev, /proc, /bin, /etc等標準檔案和目錄。rootfs就是各種不同的作業系統的發性版,比如ubuntu、centos等。

3.3,為什麼Docker映象可以很小?

對於一個精簡的docker,rootfs可以很小,只需要包含最基本的命令、工具和程式庫即可。底層會直接使用宿主機(host)的kernel,映象只需要提供rootfs,因此可以很小。由此也可看出,不同的linux發行版,bootfs基本是一致的,只是rootfs會有差別,不同的發行版可以公用bootfs。

4,Docker映象啟動過程

Docker映象都是隻讀的,當容器啟動時,一個新的可讀寫層被載入到映象的頂層。新增層就是所謂的容器層,容器層之下的都是映象層。所有的更改都在容器層中,映象層不發生改變。

1、檢測本地是否存在指定的映象,不存在就從公有倉庫下載

2、利用映象建立並啟動一個容器

3、分配一個檔案系統,並在只讀的映象層外面掛載一層可讀寫層

4、從宿主主機配置的網橋介面中橋接一個虛擬介面到容器中去

5、從地址池配置一個IP地址給容器

6、執行使用者指定的應用程式

7、執行完畢後終止容器

5,提交容器建立新的映象

容器內做了修改後想要儲存為新的映象:

docker commit -m='提交的容器資訊' -a='作者' 容器id 目標映象名:tag		#git本地類似

6,Dockerfile建立新的映象

Dockerfile就是用來構建docker映象的構建檔案,是一種命令指令碼,通過此指令碼可以生成映象。

映象是分層的,Dockerfile中的每一個命令就是一層。

docker build -f ~(dockerfile) -t ~(image名稱):tag .
'''一個例子'''

'''=======================建立dockerfile檔案(名字也可隨意取)並輸入以下內容======================='''
from centos

CMD echo '-----end-----'
CMD /bin/bash

'''=======================docker build構建映象======================='''
docker build -f dockerfile -t zhang/centos:01 .

一個問題

'''=======================建立dockerfile檔案(名字也可隨意取)並輸入以下內容======================='''
from centos

VOLUME ['volume10', 'volume11']

CMD echo '-----end-----'
CMD /bin/bash

生成後run的時候會報錯
[root@VM-0-11-centos docker-test-volum]# docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination:[volume10, Type:bind Source:/var/lib/docker/volumes/7e8b5576dee6ad0d84ab31848f12b859b6ed4e05408492477308479dcbea20c4/_data Options:[rbind]}: mount destination [volume10, not absolute: unknown.

=============================================解答===========================================
=====第一次嘗試=====
通過dockerfile的 VOLUME 指令可以在映象中建立掛載點,這樣只要通過該映象建立的容器都有了掛載點。
還有一個區別是,通過 VOLUME 指令建立的掛載點,無法指定主機上對應的目錄,是自動生成的。

VOLUME ['volume10', 'volume11']	這一句的目的是在生成映象的同時,在映象中建立'volume01', 'volume02'並自動匿名掛載,這裡說不是絕對路徑不對,但是改為VOLUME ['/volume10', '/volume11']還是報錯
[root@VM-0-11-centos docker-test-volum]# docker run -it zhang/centos
docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination:[/volume10, Type:bind Source:/var/lib/docker/volumes/fa8716e8e78b1a9af0cfd75ac9476b6fcbecf7178b34d29d390c6ab29f19cfaf/_data Options:[rbind]}: mount destination [/volume10, not absolute: unknown.

7,dockerfile詳解

7.1,使用dockerfile建立映象的步驟:

  1. 編寫一個dockerfile檔案(構建檔案,定義了一切的步驟,原始碼)
  2. docker build構建成為一個映象(通過dockerfile構建生成的映象,最終釋出和執行的產品)
  3. docker run執行映象(容器,映象執行起來提供服務)
  4. docker push釋出映象(釋出到DockerHub或者其他第三方映象倉庫)

7.2,一個dockerhub官方的例子,點到版本號上會發現跳轉到github

docker分層系統2 docker分層系統2

很多官方映象都是基礎包,很多功能都沒有,通常需要搭建自己的映象。

7.3,dockerfile的一些基本概念

  • Dockerfile由多條指令組成,每條指令在編譯映象時完成某些功能

  • 每條指令由指令+引數組成,以逗號分隔

  • 指令使用大寫字母,引數使用小寫字母,#表示註釋

  • 指令從上到下執行,每一條指令都會建立提交一個新的映象層(bootfs, rootfs(基礎映象centos/tomcat), image(jdk/tomcat...), image),在run的時候在映象的頂層增加可寫容器層(container)形成容器進行執行

    docker分層系統2

7.4,dockerfile常用指令

FROM										#基礎映象指令,一切由此開始構建(BASE IMAGE,如:centos)
MAINTAINER									#映象是誰寫的,姓名+郵箱
RUN											#映象構建時需要執行的命令
ADD											#新增內容(IMAGE,如:emacs,apache,tomcat等)
COPY										#類似ADD,將檔案拷貝到映象中
WORKDIR										#映象的工作目錄(進入映象所在的目錄,預設是根目錄/)
VOLUME										#掛載的目錄
EXPOSE										#指定暴露埠
CMD											#指定容器啟動時要執行的命令(如:CMD echo),只有最後一個生效
ENTRYPOINT									#指定容器啟動時要執行的命令,可追加命令(追加命令是直接追加到其後的)
ONBUILD										#當構建一個被繼承 dockerfile,會執行ONBUILD,觸發指令
ENV											#構建時設定環境變數(構建一個鍵值對,常量)

7.5,一些例子(可以如7.2所述,看看別人是怎麼寫的)

DockerHub中99%的映象都是從FROM scratch開始的,scratch是一個空映象,只能用於構建其他映象。

'''例子一,為官方的centos映象加入vim以及ifconfig命令'''
===========dockerfile檔案
FROM centos
MAINTAINER zhang<15009202810@163.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo '----end----'
CMD /bin/bash

===========生成映象
docker build -f mydockerfile-centos -t zhang:centos:02 .

===========生成的映象
zhang/centos          02        f86b612c2f9e   4 hours ago      295MB

===========執行
root@VM-0-11-centos dockerfile]# docker run -it f86b612c2f9e
[root@03a66e354d06 local]# pwd
/usr/local
[root@03a66e354d06 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.6  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:06  txqueuelen 0  (Ethernet)
        RX packets 7  bytes 586 (586.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@03a66e354d06 local]# vim

c;?;?
~                                                                                                         ~                                                                               
'''例子二,CMD和ENTRYPOINT的區別'''
'''CMD V1'''
===========dockerfile檔案
FROM centos
CMD ["ls","-a"]

===========生成映象
docker build -f dockerfile-cmd-test -t cmd-test:01 .

===========生成的映象
REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
cmd-test              01        09620dfdb9ab   3 seconds ago   209MB

===========執行
docker run 09620dfdb9ab						#可以執行
docker run 09620dfdb9ab -l					#報錯(不追加,相當於執行-l)
docker run 09620dfdb9ab ls -l				#可以執行(CMD最後一個生效,相當於執行ls -l)

'''ENTRYPOINT V1'''
===========dockerfile檔案
FROM centos
ENTRYPOINT ["ls","-a"]

===========生成映象
docker build -f dockerfile-entropy-test -t entrypoint-test .

===========生成的映象
REPOSITORY            TAG       IMAGE ID       CREATED              SIZE
entrypoint-test       latest    51d3b39d0e6a   About a minute ago   209MB

===========執行
docker run 09620dfdb9ab						#可以執行
docker run 09620dfdb9ab -l					#可以執行(追加,相當於執行ls -a -l)
docker run 09620dfdb9ab ls -l				#報錯(相當於執行ls -a ls -l)
'''例子三,製作tomcat映象'''
需要準備:tomcat壓縮包,jdk壓縮包

7.6,dockerfile命令彙總,詳解,分類及建議

參看:

Docker實戰-編寫Dockerfile

docker之Dockerfile實踐

必看的dockerfile禁忌與建議!

Dockerfile構建映象

命令詳解
===========================================================================================================
指令:FROM 
功能描述:設定基礎映象,一切由此開始構建
語法:FROM < image>[:< tag> | @< digest>] 
提示:映象都是從一個基礎映象(作業系統或其他映象)生成,可以在一個Dockerfile中新增多條FROM指令
注意:如果忽略tag選項,會使用latest映象
===========================================================================================================
指令:MAINTAINER 
功能描述:設定映象作者 
語法:MAINTAINER < name>
============================================================================================================
指令:RUN 
功能描述: 
語法:RUN < command> 
          RUN [“executable”,”param1”,”param2”] 
提示:RUN指令會生成容器,在容器中執行指令碼,容器使用當前映象,指令碼指令完成後,Docker Daemon會將該容器提交為一箇中間映象,供後面的指令使用 
補充:RUN指令第一種方式為shell方式,使用/bin/sh -c < command>執行指令碼,可以在其中使用\將指令碼分為多行 
          RUN指令第二種方式為exec方式,映象中沒有/bin/sh或者要使用其他shell時使用該方式,其不會呼叫shell命令 
例子:RUN source $HOME/.bashrc;\ 
          echo $HOME

          RUN [“/bin/bash”,”-c”,”echo hello”]

          RUN [“sh”,”-c”,”echo”,”$HOME”] 使用第二種方式呼叫shell讀取環境變數
============================================================================================================
指令:CMD 
功能描述:設定容器的啟動命令 
語法:CMD [“executable”,”param1”,”param2”] 
          CMD [“param1”,”param2”] 
          CMD < command> 
提示:CMD第一種、第三種方式和RUN類似,第二種方式為ENTRYPOINT引數方式,為entrypoint提供引數列表 
注意:Dockerfile中只能有一條CMD命令,如果寫了多條則最後一條生效
============================================================================================================
指令:LABEL 
功能描述:設定映象的標籤 
延伸:映象標籤可以通過docker inspect檢視 
格式:LABEL < key>=< value> < key>=< value> … 
提示:不同標籤之間通過空格隔開 
注意:每條指令都會生成一個映象層,Docker中映象最多隻能有127層,如果超出Docker Daemon就會報錯,如LABEL ..=.. <假裝這裡有個換行> LABEL ..=..合在一起用空格分隔就可以減少映象層數量,同樣,可以使用連線符\將指令碼分為多行 
          映象會繼承基礎映象中的標籤,如果存在同名標籤則會覆蓋
============================================================================================================
指令:EXPOSE 
功能描述:設定映象暴露埠,記錄容器啟動時監聽哪些埠 
語法:EXPOSE < port> < port> … 
延伸:映象暴露埠可以通過docker inspect檢視 
提示:容器啟動時,Docker Daemon會掃描映象中暴露的埠,如果加入-P引數,Docker Daemon會把映象中所有暴露埠匯出,併為每個暴露埠分配一個隨機的主機埠(暴露埠是容器監聽埠,主機埠為外部訪問容器的埠) 
注意:EXPOSE只設定暴露埠並不匯出埠,只有啟動容器時使用-P/-p才匯出埠,這個時候才能通過外部訪問容器提供的服務
============================================================================================================
指令:ENV 
功能描述:設定映象中的環境變數 
語法:ENV < key>=< value>…|< key> < value> 
注意:環境變數在整個編譯週期都有效,第一種方式可設定多個環境變數,第二種方式只設定一個環境變數 
提示:通過${變數名}或者 $變數名使用變數,使用方式${變數名}時可以用${變數名:-default} ${變數名:+cover}設定預設值或者覆蓋值 
          ENV設定的變數值在整個編譯過程中總是保持不變的
============================================================================================================
指令:ADD 
功能描述:複製檔案到映象中 
語法:ADD < src>… < dest>|[“< src>”,… “< dest>”] 
注意:當路徑中有空格時,需要使用第二種方式 
          當src為檔案或目錄時,Docker Daemon會從編譯目錄尋找這些檔案或目錄,而dest為映象中的絕對路徑或者相對於WORKDIR的路徑 
提示:src為目錄時,複製目錄中所有內容,包括檔案系統的後設資料,但不包括目錄本身 
          src為壓縮檔案,並且壓縮方式為gzip,bzip2或xz時,指令會將其解壓為目錄 
          如果src為檔案,則複製檔案和後設資料 
          如果dest不存在,指令會自動建立dest和缺失的上級目錄
============================================================================================================
指令:COPY 
功能描述:複製檔案到映象中 
語法:COPY < src>… < dest>|[“< src>”,… “< dest>”] 
提示:指令邏輯和ADD十分相似,同樣Docker Daemon會從編譯目錄尋找檔案或目錄,dest為映象中的絕對路徑或者相對於WORKDIR的路徑
============================================================================================================
指令:ENTRYPOINT 
功能描述:設定容器的入口程式 
語法:ENTRYPOINT [“executable”,”param1”,”param2”] 
          ENTRYPOINT command param1 param2(shell方式) 
提示:入口程式是容器啟動時執行的程式,docker run中最後的命令將作為引數傳遞給入口程式 
          入口程式有兩種格式:exec、shell,其中shell使用/bin/sh -c執行入口程式,此時入口程式不能接收訊號量 
          當Dockerfile有多條ENTRYPOINT時只有最後的ENTRYPOINT指令生效 
          如果使用指令碼作為入口程式,需要保證指令碼的最後一個程式能夠接收訊號量,可以在指令碼最後使用exec或gosu啟動傳入指令碼的命令 
注意:通過shell方式啟動入口程式時,會忽略CMD指令和docker run中的引數 
          為了保證容器能夠接受docker stop傳送的訊號量,需要通過exec啟動程式;如果沒有加入exec命令,則在啟動容器時容器會出現兩個程式,並且使用docker stop命令容器無法正常退出(無法接受SIGTERM訊號),超時後docker stop傳送SIGKILL,強制停止容器 
例子:FROM ubuntu <換行> ENTRYPOINT exec top -b
============================================================================================================
指令:VOLUME 
功能描述:設定容器的掛載點 
語法:VOLUME [“/data”] 
          VOLUME /data1 /data2 
提示:啟動容器時,Docker Daemon會新建掛載點,並用映象中的資料初始化掛載點,可以將主機目錄或資料卷容器掛載到這些掛載點
============================================================================================================
指令:USER 
功能描述:設定RUN CMD ENTRYPOINT的使用者名稱或UID 
語法:USER < name>
============================================================================================================
指令:WORKDIR 
功能描述:設定RUN CMD ENTRYPOINT ADD COPY指令的工作目錄 
語法:WORKDIR < Path> 
提示:如果工作目錄不存在,則Docker Daemon會自動建立 
          Dockerfile中多個地方都可以呼叫WORKDIR,如果後面跟的是相對位置,則會跟在上條WORKDIR指定路徑後(如WORKDIR /A   WORKDIR B   WORKDIR C,最終路徑為/A/B/C)
============================================================================================================
指令:ARG 
功能描述:設定編譯變數 
語法:ARG < name>[=< defaultValue>] 
注意:ARG從定義它的地方開始生效而不是呼叫的地方,在ARG之前呼叫編譯變數總為空,在編譯映象時,可以通過docker build –build-arg < var>=< value>設定變數,如果var沒有通過ARG定義則Daemon會報錯 
          可以使用ENV或ARG設定RUN使用的變數,如果同名則ENV定義的值會覆蓋ARG定義的值,與ENV不同,ARG的變數值在編譯過程中是可變的,會對比使用編譯快取造成影響(ARG值不同則編譯過程也不同) 
例子:ARG CONT_IMAG_VER <換行> RUN echo $CONT_IMG_VER 
          ARG CONT_IMAG_VER <換行> RUN echo hello 
          當編譯時給ARG變數賦值hello,則兩個Dockerfile可以使用相同的中間映象,如果不為hello,則不能使用同一個中間映象
============================================================================================================
指令:ONBUILD 
功能描述:設定自徑想的編譯鉤子指令 
語法:ONBUILD [INSTRUCTION] 
提示:從該映象生成子映象,在子映象的編譯過程中,首先會執行父映象中的ONBUILD指令,所有編譯指令都可以成為鉤子指令

ONBUILD流程
1,編譯時,讀取所有ONBUILD映象並記錄下來,在當前編譯過程中不執行指令
2,生成映象時將所有ONBUILD指令記錄在映象的配置檔案OnBuild關鍵字中
3,子映象在執行FROM指令時會讀取基礎映象中的ONBUILD指令並順序執行,如果執行過程中失敗則編譯中斷;當所有ONBUILD執行成功後開始執行子映象中的指令
4,子映象不會繼承基礎映象中的ONBUILD指令
============================================================================================================
指令:STOPSIGNAL 
功能描述:設定容器退出時,Docker Daemon向容器傳送的訊號量 
語法:STOPSIGNAL signal 
提示:訊號量可以是數字或者訊號量的名字,如9或者SIGKILL,訊號量的數字說明在Linux系統管理(https://blog.csdn.net/qq_29999343/article/details/78166574)中有簡單介紹

相關文章