前言
本文參考Docker官方文檔
撰寫Dockerfile我們有幾個大前提
- 變化最少的部分放在Dockerfile的前面,變化大的放在後面,這樣持續集成的時候可以重複使用之前的layer
- 一個容器應該只運行單個應用,不要寫一個腳本在一個容器中同時運行多個應用
構建高效和可維護的鏡像
.dockerignore
- 防止不需要的文件拷貝到
build context
- 寫法和.gitignore相似,請參考
使用多階段構建
FROM golang:1.11.1-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"]
FROM
- FROM基礎鏡像時最好精確到最小範圍的版本,而不要直接使用大版本和latest。比如
FROM golang:1.12.1
, 而不是FROM golang:1.12
,FROM golang:latest
- 可以根據需要選擇alpine鏡像,不過編譯時可能要添加
CGO_ENABLED=0
RUN
- 將多個RUN指令合併到一個
- 每個RUN指令後刪除多餘文件,例如:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y nodejs \
# added lines
&& rm -rf /var/lib/apt/lists/*
ADD . /app
RUN cd /app && npm install
CMD npm start
COPY&ADD
- 儘量將多個COPY指令合併到一個
- 儘量將多個ADD指令合併到一個
- COPY指令非常簡單,僅用於將文件拷貝到鏡像中。ADD相對來講複雜一些,可以用於下載遠程文件以及解壓壓縮包
- 如果你確定只是拷貝文件進入鏡像中,那麼直接使用COPY
- 如果你是需要下載文件等,那麼使用ADD
COPY&RUN
我們應該把變化最少的部分放在 Dockerfile 的前面,這樣可以充分利用鏡像緩存。
示例中,源代碼會經常變化,則每次構建鏡像時都需要重新安裝 NPM 模塊,這顯然不是我們希望看到的。因此我們可以先拷貝package.json,然後安裝 NPM 模塊,最後才拷貝其餘的源代碼。這樣的話,即使源代碼變化,也不需要重新安裝 NPM 模塊。
FROM node:10.18.1-alpine3.9
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
ENTRYPOINT ["./entrypoint.sh"]
CMD ["start"]
LABEL
- 儘量把多個LABEL標籤合併
例如:
# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"