Docker 鏡像多階段構建實戰總結

Docker 鏡像多階段構建實戰總結

一 背景

通常情況下,構建鏡像通常會採用兩種方式:

  1. 將全部組件及其依賴庫的編譯、測試、打包等流程封裝進一個 Docker 鏡像中。採用這種方式往往忽略了以下這些問題:
    • Dockefile 特別長,可維護性降低。
    • 鏡像的層次多,體積大,部署時間長。
    • 源代碼存在泄漏的風險。
  2. 分散到多個 Dockerfile。事先在一個 Dockerfile 將項目及其依賴庫編譯測試打包好後,再將其拷貝到運行環境中,這種方式需要我們編寫兩個 Dockerfile 和一些編譯腳本才能將其兩個階段自動整合起來,這種方式雖然可以很好地規避第一種方式存在的風險,但明顯部署過程較複雜。

爲了解決以上這些問題,Docker v17.05 開始支持多鏡像階段構建 (multistage builds)。只需要編寫一個 Dockerfile 即可。通過一段簡單的 C 語言代碼的編譯、執行來具體演示。demo.c 的內容如下:

# include<stdio.h>
int main()
{
  printf("%s\n","This is a demo!");
  return 0;
}

二 實踐步驟

2.1 只通過一個 Dockerfile 來構建【方案一】

查看對應的 Dockerfile:

FROM centos:7.8.2003

ENV VERSION 1.0

WORKDIR /demo

COPY demo.c .

RUN yum install -y gcc && \
    gcc -v
RUN gcc demo.c -o demo && \
    rm -f demo.c && \
    yum erase -y gcc && \
    cp demo /usr/local/bin/

CMD ["demo"]

感興趣的小夥伴可以直接將上面的 Dockerfile 和 docker-entrypoint.sh 在本地構建目錄創建,執行 docker build -t redis:6.0.5-buster 進行嘗試。

2.2 多個 Dockerfile 實現多階段構建【方案二】

多階段構建一般需要多個 Dockerfile 來完成,由於我們只需要源碼編譯後的產物。所以我們第一個階段可以直接使用上文中鏡像構建後的產物。第二階段的 Dockerfile 內容如下:

FROM centos:7.8.2003

ENV VERSION 1.0

WORKDIR /demo

COPY demo /usr/local/bin

CMD ["demo"]

執行構建腳本 bash build.sh, build.sh 的內容如下:

#!/bin/bash
cd stage-1
docker create --name bin demo:1.0
cd ../stage-2
docker cp bin:/usr/local/bin/demo .
docker rm -f bin
docker build -t demo:2.0 .

構建後得到的 Docker 容器運行結果:

$ docker run --rm -it demo:1.0
This is a demo!
$ docker run --rm -it demo:2.0
This is a demo!

兩個容器的環境變量:

$ docker run --rm -it demo:1.0 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=a52af1bec0af
TERM=xterm
VERSION=1.0
HOME=/root
$ docker run --rm -it demo:2.0 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=f6618fd1244b
TERM=xterm
VERSION=2.0
HOME=/root

2.3 一個 Dockerfile 實現多階段構建【方案三】

FROM centos:7.8.2003

ENV VERSION 1.0

WORKDIR /demo

COPY demo.c .

RUN yum install -y gcc && \
    gcc -v
RUN gcc demo.c -o demo && \
    rm -f demo.c && \
    yum erase -y gcc && \
    cp demo /usr/local/bin/

FROM centos:7.8.2003
COPY --from=0 /usr/local/bin/demo /usr/local/bin/demo

CMD ["demo"]

這種方式構建的 Docker 容器運行結果:

$ docker run --rm -it demo:3.0
This is a demo!
$ docker run --rm -it demo:3.0 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=7839b3d568db
TERM=xterm
HOME=/root

三個鏡像大小對比:

$ docker images|grep demo
demo                3.0                  8766031d380a        39 seconds ago           203MB
demo                2.0                  7d9c479cb421        10 minutes ago           203MB
demo                1.0                  af331209572f        38 minutes ago           350MB

三 總結

  • 3.1 通過觀察,方案一構建得到鏡像遠比方案二和方案三大得多,方案二和方案三的鏡像一樣大小。
  • 3.2 方案三並不會繼承第一階段構建的鏡像的環境變量等配置,僅僅是複製了第一階段的構建成果,需要特別注意。

四 參考文檔

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