Docker已经成为开发工作流程中十年的标准工具。大多数开发者了解基础知识(容器、镜像、Dockerfile),但有一套更高级的使用模式,将高效的Docker用户与那些与它斗争的用户区分开来。以下是基础教程通常遗漏的内容。
镜像构建最佳实践
层缓存:Docker按层构建镜像,每条Dockerfile指令一层。每一层都被缓存,除非该层本身或任何前置层发生变化。实际含义:将很少变化的指令(安装系统包)放在经常变化的指令(复制应用程序代码)之前。典型错误:Dockerfile早期的`COPY . .`意味着任何代码更改都会使所有后续层失效。正确模式:首先复制依赖清单,安装依赖项,然后复制代码。Node.js项目示例:`COPY package*.json ./; RUN npm ci; COPY . .`——这样,`npm ci`层在package.json更改之前被缓存。多阶段构建:一个大多数开发者未充分使用的强大功能。使用单独的构建阶段创建编译输出,然后只将你需要的内容复制到精简的生产镜像中。Go二进制示例:`FROM golang:1.22 AS builder; WORKDIR /app; COPY . .; RUN go build -o app; FROM alpine:3.19; COPY –from=builder /app/app /app; CMD [“/app”]`。生产镜像是Alpine(5MB)而不是Go(800MB)。.dockerignore文件:功能与.gitignore相同——防止不必要的文件被包含在构建上下文中(node_modules、.git、测试文件、本地.env)。没有它,大目录在每次构建时都被发送到Docker守护进程。非root用户:以非root用户运行容器内的应用程序进程。`RUN adduser -D appuser; USER appuser`。容器内的root如果容器被攻击仍然可能导致权限提升问题。
用于开发的docker-compose
docker-compose(现在作为Docker CLI插件的`docker compose`)是运行多容器本地开发环境的主要工具。`depends_on`陷阱:`depends_on`只等待容器启动,而不等待其中的服务就绪。快速启动但数据库进程需要5秒才能接受连接的数据库容器将导致依赖应用程序在启动时失败。解决方案:在docker-compose.yml中使用`healthcheck`定义服务实际何时就绪;在应用程序容器内使用`wait-for-it.sh`或`dockerize`轮询直到依赖项可用。环境变量:使用`.env`文件作为本地开发变量,并在docker-compose.yml中使用`${VARIABLE_NAME}`引用它们。永远不要在docker-compose.yml中提交实际密钥——引用环境变量或Docker密钥。开发用卷挂载:将源代码目录挂载到容器中可以在不重建镜像的情况下启用热重载。docker-compose.yml中的`volumes: – .:/app`。与nodemon、Air(Go)或你框架的开发模式等工具结合使用。命名卷vs绑定挂载:绑定挂载(上述)链接到主机路径;命名卷(顶部的`volumes: db_data:`,服务中的`- db_data:/var/lib/postgresql/data`)由Docker管理,不能直接作为主机路径访问。对数据库和其他有状态数据使用命名卷。
生产考虑因素
镜像大小在生产中很重要:较小的镜像意味着CI/CD中更快的拉取时间、更少的存储成本和更小的攻击面。目标:大多数Web服务低于100MB。使用基于Alpine的镜像;使用多阶段构建删除构建工具;apt-get install后的`apt-get clean && rm -rf /var/lib/apt/lists/*`。生产中的健康检查:`HEALTHCHECK –interval=30s –timeout=3s CMD curl -f http://localhost:8080/health || exit 1`——容器编排器(Kubernetes、ECS)使用健康检查来确定何时停止向容器路由流量。只读文件系统:`docker run –read-only`防止写入容器文件系统。与特定卷挂载可写区域相结合,这防止攻击者修改应用程序文件。日志管理:在容器内写入stdout/stderr——容器编排器捕获这些并将它们路由到你的日志系统。不要在容器内将日志写入文件(当容器消亡时,这些日志消失)。资源限制:始终为生产容器设置内存限制。没有内存限制的容器可以消耗所有可用的主机内存,影响其他服务。docker-compose.yml中的`deploy: resources: limits: memory: 512M`。



