国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

《Docker極簡(jiǎn)教程》--Dockerfile--Dockerfile的基本語(yǔ)法

這篇具有很好參考價(jià)值的文章主要介紹了《Docker極簡(jiǎn)教程》--Dockerfile--Dockerfile的基本語(yǔ)法。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

Dockerfile是一種文本文件,用于定義Docker鏡像的內(nèi)容和構(gòu)建步驟。它包含一系列指令,每個(gè)指令代表一個(gè)構(gòu)建步驟,從基礎(chǔ)鏡像開(kāi)始,逐步構(gòu)建出最終的鏡像。通過(guò)Dockerfile,用戶可以精確地描述應(yīng)用程序運(yùn)行環(huán)境的配置、依賴項(xiàng)安裝、文件復(fù)制等操作。這使得應(yīng)用程序的部署和分發(fā)變得更加可控和可重復(fù)。Dockerfile的內(nèi)容可以根據(jù)需求自定義,允許開(kāi)發(fā)者根據(jù)應(yīng)用程序的特性和需求來(lái)靈活配置鏡像的構(gòu)建過(guò)程,從而實(shí)現(xiàn)高效、可靠的容器化部署。

一、Dockerfile語(yǔ)法

1.1 指令
  1. FROM
    在Dockerfile中,F(xiàn)ROM語(yǔ)句用于指定基礎(chǔ)鏡像,即構(gòu)建新鏡像所需的起始點(diǎn)。基礎(chǔ)鏡像是構(gòu)建過(guò)程中的第一步,它提供了操作系統(tǒng)和運(yùn)行環(huán)境的基本配置。FROM語(yǔ)句的基本語(yǔ)法如下:

    FROM <鏡像名稱>[:<標(biāo)簽>]
    

    其中:

    • <鏡像名稱>:指定所使用的基礎(chǔ)鏡像的名稱。
    • <標(biāo)簽>:(可選)指定所使用的基礎(chǔ)鏡像的版本或標(biāo)識(shí)符。如果不指定標(biāo)簽,則默認(rèn)使用latest標(biāo)簽。

    示例:

    FROM ubuntu:20.04
    

這個(gè)示例指定了基于Ubuntu 20.04版本的官方鏡像作為基礎(chǔ)鏡像。在構(gòu)建新鏡像時(shí),Docker引擎會(huì)從Docker Hub或本地鏡像倉(cāng)庫(kù)中獲取指定的基礎(chǔ)鏡像,并在其基礎(chǔ)上執(zhí)行后續(xù)的構(gòu)建步驟。

  1. RUN
    在Dockerfile中,RUN指令用于在鏡像中執(zhí)行命令。這些命令通常用于安裝軟件包、更新系統(tǒng)、配置環(huán)境變量等。RUN指令可以多次出現(xiàn),每次出現(xiàn)都會(huì)在鏡像中創(chuàng)建一個(gè)新的中間層,這些中間層將用于構(gòu)建最終的鏡像。RUN指令的基本語(yǔ)法如下:

    RUN <command>
    

    其中<command>是要執(zhí)行的命令,可以是任何有效的Linux命令或Shell命令??梢允褂梅葱备埽╘)將一條命令拆分為多行,或者使用&&連接多個(gè)命令,以確保在同一層中執(zhí)行,從而減少鏡像大小。示例:

    FROM ubuntu:20.04
    RUN apt-get update && apt-get install -y \
        python3 \
        python3-pip \
        && rm -rf /var/lib/apt/lists/*
    

    這個(gè)示例中,RUN指令用于更新APT包列表并安裝Python3及其相關(guān)的軟件包。最后,使用rm -rf /var/lib/apt/lists/*命令清理APT緩存,以減少鏡像大小。

  2. COPY
    COPY指令用于將文件或目錄從構(gòu)建上下文中的源路徑復(fù)制到容器文件系統(tǒng)中的目標(biāo)路徑。這個(gè)指令對(duì)于將本地文件或目錄復(fù)制到鏡像中是非常有用的。COPY指令的基本語(yǔ)法如下:

    COPY <源路徑> <目標(biāo)路徑>
    

    其中:

    • <源路徑>:指定要復(fù)制的文件或目錄在構(gòu)建上下文中的路徑。這個(gè)路徑是相對(duì)于Dockerfile所在目錄的路徑。
    • <目標(biāo)路徑>:指定將文件或目錄復(fù)制到容器中的位置。這個(gè)路徑是相對(duì)于容器的根目錄的路徑。

    示例:

    FROM ubuntu:20.04
    COPY ./app /app
    

    在這個(gè)示例中,假設(shè)在與Dockerfile相同的目錄下有一個(gè)名為app的目錄,COPY指令將會(huì)把這個(gè)目錄下的所有內(nèi)容復(fù)制到容器中的/app目錄下。

    Tip:COPY指令只能復(fù)制本地文件系統(tǒng)中的文件或目錄,不能從URL或遠(yuǎn)程文件系統(tǒng)中復(fù)制文件。

  3. ADD
    ADD指令與COPY指令類似,都用于將文件從構(gòu)建上下文中復(fù)制到容器中。但ADD指令不僅可以復(fù)制本地文件,還可以解壓縮壓縮文件、使用URL等。ADD指令的基本語(yǔ)法如下:

ADD <源路徑> <目標(biāo)路徑>

其中:

  • <源路徑>:指定要復(fù)制的文件或目錄在構(gòu)建上下文中的路徑。這個(gè)路徑是相對(duì)于Dockerfile所在目錄的路徑。
  • <目標(biāo)路徑>:指定將文件或目錄復(fù)制到容器中的位置。這個(gè)路徑是相對(duì)于容器的根目錄的路徑。

示例:

FROM ubuntu:20.04
ADD ./app.tar.gz /app

在這個(gè)示例中,假設(shè)在與Dockerfile相同的目錄下有一個(gè)名為app.tar.gz的壓縮文件,ADD指令將會(huì)把這個(gè)壓縮文件解壓縮并將其中的內(nèi)容復(fù)制到容器中的/app目錄下。

Tip:相比于COPY指令,ADD指令具有更多的功能,但也可能引入一些不必要的復(fù)雜性,因此在一般情況下,建議盡量使用COPY指令來(lái)復(fù)制文件。

  1. CMD
    CMD指令用于在容器啟動(dòng)時(shí)執(zhí)行特定的命令或指定容器的默認(rèn)執(zhí)行命令。每個(gè)Dockerfile只能包含一個(gè)CMD指令,如果有多個(gè),則只有最后一個(gè)生效。如果在運(yùn)行容器時(shí)提供了命令,則會(huì)覆蓋CMD指令中定義的默認(rèn)命令。
    CMD指令有兩種形式:Shell形式和Exec形式。

    • Shell形式:
      CMD <command>
      
      其中<command>可以是任何Shell命令,例如:
      CMD echo "Hello, world!"
      
    • Exec形式:
      CMD ["executable", "param1", "param2"]
      
      其中["executable", "param1", "param2"]是一個(gè)JSON數(shù)組,用于指定可執(zhí)行文件及其參數(shù),例如:
      CMD ["python", "-u", "app.py"]
      

    在這個(gè)示例中,指定了執(zhí)行Python腳本app.py的命令。
    如果Dockerfile中沒(méi)有CMD指令,則會(huì)使用基礎(chǔ)鏡像中的默認(rèn)CMD指令,如果基礎(chǔ)鏡像中也沒(méi)有默認(rèn)CMD指令,則容器啟動(dòng)時(shí)將會(huì)立即退出。

  2. ENTRYPOINT
    ENTRYPOINT指令用于設(shè)置容器啟動(dòng)時(shí)要執(zhí)行的命令。與CMD指令不同,ENTRYPOINT指定的命令不會(huì)被覆蓋,而是作為容器的主要執(zhí)行命令。如果在運(yùn)行容器時(shí)提供了命令,則會(huì)被傳遞給ENTRYPOINT指定的命令作為參數(shù)。
    ENTRYPOINT指令的語(yǔ)法有兩種形式:Shell形式和Exec形式。

    • Shell形式:
      ENTRYPOINT <command>
      
      其中<command>可以是任何Shell命令,例如:
      ENTRYPOINT echo "Hello, world!"
      
    • Exec形式:
      ENTRYPOINT ["executable", "param1", "param2"]
      
      其中["executable", "param1", "param2"]是一個(gè)JSON數(shù)組,用于指定可執(zhí)行文件及其參數(shù),例如:
      ENTRYPOINT ["python", "app.py"]
      

    在這個(gè)示例中,指定了以Python解釋器執(zhí)行app.py腳本的命令。
    使用ENTRYPOINT指令的主要優(yōu)點(diǎn)是可以在容器啟動(dòng)時(shí)提供固定的執(zhí)行環(huán)境,從而確保容器始終以相同的方式運(yùn)行。通常,ENTRYPOINT指令與CMD指令一起使用,CMD指定默認(rèn)參數(shù),但用戶可以在運(yùn)行容器時(shí)覆蓋這些參數(shù)。

  3. WORKDIR
    WORKDIR指令用于在容器內(nèi)設(shè)置工作目錄,即定義容器啟動(dòng)時(shí)的默認(rèn)工作路徑。當(dāng)容器啟動(dòng)后,任何后續(xù)命令都會(huì)在該目錄下執(zhí)行。如果工作目錄不存在,WORKDIR指令會(huì)自動(dòng)創(chuàng)建。
    WORKDIR指令的基本語(yǔ)法如下:

    WORKDIR <路徑>
    

    其中<路徑>是容器中的工作目錄路徑。該路徑可以是相對(duì)路徑(相對(duì)于上一個(gè) WORKDIR 指令的路徑)或絕對(duì)路徑。示例:

    FROM ubuntu:20.04
    WORKDIR /app
    

    在這個(gè)示例中,WORKDIR指令將容器的工作目錄設(shè)置為/app。當(dāng)容器啟動(dòng)后,所有后續(xù)的命令都會(huì)在/app目錄下執(zhí)行。 如果該目錄不存在,Docker將自動(dòng)創(chuàng)建該目錄。
    使用WORKDIR指令可以使Dockerfile更加簡(jiǎn)潔和可讀,同時(shí)也可以確保容器內(nèi)部的命令都在預(yù)期的工作目錄中執(zhí)行,提高了容器的可維護(hù)性。

  4. ENV
    ENV指令用于設(shè)置環(huán)境變量,這些環(huán)境變量可以在構(gòu)建和運(yùn)行過(guò)程中被Docker容器使用。通過(guò)設(shè)置環(huán)境變量,可以在容器中指定一些常量或配置,以便于應(yīng)用程序的正確運(yùn)行。
    ENV指令的基本語(yǔ)法如下:

    ENV <key> <value>
    

    其中 <key> 是環(huán)境變量的名稱, <value> 是環(huán)境變量的值。
    示例:

    FROM ubuntu:20.04
    ENV LANG C.UTF-8
    

    在這個(gè)示例中,ENV指令設(shè)置了LANG環(huán)境變量為C.UTF-8。這個(gè)環(huán)境變量的設(shè)置將影響容器中所有的進(jìn)程,確保它們以正確的字符集編碼運(yùn)行。
    除了上述的基本語(yǔ)法外,還可以使用ENV指令定義多個(gè)環(huán)境變量,或者使用${variable}來(lái)引用其他環(huán)境變量,例如:

    FROM ubuntu:20.04
    ENV JAVA_HOME /usr/lib/jvm/java-11-openjdk-amd64
    ENV PATH $PATH:$JAVA_HOME/bin
    

    這個(gè)示例中,PATH環(huán)境變量被修改,以包含Java的可執(zhí)行文件目錄,這樣就可以直接在命令行中運(yùn)行Java命令了。
    使用ENV指令可以使Dockerfile更加靈活和可配置,同時(shí)也方便了容器內(nèi)部應(yīng)用程序的管理和調(diào)試。

  5. EXPOSE
    EXPOSE指令用于指定容器在運(yùn)行時(shí)將監(jiān)聽(tīng)的端口,但它并不會(huì)實(shí)際打開(kāi)或映射這些端口。它只是將指定的端口號(hào)添加到容器的元數(shù)據(jù)中,以便于與外部環(huán)境進(jìn)行交互時(shí)提供一些提示信息。
    EXPOSE指令的基本語(yǔ)法如下:

    EXPOSE <port> [<port>/<protocol>...]
    

    其中:

    • <port> 是要暴露的端口號(hào)。
    • <protocol> 是要使用的協(xié)議(通常是 TCP 或 UDP)。如果未指定協(xié)議,默認(rèn)為 TCP。

    示例:

    FROM ubuntu:20.04
    EXPOSE 80
    

    這個(gè)示例中,EXPOSE指令指定容器將監(jiān)聽(tīng)80端口,但是并沒(méi)有指定協(xié)議,默認(rèn)為TCP。當(dāng)運(yùn)行容器時(shí),可以通過(guò) -p 參數(shù)來(lái)映射宿主機(jī)上的端口到容器中的80端口。

    docker run -p 8080:80 <image_name>
    

    這個(gè)命令將容器內(nèi)部的80端口映射到宿主機(jī)的8080端口上。

    Tip:EXPOSE指令并不是強(qiáng)制性的,它只是一種標(biāo)記機(jī)制,用于告訴用戶容器內(nèi)部的服務(wù)所監(jiān)聽(tīng)的端口。在容器運(yùn)行時(shí),仍然需要使用 -p 參數(shù)來(lái)映射端口,否則容器內(nèi)部的端口對(duì)外部是不可訪問(wèn)的。

  6. VOLUME
    VOLUME指令用于在容器中創(chuàng)建一個(gè)掛載點(diǎn),并將其鏈接到主機(jī)上的一個(gè)目錄,從而允許容器中的數(shù)據(jù)持久化保存到主機(jī)上。這個(gè)掛載點(diǎn)可以用來(lái)存儲(chǔ)容器生成的數(shù)據(jù),以便于在容器重新啟動(dòng)或遷移時(shí)保持?jǐn)?shù)據(jù)的持久性。
    VOLUME指令的基本語(yǔ)法如下:

    VOLUME ["<路徑>"]
    

    其中<路徑>是容器中的目錄路徑,這個(gè)目錄將被指定為掛載點(diǎn)。如果省略路徑,則表示使用匿名掛載點(diǎn),Docker將為掛載點(diǎn)自動(dòng)分配一個(gè)路徑。
    示例:

    FROM ubuntu:20.04
    VOLUME ["/data"]
    

    在這個(gè)示例中,VOLUME指令創(chuàng)建了一個(gè)名為/data的掛載點(diǎn),它將與主機(jī)上的一個(gè)目錄進(jìn)行關(guān)聯(lián)。當(dāng)容器運(yùn)行時(shí),可以使用 -v 參數(shù)將宿主機(jī)上的目錄掛載到容器中,例如:

    docker run -v /host/path:/data <image_name>
    

    這個(gè)命令將宿主機(jī)上的/host/path目錄掛載到容器中的/data目錄,容器內(nèi)部的數(shù)據(jù)操作將直接反映到主機(jī)上掛載的目錄中。
    使用VOLUME指令可以實(shí)現(xiàn)容器內(nèi)部數(shù)據(jù)的持久化存儲(chǔ),從而實(shí)現(xiàn)容器的數(shù)據(jù)共享和遷移。

  7. USER
    USER指令用于設(shè)置容器中運(yùn)行命令的用戶或用戶組。通過(guò)USER指令,可以切換到指定的用戶或用戶組來(lái)增強(qiáng)容器的安全性和隔離性。
    USER指令的基本語(yǔ)法如下:

    USER <用戶名>[:<組名>] or <UID>[:<GID>]
    

    其中:

    • <用戶名>:指定要切換到的用戶名。
    • <組名>:(可選)指定要切換到的組名。如果未指定組名,則使用與用戶名相同的組。
    • <UID>:指定要切換到的用戶ID。
    • <GID>:(可選)指定要切換到的組ID。如果未指定組ID,則使用與用戶ID相同的組ID。

    示例:

    FROM ubuntu:20.04
    RUN groupadd -r mygroup && useradd -r -g mygroup myuser
    USER myuser
    

    在這個(gè)示例中,首先通過(guò)RUN指令創(chuàng)建了一個(gè)名為myuser的用戶和一個(gè)名為mygroup的用戶組。然后使用USER指令切換到myuser用戶,接下來(lái)的命令將以myuser用戶的身份執(zhí)行。
    使用USER指令可以降低容器內(nèi)部命令執(zhí)行的權(quán)限,從而增加了容器的安全性。通常建議在Docker鏡像中使用非特權(quán)用戶來(lái)運(yùn)行應(yīng)用程序,以最小化潛在的安全風(fēng)險(xiǎn)。

  8. LABEL
    LABEL指令用于為Docker鏡像添加元數(shù)據(jù),可以用來(lái)提供關(guān)于鏡像的信息、版本、作者等。這些標(biāo)簽信息可以在構(gòu)建和運(yùn)行鏡像時(shí)被查看和使用,有助于組織和管理鏡像。
    LABEL指令的基本語(yǔ)法如下:

    LABEL <key>=<value> <key>=<value> ...
    

    其中 <key> 是標(biāo)簽的名稱, <value> 是標(biāo)簽的值。
    示例:

    FROM ubuntu:20.04
    LABEL maintainer="John Doe <john@example.com>"
    LABEL version="1.0"
    LABEL description="This is a sample Dockerfile demonstrating the use of LABEL instruction."
    

    在這個(gè)示例中,使用了三個(gè)LABEL指令,分別指定了鏡像的維護(hù)者、版本和描述信息。
    標(biāo)簽信息可以通過(guò) docker inspect 命令來(lái)查看,例如:

    docker inspect --format='{{json .Config.Labels}}' <image_name>
    

    這個(gè)命令將會(huì)輸出鏡像的所有標(biāo)簽信息。
    使用LABEL指令可以提高鏡像的可讀性和可管理性,使其更易于識(shí)別和使用。

  9. ARG
    ARG指令用于定義構(gòu)建時(shí)的參數(shù),這些參數(shù)可以在Dockerfile中使用,并且可以在構(gòu)建鏡像時(shí)通過(guò)命令行參數(shù)進(jìn)行覆蓋。ARG指令可以用于在構(gòu)建過(guò)程中傳遞變量,從而實(shí)現(xiàn)動(dòng)態(tài)配置鏡像的構(gòu)建過(guò)程。
    ARG指令的基本語(yǔ)法如下:

ARG <name>[=<default value>]

其中 <name> 是參數(shù)的名稱, <default value> 是參數(shù)的默認(rèn)值。如果未提供默認(rèn)值,則參數(shù)可以在構(gòu)建過(guò)程中通過(guò)--build-arg選項(xiàng)進(jìn)行傳遞。
示例:

FROM ubuntu:20.04
ARG APP_VERSION=1.0
ENV APP_VERSION=${APP_VERSION}

在這個(gè)示例中,定義了一個(gè)名為APP_VERSION的構(gòu)建參數(shù),并設(shè)置了默認(rèn)值為1.0。然后將這個(gè)參數(shù)賦值給APP_VERSION環(huán)境變量,使其在鏡像中可用。
在構(gòu)建鏡像時(shí),可以通過(guò)--build-arg選項(xiàng)來(lái)覆蓋默認(rèn)值,例如:

docker build --build-arg APP_VERSION=2.0 -t myimage .

這個(gè)命令將會(huì)使用2.0作為APP_VERSION的值進(jìn)行構(gòu)建。
使用ARG指令可以使Dockerfile更加靈活和可配置,允許在構(gòu)建時(shí)根據(jù)需要?jiǎng)討B(tài)設(shè)置參數(shù)。

1.2 注釋和空白行

在Dockerfile中,注釋和空白行可以幫助提高文件的可讀性,并且可以用于添加注釋和分隔構(gòu)建步驟。注釋和空白行在Dockerfile中不會(huì)被解釋為指令,它們只是用于提供額外的說(shuō)明和組織結(jié)構(gòu)。

  1. 注釋:
    在Dockerfile中,可以使用#符號(hào)添加注釋,#符號(hào)后的內(nèi)容將被視為注釋,直到行尾。注釋可以用于解釋每個(gè)指令的作用、提供版本信息、添加作者信息等。例如:
    # This is a Dockerfile for building a custom nginx image
    # Version 1.0
    # Author: John Doe
    
    FROM nginx:latest
    
  2. 空白行:
    空白行用于在Dockerfile中創(chuàng)建可讀性更好的結(jié)構(gòu),可以用于分隔不同的構(gòu)建步驟,或者用于增加可讀性。在Dockerfile中,空白行是沒(méi)有任何指令的行,或者只包含空格或制表符的行。例如:
    FROM nginx:latest
    
    # Install additional packages
    RUN apt-get update \
        && apt-get install -y \
        curl \
        wget
    
    # Set up configuration files
    COPY nginx.conf /etc/nginx/nginx.conf
    
    # Expose ports
    EXPOSE 80
    
    # Start nginx service
    CMD ["nginx", "-g", "daemon off;"]
    
    在這個(gè)示例中,空白行被用于分隔不同的構(gòu)建步驟,使得Dockerfile更加清晰易讀。

注釋和空白行在Dockerfile中起到了組織結(jié)構(gòu)和解釋說(shuō)明的作用,建議在編寫(xiě)Dockerfile時(shí)充分利用它們來(lái)提高文件的可讀性和可維護(hù)性。

二、Dockerfile的最佳實(shí)踐

2.1 最小化鏡像大小

最小化鏡像大小是Dockerfile編寫(xiě)的一個(gè)重要方面,可以通過(guò)以下最佳實(shí)踐來(lái)實(shí)現(xiàn):

  1. 選擇輕量級(jí)基礎(chǔ)鏡像: 選擇基于Alpine Linux等輕量級(jí)操作系統(tǒng)的基礎(chǔ)鏡像,而不是使用通用的Linux發(fā)行版。輕量級(jí)基礎(chǔ)鏡像通常只包含最基本的軟件包和庫(kù),可以顯著減小鏡像大小。
  2. 單層構(gòu)建: 盡量將多個(gè)命令合并到單個(gè)RUN指令中,這樣可以減少鏡像的層數(shù),進(jìn)而減小鏡像的體積。例如,在安裝軟件包時(shí),將多個(gè)apt-get命令合并成一個(gè)RUN指令。
  3. 清理無(wú)用文件: 在每個(gè)構(gòu)建步驟中清理掉不必要的臨時(shí)文件、APT緩存等。可以使用apt-get clean、apt-get autoclean等命令來(lái)清理APT緩存,以減小鏡像的大小。
  4. 避免安裝不必要的依賴: 僅安裝應(yīng)用程序運(yùn)行所必需的依賴項(xiàng),避免安裝不必要的軟件包和庫(kù)。
  5. 使用多階段構(gòu)建: 對(duì)于編譯型語(yǔ)言(如Go、Java)的應(yīng)用程序,可以使用多階段構(gòu)建來(lái)減小鏡像大小。在一個(gè)階段中編譯應(yīng)用程序,然后在另一個(gè)階段中將編譯好的應(yīng)用程序復(fù)制到最終的鏡像中,這樣可以減少鏡像中不必要的構(gòu)建工具和依賴項(xiàng)。
  6. 優(yōu)化鏡像打包: 使用.dockerignore文件來(lái)排除不必要的文件和目錄,減少鏡像構(gòu)建上下文的大小。避免將大量數(shù)據(jù)和日志文件打包進(jìn)鏡像。
  7. 精簡(jiǎn)運(yùn)行時(shí)環(huán)境: 確保在運(yùn)行時(shí)只包含應(yīng)用程序所需的最小文件和配置,避免包含不必要的文件和目錄。使用docker history命令查看鏡像的構(gòu)建歷史,識(shí)別不必要的文件和層,進(jìn)一步優(yōu)化鏡像。

通過(guò)遵循上述最佳實(shí)踐,可以有效地減小鏡像的大小,提高鏡像的性能和安全性,同時(shí)減少存儲(chǔ)和網(wǎng)絡(luò)傳輸?shù)某杀尽?/p>

2.2 合理使用緩存

合理使用緩存是優(yōu)化Dockerfile構(gòu)建過(guò)程的重要策略,可以顯著減少構(gòu)建時(shí)間和資源消耗。以下是一些合理使用緩存的最佳實(shí)踐:

  1. 將頻繁變動(dòng)的步驟放置在最后: Docker會(huì)從之前的鏡像層緩存中執(zhí)行步驟,如果某一步驟之后的步驟發(fā)生變化,那么之后的所有步驟都會(huì)重新構(gòu)建。因此,將變動(dòng)較大的步驟放置在Dockerfile的末尾,可以最大程度地利用緩存。
  2. 合并多個(gè)命令: 盡量將多個(gè)命令合并為單個(gè)RUN指令,這樣可以減少鏡像的層數(shù),從而減少重復(fù)構(gòu)建的情況。每個(gè)RUN指令都會(huì)創(chuàng)建一個(gè)新的鏡像層,因此將多個(gè)命令合并到一個(gè)RUN指令中可以減少構(gòu)建層數(shù)。
  3. 使用有效的鏡像標(biāo)簽: 當(dāng)構(gòu)建基于其他鏡像的派生鏡像時(shí),如果基礎(chǔ)鏡像的標(biāo)簽發(fā)生了變化,那么所有依賴于該基礎(chǔ)鏡像的派生鏡像都會(huì)重新構(gòu)建。因此,確保使用穩(wěn)定的鏡像標(biāo)簽(如具體版本號(hào))而不是latest等動(dòng)態(tài)標(biāo)簽。
  4. 利用構(gòu)建緩存: Docker在構(gòu)建過(guò)程中會(huì)使用緩存,可以通過(guò)–cache-from選項(xiàng)指定一個(gè)已構(gòu)建鏡像來(lái)作為構(gòu)建緩存。這可以在多個(gè)構(gòu)建之間共享緩存,加快構(gòu)建速度。
  5. 使用.dockerignore文件: 在項(xiàng)目根目錄下創(chuàng)建.dockerignore文件,排除不必要的文件和目錄,這樣可以減少構(gòu)建上下文的大小,從而加快構(gòu)建速度。
  6. 利用Docker構(gòu)建緩存指令: 在Dockerfile中使用一些不更改鏡像層的指令,如COPY和ADD,這些指令不會(huì)使構(gòu)建緩存失效,可以最大化地利用構(gòu)建緩存。

通過(guò)遵循上述最佳實(shí)踐,可以最大程度地利用Docker的構(gòu)建緩存,減少構(gòu)建時(shí)間和資源消耗,提高構(gòu)建效率。

2.3 保持鏡像清潔

保持鏡像清潔是維護(hù) Docker 環(huán)境的重要實(shí)踐,可以通過(guò)以下方法來(lái)實(shí)現(xiàn):

  1. 定期清理無(wú)用鏡像和容器: 運(yùn)行docker image prunedocker container prune命令可以清理掉未使用的鏡像和容器。無(wú)用的鏡像和容器會(huì)占用存儲(chǔ)空間,并且可能導(dǎo)致資源浪費(fèi)。
  2. 避免構(gòu)建過(guò)多的中間鏡像層: 在編寫(xiě) Dockerfile 時(shí),盡量合并多個(gè)命令到一個(gè) RUN 指令中,以減少中間鏡像層的數(shù)量。這樣可以降低鏡像的大小,并減少構(gòu)建和存儲(chǔ)資源的消耗。
  3. 刪除不必要的文件和目錄: 確保在構(gòu)建鏡像時(shí)清理掉不必要的臨時(shí)文件、APT 緩存和其他不需要的文件。在使用 RUN 指令安裝軟件包后,可以執(zhí)行清理命令,如 apt-get clean、rm -rf /var/cache/apt/*等,以減小鏡像大小。
  4. 避免在運(yùn)行時(shí)產(chǎn)生大量臨時(shí)文件: 在應(yīng)用程序設(shè)計(jì)中,盡量避免在運(yùn)行時(shí)產(chǎn)生大量臨時(shí)文件,以防止鏡像過(guò)度膨脹。如果必須產(chǎn)生臨時(shí)文件,建議將其放置在臨時(shí)文件系統(tǒng)中,以便容器停止時(shí)自動(dòng)清理。
  5. 使用多階段構(gòu)建(Multi-stage builds): 對(duì)于需要編譯或打包的應(yīng)用程序,可以使用多階段構(gòu)建來(lái)減少最終鏡像的大小。在第一個(gè)階段中,構(gòu)建應(yīng)用程序,并將構(gòu)建好的文件復(fù)制到第二個(gè)階段中。第二個(gè)階段只包含運(yùn)行時(shí)所需的最小文件和依賴項(xiàng)。
  6. 定期審查和更新鏡像: 定期審查鏡像并更新其中的軟件包和依賴項(xiàng),以確保鏡像中的軟件包都是最新的版本。可以使用漏洞掃描工具(如 Clair、Trivy 等)來(lái)檢查鏡像中的漏洞,并及時(shí)修復(fù)。
  7. 使用最小化的基礎(chǔ)鏡像: 選擇輕量級(jí)的基礎(chǔ)鏡像,如 Alpine Linux,而不是通用的 Linux 發(fā)行版,以減小鏡像的大小。避免使用包含大量預(yù)安裝軟件包和依賴項(xiàng)的基礎(chǔ)鏡像。

通過(guò)采取上述措施,可以保持 Docker 環(huán)境中的鏡像清潔,減小鏡像大小,提高鏡像的安全性和可維護(hù)性,同時(shí)節(jié)省存儲(chǔ)和網(wǎng)絡(luò)帶寬資源。

2.4 使用多階段構(gòu)建

多階段構(gòu)建(Multi-stage builds)是一種優(yōu)化 Docker 鏡像構(gòu)建過(guò)程的方法,通過(guò)在一個(gè) Dockerfile 中定義多個(gè)構(gòu)建階段來(lái)實(shí)現(xiàn)。每個(gè)階段都可以基于不同的基礎(chǔ)鏡像,并且可以包含不同的構(gòu)建步驟,最終只將最終產(chǎn)物復(fù)制到最終的鏡像中。這樣可以減小最終鏡像的大小,同時(shí)減少構(gòu)建過(guò)程中的資源消耗。
以下是使用多階段構(gòu)建的基本方法:

  1. 定義多個(gè)構(gòu)建階段: 在 Dockerfile 中使用多個(gè) FROM 指令來(lái)定義多個(gè)構(gòu)建階段。每個(gè) FROM 指令表示一個(gè)新的構(gòu)建階段的開(kāi)始。通常第一個(gè)階段用于編譯或打包應(yīng)用程序,而后續(xù)的階段用于創(chuàng)建最終的運(yùn)行時(shí)鏡像。
  2. 在每個(gè)階段中執(zhí)行必要的構(gòu)建步驟: 在每個(gè)構(gòu)建階段中執(zhí)行必要的構(gòu)建步驟,包括安裝依賴項(xiàng)、編譯代碼、打包應(yīng)用程序等。每個(gè)階段可以基于不同的基礎(chǔ)鏡像,并且可以獨(dú)立地執(zhí)行自己的構(gòu)建步驟。
  3. 將必要的文件復(fù)制到最終階段: 在最后一個(gè)構(gòu)建階段中,使用 COPY 指令將之前階段中生成的必要文件復(fù)制到最終的鏡像中。通常只需要復(fù)制運(yùn)行時(shí)所需的最小文件和依賴項(xiàng)。
  4. 刪除不必要的中間文件: 在每個(gè)構(gòu)建階段結(jié)束時(shí),可以使用 RUN 指令刪除不必要的臨時(shí)文件和依賴項(xiàng),以減小鏡像的大小。

使用多階段構(gòu)建可以幫助減小鏡像的大小,并且可以降低構(gòu)建過(guò)程中的資源消耗,同時(shí)提高了鏡像的安全性和可維護(hù)性。

2.5 安全性考慮

在 Docker 容器中,保證安全性是至關(guān)重要的。以下是一些在 Docker 環(huán)境中考慮安全性的重要方面:

  1. 使用官方鏡像或受信任的基礎(chǔ)鏡像: 建議使用官方提供的鏡像或來(lái)自受信任來(lái)源的基礎(chǔ)鏡像作為應(yīng)用程序的基礎(chǔ)。官方鏡像通常受到更嚴(yán)格的審查和維護(hù),因此更加安全可靠。
  2. 定期更新鏡像: 定期更新基礎(chǔ)鏡像和應(yīng)用程序鏡像,以確保其中包含的軟件包和依賴項(xiàng)都是最新的版本。及時(shí)更新可以修復(fù)已知的安全漏洞和問(wèn)題,提高鏡像的安全性。
  3. 最小化容器權(quán)限: 在運(yùn)行容器時(shí),盡量以非特權(quán)用戶身份運(yùn)行應(yīng)用程序,避免使用 root 用戶。限制容器的權(quán)限可以減小攻擊面,提高容器的安全性。
  4. 使用容器內(nèi)防火墻: 在容器內(nèi)部配置防火墻規(guī)則,限制網(wǎng)絡(luò)流量的進(jìn)出,只允許必要的端口和協(xié)議。這可以防止惡意攻擊者通過(guò)容器內(nèi)部的漏洞進(jìn)行攻擊。
  5. 審查 Dockerfile 和鏡像內(nèi)容: 審查 Dockerfile 中的每一步和每個(gè)基礎(chǔ)鏡像中的內(nèi)容,確保其中沒(méi)有包含不必要的軟件包和依賴項(xiàng),以及惡意代碼。同時(shí),審查鏡像中的文件和目錄,查找潛在的安全漏洞。
  6. 限制容器資源: 使用 Docker 容器的資源限制功能,限制容器的 CPU、內(nèi)存、網(wǎng)絡(luò)和磁盤等資源使用,防止惡意容器占用過(guò)多的系統(tǒng)資源,造成拒絕服務(wù)攻擊。
  7. 加強(qiáng)容器間隔離: 使用 Docker 的安全特性,如命名空間和控制組,加強(qiáng)容器之間的隔離性,防止容器間的信息泄漏和攻擊。
  8. 監(jiān)控和日志記錄: 配置適當(dāng)?shù)谋O(jiān)控和日志記錄系統(tǒng),實(shí)時(shí)監(jiān)控容器的運(yùn)行狀態(tài)和安全事件,及時(shí)發(fā)現(xiàn)并響應(yīng)潛在的安全威脅。

保證 Docker 容器的安全性需要綜合考慮多個(gè)方面,并采取一系列措施來(lái)加強(qiáng)容器的安全性。及時(shí)更新鏡像、最小化容器權(quán)限、使用容器內(nèi)防火墻、審查 Dockerfile 和鏡像內(nèi)容等都是保障 Docker 容器安全的重要措施。

三、示例

3.1 基本示例

以下是一個(gè)簡(jiǎn)單的 Dockerfile 示例,用于構(gòu)建一個(gè)基于 Node.js 的 web 應(yīng)用程序鏡像:

# 使用官方 Node.js 鏡像作為基礎(chǔ)鏡像
FROM node:14

# 設(shè)置工作目錄
WORKDIR /app

# 復(fù)制 package.json 和 package-lock.json 到工作目錄
COPY package*.json ./

# 安裝應(yīng)用程序依賴
RUN npm install

# 將應(yīng)用程序文件復(fù)制到工作目錄
COPY . .

# 暴露端口
EXPOSE 3000

# 定義容器啟動(dòng)時(shí)運(yùn)行的命令
CMD ["node", "app.js"]

在這個(gè)示例中:

  • 使用 FROM 指令選擇官方 Node.js 14 鏡像作為基礎(chǔ)鏡像。
  • 使用 WORKDIR 指令設(shè)置工作目錄為 /app。
  • 使用 COPY 指令將 package.jsonpackage-lock.json 文件復(fù)制到工作目錄。
  • 使用 RUN 指令運(yùn)行 npm install 命令安裝應(yīng)用程序依賴。
  • 使用 COPY 指令將應(yīng)用程序文件復(fù)制到工作目錄。
  • 使用 EXPOSE 指令暴露端口 3000。
  • 使用 CMD 指令定義容器啟動(dòng)時(shí)運(yùn)行的命令,這里是運(yùn)行 node app.js。

這個(gè) Dockerfile 示例用于構(gòu)建一個(gè)簡(jiǎn)單的 Node.js web 應(yīng)用程序鏡像。你可以根據(jù)自己的實(shí)際需求和應(yīng)用程序進(jìn)行相應(yīng)的修改和定制。

3.2 多階段構(gòu)建示例

以下是一個(gè)使用多階段構(gòu)建的 Dockerfile 示例,用于構(gòu)建一個(gè)基于 Go 語(yǔ)言的靜態(tài)網(wǎng)站生成器的鏡像:

# 第一階段:編譯 Go 應(yīng)用程序
FROM golang:1.17 AS builder

WORKDIR /app

# 將源代碼復(fù)制到工作目錄
COPY . .

# 編譯應(yīng)用程序
RUN go build -o static-generator .

# 第二階段:創(chuàng)建最終鏡像
FROM alpine:latest

# 設(shè)置工作目錄
WORKDIR /app

# 從第一階段中復(fù)制編譯好的應(yīng)用程序
COPY --from=builder /app/static-generator .

# 設(shè)置容器啟動(dòng)時(shí)的命令
CMD ["./static-generator"]

在這個(gè)示例中:

  • 第一階段使用 golang:1.17 作為基礎(chǔ)鏡像,并在其中編譯 Go 應(yīng)用程序。
  • 第二階段使用 alpine:latest 作為基礎(chǔ)鏡像,并從第一階段中復(fù)制編譯好的應(yīng)用程序。
  • 最終的鏡像只包含了編譯好的應(yīng)用程序文件,而不包含編譯工具和其他不必要的文件。

這個(gè)示例演示了如何使用多階段構(gòu)建來(lái)減小最終鏡像的大小,并且使鏡像更加精簡(jiǎn)。

3.3 鏡像優(yōu)化示例

以下是一個(gè)鏡像優(yōu)化示例,假設(shè)我們要構(gòu)建一個(gè)基于 Python 的 Web 應(yīng)用程序鏡像:

# 使用官方 Python 鏡像作為基礎(chǔ)鏡像
FROM python:3.9-slim

# 設(shè)置工作目錄
WORKDIR /app

# 復(fù)制依賴文件到工作目錄
COPY requirements.txt .

# 安裝依賴
RUN pip install --no-cache-dir -r requirements.txt

# 復(fù)制應(yīng)用程序文件到工作目錄
COPY . .

# 設(shè)置環(huán)境變量
ENV FLASK_APP=app.py

# 暴露端口
EXPOSE 5000

# 啟動(dòng)應(yīng)用程序
CMD ["flask", "run", "--host=0.0.0.0"]

這個(gè) Dockerfile 示例進(jìn)行了一些鏡像優(yōu)化:

  1. 使用 python:3.9-slim 作為基礎(chǔ)鏡像。-slim 版本相比標(biāo)準(zhǔn)版本來(lái)說(shuō)更小,因?yàn)樗话~外的依賴項(xiàng)和工具。
  2. 使用 --no-cache-dir 選項(xiàng)在 pip install 中安裝 Python 依賴項(xiàng),這可以避免在鏡像中生成緩存文件,減小鏡像的體積。
  3. 設(shè)置了 FLASK_APP 環(huán)境變量,以指定 Flask 應(yīng)用程序的入口文件。
  4. 使用 EXPOSE 指令暴露應(yīng)用程序的端口。
  5. 使用 CMD 指令定義容器啟動(dòng)時(shí)運(yùn)行的命令,這里是啟動(dòng) Flask 應(yīng)用程序。

通過(guò)以上優(yōu)化,可以使得鏡像更加精簡(jiǎn)、高效,減小鏡像的大小,同時(shí)保證了容器的安全性和可靠性。

四、總結(jié)

本文介紹了編寫(xiě)Docker鏡像構(gòu)建腳本的基礎(chǔ)知識(shí)。首先,通過(guò)FROM指令選擇基礎(chǔ)鏡像,然后使用RUN指令運(yùn)行命令,COPY和ADD指令復(fù)制文件,CMD和ENTRYPOINT指令定義容器啟動(dòng)時(shí)執(zhí)行的命令。另外,還介紹了WORKDIR、ENV、EXPOSE、VOLUME、ARG、LABEL等指令的用法。了解并熟練使用這些指令,能夠有效地構(gòu)建出高效、可靠的Docker鏡像。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-830629.html

到了這里,關(guān)于《Docker極簡(jiǎn)教程》--Dockerfile--Dockerfile的基本語(yǔ)法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Docker容器:docker鏡像的創(chuàng)建及dockerfile

    Docker容器:docker鏡像的創(chuàng)建及dockerfile

    創(chuàng)建鏡像有三種方法:基于現(xiàn)有鏡像創(chuàng)建、基于本地模板創(chuàng)建及基于dockerfile創(chuàng)建 1.1 啟動(dòng)鏡像 1.2 生成新鏡像 2.1 OPENVZ 下載模板 2.2 導(dǎo)入容器生成鏡像 3.1 dockerfile結(jié)構(gòu)及分層 (1)dockerfile結(jié)構(gòu)大致分為4個(gè)部分 基礎(chǔ)鏡像信息 維護(hù)者信息 鏡像操作指令 容器啟動(dòng)時(shí)執(zhí)行指令 Dockerfil

    2024年02月11日
    瀏覽(93)
  • Docker容器---dockerfile簡(jiǎn)介

    Docker容器---dockerfile簡(jiǎn)介

    1、dockerfile介紹 dockerfile是自定義鏡像的一套規(guī)則,dockerfie由多條指令構(gòu)成,Dockerfile中的每一條指令都會(huì)對(duì)應(yīng)于Docker鏡像中的每一層。Docker鏡像是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序、庫(kù)、資源、配置等文件外,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(

    2023年04月23日
    瀏覽(26)
  • Docker容器 - DockerFile詳解

    Docker容器 - DockerFile詳解

    目錄 DockerFile 一、是什么 二、構(gòu)建步驟 DockerFile構(gòu)建過(guò)程 一、DockerFile基礎(chǔ) 二、Docker執(zhí)行DockerFile的流程 三、總結(jié) DockerFile常用保留字 零、參考Tomcat的DockerFile 一、FROM 二、MAINTAINER 三、RUN 1.shell 2.exec 四、EXPOSE 五、WORKDIR 六、USER 七、ENV 八、ADD 九、COPY 十、VOLUME 十一、CMD 1.舉個(gè)

    2024年02月15日
    瀏覽(23)
  • 【Docker】Docker容器數(shù)據(jù)卷、容器卷之間的繼承和DockerFIle的詳細(xì)講解

    【Docker】Docker容器數(shù)據(jù)卷、容器卷之間的繼承和DockerFIle的詳細(xì)講解

    ??歡迎來(lái)到本文?? ??個(gè)人簡(jiǎn)介:陳童學(xué)哦,目前學(xué)習(xí)C/C++、算法、Python、Java等方向,一個(gè)正在慢慢前行的普通人。 ??系列專欄:陳童學(xué)的日記 ??其他專欄:C++STL,感興趣的小伙伴可以看看。 ??希望各位→點(diǎn)贊?? + 收藏?? + 留言?? ? ??萬(wàn)物從心起,心動(dòng)則萬(wàn)物動(dòng)??

    2024年02月14日
    瀏覽(25)
  • Docker容器:docker數(shù)據(jù)管理、鏡像的創(chuàng)建及dockerfile案例

    Docker容器:docker數(shù)據(jù)管理、鏡像的創(chuàng)建及dockerfile案例

    因?yàn)閿?shù)據(jù)寫(xiě)入后如果停止了容器,再開(kāi)啟數(shù)據(jù)就會(huì)消失,使用數(shù)據(jù)管理的數(shù)據(jù)卷掛載,實(shí)現(xiàn)了數(shù)據(jù)的持久化,重啟數(shù)據(jù)還會(huì)存在;還有一種方式,容器之間共享文件即相當(dāng)于有個(gè)備份,也會(huì)解決停止容器后數(shù)據(jù)消失的問(wèn)題。 管理 Docker 容器中數(shù)據(jù)主要有兩種方式:數(shù)據(jù)卷(

    2024年02月12日
    瀏覽(27)
  • Docker容器與虛擬化技術(shù):Docker鏡像創(chuàng)建、Dockerfile實(shí)例

    Docker容器與虛擬化技術(shù):Docker鏡像創(chuàng)建、Dockerfile實(shí)例

    目錄 一、理論 1.Docker鏡像的創(chuàng)建方法 2.Docker鏡像結(jié)構(gòu)的分層 3.Dockerfile 案例 4.構(gòu)建Systemctl鏡像(基于SSH鏡像) 5.構(gòu)建Tomcat 鏡像 6.構(gòu)建Mysql鏡像 二、實(shí)驗(yàn) 1.Docker鏡像的創(chuàng)建 2.?Dockerfile 案例 3.構(gòu)建Systemctl鏡像(基于SSH鏡像) 三、問(wèn)題 1.nginx網(wǎng)頁(yè)打不開(kāi) ?2.Apache容器啟動(dòng)一直為Ex

    2024年02月12日
    瀏覽(94)
  • 《Docker極簡(jiǎn)教程》--前言--Docker的簡(jiǎn)介

    Docker 是一種用于構(gòu)建、部署和運(yùn)行應(yīng)用程序的開(kāi)源平臺(tái),它使用容器技術(shù)來(lái)實(shí)現(xiàn)輕量級(jí)、可移植和自包含的應(yīng)用程序環(huán)境。Docker 的核心思想是將應(yīng)用程序及其依賴項(xiàng)打包到一個(gè)稱為容器的封閉單元中,從而消除了在不同環(huán)境中運(yùn)行應(yīng)用程序時(shí)可能出現(xiàn)的許多兼容性和依賴性

    2024年02月21日
    瀏覽(23)
  • Docker容器化技術(shù)(使用Dockerfile制作鏡像)

    Docker容器化技術(shù)(使用Dockerfile制作鏡像)

    Docker 支持通過(guò)擴(kuò)展現(xiàn)有鏡像,創(chuàng)建新的鏡像。實(shí)際上,Docker Hub 中 99% 的鏡像都是通過(guò)在 base 鏡像中安裝和配置需要的軟件構(gòu)建出來(lái)的。 1、Docker 鏡像為什么分層 鏡像分層最大的一個(gè)好處就是共享資源。 比如說(shuō)有多個(gè)鏡像都從相同的 base 鏡像構(gòu)建而來(lái),那么 Docker Host 只需在

    2024年03月19日
    瀏覽(861)
  • docker容器:docker鏡像的三種創(chuàng)建方法及dockerfile案例

    docker容器:docker鏡像的三種創(chuàng)建方法及dockerfile案例

    目錄 一、基于現(xiàn)有鏡像創(chuàng)建 1、創(chuàng)建啟動(dòng)鏡像 2、生成新鏡像 二、基于本地模板創(chuàng)建? 1、OPENVZ 下載模板 2、導(dǎo)入容器生成鏡像 三、基于dockerfile創(chuàng)建? 1、dockerfile結(jié)構(gòu)及分層 2、聯(lián)合文件系統(tǒng) 3、docker鏡像加載原理 4、dockerfile操作常用的指令 (1)FROM指令 (2)MAINTAINER 指令 (3)RUN指令

    2023年04月20日
    瀏覽(41)
  • 《Docker極簡(jiǎn)教程》--Docker網(wǎng)絡(luò)--Docker網(wǎng)絡(luò)的概念

    深入了解 Docker 網(wǎng)絡(luò)對(duì)于使用 Docker 構(gòu)建和管理容器化應(yīng)用程序的開(kāi)發(fā)人員和運(yùn)維人員來(lái)說(shuō)至關(guān)重要。 網(wǎng)絡(luò)是容器化應(yīng)用程序的核心組成部分 :在容器化應(yīng)用程序中,網(wǎng)絡(luò)不僅用于容器之間的通信,還用于與外部系統(tǒng)和服務(wù)進(jìn)行交互。了解 Docker 網(wǎng)絡(luò)如何工作可以幫助確保應(yīng)

    2024年02月21日
    瀏覽(24)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包