Dockerfile 最佳實踐已經出現在官方文檔中,地址在 Best practices for writing Dockerfiles。如果再寫一份最佳實踐,倒有點關公門前耍大刀之意。因此本篇文章是對官方文檔的翻譯,理解,擴展與示例補充
容器應該是短暫的
通過 Dockerfile
構建的鏡像所啟動的容器應該盡可能短暫 (ephemeral)。短暫意味着可以很快地啟動並且終止
使用 .dockerignore 排除構建無關文件
.dockerignore
語法與 .gitignore
語法一致。使用它排除構建無關的文件及目錄,如 node_modules
使用多階段構建
多階段構建可以有效減小鏡像體積,特別是對於需編譯語言而言,一個應用的構建過程往往如下
- 安裝編譯工具
- 安裝第三方庫依賴
- 編譯構建應用
而在前兩步會有大量的鏡像體積冗余,使用多階段構建可以避免這一問題
這是構建 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
跳過緩存
ADD
和COPY
將會計算文件的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