Docker 入门教程(八):Dockerfile

发布于:2025-06-30 ⋅ 阅读:(17) ⋅ 点赞:(0)

🐳 Docker 入门教程(八):Dockerfile


一、Dockerfile 是什么?

Dockerfile 是构建 Docker 镜像的“说明书”,它告诉 Docker:

  • 从哪开始构建(FROM)
  • 要做哪些修改(RUN / COPY / ADD)
  • 最终如何启动(CMD / ENTRYPOINT)

构建命令:

docker build -t myapp:1.0 .

二、Dockerfile 指令详解

这里列出常用指令,并提供格式、示例、说明、最佳实践。

FROM:指定基础镜像(必须是第一行)

FROM ubuntu:22.04
  • 所有构建都必须有个基础镜像
  • 可以使用官方、私有或自定义镜像
  • 可以通过 AS 给阶段命名(多阶段构建)

多阶段构建:

FROM golang:1.20 AS builder
WORKDIR /app
RUN go build -o mybin

FROM scratch
COPY --from=builder /app/mybin /mybin
ENTRYPOINT ["/mybin"]

RUN:执行命令生成新镜像层

RUN apt update && apt install -y curl
  • 用于安装依赖、配置环境
  • 每条 RUN 都创建一个新层

合并多个命令,减少镜像层数

RUN apt update && \
    apt install -y curl git && \
    rm -rf /var/lib/apt/lists/*

COPY:将本地文件复制进镜像

COPY . /app
  • 第一个参数是宿主机相对路径(构建上下文)
  • 第二个参数是容器内路径

指定复制文件:

COPY requirements.txt /app/

ADD:类似 COPY,但更智能

ADD app.tar.gz /app/
  • 可以自动解压 .tar 文件
  • 支持远程 URL(不推荐)
  • 对本地文件请尽量用 COPY,行为更可控

WORKDIR:设置容器内的工作目录

WORKDIR /app
  • 相当于进入了 /app 目录
  • 所有后续命令(RUN、CMD、ENTRYPOINT)都在这个目录中执行
  • 多次使用将自动拼接:WORKDIR /aWORKDIR b/a/b

CMD:容器默认执行的命令(可被覆盖)

CMD ["python", "app.py"]
  • 容器启动时默认执行(docker run 不指定命令时)

  • 只能有一条,写多条只保留最后一条

  • 支持两种写法:

    • JSON 数组:首选方式,精确执行命令
    • Shell 字符串:通过 /bin/sh -c 执行

ENTRYPOINT:固定的启动命令(不建议覆盖)

ENTRYPOINT ["python"]
CMD ["app.py"]
  • ENTRYPOINT 是主程序,不会被 run 覆盖
  • CMD 是参数,可以在 run 里改写
  • 两者合用,实现默认行为可改、主程序不可改

示例:

docker run myapp          # python app.py
docker run myapp test.py  # python test.py

ENV:设置环境变量

ENV APP_ENV=production
  • 可用于 RUN、CMD 中引用:
RUN echo $APP_ENV
  • 容器启动后这些变量也会存在

EXPOSE:声明容器要用的端口(仅声明,不映射)

EXPOSE 80
  • 不会自动映射端口
  • 只是标记,供文档/编排系统参考(如 Compose)

VOLUME:声明挂载点

VOLUME ["/data"]
  • 建议容器外部挂载这个路径
  • 自动创建匿名卷
  • 可由用户显式绑定实际路径

ARG:构建时变量(不同于 ENV)

ARG VERSION=1.0
RUN echo "Building version $VERSION"
  • 使用 --build-arg 提供参数:
docker build --build-arg VERSION=2.0 -t app:2.0 .

三、RUN / CMD / ENTRYPOINT 的本质区别

指令 用于何时 作用对象 是否写入镜像 会不会被 docker run 覆盖
RUN 构建镜像时 构建阶段行为 写进镜像层 不能被覆盖
CMD 容器运行时 默认启动命令 写进镜像元数据 会被 run 的命令替换
ENTRYPOINT 容器运行时 强制主程序入口 写进镜像元数据 不会被 run 替换主程序,只能追加参数

时间线类比:三者分别出现在 Docker 生命周期的哪一刻?

① docker build 时
   └── RUN:安装、配置、打包(一次性的“做菜”过程)
           
② docker run 时
   └── ENTRYPOINT:一定要执行的“主程序”或“框架”
   └── CMD:主程序的默认参数(可以临时替换)

之后区分ENTRYPOINTCMD

ENTRYPOINT你必须执行的程序
CMD你建议的默认参数

示例 A:CMD 单独使用

FROM ubuntu
CMD ["echo", "hello"]
  • 默认执行:echo hello
  • docker run image → 输出 hello
  • docker run image hi → 执行 hi(完全覆盖)

示例 B:ENTRYPOINT 单独使用

FROM ubuntu
ENTRYPOINT ["echo"]
  • docker run image hi → 执行 echo hi
  • docker run image ls → 执行 echo ls
  • 想执行别的(如 ls),你做不到,除非:
docker run --entrypoint ls image

示例 C:ENTRYPOINT + CMD 联用(推荐)

FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["hello"]
执行命令 实际执行
docker run image echo hello
docker run image world echo world
docker run --entrypoint date image date

CMD 是默认参数,ENTRYPOINT 是主程序


网站公告

今日签到

点亮在社区的每一天
去签到