dockerfile 最佳實踐及示例


Dockerfile 最佳實踐已經出現在官方文檔中,地址在 Best practices for writing Dockerfiles。如果再寫一份最佳實踐,倒有點關公門前耍大刀之意。因此本篇文章是對官方文檔的翻譯,理解,擴展與示例補充

容器應該是短暫的

通過 Dockerfile 構建的鏡像所啟動的容器應該盡可能短暫 (ephemeral)。短暫意味着可以很快地啟動並且終止

使用 .dockerignore 排除構建無關文件

.dockerignore 語法與 .gitignore 語法一致。使用它排除構建無關的文件及目錄,如 node_modules

使用多階段構建

多階段構建可以有效減小鏡像體積,特別是對於需編譯語言而言,一個應用的構建過程往往如下

  1. 安裝編譯工具
  2. 安裝第三方庫依賴
  3. 編譯構建應用

而在前兩步會有大量的鏡像體積冗余,使用多階段構建可以避免這一問題

這是構建 Go 應用的一個示例

FROM golang:1.11-alpine AS build

# Install tools required for project
# Run `docker build --no-cache .` to update dependencies
RUN apk add --no-cache git
RUN go get github.com/golang/dep/cmd/dep

# List project dependencies with Gopkg.toml and Gopkg.lock
# These layers are only re-built when Gopkg files are updated
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
# Install library dependencies
RUN dep ensure -vendor-only

# Copy the entire project and build it
# This layer is rebuilt when a file changes in the project directory
COPY . /go/src/project/
RUN go build -o /bin/project

# This results in a single layer image
FROM scratch
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]

這是構建前端應用的一個示例,可以參考 如何使用 docker 高效部署前端應用

FROM node:10-alpine as builder

ENV PROJECT_ENV production
ENV NODE_ENV production

# http-server 不變動也可以利用緩存
WORKDIR /code

ADD package.json /code
RUN npm install --production

ADD . /code
RUN npm run build

# 選擇更小體積的基礎鏡像
FROM nginx:10-alpine
COPY --from=builder /code/public /usr/share/nginx/html

避免安裝不必要的包

減小體積,減少構建時間。如前端應用使用 npm install --production 只裝生產環境所依賴的包。

一個容器只做一件事

如一個web應用將會包含三個部分,web 服務,數據庫與緩存。把他們解耦到多個容器中,方便橫向擴展。如果你需要網絡通信,則可以將他們至於一個網絡下。

如在我的個人服務器中,我使用 traefik 做負載均衡與服務發現,所有應用及數據庫都在 traefik_default 網絡下,詳情參考 使用 traefik 做負載均衡與服務發現

version: '3'

services:
  # 該鏡像會暴露出自身的 `header` 信息
  whoami:
    image: containous/whoami
    restart: always
    labels:
      # 設置Host 為 whoami.docker.localhost 進行域名訪問
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

# 使用已存在的 traefik 的 network
networks:
  default:
    external:
      name: traefik_default

減少鏡像層數

  • 只有 RUN, COPY, ADD 會創建層數, 其它指令不會增加鏡像的體積
  • 盡可能使用多階段構建

使用以下方法安裝依賴

RUN yum install -y node python go

錯誤的方法安裝依賴,這將增加鏡像層數

RUN yum install -y node
RUN yum install -y python
RUN yum install -y go

將多行參數排序

便於可讀性以及不小心地重復裝包

RUN apt-get update && apt-get install -y \
  bzr \
  cvs \
  git \
  mercurial \
  subversion

充分利用構建緩存

在鏡像的構建過程中 docker 會遍歷 Dockerfile 文件中的所有指令,順序執行。對於每一條指令,docker 都會在緩存中查找是否已存在可重用的鏡像,否則會創建一個新的鏡像

我們可以使用 docker build --no-cache 跳過緩存

  • ADDCOPY 將會計算文件的 checksum 是否改變來決定是否利用緩存
  • RUN 僅僅查看命令字符串是否命中緩存,如 RUN apt-get -y update 可能會有問題

如一個 node 應用,可以先拷貝 package.json 進行依賴安裝,然后再添加整個目錄,可以做到充分利用緩存的目的。

FROM node:10-alpine as builder

WORKDIR /code

ADD package.json /code
# 此步將可以充分利用 node_modules 的緩存
RUN npm install --production

ADD . /code

RUN npm run build 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM