【Docker】Dockerfile自定义镜像
创建自定义的镜像有两种方法
1.命令式创建镜像--进入容器输入命令创建镜像
apk updateapk add#安装软件
将容器保存为新镜像分享commit
将容器 9aaf3cd86741 (容器id)的当前状态提交为一个新的镜像,镜像名称为 alpine-figlet。
docker commit 9aaf3cd86741 alpine-figlet
命令式创建的局限性
- 不可重复性:容器安装过程依赖人工操作,无法保证环境一致性
- 臃肿镜像:容器可能包含临时文件/缓存,导致镜像体积膨胀
- 安全风险:无法追溯安装过程,可能存在安全隐患
- 维护困难:无法版本化管理构建步骤
2.声明式创建镜像--用dockerfile
Dockerfile
Dockerfile 是一个纯文本文件,用于定义如何构建 Docker 镜像。它包含了一系列指令,Docker 会按照这些指令的顺序自动执行,最终生成一个可复用的镜像。
常用指令
| 指令 | 作用 | 示例 |
|---|---|---|
FROM | 指定基础镜像,是 Dockerfile 的第一个指令。 | FROM ubuntu:25.04 |
RUN | 在镜像构建过程中执行命令,用于安装软件、配置环境等。 | RUN apt-get update && apt-get install -y nginx |
COPY | 将宿主机的文件或目录复制到镜像中。 | COPY index.html /var/www/html/ |
ADD | 类似 COPY,还支持远程文件下载、解压压缩包等。 | ADD https://example.com/file.tar.gz /app/ |
CMD | 容器启动时执行的默认命令,若镜像启动时指定了其他命令则会覆盖。 | CMD ["nginx", "-g", "daemon off;"] |
EXPOSE | 声明容器对外暴露的端口(仅为说明,实际端口映射需在 docker run 时指定)。 | EXPOSE 80 |
WORKDIR | 设置后续指令的工作目录,避免使用绝对路径,增强可维护性。 | WORKDIR /app |
ENV | 设置环境变量,可在后续指令和容器运行时使用。 | ENV APP_PORT=8080 |
dockerfile例子
#声明式构建镜像:使用 ubuntu:25.04 作为基础镜像
FROM ubuntu:25.04#首先要更新本地软件包索引&&
#安装 nginx(Nginx是一款高性能的开源 Web 服务器、反向代理服务器和负载均衡器)
RUN apt-get update && \apt-get install -y nginx#创建一个简单的 HTML 文件
RUN echo '<h1>Hello Docker!</h1>' > /tmp/index.html#将刚刚的 HTML 文件移动到容器内的 Nginx 默认的静态网站根目录,即 `/var/www/html/`
RUN mv /tmp/index.html /var/www/html/#暴露 80 端口
EXPOSE 80#启动 nginx 服务
CMD ["nginx", "-g", "daemon off;"]
可以用一条 apt-get install 命令一次性安装多个软件,用空格将不同的软件名隔开即可。 例如 apt-get install -y tree python3 表示安装 tree 和 python3。
每条指令都创建并提交一个新的镜像层
使用dockerfile构建
根据当前目录下的 Dockerfile 文件,构建一个名为 alpine-figlet-from-dockerfile 的 Docker 镜像
docker build -t 依据的文件名 -f 文件位置 输出位置
docker build -t alpine-figlet-from-dockerfile .
分阶段构建
单阶段
Dockerfile.single
FROM golang:1.23# 定义构建参数
ARG PORT=8080
# 设置环境变量
ENV PORT=${PORT}
# 指定工作目录
WORKDIR /app#将本地的 go.mod(依赖管理文件)和 main.go(应用主代码)复制到容器的 /app 目录下。
COPY go.mod .
COPY main.go .#禁用 CGO(Go 调用 C 代码的机制),确保编译出的程序是纯 Go 静态链接的,不依赖系统动态库。
ENV CGO_ENABLED=0
#指定目标操作系统为 Linux,确保编译出的程序能在 Linux 容器中运行。
ENV GOOS=linux#根据go.mod整理依赖 && 编译 Go 程序
RUN go mod tidy && go build -ldflags="-w -s" -o server .EXPOSE ${PORT}#运行
CMD ["./server"]
多阶段
构建和执行阶段分开。
每个阶段都要设置初始镜像、环境、工作目录
执行阶段把构建阶段编译好的文件复制过来执行
AS 阶段名:为阶段命名(如AS builder),方便后续通过--from=阶段名引用。COPY --from=阶段名:从指定阶段复制文件到当前阶段(核心指令)。
# 第一阶段:构建阶段
# builder是别名
FROM golang:1.23 AS builder# 设置工作目录
WORKDIR /app# 将源代码复制到容器中
COPY go.mod .
COPY main.go .# 设置必要的 Go 环境变量
ENV CGO_ENABLED=0
ENV GOOS=linux# 编译 Go 应用
RUN go mod tidy && go build -ldflags="-w -s" -o server .# 第二阶段:运行阶段
FROM alpine:latest# 定义构建参数
ARG PORT=8081
# 设置环境变量
ENV PORT=${PORT}# 安装 CA 证书,这在某些需要 HTTPS 请求的应用中可能需要
RUN apk --no-cache add ca-certificates# 设置工作目录
WORKDIR /root/# 从 builder 阶段复制编译好的二进制文件
COPY --from=builder /app/server .# 暴露应用端口
EXPOSE ${PORT}# 运行应用
CMD ["./server"]
多阶段构建的优点
- 减小镜像体积:最终镜像仅包含运行所需的可执行文件,不包含编译工具(如 Go 编译器)和源码,体积可缩小 90% 以上。
- 隔离构建依赖:构建阶段的依赖(如编译工具、临时文件)不会污染最终镜像,提升安全性。
- 简化流程:无需手动编写脚本复制产物,所有步骤在一个 Dockerfile 中完成。

