Docker如何製作映象-Dockerfile的使用

竹根七發表於2021-12-31

1:什麼是Dockerfile

Dockerfile是一個文字文件,可以通過docker build 命令構建成一個映象。
我們可以在Dockerfile中定義一系列的命令,構建出我們想要的映象。
想要製作一個新的映象離不開Dockerfile。

2:Dockerfile 相關命令解釋

只做比較重要的命令進行簡單介紹,詳情可看官網。
Dockerfile 官方文件:https://docs.docker.com/engine/reference/builder/#entrypoint

2.1:FROM

格式:

FROM [--platform=<platform>] <image> [AS <name>] 

Or

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

Or

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

代表映象來源,比如 FROM centos:7 就代表當前映象的基礎映象為centos7。
若不需要基礎映象可以寫成 FROM scratch

2.2:RUN

格式:

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

也可以寫成:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

\代表可換行拼接執行語句。

要使用除“/bin/sh”之外的不同 shell,請使用傳入所需 shell的exec形式。例如:

RUN ["/bin/bash", "-c", "echo hello"]

docker 映象在構建過程中將執行RUN 後面定義的命令。

2.3:CMD

格式:

FROM ubuntu
CMD echo "This is a test." | wc -

or

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

比如:
CMD netstat -ntpl 可以寫成 CMD ["netstat","ntpl"]


CMD 命令在映象構建期間並不會執行任何命令,而是指的映象預期命令。

比如Dockerfile中的內容為:

FROM centos:7

CMD echo "hello docker"

進行docker build後不會報錯,且執行docker run後也不會報錯,因為 echo "hello word" 這條shell 命令在基礎映象 centos:7本身就是支援的。


但是Dockerfile中的內容若為:

FROM centos:7

CMD ["netstat","-ntpl"]

進行docker build後不會報錯,且執行docker run後會報錯,
報錯圖
因為 netstat -ntpl 這條shell 命令在基礎映象 centos:7中是不被支援的。

2.4:LABEL

映象標籤。一個映象可以有多個標籤。打標籤時要在LABEL值中包含空格,請像在命令列解析中一樣使用引號和反斜槓。
格式:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \

可以通過 docker image inspect --format='' {映象名稱}:{映象tag} 進行檢視。
如:

FROM centos:7

LABEL version=2.0

