智能
助手
最大化  清空记录 停止  历史记录
翻译选中文本
选中一段文本后进行翻译
名词解释
选中一段文本后进行名词解释
知识图谱生成
通过图谱展示知识信息
登录用户在知识浏览页面可用
答案生成
AI自动回答一个问答功能中的问题
登录用户在问答浏览页面,且问题开放回答中可用
知识摘要
自动为当前知识生成摘要
知识浏览页面可用
知识问答
针对当前知识进行智能问答
知识浏览面可用
2025-12-22 00:09:52 版本 : 8 docker镜像制作-2-Docker基于dockerfile制作镜像
作者: 文艺范儿 于 2025年12月22日 发布在分类 / Docker & K8S / docker基础 下,并于 2025年12月22日 编辑
 历史版本

备注 修改日期 修改人
修改标题 2025-12-22 00:09:52[当前版本] 文艺范儿
创建版本 2025-12-22 00:09:33 文艺范儿

8.3 Docker基于dockerfile制作镜像

Dockerfile 是一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。通过 Dockerfile,你可以定义镜像的基础环境、安装的软件、配置文件、启动命令等,实现镜像的可重复构建版本控制

优势 说明

可重复性

相同的 Dockerfile 总是构建出相同的镜像

版本控制

可以与代码一起纳入 Git 管理

透明性

构建过程清晰可见,易于审查

协作性

团队成员使用相同的构建流程

维护性

修改配置只需编辑文本文件

8.3.1 Dockerfile 基本结构

# 基础镜像
FROM ubuntu:20.04

# 维护者信息(已废弃,推荐使用 LABEL)
LABEL maintainer="your-name@example.com"

# 环境变量
ENV APP_HOME=/app

# 工作目录
WORKDIR $APP_HOME

# 复制文件
COPY . .

# 运行命令
RUN apt-get update && apt-get install -y python3

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["python3", "app.py"]

8.3.2 核心指令详解

1. FROM - 指定基础镜像
FROM <image>[:<tag>] [AS <name>]

作用:指定构建的基础镜像

示例

FROM alpine:3.18
FROM python:3.11-slim
FROM node:18-alpine AS builder
2. LABEL - 添加元数据
LABEL <key>=<value> <key>=<value> ...

作用:为镜像添加元数据

LABEL maintainer="dev@example.com"
LABEL version="1.0" \
      description="My Application" \
      build-date="2024-01-01"
3. ENV - 设置环境变量
ENV <key>=<value> ...

作用:设置环境变量,在构建和运行时都可用,容器运行时仍然存在,可以被应用程序读取,可以将 ARG 的值赋给 ENV,使其在运行时可用

示例

ENV APP_PORT=8080
ENV SQL_PASSWD=123456
ENV PATH="/usr/local/bin:${PATH}"
ENV JAVA_HOME=/usr/lib/jvm/java-11

# 查看容器内的环境变量
docker exec container_name env
4. WORKDIR - 设置工作目录
WORKDIR /path/to/workdir

作用:设置工作目录,后续的 RUN、CMD、ENTRYPOINT 都在该目录下执行,进入容器时的默认目录

示例

WORKDIR /app
WORKDIR /usr/src/myapp
5. COPY - 复制文件
COPY [--chown=<user>:<group>] <src>... <dest>

作用:从构建上下文复制文件到镜像中

示例

COPY package.json .
COPY src/ /app/src/
COPY --chown=www-data:www-data . /var/www/html
6. ADD - 添加文件(增强 版 COPY)
ADD [--chown=<user>:<group>] <src>... <dest>

作用:类似 COPY,但支持 URL 和自动解压

示例

ADD https://example.com/file.tar.gz /tmp/
ADD file.tar.gz /usr/src/
7. RUN - 执行命令
RUN <command>                    # shell 形式
RUN ["executable", "param1", "param2"]  # exec 形式

作用:在构建过程中执行命令

示例

