Dockerfile 是一个文本文件,包含一系列指令,用于自动化构建 Docker 镜像。每条指令对应镜像的一层(Layer),通过分层机制实现高效构建和缓存管理。
基本语法结构
bash
# 注释
INSTRUCTION arguments
常用指令
FROM
指定基础镜像,必须为第一条指令。例如:
dockerfile
# 语法
FROM <image>[:<tag>] [AS <name>]
# 示例
FROM ubuntu:22.04
FROM python:3.11-slim
FROM node:18-alpine AS builder
LABEL - 元数据标签
bash
LABEL maintainer="user@example.com"
LABEL version="1.0"
LABEL description="This is a sample application"
# 多标签写法
LABEL maintainer="user@example.com" \
version="1.0" \
description="Sample app"
ENV - 环境变量
bash
# 语法
ENV <key>=<value> [<key>=<value>...]
# 示例
ENV APP_HOME=/app
ENV NODE_ENV=production
ENV PATH=$PATH:/app/bin
RUN
执行命令并创建新的镜像层,常用于安装软件或配置环境。例如:
dockerfile
# Shell格式
RUN apt-get update && apt-get install -y python3
# Exec格式
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "python3"]
# 多行命令(减少层数)
RUN apt-get update && \
apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
COPY 与 ADD
将文件从主机复制到镜像中。ADD 支持自动解压和远程 URL,但推荐优先使用 COPY。例如:
dockerfile
# COPY - 复制本地文件到镜像
COPY package.json /app/
COPY . /app/
# ADD - 增强版COPY(支持URL和自动解压)
ADD https://example.com/file.tar.gz /tmp/
ADD archive.tar.gz /app/ # 自动解压
WORKDIR
设置工作目录,后续指令均在此目录下执行。例如:
dockerfile
WORKDIR /app
EXPOSE
声明容器运行时监听的端口,但实际映射需通过 -p 参数指定。例如:
dockerfile
# 仅文档作用,实际映射需用-p参数
EXPOSE 8080
EXPOSE 8080/tcp
EXPOSE 8080/udp
CMD 与 ENTRYPOINT
定义容器启动时的默认命令。CMD 可被覆盖,ENTRYPOINT 通常固定。例如:
dockerfile
# CMD - 默认命令(可被覆盖)
CMD ["python", "app.py"]
CMD python app.py
# ENTRYPOINT - 入口点(不易被覆盖)
ENTRYPOINT ["python", "app.py"]
# 组合使用(最佳实践)
ENTRYPOINT ["python"]
CMD ["app.py"]
# 相当于默认执行: python app.py
# 运行时 docker run myimage test.py -> python test.py
ARG - 构建参数
bash
# 定义构建参数
ARG VERSION=latest
ARG BUILD_DATE
# 使用参数
RUN echo "Building version: ${VERSION}"
USER - 切换用户
bash
# 创建用户并切换
RUN useradd -m -s /bin/bash appuser
USER appuser
优化实践
-
多阶段构建 :减少最终镜像体积。例如先编译代码,再复制到轻量级镜像:
dockerfileFROM golang:1.18 AS builder WORKDIR /app COPY . . RUN go build -o myapp FROM alpine:latest COPY --from=builder /app/myapp /usr/local/bin/ -
合并 RUN 指令 :减少层数并清理缓存:
dockerfileRUN apt-get update \ && apt-get install -y --no-install-recommends python3 \ && rm -rf /var/lib/apt/lists/* -
使用 .dockerignore :忽略无需复制的文件(如
node_modules),加速构建。dockerfileFROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]调试技巧
- 使用
docker build -t myimage .构建镜像。 - 通过
docker run -it --rm myimage sh进入容器调试。 - 检查镜像层历史:
docker history myimage。
示例1: Python Web应用
bash
# Python Flask应用
FROM python:3.11-slim
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
APP_HOME=/app
WORKDIR $APP_HOME
# 安装系统依赖
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户
RUN useradd -m -s /bin/bash appuser && \
chown -R appuser:appuser $APP_HOME
USER appuser
EXPOSE 5000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:5000/health')"
CMD ["python", "app.py"]
示例2: Java Spring Boot应用
bash
# 多阶段构建 - Maven构建
FROM maven:3.8-openjdk-17 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests
# 运行阶段
FROM openjdk:17-slim
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
RUN useradd -m -s /bin/bash spring && \
chown spring:spring app.jar
USER spring
EXPOSE 8080
ENV JAVA_OPTS="-Xmx512m -Xms256m"
ENTRYPOINT ["java", "-jar", "app.jar"]
构建命令
基本构建
bash
# 基本构建
docker build -t myapp:latest .
# 指定Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .
# 使用构建参数
docker build --build-arg VERSION=1.0 -t myapp:v1 .
# 不使用缓存
docker build --no-cache -t myapp:latest .
多阶段构建
bash
# 构建指定阶段
docker build --target builder -t myapp:builder .
# 多标签构建
docker build -t myapp:latest -t myapp:v1.0.0 .
最佳实践
1.优化镜像大小
bash
# ❌ 不好的做法
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y python3-pip
RUN rm -rf /var/lib/apt/lists/*
# ✅ 好的做法
FROM python:3.11-slim # 使用精简镜像
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
2. 利用构建缓存
bash
# ✅ 先复制不常变的文件
COPY package.json package-lock.json ./
RUN npm install
# 再复制经常变化的代码
COPY . .
3. .dockerignore文件
bash
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
*.md
.DS_Store
coverage
.nyc_output
dist
build
4. 安全最佳实践
bash
# ✅ 使用特定版本标签
FROM node:18.15.0-alpine3.17
# ✅ 使用非root用户
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
USER appuser
# ✅ 扫描漏洞(构建后)
# docker scan myapp:latest
调试技巧
检查构建过程
bash
# 查看构建历史
docker image history myapp:latest
# 进入中间容器
docker run --rm -it <image-id> /bin/sh
# 导出镜像
docker save myapp:latest -o myapp.tar
Dockerfile Linter
bash
# 使用hadolint检查
docker run --rm -i hadolint/hadolint < Dockerfile
# 使用dockerfilelint
npm install -g dockerfilelint
dockerfilelint Dockerfile