一. docker鏡像原理剖析
靈魂三問:
1. docker 鏡像的本質是什么?
2. docker中一個centos鏡像大約200M左右,為什么一個centos系統的iso安裝文件要好幾個G?
3. docker中一個tomcat鏡像大約500M左右,為什么一個tomcat安裝包不足100M呢?
1. 操作系統掃盲
操作系統由:進程調度子系統、進程通信子系統、內存管理子系統、設備管理子系統、文件管理子系統、網絡通信子系統、作業控制子系統組成。
Linux的文件管理子系統由bootfs和rootfs組成。
(1). bootfs:包含bootloader(引導加載程序)和 kernel(內核)
(2). rootfs: root文件系統,包含的就是典型 Linux 系統中的/dev,/proc,/bin,/etc等標准目錄和文件
PS: 不同的linux發行版,bootfs基本一樣,而rootfs不同,如ubuntu,centos等
2. 鏡像原理
(1). Docker鏡像是由特殊的文件系統疊加而成,最底端是 bootfs,並使用宿主機的bootfs;第二層是 root文件系統rootfs,稱為base image;然后再往上可以疊加其他的鏡像文件。
(2). 統一文件系統(Union File System)技術能夠將不同的層整合成一個文件系統,為這些層提供了一個統一的視角,這樣就隱藏了多層的存在,在用戶的角度看來,只存在一個文件系統。
(3). 一個鏡像可以放在另一個鏡像的上面。位於下面的鏡像稱為父鏡像,最底部的鏡像成為基礎鏡像。
(4). 當從一個鏡像啟動容器時,Docker會在最頂層加載一個讀寫文件系統作為容器。
3. 解答靈魂三問
(1). docker 鏡像的本質是什么?
答:是一個分層的文件系統。
(2). docker中一個centos鏡像大約200M左右,為什么一個centos系統的iso安裝文件要好幾個G?
答:centos的iso文件包括bootfs和rootfs,而docker的centos鏡像復用操作系統的bootfs。
(3). docker中一個tomcat鏡像大約500M左右,為什么一個tomcat安裝包不足100M呢?
答:docker中的鏡像是分層的,tomcat雖然只有70多M,但是它需要依賴父鏡像和基礎鏡像,所有整個對外暴露的tomcat鏡像大約500M左右。
二. 容器轉為鏡像
1. 容器變為鏡像
(1). 指令
docker commit <containerId> 鏡像名稱:版本號
注:不加版本號的話,默認為latest
將容器制作為鏡像,容器內掛載目錄(數據卷)下的文件不會被包含!!!其它非掛在目錄下的文件都會被一起打包轉為容器。
(2). 案例
在一個名為mycentoscon1的centos容器中的工作目錄下,新建一個11.txt文件,然后把這個容器轉為一個鏡像,名為myowincentos1。
2. 如何移動遷移鏡像
(1). 把鏡像制成壓縮包
指令:
docker save -o 壓縮文件名稱 鏡像名稱:版本號
(2). 再把壓縮包轉為鏡像
指令:
docker load -i 壓縮文件名稱
三. 通過Dockerfile制作鏡像
1. 制作鏡像的指令
docker build -f dockerfile文件路徑 -t 鏡像名稱:版本號 .
(1). -f dockerfile文件路徑 : dockerfile文件可以自定義命名,比如:ypfdockerfile,只要指定路徑即可。
注:如果在當前目錄下,且名字就叫 Dockerfile,可以省略 【 -f dockerfile文件路徑】 即簡版指令為 【docker build -t 鏡像名稱:版本號 .】
(2). 如果不指定版本號,默認為latest
(3). 指令最后必須有: 1個空格+1個點
2. 什么是Dockerfile文件
Dockerfile 是一個文本文件,包含了一條條的指令,每一條指令構建一層,基於基礎鏡像,最終構建出一個新的鏡像。他有以下作用
(1).對於開發人員:可以為開發團隊提供一個完全一致的開發環境。
(2).對於測試人員:可以直接拿開發時所構建的鏡像或者通過Dockerfile文件構建一個新的鏡像開始工作了。
(3).對於運維人員:在部署時,可以實現應用的無縫移植。
一張圖說明幾個核心配置
分享幾個Dockerfile案例:
A.自己制作一個nginx鏡像
FROM centos:7.6 RUN yum -y install gcc make pcre-devel zlib-devel tar zlib WORKDIR /nginx COPY nginx-1.15.2.tar.gz /nginx RUN tar -zxvf nginx-1.15.2.tar.gz RUN cd nginx-1.15.2 && ./configure && make && make install EXPOSE 8080 COPY nginx.sh /nginx.sh RUN chmod 755 /nginx.sh CMD [“/nginx.sh”]
B.自己制作一個core webapi鏡像
#1.依賴兩個基礎鏡像 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster #2.制作人 MAINTAINER ypf <ypf@qq.com> #3.指定程序運行的端口(也可以在項目中通過UseUrls指定, 或者發布容器的時候通過--env ASPNETCORE_URLS=xxx動態指定) ENV ASPNETCORE_URLS=http://*:9000 #4.容器對外暴露的端口 EXPOSE 9000 #5.指定默認工作目錄 WORKDIR /userapi #6. 將當前目錄(Dockerfile文件下)的所有文件拷貝到鏡像的userapi工作目錄下 COPY . /userapi/ #7.啟動容器的時候執行shell命令:dotnet webapi1.dll,即運行該項目 ENTRYPOINT ["dotnet", "webapi1.dll"]
C. 自定義一個centos鏡像
#1.定義依賴鏡像(宿主機中沒有話則去下載) FROM centos:7 #2.定義作者信息(可以不寫) MAINTAINER ypf <ypf@qq.com> #3. 執行安裝vim的命令(-y表示安裝過程中不提示) RUN yum install -y vim #4. 定義默認的工作目錄 WORKDIR /ypfusr #5 定義容器啟動執行的命令 CMD /bin/bash
3. 剖析
(1). FROM
定義構建新鏡像所需依賴的父鏡像(基礎鏡像)。
FROM centos:7.6
(2). MAINTAINER 或 LABEL
定義鏡像的作者。
MAINTAINER ypf <ypf@qq.com> # 或者用 LABEL (推薦) LABEL maintainer="ypf"
(3) .ENV
設置環境變量
# 設置asp.net項目啟動端口為8000(程序中不設置的情況下用) ENV ASPNETCORE_URLS=http://*:8000 # 設置Java環境 ENV JAVA_HOME /usr/local/jdk1.11.0 # 設置mysql的密碼 ENV MYSQL_ROOT_PASSWORD 123456
(4). EXPOSE
聲明容器運行的端口。
PS:在通過docker run 指令構建容器的要通過-p 將宿主機的端口和容器端口進行映射。
(5). RUN
指定構建鏡像所需要運行的shell命令
#解壓並安裝 RUN tar -zxvf nginx-1.15.2.tar.gz RUN cd nginx-1.15.2 && ./configure && make && make install # 安裝vim RUN yum install -y vim
(6). WORKDIR
指定工作目錄,發布成容器時,默認進入的就是這里指定目錄。
#定義默認的工作目錄
WORKDIR /ypfusr
(7). VOLUME
指定生成容器時掛載宿主機的目錄
VOLUME ["/var/lib/mysql"]
注:基本上不在Dockerfile文件中使用,而是在構建容器的時候通過 -v 指令來設置。
(8) . ADD
拷貝文件或目錄到鏡像中 (此處要測試一下,如果鏡像中的目錄不存在是否會自動創建???)
#將當前目錄中xx1.tar.gz 復制到鏡像中的/home/test文件夾下,並自動解壓 ADD xx1.tar.gz /home/test #下載xx2到鏡像中的/home/test文件夾中 ADD https://xxx.com/xx2.tar.gz /home/test #將當前目錄下的start.sh 復制到鏡像中的目錄中 ADD ./start.sh /start.sh
PS:當拷貝的是壓縮包或者URL的時候,會自動解壓或自動下載。
(9). COPY
拷貝文件或目錄到鏡像中,同ADD,但不支持自動下載和解壓。
# 將當前目錄下的start.sh 復制到鏡像中的目錄中
COPY ./start.sh /start.sh
注:ADD和COPY的共同特點是 只能復制Dockerfile所在目錄下的文件,如果目標鏡像中的路徑不存在,會自動創建。
(10). CMD
啟動容器時執行的shell命令。
# 啟動容器時候下面指令效果等效: # ENTRYPOINT ["dotnet", "webapi1.dll"] # ENTRYPOINT dotnet webapi1.dll # CMD ["dotnet", "webapi1.dll"] # CMD dotnet webapi1.dll
(11). ENTRYPOINT
啟動容器時執行的shell命令。同CMD類似,只是由ENTRYPOINT啟動的程序不會被docker run命令行指定的參數所覆蓋,而且,這些命令行參數會被當作參數傳遞給ENTRYPOINT指定的程序。
# 啟動容器時候下面指令效果等效: # ENTRYPOINT ["dotnet", "webapi1.dll"] # ENTRYPOINT dotnet webapi1.dll # CMD ["dotnet", "webapi1.dll"] # CMD dotnet webapi1.dll
注:如果存在多個ENTRYPOINT,僅最有一個生效。
(12). HEALTHCHECK
健康檢查
HEALTHCHECK --interval=5m --timeout=3s --retries=3 CMD curl -f http:/xxxx/ || exit 1
參數說明:
--interval=DURATION (default: 30s):每隔多長時間探測一次,默認30秒
-- timeout= DURATION (default: 30s):服務響應超時時長,默認30秒
-- start-period= DURATION (default: 0s):服務啟動多久后開始探測,默認0秒
-- retries=N (default: 3):認為檢測失敗幾次為宕機,默認3次
一些返回值的說明:
0:容器成功是健康的,隨時可以使用
1:不健康的容器無法正常工作
2:保留不使用此退出代碼
(13). USER
為RUN、CMD、ENTRYPOINT執行shell命令指定用戶
USER <user>[:<usergroup>] USER <UID>[:<UID>] USER ypf
(14). ARG
構建參數,與 ENV 作用一至。不過作用域不一樣。ARG 設置的環境變量僅對 Dockerfile 內有效,也就是說只有 docker build 的過程中有效,構建好的鏡像內不存在此環境變量。
構建命令 docker build 中可以用 --build-arg <參數名>=<值> 來覆蓋。
格式:ARG <參數名>[=<默認值>]
#Dockerfile文件中
ARG user=ypf #構建鏡像的時候覆蓋 docker build --build-arg user=lmr webapi1 .
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。