RUN apt-get update && apt-get install -y curl
RUN ["/bin/bash", "-c", "echo hello"]
RUN pip install -r requirements.txt
8. CMD - 默认命令
CMD ["executable","param1","param2"]  # exec 形式(推荐)
CMD command param1 param2              # shell 形式

作用:设置容器启动时默认执行的命令(启动容器时指定启动命令的方式可以被覆盖 例如:docker run -d —name apline-nginx-02 -p 88:80 apline-nginx:v1.1 sleep 10;sleep 10 就会被当做启动命令启动)

示例

CMD ["nginx", "-g", "daemon off;"]
CMD ["python", "app.py"]
CMD ["/bin/bash"]
9. ENTRYPOINT - 入口点
ENTRYPOINT ["executable", "param1", "param2"]  # exec 形式(推荐)
ENTRYPOINT command param1 param2              # shell 形式

作用:配置容器启动时运行的可执行文件(启动容器时指定启动命令的方式不能被覆盖,指定的启动命令被当做参数传递 例如:docker run -d —name apline-nginx-02 -p 88:80 apline-nginx:v1.1 haha;haha就会被当做参数传递)

示例

ENTRYPOINT ["/app/start.sh"]
ENTRYPOINT ["nginx"]
10. EXPOSE - 声明端口
EXPOSE <port>[/<protocol>] ...

作用:声明容器运行时监听的端口(仅为文档目的)

示例

EXPOSE 80
EXPOSE 443/tcp
EXPOSE 8080 8443
11. VOLUME - 定义卷
VOLUME ["/data"]

作用:创建挂载点,用于数据持久化,VOLUME指令创建的是匿名卷,不能直接指定名称

示例

VOLUME ["/var/log/nginx"]
VOLUME /app/data
12. USER - 指定用户
USER <user>[:<group>]

作用:设置运行时的用户

示例

USER www-data
USER 1001:1001
13. ARG - 构建参数
ARG <name>[=<default-value>]

作用:定义构建时的变量(可带默认值),只在构建过程中有效,构建完成后变量消失

构建参数不适合敏感信息(会留在构建历史中),敏感信息应该在运行时通过 -e 或 secrets 管理

示例

ARG VERSION=latest
ARG BUILD_DATE

# 构建命令
docker build \
  --build-arg APP_VERSION=2.1.0 \
  --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
14. HEALTHCHECK - 健康检查
HEALTHCHECK [OPTIONS] CMD command

作用:定义容器健康状态检查

示例

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost/ || exit 1


#1. 健康检查失败的影响
#容器状态变为 (unhealthy),但容器仍在运行
#不会影响容器的基本功能
#可以用于监控和告警

#2. 性能考虑
#不要设置过于频繁的检查(如 1s),会增加负载
#超时时间要合理,既要快速检测问题,又要避免误判

#3. 命令选择
#确保检查命令在容器内可用(安装了 curl、nc 等工具)
#检查命令应该是轻量级的
15. ONBUILD - 构建参数
ONBUILD <INSTRUCTION>

作用

延迟执行:在当前镜像构建时不执行,在基于它的子镜像构建时执行

镜像模板:创建一个”模板镜像”,供其他项目继承和使用

代码复用:避免在每个项目的 Dockerfile 中重复相同的指令

示例

1:创建基础构建镜像

父镜像 Dockerfile (base-builder):

FROM golang:1.21-alpine

# 设置工作目录
WORKDIR /app

# 定义 ONBUILD 触发器
ONBUILD COPY go.mod go.sum ./
ONBUILD RUN go mod download
ONBUILD COPY . .
ONBUILD RUN go build -o main .

# 设置默认命令
CMD ["./main"]

构建父镜像:

docker build -t base-builder .

子镜像 Dockerfile (child-app):

# 基于父镜像
FROM base-builder

# 不需要任何额外指令,ONBUILD 会自动执行
# 当构建这个镜像时,会自动执行:
# 1. COPY go.mod go.sum ./
# 2. RUN go mod download  
# 3. COPY . .
# 4. RUN go build -o main .

构建子镜像:

