Dockerfile编写 #
什么是Dockerfile? #
Dockerfile是一个文本文件,包含构建Docker镜像所需的所有指令。Docker通过读取Dockerfile中的指令自动构建镜像。
基本结构 #
dockerfile
# 基础镜像
FROM ubuntu:22.04
# 维护者信息
LABEL maintainer="user@example.com"
# 安装依赖
RUN apt-get update && apt-get install -y \
curl \
vim
# 设置工作目录
WORKDIR /app
# 复制文件
COPY . /app
# 暴露端口
EXPOSE 8080
# 启动命令
CMD ["nginx", "-g", "daemon off;"]
常用指令详解 #
FROM - 基础镜像 #
指定构建镜像的基础镜像。
dockerfile
# 使用官方镜像
FROM ubuntu:22.04
# 使用Alpine版本
FROM alpine:3.18
# 使用多阶段构建
FROM node:18 AS builder
FROM nginx:alpine AS production
# 使用特定平台
FROM --platform=linux/arm64 alpine:3.18
LABEL - 元数据标签 #
添加镜像的元数据信息。
dockerfile
# 添加多个标签
LABEL maintainer="user@example.com"
LABEL version="1.0.0"
LABEL description="This is a web application"
# 一次性添加多个标签
LABEL maintainer="user@example.com" \
version="1.0.0" \
description="Web application"
RUN - 执行命令 #
在构建过程中执行命令。
dockerfile
# 单行命令
RUN apt-get update
# 多行命令(推荐使用\连接)
RUN apt-get update && apt-get install -y \
curl \
vim \
git \
&& rm -rf /var/lib/apt/lists/*
# exec形式
RUN ["apt-get", "install", "-y", "nginx"]
# 使用管道
RUN wget -O - https://example.com/install.sh | bash
COPY - 复制文件 #
从构建上下文复制文件到镜像。
dockerfile
# 复制单个文件
COPY package.json /app/
# 复制目录
COPY src/ /app/src/
# 复制并重命名
COPY config.prod.json /app/config.json
# 使用通配符
COPY *.json /app/
COPY hom?.txt /app/
# 设置文件权限
COPY --chown=user:group file.txt /app/
COPY --chmod=755 script.sh /app/
ADD - 添加文件 #
类似COPY,但支持URL和解压tar文件。
dockerfile
# 复制文件
ADD file.txt /app/
# 从URL下载
ADD https://example.com/file.tar.gz /app/
# 自动解压tar文件
ADD archive.tar.gz /app/
# 推荐使用COPY(除非需要解压或下载)
WORKDIR - 工作目录 #
设置工作目录。
dockerfile
# 设置工作目录
WORKDIR /app
# 相对路径(基于上一个WORKDIR)
WORKDIR src
# 结果: /app/src
# 绝对路径
WORKDIR /var/www
# 可以使用环境变量
ENV DIR=/app
WORKDIR $DIR
ENV - 环境变量 #
设置环境变量。
dockerfile
# 设置单个环境变量
ENV APP_ENV=production
# 设置多个环境变量
ENV APP_ENV=production \
NODE_VERSION=18 \
PATH=/app/bin:$PATH
# 使用环境变量
ENV APP_HOME=/app
WORKDIR $APP_HOME
ARG - 构建参数 #
定义构建时的变量。
dockerfile
# 定义构建参数
ARG VERSION=1.0.0
ARG NODE_VERSION=18
# 使用构建参数
FROM node:${NODE_VERSION}
ARG VERSION
ENV APP_VERSION=$VERSION
# 构建时传递
# docker build --build-arg VERSION=2.0.0 -t myapp .
EXPOSE - 暴露端口 #
声明容器运行时监听的端口。
dockerfile
# 暴露单个端口
EXPOSE 80
# 暴露多个端口
EXPOSE 80 443
# 暴露UDP端口
EXPOSE 53/udp
# 注意: EXPOSE只是声明,不会实际发布端口
# 需要使用 -p 参数映射端口
CMD - 容器启动命令 #
指定容器启动时默认执行的命令。
dockerfile
# exec形式(推荐)
CMD ["nginx", "-g", "daemon off;"]
# shell形式
CMD nginx -g "daemon off;"
# 作为ENTRYPOINT的默认参数
CMD ["--port", "8080"]
ENTRYPOINT - 入口点 #
配置容器为可执行程序。
dockerfile
# exec形式(推荐)
ENTRYPOINT ["docker-entrypoint.sh"]
# 结合CMD使用
ENTRYPOINT ["node"]
CMD ["app.js"]
# 可以被 --entrypoint 覆盖
# docker run --entrypoint /bin/bash myimage
CMD vs ENTRYPOINT #
text
┌─────────────────────────────────────────────────────┐
│ CMD vs ENTRYPOINT │
├─────────────────────────────────────────────────────┤
│ │
│ ENTRYPOINT: │
│ - 定义容器的主命令 │
│ - 不容易被覆盖 │
│ - 适合将容器作为可执行程序 │
│ │
│ CMD: │
│ - 设置默认参数或命令 │
│ - 容易被docker run参数覆盖 │
│ - 适合设置默认启动命令 │
│ │
│ 组合使用: │
│ ENTRYPOINT ["node"] │
│ CMD ["app.js"] │
│ │
│ 运行: docker run myimage server.js │
│ 实际执行: node server.js │
│ │
└─────────────────────────────────────────────────────┘
VOLUME - 数据卷 #
创建挂载点。
dockerfile
# 创建匿名卷
VOLUME /data
# 创建多个卷
VOLUME ["/data", "/logs"]
# 注意: 不能指定宿主机路径
# 需要在运行时使用 -v 指定
USER - 用户 #
指定运行容器的用户。
dockerfile
# 创建用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 切换用户
USER appuser
# 使用UID/GID
USER 1000:1000
HEALTHCHECK - 健康检查 #
定义健康检查命令。
dockerfile
# 基本用法
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
# 完整配置
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 禁用健康检查
HEALTHCHECK NONE
ONBUILD - 构建触发器 #
定义触发器,在子镜像构建时执行。
dockerfile
# 定义触发器
ONBUILD COPY . /app
ONBUILD RUN npm install
# 当其他镜像FROM这个镜像时,会执行上述命令
Dockerfile示例 #
Node.js应用 #
dockerfile
FROM node:18-alpine
WORKDIR /app
# 先复制依赖文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s CMD curl -f http://localhost:3000/health || exit 1
# 启动应用
USER node
CMD ["node", "server.js"]
Python应用 #
dockerfile
FROM python:3.11-slim
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 创建非root用户
RUN useradd -m appuser
USER appuser
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Nginx应用 #
dockerfile
FROM nginx:alpine
# 复制配置文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf.d/ /etc/nginx/conf.d/
# 复制静态文件
COPY dist/ /usr/share/nginx/html/
# 设置权限
RUN chown -R nginx:nginx /usr/share/nginx/html
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
多阶段构建 #
dockerfile
# 构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
最佳实践 #
1. 使用.dockerignore #
text
# .dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
*.md
.env
2. 最小化层数 #
dockerfile
# 不推荐
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
# 推荐
RUN apt-get update && apt-get install -y \
curl \
vim \
&& rm -rf /var/lib/apt/lists/*
3. 利用构建缓存 #
dockerfile
# 先复制依赖文件,利用缓存
COPY package*.json ./
RUN npm install
# 再复制源代码
COPY . .
4. 使用特定版本 #
dockerfile
# 不推荐
FROM node:latest
# 推荐
FROM node:18.19.0-alpine
5. 安全实践 #
dockerfile
# 不以root运行
RUN useradd -m appuser
USER appuser
# 不存储敏感信息
# 使用环境变量或secrets
小结 #
本节学习了Dockerfile的编写方法:
- 常用指令的使用方法
- CMD和ENTRYPOINT的区别
- 多阶段构建
- 最佳实践
下一步 #
接下来,让我们学习 镜像构建与优化,了解如何高效构建和优化Docker镜像。