00000213
Dockerfile 是一个文本文件,包含了一系列指令,用于自动化构建 Docker 镜像。通过 Dockerfile,你可以定义镜像的基础环境、安装的软件、配置文件、启动命令等,实现镜像的可重复构建和版本控制。
| 优势 | 说明 |
|---|---|
可重复性 |
相同的 Dockerfile 总是构建出相同的镜像 |
版本控制 |
可以与代码一起纳入 Git 管理 |
透明性 |
构建过程清晰可见,易于审查 |
协作性 |
团队成员使用相同的构建流程 |
维护性 |
修改配置只需编辑文本文件 |
# 基础镜像 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"]
FROM <image>[:<tag>] [AS <name>]
作用:指定构建的基础镜像
示例:
FROM alpine:3.18 FROM python:3.11-slim FROM node:18-alpine AS builder
LABEL <key>=<value> <key>=<value> ...
作用:为镜像添加元数据
LABEL maintainer="dev@example.com"
LABEL version="1.0" \
description="My Application" \
build-date="2024-01-01"
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
WORKDIR /path/to/workdir
作用:设置工作目录,后续的 RUN、CMD、ENTRYPOINT 都在该目录下执行,进入容器时的默认目录
示例:
WORKDIR /app WORKDIR /usr/src/myapp
COPY [--chown=<user>:<group>] <src>... <dest>
作用:从构建上下文复制文件到镜像中
示例:
COPY package.json . COPY src/ /app/src/ COPY --chown=www-data:www-data . /var/www/html
ADD [--chown=<user>:<group>] <src>... <dest>
作用:类似 COPY,但支持 URL 和自动解压
示例:
ADD https://example.com/file.tar.gz /tmp/ ADD file.tar.gz /usr/src/
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
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"]
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"]
EXPOSE <port>[/<protocol>] ...
作用:声明容器运行时监听的端口(仅为文档目的)
示例:
EXPOSE 80 EXPOSE 443/tcp EXPOSE 8080 8443
VOLUME ["/data"]
作用:创建挂载点,用于数据持久化,VOLUME指令创建的是匿名卷,不能直接指定名称
示例:
VOLUME ["/var/log/nginx"] VOLUME /app/data
USER <user>[:<group>]
作用:设置运行时的用户
示例:
USER www-data USER 1001:1001
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') \
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 等工具) #检查命令应该是轻量级的
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 指令的执行
创建 .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
docker build [OPTIONS] PATH | URL | -
| 参数 | 简写 | 说明 | 示例 |
|---|---|---|---|
—tag |
|
指定镜像名称和标签 |
-t myapp:1.0 |
—file |
|
指定 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 .
[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"]
# 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
[root@docker-71 nginx]# docker image build -t apline-nginx:v1.1 .
[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
多阶段构建(Multi-stage Builds)是 Docker 17.05 引入的强大功能,允许在一个 Dockerfile 中使用多个 FROM指令,每个阶段可以使用不同的基础镜像,最终只将需要的文件复制到最终镜像中。
解决的问题
带来的好处
# 第一阶段:构建阶段 FROM <builder-image> AS builder # 构建相关的指令... # 第二阶段:运行阶段 FROM <runtime-image> AS runtime # 从构建阶段复制文件 COPY --from=builder /app/dist /app/ # 运行时配置...
传统方式的问题:
# 不好的做法 - 镜像很大,包含构建工具 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"]
体积对比:
# 阶段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"]
减少构建上下文大小,加快构建速度。
减少镜像层数,清理缓存:
RUN apt-get update && \
apt-get install -y package1 package2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
--no-cache当需要全新构建时分离构建环境和运行环境,减小最终镜像大小。
避免使用 latest标签,确保构建的一致性。