docker build -t child-app .
# 构建过程中会看到 ONBUILD 指令的执行

8.3.3 .dockerignore 文件

创建 .dockerignore文件来排除不需要的文件:

例如 :

# 版本控制
.git
.gitignore
.svn

# IDE
.vscode
.idea
*.swp
*.swo

# 临时文件
*.tmp
*.log
.DS_Store
Thumbs.db

# 构建产物
dist/
build/
*.egg-info/

# 依赖目录(如果使用包管理)
node_modules/
vendor/
__pycache__/

# 环境变量文件
.env
.env.local

8.3.4 docker build 命令详解

1. 基本语法
docker build [OPTIONS] PATH | URL | -
2. 常用参数
参数 简写 说明 示例

—tag

-t

指定镜像名称和标签

-t myapp:1.0

—file

-f

指定 Dockerfile 路径

-f Dockerfile.prod

—build-arg

设置构建参数

—build-arg VERSION=1.0

—no-cache

不使用构建缓存

—no-cache

—pull

总是尝试拉取新镜像

—pull

—target

多阶段构建的目标

—target builder

—platform

指定目标平台

—platform linux/amd64

—progress

设置进度输出类型

—progress=plain

使用示例

# 基本构建
docker build -t myapp:latest .

# 指定标签和构建参数
docker build -t myapp:1.0 -t myapp:latest \
  --build-arg VERSION=1.0 \
  --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
  .

# 指定 Dockerfile 路径
docker build -t myapp:dev -f Dockerfile.dev .

# 不使用缓存构建
docker build --no-cache -t myapp:clean .

# 多阶段构建指定目标
docker build --target production -t myapp:prod .

# 详细输出
docker build --progress=plain -t myapp:debug .

8.3.4 nginx配置优化案例

1. 编写dockerfile文件
[root@docker-71 ~]# mkdir -p /home/deploy/dockerfile/nginx
[root@docker-71 ~]# cd /home/deploy/dockerfile/nginx
[root@docker-71 nginx]# cat Dockerfile

以下为dockerfile文件内容:

# 建议后面跟具体版本号
FROM nginx:alpine

# 维护者信息
LABEL maintainer="21325307@qq.com" \
      version="1.0" \
      build-date="2024-01-01"

# 替换安装源和安装必要工具
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk add --no-cache \
    curl \
    bash \
    tzdata

# 设置时区
ENV TZ=Asia/Shanghai

# 创建目录
RUN mkdir -p /var/www/html

# 复制自定义配置
# COPY nginx.conf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf

# 复制网站文件 如果是tar.gz 建议ADD 
COPY html/ /var/www/html/

# 创建启动脚本
RUN echo '#!/bin/sh' > /start.sh && \
    echo 'nginx -g "daemon off;"' >> /start.sh && \
    chmod +x /start.sh

# 设置权限
RUN chown -R nginx:nginx /var/www/html && \
    chmod -R 755 /var/www/html

# 暴露端口
EXPOSE 80 443

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost/ || exit 1

# 启动命令
CMD ["/start.sh"]
2. 编写nginx相关文件
# 1. 编写default.conf
[root@docker-71 nginx]# cat > default.conf << 'EOF'
server {
    listen 80;
    server_name loaclhost;

    # 根目录
    root /var/www/html;
    index index.html index.htm;

    # 访问日志
    access_log /var/log/access.log;
    error_log /var/log/error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}
EOF

# 2. 创建简单的测试页面
[root@docker-71 nginx]# mkdir -p html
[root@docker-71 nginx]# cat > ./html/index.html << 'EOF'
dsf-1 alpine-nginx-test
EOF
3. 打镜像
[root@docker-71 nginx]# docker image build -t apline-nginx:v1.1 .
4. 基于镜像启动服务
[root@docker-71 ~]# docker run -d --name apline-nginx-02 -p 88:80 apline-nginx:v1.1
#测试
[root@docker-71 ~]# curl 127.0.0.1:88
dsf-1 alpine-nginx-test

