2. Docker 基础回顾:Docker 镜像与容器、Dockerfile 编写、Docker Compose 入门
在微服务架构的故障排查与日志分析中,Docker 是底层运行环境的核心。理解 Docker 的三大基础概念——镜像、容器与编排——是后续进行容器级监控、日志采集和故障定位的前提。本节将系统回顾 Docker 镜像与容器的生命周期、Dockerfile 的最佳编写实践,以及 Docker Compose 在微服务环境中的入门用法。
2.1 Docker 镜像与容器:核心概念与生命周期
Docker 镜像是一个只读的、分层构建的模板,包含了运行某个应用所需的完整文件系统、依赖库、环境变量和启动命令。容器则是镜像的一个可写、可运行的实例。镜像与容器的关系类似于面向对象编程中的“类”与“对象”。
| 概念 | 特性 | 生命周期 | 典型操作 |
|---|---|---|---|
| 镜像 (Image) | 只读、分层、可分发 | 构建 → 存储 → 拉取/推送 → 删除 | docker build, docker pull, docker push, docker rmi |
| 容器 (Container) | 可写层、隔离、可运行 | 创建 → 启动 → 运行 → 停止 → 删除 | docker run, docker start, docker stop, docker rm |
故障排查要点: 当容器日志丢失或应用异常退出时,优先检查容器状态(
docker ps -a)和镜像层缓存(docker history)。容器停止后,其可写层默认保留,但若使用 --rm 参数,退出后容器会被自动删除,日志文件也会随之消失。
下图展示了镜像分层构建与容器实例化的核心流程:
2.2 Dockerfile 编写:从基础到生产级实践
Dockerfile 是定义镜像构建过程的脚本。在微服务架构中,每个服务通常对应一个 Dockerfile。编写 Dockerfile 时,需要关注镜像体积、构建缓存、安全性和可重复性。
2.2.1 核心指令速查表
| 指令 | 作用 | 最佳实践 |
|---|---|---|
FROM |
指定基础镜像 | 优先使用官方 Alpine 或 slim 版本,减少攻击面 |
RUN |
执行命令并创建新层 | 合并多个 RUN 命令,减少层数;使用 && 连接 |
COPY / ADD |
将文件从上下文复制到镜像 | 优先使用 COPY;ADD 仅用于自动解压 tar 或远程 URL |
WORKDIR |
设置工作目录 | 始终使用绝对路径,避免 cd 命令 |
EXPOSE |
声明容器监听端口 | 仅作为文档用途,实际端口映射在 docker run -p 中指定 |
CMD / ENTRYPOINT |
指定容器启动命令 | ENTRYPOINT 用于固定执行程序,CMD 提供默认参数 |
2.2.2 生产级 Dockerfile 示例(Java Spring Boot 微服务)
# 1. 多阶段构建:编译阶段
FROM maven:3.8.6-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests
# 2. 运行阶段:使用最小化 JRE 镜像
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 从 builder 阶段复制构建产物
COPY --from=builder /app/target/*.jar app.jar
# 非 root 用户运行,提升安全性
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
故障排查提示: 如果容器启动后立即退出,检查
ENTRYPOINT 或 CMD 中的命令是否在前台运行。例如,java -jar 默认在前台运行,但若使用 nohup 或 & 将进程放入后台,容器会立即退出。日志采集时,确保应用日志输出到 stdout/stderr,而非文件。
2.3 Docker Compose 入门:微服务编排基础
Docker Compose 通过一个 docker-compose.yml 文件定义和运行多个容器。在微服务架构中,Compose 常用于本地开发环境、CI/CD 测试环境以及小型生产部署。它解决了“手动启动多个容器并配置网络、卷、环境变量”的痛点。
2.3.1 Compose 文件核心结构
version: '3.8'
services:
# 服务 A:用户服务
user-service:
build: ./user-service
ports:
- "8081:8080"
environment:
- DB_HOST=postgres
- DB_PORT=5432
depends_on:
- postgres
networks:
- backend
# 服务 B:订单服务
order-service:
build: ./order-service
ports:
- "8082:8080"
environment:
- REDIS_HOST=redis
depends_on:
- redis
networks:
- backend
# 基础设施:PostgreSQL
postgres:
image: postgres:15-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: microservices
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
networks:
- backend
# 基础设施:Redis
redis:
image: redis:7-alpine
networks:
- backend
volumes:
pgdata:
networks:
backend:
driver: bridge
2.3.2 常用 Compose 命令与故障排查场景
| 命令 | 用途 | 故障排查场景 |
|---|---|---|
docker-compose up -d |
后台启动所有服务 | 服务启动顺序异常时,检查 depends_on 配置 |
docker-compose logs -f |
实时查看所有服务日志 | 定位哪个服务启动失败或抛出异常 |
docker-compose ps |
查看服务状态 | 确认容器是否处于 Up 或 Exit 状态 |
docker-compose exec <service> sh |
进入运行中的容器 | 手动检查配置文件、环境变量或网络连通性 |
docker-compose down -v |
停止并删除容器、网络、卷 | 清理环境后重新部署,解决数据或网络残留问题 |
常见陷阱: Compose 中的
depends_on 仅控制容器启动顺序,不等待服务内部就绪。例如,user-service 依赖 postgres,但 PostgreSQL 可能尚未完成初始化。建议在应用代码中添加重试机制,或使用 healthcheck 指令确保依赖服务真正可用。
下图展示了使用 Docker Compose 编排的典型微服务拓扑结构: