









在云原生时代,容器化是应用交付的基石,而 Dockerfile 则是构建容器镜像的蓝图。本文整理自实战文档,详细解析如何编写 Dockerfile、常用指令的深层机制、多架构镜像构建方法以及镜像瘦身的最佳实践。
Dockerfile 是一个文本文件,它包含了一系列指令。Docker 能够读取这些指令,自动构建出一个定制化的镜像。每一条指令通常对应镜像中的一层。
FROM: 指定基础镜像。构建必须基于一个已存在的镜像(如 centos:7, alpine)。
# 使用官方 Python 3.9 Slim 版本作为基础镜像 FROM python:3.9-slim
LABEL (替代 MAINTAINER): 用于添加镜像的元数据,如作者信息、版本等。
LABEL maintainer="devops@example.com" LABEL version="1.0" LABEL description="This is a sample image"
USER: 指定运行容器时的用户名或 UID
# 创建用户并切换 RUN useradd -m tomcat -u 1001 USER 1001 -u 指定用户id -m 创建用户的时候创建家目录
WORKDIR: 设置工作目录。
RUN, CMD, COPY 等指令都会在该目录下执行。# 设置工作目录为 /app WORKDIR /app # 此时 copy 会将文件复制到 /app/config.json COPY config.json ./
COPY: 将宿主机文件复制到容器内。
COPY src dest 若 src 是目录,只会复制目录下的内容,不会复制目录本身。#复制文件并修改文件权限与属组 COPY --chown=huiye:huiye file /mnt/file COPY --chmod=644 file /mnt/file COPY --chown=huiye:huiye --chmod=644 file /mnt/file
ADD: 与 COPY 类似,但功能更高级。
# 自动解压 nginx.tar.gz 到 /usr/share/nginx/html/ ADD nginx.tar.gz /usr/share/nginx/html/
ENV: 设置环境变量。
docker run -e 的优先级高于 Dockerfile 中的 ENV。ENV APP_ENV=production
ENV APP_PORT=8080
# 在后续指令中使用变量
CMD ["java", "-jar", "app.jar", "--port=${APP_PORT}"]
ARG: 构建参数。
docker build 过程中有效,容器运行时不生效docker build --build-arg name=value 动态传入。FROM centos:7 LABEL maintainer="huiye" #设置一个参数为username ARG username #设置一个有默认值的参数path1,如果没有传入这个参数的值,则这个参数使用默认值"/home/hiuye" ARG path1="/home/huiye" ENV NAME=test1 #使用这个参数username RUN useradd -m $username -u 1001 USER 1001 WORKDIR $path1 CMD ["/bin/bash","-c","whoami && pwd"] #构建命令 docker build --build-arg username=huiyex --build-arg path1=/home/huiyex -t centos:arg .
RUN: 在构建镜像时执行的 Shell 命令。
&& 连接多条命令,并清理缓存以减小体积。RUN yum install -y net-tools && \
yum install -y iproute && \
yum clean all
CMD: 容器启动时的默认命令。
["executable", "param1", "param2"]。docker run 后面的命令会覆盖 Dockerfile 中的 CMD。FROM centos:7 LABEL maintainer="huiye" ENV NAME=test1 RUN useradd -m huiye -u 1001 USER 1001 WORKDIR /home/huiye CMD ["/bin/bash","-c","echo \"NAME=$NAME\""]
ENTRYPOINT: 也可以指定容器默认运行的程序
docker run 后面的命令会被追加到 ENTRYPOINT 之后,作为参数传递,而不是覆盖它。例:比如 docker run -it –rm –entrypoint ls centos:latest /tmp ,就是将 CMD 的 /tmp 作为参数传给 –entrypoint ls,那么容器内执行的就是 ls /tmp# 定义固定命令 ENTRYPOINT ["/bin/ping"] # 定义默认参数(可被覆盖) CMD ["--help"]
EXPOSE: 声明端口。仅仅是声明,方便阅读和映射,不会自动开启端口映射。
FROM centos:7 LABEL maintainer="huiye" ENV NAME=test1 RUN useradd -m huiye -u 1001 USER 1001 WORKDIR /home/huiye CMD ["/bin/bash","-c","echo \"NAME=$NAME\""] EXPOSE 80 EXPOSE 443
VOLUME: 定义匿名数据卷。即使启动时不指定 -v,容器也会自动挂载该目录。
# 在创建容器的时候,即使没有指定卷,默认就会有 -v /data VOLUME ["/data"] # 指定多个卷 VOLUME ["/var/log", "/var/db"]
| 指令 | 作用 | 被 docker run [command] 覆盖? |
| CMD | 指定默认命令 | 是,完全覆盖 |
| ENTRYPOINT | 指定入口程序 | 否,[command] 会作为参数传给 ENTRYPOINT |
实战用法: 将 ENTRYPOINT 设置为固定程序,CMD 设置为默认参数。
ENTRYPOINT ["/bin/my-app"] CMD ["--help"] # 运行 docker run my-image --help # 实际执行:/bin/my-app --help
nginx.tar.gz 放入容器并解压,使用 ADD nginx.tar.gz /usr/share/nginx/html/ 一步到位。docker build -t my-app:v2 -f Dockerfile3 . # -t: 指定镜像名和标签 # -f: 指定 Dockerfile 文件路径(不指定时默认为当前目录下的 Dockerfile) # .: 上下文目录(COPY 命令寻找文件的根目录)
配合 Dockerfile 中的 ARG 指令:
docker build --build-arg username=admin -t my-app:args .
随着 ARM 架构服务器的普及,构建支持多平台(x86_64/arm64)的镜像变得尤为重要。这需要使用 docker buildx。但是用来构建镜像的基础镜像也需要是 支持 ARM 架构的。可以在 hub 官方查看该镜像是否支持 ARM

查看当前构建器支持的架构:

建议安装一个新的构建器
docker buildx create --name mybuilder --use --platform linux/amd64,linux/arm64 --driver docker-container 参数解析 --name 自定义构建器的名称 --platform 指定构建器支持的目标平台 --driver docker-container 指定构建器的底层驱动模式为“容器化” --use 创建完成后,立即切换到这个构建器。省去了单独执行 docker buildx use mybuilder 的步骤。也就是说,接下来的 docker buildx build 命令都会默认使用这个新创建的 builder。 如需要删除 builder,使用以下命令 docker buildx rm mybuilder
此时看到使用 docker builder ls 可以看到这个builder是inactive 未启用的状态

激活构建器
docker buildx inspect --bootstrap

注:该命令会拉取 一个镜像 moby/buildkit:buildx-stable-1,如果网络不好的情况,可以提前把这个镜像下载到本地上
安装所有架构的仿真环境,用于构建ARM镜像
docker run --privileged --rm tonistiigi/binfmt --install all
可以看到增加了一些架构类型

构建并推送到镜像仓库
docker buildx build --platform linux/arm64 -t xxxhub/huiye-private/buildx:armv1 --push -f ./Dockerfile . 参数解析 --push 构建好了就直接推送到镜像仓库 若需要同时构建多种架构,可以把 linux/arm64 修改为 linux/arm64,linux/amd64
只构建不推送到镜像仓库
docker buildx build --platform linux/arm64/v8 -t xxxhub/huiye-private/buildx:armv2 -f ./Dockerfile . --load
这是减少镜像体积最有效的方法。将编译环境和运行环境分离。
示例:
FROM centos:7
RUN rm -rf /etc/yum.repos.d/*
COPY CentOS-7.repo /etc/yum.repos.d/
RUN yum install -y net-tools && \
yum install -y iproute
#第一次构建临时容器,编号为0
FROM centos:7
COPY --from=0 /usr/sbin/ifconfig /sbin/
COPY --from=0 /usr/sbin/ip /sbin/
CMD ["/bin/bash"]
#第二次构建临时容器,编号为1。
#COPY --from=0 意为从第一次构建的临时容器中拷贝文件到本次构建的临时容器内
也可以
FROM centos:7 AS builder
#给第一阶段起名为 builder
RUN rm -rf /etc/yum.repos.d/*
COPY CentOS-7.repo /etc/yum.repos.d/
RUN yum install -y net-tools && \
yum install -y iproute
FROM centos:7
COPY --from=builder /usr/sbin/ifconfig /sbin/
COPY --from=builder /usr/sbin/ip /sbin/
CMD ["/bin/bash"]
#COPY --from=builder 意为从命名为builder构建的临时容器中拷贝文件到本次构建的临时容器内
合并 RUN 指令,参考如下,将多个命令放到一个 RUN 里面,一个 RUN 就是一层,官方不建议镜像层数过多
FROM registry.cn-beijing.aliyuncs.com/dotbalo/alpine:3.20
#RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories
#RUN apk update
#RUN apk add nginx curl
RUN sed -i "s@dl-cdn.alpinelinux.org@mirrors.aliyun.com@g" /etc/apk/repositories && \
apk update && \
apk add nginx curl
不要这样做:
COPY file /app/ RUN chmod 755 /app/file # 导致多一层,文件实际存了两份(一份原权限,一份新权限)
推荐做法:
COPY --chmod=755 file /app/ # 或者 COPY --chown=user:group file /app/
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。