8.3.5 多阶段构建

多阶段构建(Multi-stage Builds)是 Docker 17.05 引入的强大功能,允许在一个 Dockerfile 中使用多个 FROM指令,每个阶段可以使用不同的基础镜像,最终只将需要的文件复制到最终镜像中。

1. 核心价值

解决的问题

  1. 镜像体积过大 - 传统方式中构建工具和源码都包含在最终镜像中
  2. 安全风险 - 构建工具可能带来不必要的安全漏洞
  3. 构建复杂 - 需要编写复杂的构建脚本和外部 Dockerfile

带来的好处

  • 减小镜像体积 - 只包含运行时必需的文件
  • 提高安全性 - 移除构建工具和中间文件
  • 简化流程 - 一个 Dockerfile 完成所有构建步骤
  • 更好的缓存 - 不同阶段可以独立缓存
2. 基本语法
# 第一阶段:构建阶段
FROM <builder-image> AS builder
# 构建相关的指令...

# 第二阶段:运行阶段  
FROM <runtime-image> AS runtime
# 从构建阶段复制文件
COPY --from=builder /app/dist /app/
# 运行时配置...

3. 基础示例
示例 1:Go 应用多阶段构建

传统方式的问题:

# 不好的做法 - 镜像很大,包含构建工具
FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o myapp
CMD ["./myapp"]
# 最终镜像包含 Go 编译器、源码等,体积几百MB

多阶段构建解决方案:

# 第一阶段:构建 AS关键字用于为多阶段构建中的不同阶段命名,如果不AS,默认从0开始命名
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 复制依赖文件(利用缓存)
COPY go.mod go.sum ./
RUN go mod download

# 复制源码并构建
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .

# 第二阶段:运行(只包含运行时)
FROM alpine:latest

RUN apk --no-cache add ca-certificates

WORKDIR /root/

# 从构建阶段复制二进制文件,指定从名为builder的阶段复制文件
COPY --from=builder /app/myapp .

EXPOSE 8080

CMD ["./myapp"]

体积对比:

  • 传统方式:~800MB
  • 多阶段构建:~10MB
示例 2:Java Spring Boot 应用
# 阶段1:构建应用
FROM maven:3.8-openjdk-17 AS builder

WORKDIR /app

# 复制 POM 文件
COPY pom.xml .
COPY mvnw ./
COPY .mvn ./.mvn/

# 下载依赖(利用缓存)
RUN ./mvnw dependency:go-offline -B

# 复制源码并构建
COPY src ./src
RUN ./mvnw package -DskipTests

# 阶段2:运行环境准备
FROM openjdk:17-jre-slim AS runtime

# 安装时区数据
RUN apt-get update && \
    apt-get install -y --no-install-recommends tzdata && \
    rm -rf /var/lib/apt/lists/*

# 设置时区
ENV TZ=Asia/Shanghai

WORKDIR /app

# 从构建阶段复制 JAR 文件
COPY --from=builder /app/target/*.jar app.jar

# 创建非 root 用户
RUN groupadd -r appuser && \
    useradd -r -g appuser -d /app -s /sbin/nologin appuser && \
    chown -r appuser:appuser /app

USER appuser

EXPOSE 8080

# 使用 exec 形式确保信号正确处理
ENTRYPOINT ["java", "-jar", "app.jar"]

8.3.6 构建优化技巧

1. 使用 .dockerignore

减少构建上下文大小,加快构建速度。

2. 合并 RUN 指令

减少镜像层数,清理缓存:

RUN apt-get update && \
    apt-get install -y package1 package2 && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
3. 合理使用构建缓存
  • 将不经常变化的指令放在前面
  • 将经常变化的指令放在后面
  • 使用 --no-cache当需要全新构建时
4. 多阶段构建

分离构建环境和运行环境,减小最终镜像大小。

5. 使用特定版本的基础镜像

避免使用 latest标签,确保构建的一致性。

历史版本-目录  [回到顶端]
    文艺知识分享平台 -V 5.2.5 -wcp