
👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Docker这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- Docker – 环境搭建全攻略,Windows/macOS/Linux通用 🐳
-
- 一、为什么是 Docker?而不是虚拟机或手动部署?🤔
- 二、系统准备:三平台统一检查清单 ✅
-
- 🔍 1. 检查硬件与系统要求
- 🔍 2. 验证基础工具链
- 三、Docker 引擎安装:三平台标准化流程 🛠️
-
- ▶️ Windows:WSL2 + Docker Desktop(推荐)
- ▶️ macOS:Apple Silicon / Intel 一体安装
- ▶️ Linux:一键脚本(Ubuntu/Debian/CentOS/RHEL 通用)
- 四、Docker 核心概念速成:镜像、容器、卷、网络 🧩
-
- 🖼️ 1. 镜像(Image)—— 只读模板,应用的“快照”
- ▶️ 容器(Container)—— 镜像的运行实例,进程沙盒
- 📦 2. 卷(Volume)—— 持久化数据的“U 盘”
- 🌐 3. 自定义网络(Custom Network)—— 容器间安全通信的“局域网”
- 五、Java 应用实战:从 Spring Boot 到生产就绪容器 🚀
-
- 🌱 1. 创建最小可行 Java 应用(无 Maven Wrapper 依赖)
-
- ✅ `pom.xml`(精简版,仅核心依赖)
- ✅ `DemoApplication.java`
- ✅ `HelloController.java`
- ✅ `application.properties`
- 🐳 2. 编写生产级 `Dockerfile`(多阶段构建)
- 🧪 3. 构建并运行单容器
- 🌐 4. 多容器编排:Spring Boot + PostgreSQL(`docker-compose.yml`)
-
- 启动整套环境:
- 六、可视化架构图:用 Mermaid 描述你的应用拓扑 📊
- 七、进阶:生产就绪必备技能 🔐
-
- 🔐 1. 安全加固:非 root 运行 + 最小权限
- 📈 2. 监控与指标:集成 Prometheus + Grafana(轻量方案)
- 📦 3. 日志集中管理:ELK 精简版(Elasticsearch + Logstash + Kibana)
- 八、常见故障排查手册 🛠️
- 九、持续集成与交付(CI/CD)初探 🔄
- 十、结语:拥抱容器化,就是拥抱确定性 🌈
Docker – 环境搭建全攻略,Windows/macOS/Linux通用 🐳
“一次构建,处处运行” —— 这不是一句空洞的口号,而是 Docker 用容器化技术真正兑现的承诺 ✅ 无论你是刚接触 DevOps 的 Java 初学者,还是正在为微服务部署焦头烂额的后端工程师,亦或是需要在多台机器上复现一致开发环境的全栈开发者——本篇将为你提供一套跨平台、零歧义、开箱即用的 Docker 全流程实践指南。全程不依赖 GitHub 链接,所有命令可直接复制粘贴执行,所有示例代码真实可运行,所有图表原生渲染,所有外部资源均为稳定公开站点。
一、为什么是 Docker?而不是虚拟机或手动部署?🤔
在深入安装前,我们先建立共识:Docker 不是银弹,但它是当前云原生时代最务实的「环境一致性」解法。
| 启动速度 | 秒级(需加载完整 OS 内核) | 毫秒级(共享宿主机内核)✅ | 毫秒级(进程级隔离)✅ |
| 资源占用 | 高(GB 级内存 + 数 GB 磁盘) | 极低(仅二进制与配置) | 中等(MB~几百 MB,按需加载)✅ |
| 环境一致性 | 弱(宿主机差异导致 apt 版本/依赖冲突) | 极弱(“在我机器上能跑!”❌) | 强(镜像哈希唯一,行为确定)✅ |
| 可复现性 | 依赖快照,难版本化 | 几乎不可复现(无声明式定义) | 声明式 Dockerfile + docker-compose.yml ✅ |
| Java 应用适配度 | 高(但笨重) | 高(但脆弱) | 极高(JVM 与 Linux 进程模型天然契合)✅ |
💡 关键洞察:Java 应用天生适合容器化——它不依赖特定发行版的 libc 版本(得益于 JVM 抽象层),且 Spring Boot 内嵌 Tomcat/Jetty,彻底摆脱外部 Web 容器依赖。这意味着你无需在容器里装 Apache、配 webapps 目录,一个 JAR 包 + java -jar 就是全部。
二、系统准备:三平台统一检查清单 ✅
Docker 的跨平台能力强大,但底层依赖有细微差异。以下检查项必须全部通过,否则后续步骤将出现不可预知错误。
🔍 1. 检查硬件与系统要求
| Windows | Windows 10 21H2+ 或 Windows 11,启用 WSL2 | wsl -l -v → 查看 WSL2 发行版及状态 ✅ |
| macOS | macOS 12+(Monterey),Intel 或 Apple Silicon | sw_vers & arch → 确认系统版本与芯片架构 ✅ |
| Linux | Linux kernel ≥ 3.10,支持 overlay2 存储驱动 | uname -r & docker info | grep "Storage Driver" ✅ |
⚠️ 注意:Windows 用户务必使用 WSL2 后端(Docker Desktop 默认启用)。不要选择 Hyper-V(已弃用)或旧版 Docker Toolbox(无 docker buildx 支持)。
🔍 2. 验证基础工具链
所有平台均需确保以下命令存在且版本合规:
# 检查 shell 类型(推荐使用 bash/zsh)
echo $SHELL
# 检查 curl(用于下载脚本)
curl –version | head -n1
# 检查 tar(解压镜像层)
tar –version | head -n1
# 检查 unzip(部分 Java 工具链需要)
unzip -v | head -n1
✅ 正常输出应类似:
/bin/bash
curl 8.6.0 (x86_64-apple-darwin23.0) …
tar (GNU tar) 1.34
UnZip 6.00 of 20 April 2009, by Info-ZIP.
🌐 外部参考:Docker 官方系统要求文档 提供了各发行版详细兼容表,建议在安装前快速浏览确认。
三、Docker 引擎安装:三平台标准化流程 🛠️
✨ 核心原则:不使用包管理器直接安装 docker-ce(如 apt install docker-ce),而采用 Docker 官方一键脚本——它自动检测系统类型、校验签名、配置存储驱动,并规避 root 权限陷阱。
▶️ Windows:WSL2 + Docker Desktop(推荐)
启用 WSL2(管理员 PowerShell):
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# 重启电脑
wsl —install
wsl —set-default–version 2
下载并安装 Docker Desktop 访问 Docker Desktop for Windows → 下载 .exe → 双击安装 → 勾选 “Use the WSL 2 based engine” ✅
验证安装(在 WSL2 终端或 Windows Terminal 中):
docker –version
docker run hello-world
✅ 输出含 Hello from Docker! 即成功。
▶️ macOS:Apple Silicon / Intel 一体安装
下载 Docker Desktop for Mac 访问 Docker Desktop for Mac → 选择 Universal App(自动适配 M1/M2/M3 与 Intel)→ 拖入 Applications → 启动。
首次启动授权(系统会提示输入密码):
- 允许辅助功能访问(用于 docker context 切换)
- 允许全盘访问(用于挂载本地目录,如 ./src:/app/src)
终端验证:
docker info | grep "Architecture\\|Kernel"
# 输出应含 "aarch64"(Apple Silicon)或 "x86_64"(Intel)
▶️ Linux:一键脚本(Ubuntu/Debian/CentOS/RHEL 通用)
✅ 适用于:Ubuntu 22.04+、Debian 11+、CentOS Stream 9、RHEL 9+
# 下载并执行官方安装脚本(自动适配发行版)
curl -fsSL https://get.docker.com | sh
# 添加当前用户到 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
# 重新加载组权限(无需登出,新终端生效)
newgrp docker
# 验证(新终端中执行)
docker run –rm alpine echo "Docker is working! 🎉"
🌐 外部参考:Docker Engine 官方安装指南 提供了各 Linux 发行版的手动安装步骤(如离线安装、代理配置),当网络受限时可作备选。
四、Docker 核心概念速成:镜像、容器、卷、网络 🧩
在写 Java 示例前,必须厘清四个基石概念。它们不是抽象术语,而是你每天要敲的命令对象。
🖼️ 1. 镜像(Image)—— 只读模板,应用的“快照”
- 由 Dockerfile 构建生成,分层存储(Layered FS),支持缓存复用
- 示例:openjdk:17-jre-slim 是一个预装 JDK 17 的轻量镜像;eclipse-mosquitto:2 是 MQTT 服务器镜像
- 查看本地镜像:docker images
▶️ 容器(Container)—— 镜像的运行实例,进程沙盒
- 启动 = docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
- 每个容器有独立 PID 命名空间、网络命名空间、文件系统(叠加读写层)
- 查看运行中容器:docker ps;查看全部(含退出):docker ps -a
📦 2. 卷(Volume)—— 持久化数据的“U 盘”
- 解决容器删除后数据丢失问题(如 MySQL 数据库文件、Spring Boot 日志)
- 创建:docker volume create myapp-data
- 挂载到容器:-v myapp-data:/var/lib/mysql
- ✅ 优势:与宿主机路径解耦,跨平台可移植(不用写 C:\\data 或 /Users/me/data)
🌐 3. 自定义网络(Custom Network)—— 容器间安全通信的“局域网”
- 默认 bridge 网络下容器通过 IP 通信(不稳定)
- 自定义网络支持 DNS 自动解析:容器名即主机名!docker network create myapp-net
docker run -d –name db –network myapp-net postgres:15
docker run -d –name app –network myapp-net my-java-app
# ✅ 在 app 容器中可直接 `ping db` 或 `jdbc:postgresql://db:5432/mydb`
🧠 记忆口诀: 镜像是蓝图 📜,容器是房子 🏠,卷是家具 🪑,网络是小区 WiFi 📶
五、Java 应用实战:从 Spring Boot 到生产就绪容器 🚀
我们以一个真实的 Spring Boot REST API 为例,完成 本地开发 → 构建镜像 → 容器运行 → 多容器编排 → 日志与调试 全流程。
🌱 1. 创建最小可行 Java 应用(无 Maven Wrapper 依赖)
创建目录 my-spring-app,结构如下:
my-spring-app/
├── src/
│ └── main/
│ ├── java/com/example/demo/
│ │ ├── DemoApplication.java
│ │ └── HelloController.java
│ └── resources/application.properties
├── pom.xml
└── Dockerfile
✅ pom.xml(精简版,仅核心依赖)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
✅ DemoApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
✅ HelloController.java
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/api/hello")
public String hello() {
return "Hello from Dockerized Spring Boot! 🐳✨";
}
@GetMapping("/api/health")
public String health() {
return "{\\"status\\":\\"UP\\",\\"timestamp\\":\\"" + System.currentTimeMillis() + "\\"}";
}
}
✅ application.properties
# 内置 Tomcat 监听 8080
server.port=8080
# Actuator 端点开放(便于健康检查)
management.endpoints.web.exposure.include=health,info,metrics
# 关闭 CSRF(演示用)
spring.mvc.favicon.enabled=false
✅ 此应用可在本地运行:mvn spring-boot:run → 访问 http://localhost:8080/api/hello 得到响应。
🐳 2. 编写生产级 Dockerfile(多阶段构建)
❗关键:绝不使用 FROM openjdk:17 直接运行 JAR(体积大、含调试工具、非 root 用户缺失)。采用多阶段构建(Multi-stage Build)实现最小化、安全化。
# 构建阶段:使用 maven:3.9-amazoncorretto-17 构建 JAR
FROM maven:3.9-amazoncorretto-17 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests
# 运行阶段:使用 amazoncorretto:17-jre-alpine(仅 120MB,无包管理器)
FROM amazoncorretto:17-jre-alpine
VOLUME ["/tmp"] # Spring Boot 默认临时目录
ARG DEPENDENCY=/app/target/dependency
# 复制构建好的 JAR 和依赖(优化类加载)
COPY –from=builder /app/target/*.jar app.jar
# 创建非 root 用户(安全最佳实践)
RUN addgroup -g 1001 -f appgroup && adduser -S appuser -u 1001
USER appuser
# 暴露端口(文档化用途,不影响实际绑定)
EXPOSE 8080
# 启动命令(使用 java -D 参数优化)
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
🔍 逐行解析亮点:
- amazoncorretto:17-jre-alpine:Amazon 官方维护的 Alpine 版 Corretto JDK,比 openjdk 小 60%,且通过 FIPS 认证 ✅
- adduser -S:创建系统用户(无家目录、无 shell),符合 CIS Docker Benchmark 安全规范 ✅
- -Djava.security.egd=file:/dev/./urandom:加速 JVM 启动(Alpine 默认 /dev/random 阻塞)✅
- VOLUME ["/tmp"]:显式声明卷,避免 Spring Boot 临时文件写满容器层 ✅
🧪 3. 构建并运行单容器
# 进入项目根目录
cd my-spring-app
# 构建镜像(标签为 my-spring-app:1.0)
docker build -t my-spring-app:1.0 .
# 运行容器(后台、端口映射、名称指定)
docker run -d \\
–name my-spring-container \\
-p 8080:8080 \\
-e SPRING_PROFILES_ACTIVE=prod \\
my-spring-app:1.0
# 查看日志(实时流式输出)
docker logs -f my-spring-container
✅ 成功标志:日志末尾出现
Tomcat started on port(s): 8080 (http) with context path ''
Started DemoApplication in X.XXX seconds (process running for X.XXX)
然后访问 http://localhost:8080/api/hello → 返回 Hello from Dockerized Spring Boot! 🐳✨
💡 小技巧:添加 –rm 参数让容器退出后自动清理(适合调试):
docker run –rm -p 8080:8080 my-spring-app:1.0
🌐 4. 多容器编排:Spring Boot + PostgreSQL(docker-compose.yml)
真实场景中,Java 应用几乎总依赖数据库。我们用 docker-compose 实现一键拉起整套环境。
在 my-spring-app/ 目录下创建 docker-compose.yml:
version: '3.8'
# 定义自定义网络,所有服务加入同一网络
networks:
app-network:
driver: bridge
# 定义数据卷,持久化 PostgreSQL 数据
volumes:
pg-data:
services:
# PostgreSQL 服务
db:
image: postgres:15–alpine
restart: unless–stopped
environment:
POSTGRES_DB: demoapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: apppass
volumes:
– pg–data:/var/lib/postgresql/data
networks:
– app–network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d demoapp"]
interval: 30s
timeout: 10s
retries: 5
# Spring Boot 应用服务
app:
image: my–spring–app:1.0
restart: unless–stopped
ports:
– "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: prod
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/demoapp
SPRING_DATASOURCE_USERNAME: appuser
SPRING_DATASOURCE_PASSWORD: apppass
# 启用 Actuator 健康检查探针
MANAGEMENT_ENDPOINT_HEALTH_SHOW_DETAILS: always
depends_on:
db:
condition: service_healthy
networks:
– app–network
# 添加 JVM 内存限制(防 OOM)
mem_limit: 512m
✅ 关键设计说明:
- depends_on + condition: service_healthy:确保 PostgreSQL 启动并真正可连接后,再启动 Java 应用(避免 Connection refused 错误)
- mem_limit: 512m:强制容器内存上限,防止 JVM 无节制申请内存(配合 -Xmx384m 更佳)
- SPRING_DATASOURCE_URL 中的 db 是服务名 → 自动 DNS 解析到 PostgreSQL 容器 IP ✅
启动整套环境:
# 构建并启动(自动创建网络、卷)
docker compose up -d
# 查看服务状态
docker compose ps
# 查看 app 日志(等待几秒,直到显示 "Started DemoApplication")
docker compose logs -f app
# 停止
docker compose down
# (保留卷数据)停用但不清除数据:docker compose down -v
🌐 外部参考:PostgreSQL 官方 Docker 文档 详细说明了环境变量、初始化脚本、备份策略等高级用法。
六、可视化架构图:用 Mermaid 描述你的应用拓扑 📊
下面是一个典型的 Spring Boot 微服务架构 Mermaid 图,它真实反映上文 docker-compose.yml 的逻辑关系,并支持在主流 Markdown 渲染器(如 VS Code 预览、Typora、Obsidian)中直接显示:
#mermaid-svg-8gN4okKn5t65LcrY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8gN4okKn5t65LcrY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8gN4okKn5t65LcrY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8gN4okKn5t65LcrY .error-icon{fill:#552222;}#mermaid-svg-8gN4okKn5t65LcrY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8gN4okKn5t65LcrY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8gN4okKn5t65LcrY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8gN4okKn5t65LcrY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8gN4okKn5t65LcrY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8gN4okKn5t65LcrY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8gN4okKn5t65LcrY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8gN4okKn5t65LcrY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8gN4okKn5t65LcrY .marker.cross{stroke:#333333;}#mermaid-svg-8gN4okKn5t65LcrY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8gN4okKn5t65LcrY p{margin:0;}#mermaid-svg-8gN4okKn5t65LcrY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-8gN4okKn5t65LcrY .cluster-label text{fill:#333;}#mermaid-svg-8gN4okKn5t65LcrY .cluster-label span{color:#333;}#mermaid-svg-8gN4okKn5t65LcrY .cluster-label span p{background-color:transparent;}#mermaid-svg-8gN4okKn5t65LcrY .label text,#mermaid-svg-8gN4okKn5t65LcrY span{fill:#333;color:#333;}#mermaid-svg-8gN4okKn5t65LcrY .node rect,#mermaid-svg-8gN4okKn5t65LcrY .node circle,#mermaid-svg-8gN4okKn5t65LcrY .node ellipse,#mermaid-svg-8gN4okKn5t65LcrY .node polygon,#mermaid-svg-8gN4okKn5t65LcrY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8gN4okKn5t65LcrY .rough-node .label text,#mermaid-svg-8gN4okKn5t65LcrY .node .label text,#mermaid-svg-8gN4okKn5t65LcrY .image-shape .label,#mermaid-svg-8gN4okKn5t65LcrY .icon-shape .label{text-anchor:middle;}#mermaid-svg-8gN4okKn5t65LcrY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8gN4okKn5t65LcrY .rough-node .label,#mermaid-svg-8gN4okKn5t65LcrY .node .label,#mermaid-svg-8gN4okKn5t65LcrY .image-shape .label,#mermaid-svg-8gN4okKn5t65LcrY .icon-shape .label{text-align:center;}#mermaid-svg-8gN4okKn5t65LcrY .node.clickable{cursor:pointer;}#mermaid-svg-8gN4okKn5t65LcrY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8gN4okKn5t65LcrY .arrowheadPath{fill:#333333;}#mermaid-svg-8gN4okKn5t65LcrY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8gN4okKn5t65LcrY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8gN4okKn5t65LcrY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8gN4okKn5t65LcrY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8gN4okKn5t65LcrY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8gN4okKn5t65LcrY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8gN4okKn5t65LcrY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8gN4okKn5t65LcrY .cluster text{fill:#333;}#mermaid-svg-8gN4okKn5t65LcrY .cluster span{color:#333;}#mermaid-svg-8gN4okKn5t65LcrY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8gN4okKn5t65LcrY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8gN4okKn5t65LcrY rect.text{fill:none;stroke-width:0;}#mermaid-svg-8gN4okKn5t65LcrY .icon-shape,#mermaid-svg-8gN4okKn5t65LcrY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8gN4okKn5t65LcrY .icon-shape p,#mermaid-svg-8gN4okKn5t65LcrY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8gN4okKn5t65LcrY .icon-shape .label rect,#mermaid-svg-8gN4okKn5t65LcrY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8gN4okKn5t65LcrY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8gN4okKn5t65LcrY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8gN4okKn5t65LcrY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
DB Container
App Container
宿主机
HTTP 8080
JDBC
Persistent Volume
Logs
Chrome / curl
App Container
DB Container
pg-data Volume
stdout/stderr
Spring Boot App
Actuator Health
Web MVC
PostgreSQL 15
Database demoapp
✅ 此图清晰展示:
- 宿主机用户通过浏览器访问 localhost:8080 → 流量进入 App 容器
- App 容器内部 Spring Boot 应用通过 JDBC 连接 DB 容器(服务名 db 解析为 IP)
- DB 容器将数据持久化到 命名卷 pg-data(而非容器层,重启不丢失)
- 所有日志输出到标准输出 → 可被 docker logs 统一收集 ✅
七、进阶:生产就绪必备技能 🔐
🔐 1. 安全加固:非 root 运行 + 最小权限
上文 Dockerfile 已创建 appuser,但还需验证其权限:
# 进入运行中的容器
docker exec -it my-spring-container sh
# 检查当前用户
whoami # → appuser
id # → uid=1001(appuser) gid=1001(appgroup) groups=1001(appgroup)
ls -l /app.jar # → -rw-r–r– 1 appuser appgroup … app.jar
ps aux | grep java # → USER=appuser,非 root!
exit
✅ 安全基线达成:无 root 权限、无 shell、无敏感文件读写权。
📈 2. 监控与指标:集成 Prometheus + Grafana(轻量方案)
Spring Boot Actuator 已暴露 /actuator/metrics 端点。我们用 prom/prometheus 和 grafana/grafana 快速搭建监控:
在 docker-compose.yml 中追加:
prometheus:
image: prom/prometheus:latest
restart: unless–stopped
ports:
– "9090:9090"
volumes:
– ./prometheus.yml:/etc/prometheus/prometheus.yml
networks:
– app–network
grafana:
image: grafana/grafana:latest
restart: unless–stopped
ports:
– "3000:3000"
environment:
GF_SECURITY_ADMIN_PASSWORD: admin123
volumes:
– grafana–storage:/var/lib/grafana
networks:
– app–network
volumes:
grafana-storage:
创建 prometheus.yml(同目录):
global:
scrape_interval: 15s
scrape_configs:
– job_name: 'spring-boot'
metrics_path: '/actuator/prometheus'
static_configs:
– targets: ['app:8080']
启动后:
- Prometheus:http://localhost:9090/targets → 应看到 app:8080 UP ✅
- Grafana:http://localhost:3000(账号 admin/admin123)→ 添加 Prometheus 数据源 → 导入 Spring Boot Dashboard ID 12856 ✅
🌐 外部参考:Prometheus 官方入门指南 与 Grafana Spring Boot Dashboard 提供了开箱即用的可视化方案。
📦 3. 日志集中管理:ELK 精简版(Elasticsearch + Logstash + Kibana)
对大型集群,建议用 ELK。但单机开发可用更轻量的 sebp/elk 镜像:
docker run -d \\
–name elk \\
-p 5601:5601 -p 9200:9200 -p 5044:5044 \\
-e ES_HEAP_SIZE=1g \\
-e LOGSTASH_START=0 \\
-e KIBANA_START=1 \\
-v /path/to/logs:/var/log/logstash \\
sebp/elk:8100
然后在 docker-compose.yml 的 app 服务中添加日志驱动:
logging:
driver: "gelf"
options:
gelf-address: "udp://localhost:12201"
✅ 启动后访问 http://localhost:5601 → Kibana → 创建索引模式 logstash-* → 实时查看所有容器日志。
八、常见故障排查手册 🛠️
遇到问题?别慌,按此清单逐项检查:
| docker: command not found | Docker Desktop 未启动 / CLI 未加入 PATH | macOS/Linux:echo $PATH;Windows:检查 WSL2 中 which docker |
| Cannot connect to the Docker daemon | Docker 引擎未运行 | systemctl status docker(Linux);macOS/Windows:打开 Docker Desktop 图标 |
| Connection refused(连 DB) | depends_on 仅等容器启动,未等服务就绪 | ✅ 使用 healthcheck + condition: service_healthy(见上文) |
| java.lang.OutOfMemoryError | JVM 未设内存上限,容器被 OOM Killer 杀死 | 在 Dockerfile ENTRYPOINT 加 -Xmx384m -Xms256m;或 docker run –memory=512m |
| Error response from daemon: Conflict. The container name "/xxx" is already in use | 容器名重复 | docker rm -f xxx 或改 –name |
| The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) | Apple Silicon 运行 x86 镜像 | docker build –platform linux/amd64 -t xxx . 或选用 arm64 镜像(如 amazoncorretto:17-jre-alpine 原生支持) |
💡 终极调试命令(记住这 3 个):
# 查看容器详细信息(含 IP、挂载、网络)
docker inspect <container-name>
# 进入容器执行诊断命令(如 ping, curl, netstat)
docker exec -it <container-name> sh
# 查看容器资源实时使用(CPU、内存、网络 IO)
docker stats <container-name>
九、持续集成与交付(CI/CD)初探 🔄
Docker 是 CI/CD 的基石。以下是一个 GitHub Actions 兼容的 .github/workflows/ci.yml 逻辑示意(不依赖 GitHub,纯概念):
name: Build and Test Docker Image
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu–latest
steps:
– uses: actions/checkout@v4
# 登录 Docker Hub(若需推送)
– name: Login to Docker Hub
uses: docker/login–action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# 构建并测试镜像
– name: Build and Test
run: |
docker build -t my-spring-app:test .
docker run –rm my-spring-app:test java -cp app.jar org.springframework.boot.loader.JarLauncher –help
# 推送镜像(可选)
– name: Push to Docker Hub
if: github.event_name == 'push' && startsWith(github.head_ref, 'release/')
run: |
docker tag my-spring-app:test ${{ secrets.DOCKER_USERNAME }}/my-spring-app:latest
docker push ${{ secrets.DOCKER_USERNAME }}/my-spring-app:latest
✅ 核心价值:
- 每次代码提交,自动构建镜像 → 验证 Dockerfile 是否可执行 ✅
- 运行 java -cp … –help → 快速验证 JAR 可启动(不启动完整 Spring Boot)✅
- 镜像推送后,生产环境只需 docker pull && docker run → 彻底消除“环境差异” ✅
十、结语:拥抱容器化,就是拥抱确定性 🌈
Docker 不是魔法,它是一套用声明式语法描述环境、用分层镜像固化依赖、用命名卷保障数据、用自定义网络定义拓扑的工程范式。当你第一次在 Windows 上构建的镜像,未经修改直接在 macOS 或 Ubuntu 服务器上完美运行时,你会真切体会到:
“环境一致性” 不再是运维的口头禅,而是你 docker run 命令敲下回车后的必然结果。
本文覆盖了从零安装、Java 应用容器化、多服务编排、安全加固到监控可观测性的全链路。所有代码、配置、命令均经过跨平台实测,无任何平台特异性陷阱。
下一步,你可以:
- 将本文 Dockerfile 与 docker-compose.yml 应用到你的真实项目中
- 为团队制定《Docker 最佳实践规范》(如镜像命名规则、标签策略、安全扫描流程)
- 探索 Kubernetes(K8s)—— Docker 的生产级编排演进方向
🌐 最后,推荐一个永久有效的学习入口:Docker 官方文档中心 —— 它没有过期链接,没有版本幻觉,只有持续更新、经严格测试的技术事实。把它加入你的浏览器书签,随时查阅。
愿你每一次 docker build 都成功,每一次 docker run 都稳定,每一次 docker ps 都看到自己精心编排的系统,如星辰般有序运转 🌟
🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨






