1,鏡像是什么
鏡像是一種輕量級、可執行的獨立軟件包,用來打包軟件運行環境和基於運行環境開發的軟件,它包含運行某個軟件所需的所有內容,包括代碼、運行時、庫、環境變量和配置文件
在docker中所有應用直接打包為鏡像,下載下來就可以直接運行。
2,如何獲取鏡像
- 從遠程倉庫下載
- 拷貝
- 自己制作鏡像DockerFile
3,Docker鏡像基本概念
3.1,UnionFS(聯合文件系統)(Docker鏡像分層)
一種分層、輕量級並且高性能的文件系統,支持對文件系統的修改作為提交並一層層疊加,同時可以將不同目錄掛載到同一虛擬文件系統下(unite several directories into a single virtual filesystem)。Union文件系統是Docker鏡像的基礎,鏡像可以通過分層進行繼承,基於基礎鏡像(無父鏡像),可以制作各種具體的應用鏡像。
特性:一次同時加載多個文件系統,但從外面看來,只能看到一個文件系統;聯合加載會把各層文件系統疊加起來,這樣最終的文件系統會包含所有底層的文件和目錄。
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創建鏡像的步驟:
- 編寫一個dockerfile文件(構建文件,定義了一切的步驟,源代碼)
- docker build構建成為一個鏡像(通過dockerfile構建生成的鏡像,最終發布和運行的產品)
- docker run運行鏡像(容器,鏡像運行起來提供服務)
- docker push發布鏡像(發布到DockerHub或者其他第三方鏡像倉庫)
7.2,一個dockerhub官方的例子,點到版本號上會發現跳轉到github
很多官方鏡像都是基礎包,很多功能都沒有,通常需要搭建自己的鏡像。
7.3,dockerfile的一些基本概念
-
Dockerfile由多條指令組成,每條指令在編譯鏡像時完成某些功能
-
每條指令由指令+參數組成,以逗號分隔
-
指令使用大寫字母,參數使用小寫字母,#表示注釋
-
指令從上到下執行,每一條指令都會創建提交一個新的鏡像層(bootfs, rootfs(基礎鏡像centos/tomcat), image(jdk/tomcat...), image),在run的時候在鏡像的頂層增加可寫容器層(container)形成容器進行運行
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)
命名為Dockerfile,在build時不用指定-f,默認就是docker build -f Dockerfile
使用ADD命令添加進來的壓縮包自動解壓縮
'''例子三,制作tomcat鏡像'''
需要准備:
tomcat壓縮包https://tomcat.apache.org/download-90.cgi,apache-tomcat-9.0.48.tar.gz
jdk壓縮包https://www.oracle.com/java/technologies/javase-jdk16-downloads.html,jdk-8u291-linux-x64.tar.gz
===========Dockerfile文件
FROM centos
MAINTAINER zhang<15009202810@163.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u291-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.48.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_291
ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.48
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.48
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.48/bin/startup.sh && tail -F /url/local/apache-tomcat-9.0.48/bin/logs/catalina.out
===========生成鏡像
docker build -t zhang/tomcat:01 .
===========生成的鏡像
REPOSITORY TAG IMAGE ID CREATED SIZE
zhang/tomcat 01 39da52a8d285 11 seconds ago 646MB
===========運行
docker run -d -p 9090:8080 --name zhang-tomcat -v /home/tomcat-ceshi/test:/usr/local/apache-tomcat-9.0.48/webapps/test -v /home/tomcat-ceshi/logs:/usr/local/apache-tomcat-9.0.48/logs 39da52a8d285
===========訪問測試
http://analysis1.space:9090/
===========發布項目(由於做了卷掛載,直接在本地編寫項目即可發布)
===========發布鏡像到dockerhub
https://registry.hub.docker.com/ 注冊賬號
docker push 名字/鏡像:tag 鏡像命名時/前面的部分要與dockerhub用戶名一致(不行就用tag改)
docker tag 39da52a8d285 zhangkaiyu/tomcat
Using default tag: latest
The push refers to repository [docker.io/zhangkaiyu/tomcat]
54200ad49e1d: Pushing [====> ] 4.937MB/60.65MB
c93fb61e83b5: Pushing [========> ] 2.7MB/15.93MB
e186d35963f1: Retrying in 4 seconds
e32f38ca1f9e: Pushing 2.56kB
2653d992f4ef: Pushing [=> ] 4.914MB/209.3MB
7.6,python腳本打包為docker鏡像
docker exec -it 容器id pip install -i 鏡像加速地址 三方庫 就可以下載文件了
Dockerfile中
ADD ./* /
才是將當前目錄中所有文件加入dockerfile中
不然生成鏡像后 docker tun -it 鏡像id /bin/bash 運行ls 發現並沒有自己所寫的文件
官方所給的python3鏡像中沒有發現數據文件,好像還是需要自己生成?
7.7,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)中有簡單介紹

