Docker如何製作鏡像-Dockerfile的使用

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

隨着鏡像的累積會導致鏡像體積越來越大。

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