CMD ["netstat","-ntp

執行後佔用的埠模式80。
drawing

2.5:EXPOSE

格式:

EXPOSE 80/tcp

用以告知Docker 容器在執行時偵聽指定的網路埠。可以指定埠是監聽TCP還是UDP,如果不指定協議,預設為TCP。
但是無EXPOSE怎麼設定,進行docker run -p port:port 命令時任然可以指定容器佔用的埠。


如:

docker run -dit v3:3.0

執行後期望佔用的埠為80(這麼執行實際不會佔用埠)。
drawing


但是若執行

docker run -dit -p 8081:8081 v3:3.0

那麼容器執行後佔用的埠為8081。
drawing

2.6:EVN

格式:

ENV <key>=<value>

簡單來說就是為構建後的映象定義環境變數(執行為容器後生效),如jdk版本、資料庫連線配置等都可以設定。

2.7:ADD

格式:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

該功能僅在用於構建 Linux 容器的 Dockerfile 上受支援,不適用於 Windows 容器。由於使用者和組所有權概念不Linux和Windows,使用之間進行轉換/etc/passwd,並/etc/group用於轉換的使用者和組名ID的限制此功能僅適用於基於Linux作業系統的容器是可行的。

ADD 命令即可新增本地的檔案,也可以通過遠端連結進行檔案新增。

如果ADD的檔案是本地tar檔案,那麼ADD到映象後會自動解壓縮。

2.8:COPY

格式:

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

該功能僅在用於構建 Linux 容器的 Dockerfile 上受支援,不適用於 Windows 容器。由於使用者和組所有權概念不Linux和Windows,使用之間進行轉換/etc/passwd,並/etc/group用於轉換的使用者和組名ID的限制此功能僅適用於基於Linux作業系統的容器是可行的。

COPY 命令可將本地檔案新增到映象中,且無論何種檔案都不會自動解壓。

2.9:ENTRYPOINT

格式:

ENTRYPOINT ["executable", "param1", "param2"]

or

ENTRYPOINT command param1 param2

ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程式及引數。

如:

FROM centos:7

ENTRYPOINT echo "hello docker"

執行後效果為:
drawing


Dockerfile ENTRYPOINT、CMD、RUN的一些關係和區別。

2.10:VOLUME

格式:

VOLUME ["/data"]

作用執行映象後再容器內部建立一個匿名資料卷,掛載在宿主機的檔案系統下。
但是掛載的目錄是隨機預設的,無法指定在宿主機檔案系統的具體哪個位置。


如:

FROM centos:7

VOLUME /application/dockerfile/volume

CMD ["/bin/bash"]

代表執行映象後會在容器內部生成一個目錄地址為 /application/dockerfile/volume 的資料卷。
通過docker volume ls 檢視所有的資料卷。(再通過容器的啟動時間和宿主機匿名資料夾建立的時間可以找到具體的資料夾位置)
再通過docker volume inspect {volume_name}可以看到掛載宿主機的哪個位置。
drawing

宿主機的這個位置下的檔案是和容器中掛載的資料卷是互通的。宿主機新建、編輯、刪除檔案等操作會同步到容器中。

docker volume 詳細官方文件為:https://docs.docker.com/storage/volumes/
部落格文件為:

2.11:WORKDIR

格式:

WORKDIR /path/to/workdir

知名了WORKDIR 後 Dockerfile 中的 RUN、CMD、ENTRYPOINT、COPY和ADD 命令都將基於該資料夾下。


如:

FROM centos:7

WORKDIR /home

CMD ["/bin/bash"]

執行映象後,進入容器的位置便是在/home位置下。


其他相關命令請參考官方文件。

3:如何構建一個新的映象

3.1:如何從0-1構建一個映象

1:我們先來看看centos官方是如何構建映象的
github地址:https://github.com/CentOS/sig-cloud-instance-images/tree/CentOS-7.8.2003-x86_64/docker
結構圖:
drawing

Dockerfile 中的內容為:

es (13 sloc)  523 Bytes

FROM scratch
ADD centos-7.8.2003-x86_64-docker.tar.xz /

LABEL \
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20200504" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-05-04 00:00:00+01:00"

CMD ["/bin/bash"]

基礎映象也是需要一個二進位制的檔案的。如果你做過系統裁剪移植,那麼很容易做出屬於自己的體積更小的系統包(目前體積比較小的映象有 busybox、alpine 等)。

docker 官方也提供了構建基礎映象的文章

2:開始嘗試構建一個屬於自己的基礎映象
我構建的基礎映象環境包括:

  • centos7
  • jdk8
  • net-tools(網路工具)

Dockerfile內容:

# 空映象
FROM scratch
# 新增官方給的二進位制檔案(會自動解壓)
ADD centos-7.8.2003-x86_64-docker.tar.xz /
# 建立一個資料夾
RUN mkdir -p /application/jdk
# 將jdk8的
COPY jdk-8u261-linux-x64.tar.gz /application/jdk
# 安裝net-tools 並刪除jdk tar包以減少映象的佔用空間大小
RUN yum install net-tools -y && \
        cd /application/jdk && \
        tar -zxvf jdk-8u261-linux-x64.tar.gz && \
        rm -rf jdk-8u261-linux-x64.tar.gz
# 設定jdk的環境變數
ENV JAVA_HOME=/application/jdk/jdk1.8.0_261
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH

CMD ["/bin/bash"]

Dockerfile所處資料夾下需要有centos-7.8.2003-x86_64-docker.tar.xz、jdk-8u261-linux-x64.tar.gz 兩個檔案。
構建:

docker build -t centos7-jdk8:v1.0 .

執行:

docker run -dit --name centos7-jdk8 centos7-jdk8:v1.0

進入容器後執行java -versionnetstat -ntpl 命令都可執行。

drawing

3.2:如何在基礎映象上構建一個映象

經過上一個步驟後已經構建出了一個基礎映象了,然後我想把一個SpringBoot專案部署進去。
那麼我應該如何寫?
因為我的基礎映象已經有我要執行專案的所有環境了,因此我只需要把可執行的jar包丟進去執行即可。
Dockerfile內容:

# 基礎映象
FROM centos7-jdk8:v1.0
# 工作空間
WORKDIR /application/webapp
# 複製 jr包和啟動指令碼
COPY demo.jar .
COPY app.sh .
# 宣告容器需要的埠號
EXPOSE 8022
# 賦予啟動指令碼可執行許可權
RUN chmod a+x app.sh
# 容器啟動後執行指令碼啟動
ENTRYPOINT ["./app.sh","start"]

Dockerfile資料夾下需要有demo.jar、app.sh 兩個檔案。
構建:

docker build -t demo:v1.0 .

執行:

# 因為jar包執行後佔用埠為8022,因此需要宿主機和docker容器做一個埠對映
docker run -dit -p 8022:8022 --name dmeo demo:v1.0 /bin/bash

因為ENTRYPOINT命令在執行完命令後若沒有一個前臺程式執行,容器認為空閒,就會自行退出。
因此我在app.sh中特意新增了一句:
drawing
這樣容器在啟動後就不會自動退出了。


在宿主機執行curl -i 127.0.0.1:8022 '\w' 可以看到可以訪問到請求404(說明服務啟動了)。

drawing

4:映象示意圖

drawing

隨著映象的累積會導致映象體積越來越大。

相關文章