Dockerfile编写最佳实践

写Dockerfile不是把应用塞进镜像就完事。踩过坑的都知道,镜像体积动辄几个G、构建慢到怀疑人生、安全漏洞一堆,基本都是Dockerfile写得太随意。下面是我日常总结的硬核实践,直接照着改。 1. 基础镜像选alpine或slim 能用alpine就别用ubuntu。一个python:3.11-slim才40MB,python:3.11直接干到900MB。alpine的包管理器apk比apt快,而且musl libc对如果遇到编译依赖问题,用-slim版加build-deps临时安装编译工具,构建完删掉。
FROM python:3.11-alpine AS builder
# 编译阶段用alpine,最终镜像切到slim
2. 多阶段构建是必选项 一个典型场景:Go编译需要golang镜像,但运行只需要scratch。分阶段:
FROM golang:1.21 AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o server .

FROM alpine:3.19
COPY --from=build /app/server /server
EXPOSE 8080
CMD ["/server"]
最终镜像只有alpine+二进制,没有go编译器。同理,前端构建用node镜像,产物丢到nginx镜像。 3. 合并RUN命令,减少层数 每个RUN、COPY都会生成一层。层数多了构建慢,推拉也慢。能用&&连接的绝不分行:
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        ca-certificates && \
    rm -rf /var/lib/apt/lists/*
注意清理apt缓存,否则那层会永久保留几百MB垃圾。 4. COPY放在利用构建缓存 Docker构建时每层都有缓存。把不会变的东西(比如apt源、pip依赖)先COPY,这样改代码时不会重新安装依赖:
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
如果先COPY整个项目再pip install,每次改代码都要重装依赖,神经病才这么写。 5. 指定精确版本tag,不用latest latest今天指向3.11明天可能变3.12,构建结果不可控。用python:3.11.5-slim而不是python:3.11-slim。基础镜像更新后本地缓存失效,构建可能突然报错。生产环境锁死版本号。 6. 用.dockerignore排除垃圾 类似.gitignore,把node_modules、.git、__pycache__、.env这些丢进去。否则docker会把整个项目目录发到daemon,构建慢到哭。
node_modules
.git
*.pyc
.env
Dockerfile
7. 非root用户运行 默认容器内是root,被攻破后宿主机也危险。创建专用用户:
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup
USER appuser
有些镜像自带用户(比如nginx的nginx用户),直接用就行。 8. 合理设置WORKDIR和EXPOSE WORKDIR /app 比 cd /app 干净。EXPOSE只是文档作用,实际端口映射在docker run -p指定。但写上能让阅读者知道应用监听哪个端口。 9. 健康检查 生产环境必须加HEALTHCHECK,不然容器挂了k8s不知道:
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1
10. 体积优化实战 一个Java应用,用maven构建后镜像1.2G。优化后:
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:17-jre-alpine
COPY --from=build /build/target/app.jar /app.jar
EXPOSE 8080
CMD ["java", "-jar", "/app.jar"]
最终镜像180MB。关键点:用jre而不是jdk,多阶段只留jar,alpine基础镜像。 11. 构建时ARG和ENV的区别 ARG只在构建时可用,ENV会写入镜像。敏感信息(比如私有仓库密码)用ARG –build-arg传,但注意ARG值会留在镜像历史中。真敏感信息用docker secret或挂载文件。
ARG APP_VERSION=1.0
ENV VERSION=$APP_VERSION
12. 生产环境用docker build –no-cache 测试时用缓存爽,上线前必须–no-cache。避免缓存导致旧版本依赖或漏洞没更新。CI/CD里直接加参数。 如果你要在云上跑这些优化过的镜像,推荐用雨云。他们家的容器服务性价比高,部署稳定,拉镜像速度也快,适合折腾这些最佳实践。

雨云是国内一家老牌云服务商,提供高性价比的云服务器和虚拟主机。我用它部署了好几个项目,速度和稳定性都不错。通过 https://www.rainyun.com/SAJA_ 注册可以领一张 5折优惠券,有需要的朋友可以看看。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容