Dockerfile編寫規(guī)范檢查工具
hadolint是一個檢查Dockerfile是否符合編寫規(guī)范的工具。使用起來非常簡單拴袭,從GitHub上下載對應(yīng)系統(tǒng)的可執(zhí)行文件然后執(zhí)行:
hadolint Dockerfile
GitHub官網(wǎng)和介紹:https://github.com/hadolint/hadolint/blob/master/README.md
查看Docker構(gòu)建歷史
對于已有鏡像,可以查看docker image構(gòu)建歷史和每層大小沽损,決定是否需要優(yōu)化渐排。
docker history <image>
最佳實踐
Docker官網(wǎng)最佳實踐講解:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
保持鏡像簡單
- 不要將多個應(yīng)用打包到一個鏡像中屈暗。
- 不要安裝用不到的軟件包。
- 減少鏡像的層數(shù)屏富。將RUN命令的內(nèi)容合并在一起晴竞,形成一條RUN命令。
使用.dockerignore
在不影響項目結(jié)構(gòu)的情況下役听,可以使用.dockerignore
文件(寫法和.gitignore類似)颓鲜,排除不需要加入鏡像的文件。
使用多階段構(gòu)建
多階段構(gòu)建可以顯著減少最終鏡像占用的空間大小典予。
一個典型的用法是將項目編譯和和最終使用環(huán)境分離開甜滨。這樣最終鏡像不會包含編譯過程的中間產(chǎn)物。
# syntax=docker/dockerfile:1
FROM golang:1.16-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"]
Dockerfile指令順序
Dockerfile中盡量把可能發(fā)生變化的指令放在后面瘤袖。這樣構(gòu)建時可以充分利用鏡像緩存衣摩。
容器內(nèi)不要使用sudo
不能使用sudo。sudo和su命令處理signal的時候會有非常奇怪的問題捂敌。sudo的進程號為1艾扮,sudo后命令的進程號不是1。只有PID為1的進程才會響應(yīng)系統(tǒng)發(fā)送過來的信號量占婉。所以容器內(nèi)不能使用sudo su等命令啟動應(yīng)用進程泡嘴。
解決方法:
- 如果入口腳本不需要root用戶執(zhí)行,建議使用Dockerfile的USER指令逆济,在
CMD
/ENTRYPOINT
之前切換用戶酌予。 - 如果入口腳本需要用root執(zhí)行,但是啟動主進程的時候需要其他用戶奖慌,建議使用gosu抛虫。可參考:https://blog.csdn.net/boling_cavalry/article/details/93380447
主進程PID需要為1
如果主進程PID不為1简僧,Docker容器主進程無法響應(yīng)系統(tǒng)signal建椰。
為了確保主進程PID為1,入口腳本執(zhí)行主進程的時候必須使用exec <啟動命令>
方式調(diào)用岛马。例如:
exec gosu redis "$0" "@"
apt-get之后需要清理
不推薦的使用方式:
RUN apt-get update && apt-get install -y python
推薦的使用方式:
RUN apt-get update && apt-get install -y python \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR 需要使用絕對路徑
WORKDIR使用相對路徑的話棉姐,需要搞清楚上文中的WORKDIR屠列。上文中的WORKDIR可能隱藏在了base image中,出現(xiàn)問題非常難以排查伞矩。因此WORKDIR需要使用絕對路徑脸哀。
Dockerfile中使用root用戶執(zhí)行命令之后,一定要切換會非root用戶
不推薦使用:
FROM debian:buster
USER root
RUN ...
推薦使用:
FROM debian:buster
USER root
RUN ...
USER guest
使用WORKDIR 切換工作目錄扭吁,盡量不要使用cd命令。
建議所有的路徑使用絕對路徑盲镶。
RUN命令中如果使用了cd命令侥袜,僅在這一條RUN中生效。后面RUN命令的目錄會回到WORKDIR溉贿。
base image需要指定版本
不推薦使用:
FROM debian:latest
推薦使用:
FROM debian:jessie
yum apt-get等命令安裝軟件包時使用-y參數(shù)
不加-y
很容易遇到問題中斷構(gòu)建過程枫吧。
pip安裝時添加參數(shù)--no-cache-dir
在Docker鏡像中沒有緩存軟件包的必要。加上此參數(shù)可減小鏡像空間占用宇色。
RUN pip3 install --no-cache-dir foobar
apk安裝軟件使用--no-cache參數(shù)
FROM alpine:3.7
RUN apk --no-cache add foo=1.0
apt yum pip等包管理工具安裝軟件時需要指定軟件包版本
如果不指定版本號九杂,隨著軟件包的更新,不同時間構(gòu)建出的鏡像中安裝的軟件包版本可能會不同宣蠕。
不要使用apt命令例隆,使用apt-get
apt是一個用戶終端工具。它的行為不穩(wěn)定抢蚀,可能隨著版本的變化而變化镀层。不推薦使用。
yum dnf zypper 等安裝軟件包之后需要執(zhí)行clean all
例如:
RUN yum install -y httpd-2.24.2 && yum clean all
RUN dnf install -y httpd-2.24.2 && dnf clean all
RUN zypper install -y httpd=2.4.46 && zypper clean
添加文件和目錄的時候使用COPY命令
僅僅在需要使用自動解壓(將tar或者zip解壓到鏡像某個目錄中)的時候才允許使用ADD皿曲。其他情況一律使用COPY唱逢。
useradd需要指定-l參數(shù)
英文解釋如下:
Without the -l or the --no-log-init flag, useradd will add the user to the lastlog and faillog databases. This can result in the creation of logically large (sparse) files under /var/log, which in turn unnecessarily inflates container image sizes. This is due to the lack of support for sparse files in overlay filesystems.
大致解釋為如果不添加-l
或者是--no-log-init
,useradd
命令會把用戶加入lastlog和faillog數(shù)據(jù)庫屋休。會在/var/log
目錄創(chuàng)建大量的疏松文件坞古。Docker image用的是overlay文件系統(tǒng),對這種疏松文件的支持不足劫樟。建議創(chuàng)建用戶時添加-l
或者--no-log-init
痪枫。
使用cd ... || exit代替簡單的cd
構(gòu)建時cd命令可能會失敗,但是構(gòu)建會繼續(xù)執(zhí)行毅哗。后續(xù)的構(gòu)建命令會在錯誤的目錄中執(zhí)行听怕。
需要使用cd ... || exit(function內(nèi)使用cd ... || return)可以在cd遇到錯誤的時候退出構(gòu)建。
wget大文件需要使用--progress參數(shù)
可以避免打印過多的日志虑绵。
FROM ubuntu:20
RUN wget --progress=dot:giga https://example.com/big_file.tar