Docker鏡像
- 一、Docker鏡像的分層結構
- 二、Docker鏡像的建構
-
- 建構方法一(正常)
- 建構方法二(Dockerfile)
- 三、Dockerfile詳解
- 四、鏡像的封裝及優化
-
- Docker封裝rhel7+nginx鏡像執行個體
- 封裝後鏡像的優化
一、Docker鏡像的分層結構
鏡像的分層結構:
- 共享主控端的kernel
- base鏡像提供的是最小的Linux發行版
- 同一docker主機支援運作多種Linux發行版
- 采用分層結構的最大好處是:共享資源
- Copy-on-Write 可寫容器層
- 容器層以下所有鏡像層都是隻讀的
- docker從上往下依次查找檔案
- 容器層儲存鏡像變化的部分,并不會對鏡像本身進行任何修改
- 一個鏡像最多127層
二、Docker鏡像的建構
鏡像的分層結構:base image提供了根檔案系統,所有容器資料都分類存放在/var/lib/docker目錄中,可以共享資源,減少網絡帶寬資源占用
建構方法一(正常)
- docker commit 建構新鏡像三部曲
- 運作容器
- 修改容器
- 将容器儲存為新的鏡像
-
缺點:
效率低、可重複性弱、容易出錯
使用者無法對鏡像進行審計,存在安全隐患
這裡我們先在server1上拉取busybox鏡像
然後進行建構新鏡像三部曲
#運作容器
docker run -it --name demo busybox
#修改容器 (以下指令在容器内運作)
echo helloworld > testfile
#将容器儲存為新的鏡像
docker commit demo demo:v1
#檢視鏡像
docker images demo:v1
将demo容器送出儲存為demo:v1新的鏡像後,檢視比較busybox和demo:v1可以看到demo:v1是在busybox鏡像的基礎上新加了一層
建構方法二(Dockerfile)
建立一個Dockerfile
此處需要注意:
- dockerfile有審計功能,每新加一層鏡像都會有動作審計說明
- dockerfile不能放在根下,否則會把根下所有資料發送給docker引擎
(1)建立docker目錄,在目錄中建立編輯dockerfile
(2)使用dockerfile建立一個demo:v2新的鏡像
(3)新的鏡像已經建立為demo:v2,檢視比較busybox和demo:v2可以看到demo:v2是在busybox鏡像的基礎上新加了一層
三、Dockerfile詳解
dockerfile常用指令
-
FROM
指定base鏡像,如果本地不存在會從遠端倉庫下載下傳。
-
MAINTAINER
設定鏡像的作者,比如使用者郵箱等。
-
COPY
把檔案從build context複制到鏡像
支援兩種形式:COPY src dest 和 COPY [“src”, “dest”]
src必須指定build context中的檔案或目錄
-
ADD
用法與COPY類似,不同的是src可以是歸檔壓縮檔案,檔案會被自動解壓到dest,也可以自動下載下傳URL并拷貝到鏡像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www
-
ENV
設定環境變量,變量可以被後續的指令使用:
ENV HOSTNAME sevrer1.example.com
-
EXPOSE
如果容器中運作應用服務,可以把服務端口暴露出去:
EXPOSE 80
-
VOLUME
申明資料卷,通常指定的是應用的資料挂在點:
VOLUME ["/var/www/html"]
-
WORKDIR
為RUN、CMD、ENTRYPOINT、ADD和COPY指令設定鏡像中的目前工作目錄,如果目錄不存在會自動建立。
-
RUN
在容器中運作指令并建立新的鏡像層,常用于安裝軟體包:
RUN yum install -y vim
-
CMD 與 ENTRYPOINT
這兩個指令都是用于設定容器啟動後執行的指令,但CMD會被docker run後面的指令行覆寫,而ENTRYPOINT不會被忽略,一定會被執行。
docker run後面的參數可以傳遞給ENTRYPOINT指令當作參數。
Dockerfile中隻能指定一個ENTRYPOINT,如果指定了很多,隻有最後一個有效。
Shell和exec格式的差別
Shell格式底層會調用/bin/sh -c來執行指令,可以解析變量,而下面的exec格式不會:
cat Dockerfile
///
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo", "hello, $name"]
shell需要改寫成以下形式:
cat Dockerfile
///
FROM busybox
ENV name world
ENTRYPOINT ["/bin/sh", "-c", "echo hello, $name"]
Exec格式時,ENTRYPOINT可以通過CMD提供額外參數,CMD的額外參數可以在容器啟動時動态替換。在shell格式時ENTRYPOINT會忽略任何CMD或docker run提供的參數。
cat Dockerfile
///
FROM busybox
ENTRYPOINT ["/bin/echo", "hello"]
CMD ["world"]
下面可以看出在運作容器時的差別:
官方推薦使用exec格式書寫
///Exec
docker run --rm busybox:v1
hello world
///Sell
docker run --rm busybox:v1 linux
hello linux
四、鏡像的封裝及優化
- 選擇最精簡的基礎鏡像
- 減少鏡像的層數
- 清理鏡像建構的中間産物
- 注意優化網絡請求
- 盡量去用建構緩存
- 使用多階段建構鏡像
Docker封裝rhel7+nginx鏡像執行個體
(1)删除之前建立的所有demo容器,真實主機下載下傳rhel7和nginx的鏡像源壓縮包并發送給server1
docker rmi `docker images | grep ^demo | awk '{print $3}'` #删除之前所有的demo容器
///真機中
scp rhel7.tar nginx-1.20.1.tar server1:
(2)準備軟體倉庫檔案
(3)建立互動式容器,用于測試鏡像環境是否損壞
(4)将nginx和倉庫檔案拷貝到容器中,并編輯Dockerfile檔案,建立新的鏡像
(5)使用rhel7鏡像建立一個容器demo
docker inspect demo檢視容器資訊,看到配置設定的ip和在真實主機上挂載的路徑
(6)在真實主機挂載路徑上建立預設釋出檔案index.html,curl進行通路,可以擷取到釋出内容
封裝後鏡像的優化
封裝好的鏡像就可以正常運作了,但是檢視鏡像曆史及清單,會發現該鏡像的空間占用較大,不符合輕量化的原則,是以需要進行優化
1.減少鏡像層數,減少中間産物
重新編輯Dockerfile
vim Dockerfile
建立鏡像v2,可以看到鏡像大小減少了
2.使用多階段建構鏡像進行優化
再次編輯Dockerfile:
vim Dockerfile
建立鏡像v3,可以看到鏡像更小了
最終優化需要下載下傳base-debian10.tar ,下載下傳并導入
vim Dockerfile
////
FROM nginx as base
ARG Asia/Shanghai
RUN mkdir -p /opt/var/cache/nginx && \
cp -a --parents /usr/lib/nginx /opt && \
cp -a --parents /usr/share/nginx /opt && \
cp -a --parents /var/log/nginx /opt && \
cp -aL --parents /var/run /opt && \
cp -a --parents /etc/nginx /opt && \
cp -a --parents /etc/passwd /opt && \
cp -a --parents /etc/group /opt && \
cp -a --parents /usr/sbin/nginx /opt && \
cp -a --parents /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libc* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \
cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \
cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtime
FROM gcr.io/distroless/base-debian10
COPY --from=base /opt /
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
////
docker build -t rhel7:v4 #建立新的rhel7鏡像
docker images rhel7 #檢視鏡像大小發現筆之前小了很多
優化為如此小之後依然可以運作一個容器,通過curl看到nginx釋出的頁面!