1. 为什么选择这套技术栈?
这套组合拳在中小型互联网项目中几乎成了标配。Docker 提供了环境隔离和快速部署能力,Redis 作为高性能缓存解决高并发场景下的数据读取瓶颈,SpringBoot 简化了后端服务开发,Nginx 则承担着流量入口和负载均衡的重任。
我在三个不同规模的项目中验证过这个架构:
- 电商秒杀系统(日均 50 万 PV)
- 在线教育平台(峰值 3000 并发)
- IoT 数据中台(每秒 2 万+ 设备消息)
实测下来,这套架构在 1C2G 的云服务器上就能支撑日均 100 万 PV 的访问量。特别是 Docker 化部署后,从代码提交到生产环境上线只需 7 分钟(传统方式至少 2 小时)。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与工具选型
2.1 宿主机环境配置
推荐使用 Ubuntu 20.04 LTS,这是目前最稳定的生产环境选择。关键配置项:
bash复制# 关闭 swap(Redis 性能杀手)
sudo swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 调整内核参数
echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf
sysctl -p
特别注意:如果使用 Windows 开发环境,WSL2 的虚拟化问题会导致 Docker 启动失败。错误提示 "virtualisation support wasn't detected" 时:
- 检查 BIOS 中开启 VT-x/AMD-V
- 以管理员身份运行:
bcdedit /set hypervisorlaunchtype auto- 重启后执行
wsl --update
2.2 Docker 安装与优化
使用国内镜像源加速安装:
bash复制curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
配置 Docker 镜像加速(在 /etc/docker/daemon.json):
json复制{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
重启服务后验证:
bash复制sudo systemctl restart docker
docker info | grep -i mirror
3. Redis 容器化部署实战
3.1 单节点部署
使用官方镜像启动 Redis:
bash复制docker run -d --name redis-server \
-p 6379:6379 \
-v /data/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf \
-v /data/redis/data:/data \
redis:6.2-alpine \
redis-server /usr/local/etc/redis/redis.conf
关键配置项(redis.conf):
conf复制# 绑定所有网络接口
bind 0.0.0.0
# 启用持久化
appendonly yes
appendfilename "appendonly.aof"
# 内存策略(根据实际情况调整)
maxmemory 1gb
maxmemory-policy allkeys-lru
3.2 主从集群搭建
创建自定义网络:
bash复制docker network create redis-net
启动主节点:
bash复制docker run -d --name redis-master \
--net redis-net \
-v /data/redis/master/conf/redis.conf:/usr/local/etc/redis/redis.conf \
redis:6.2-alpine \
redis-server /usr/local/etc/redis/redis.conf --appendonly yes
启动从节点(注意 replicaof 参数):
bash复制docker run -d --name redis-replica \
--net redis-net \
-v /data/redis/replica/conf/redis.conf:/usr/local/etc/redis/redis.conf \
redis:6.2-alpine \
redis-server /usr/local/etc/redis/redis.conf \
--replicaof redis-master 6379 \
--appendonly yes
验证主从同步:
bash复制docker exec -it redis-master redis-cli info replication
4. SpringBoot 应用容器化
4.1 Dockerfile 最佳实践
多阶段构建示例:
dockerfile复制# 构建阶段
FROM maven:3.8.4-openjdk-11 AS build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
构建优化技巧:
- 使用
.dockerignore排除无关文件 - 固定基础镜像版本(避免使用 latest)
- 分层的 COPY 指令顺序(把变化频率低的放前面)
4.2 容器网络互联
创建应用专属网络:
bash复制docker network create app-net
启动应用并连接 Redis:
bash复制docker run -d --name myapp \
--net app-net \
-p 8080:8080 \
-e "SPRING_REDIS_HOST=redis-server" \
myapp:latest
5. Nginx 配置与优化
5.1 反向代理配置
基础配置模板(nginx.conf):
nginx复制upstream backend {
server myapp:8080;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg)$ {
expires 30d;
add_header Cache-Control "public";
}
}
启动 Nginx 容器:
bash复制docker run -d --name nginx \
--net app-net \
-p 80:80 \
-v /path/to/nginx.conf:/etc/nginx/nginx.conf \
nginx:1.21-alpine
5.2 性能调优参数
调整 worker 进程数(nginx.conf 的 main 上下文):
nginx复制worker_processes auto;
worker_rlimit_nofile 100000;
events {
worker_connections 2048;
multi_accept on;
use epoll;
}
TCP 优化(在 http 上下文):
nginx复制sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
6. 常见问题排查手册
6.1 Docker 容器网络不通
排查步骤:
- 检查容器是否在同一个网络:
bash复制
docker network inspect app-net - 测试容器间连通性:
bash复制docker exec -it nginx ping myapp - 检查 iptables 规则:
bash复制sudo iptables -L -n
6.2 Redis 连接超时
典型错误日志:
code复制io.lettuce.core.RedisConnectionException: Unable to connect to redis-server:6379
解决方案:
- 确认 Redis 绑定地址为 0.0.0.0
- 检查防火墙规则:
bash复制sudo ufw status - 测试从容器内部连接:
bash复制docker exec -it myapp telnet redis-server 6379
6.3 Nginx 502 Bad Gateway
诊断流程:
- 查看 Nginx 错误日志:
bash复制docker logs nginx --tail 100 - 检查后端服务健康状态:
bash复制docker exec -it nginx curl -I http://myapp:8080/actuator/health - 调整 proxy 超时时间:
nginx复制proxy_connect_timeout 60s; proxy_read_timeout 60s;
7. 生产环境增强建议
7.1 监控方案
推荐组合:
- Prometheus + Grafana 监控容器指标
- ELK 收集日志
- SpringBoot Actuator 暴露健康检查
Docker Compose 示例:
yaml复制version: '3'
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
7.2 安全加固措施
必做清单:
- Redis 设置密码:
conf复制requirepass yourstrongpassword - Nginx 禁用 server_tokens:
nginx复制server_tokens off; - Docker 容器用户非 root 运行:
dockerfile复制USER nobody - 定期更新镜像版本
8. 部署流程自动化
8.1 CI/CD 流水线示例
GitHub Actions 配置片段:
yaml复制jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
docker pull myapp:${{ github.sha }}
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp \
--net app-net \
-p 8080:8080 \
myapp:${{ github.sha }}
8.2 数据库迁移方案
使用 Flyway 进行版本控制:
java复制@Configuration
public class FlywayConfig {
@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() {
return flyway -> {
flyway.repair();
flyway.migrate();
};
}
}
SpringBoot 配置:
properties复制spring.flyway.locations=classpath:db/migration
spring.flyway.baseline-on-migrate=true
9. 性能压测对比数据
使用 JMeter 进行基准测试(4C8G 服务器):
| 场景 | 纯物理机部署 | Docker 化部署 | 性能损耗 |
|---|---|---|---|
| 静态页面 QPS | 12,000 | 11,500 | 4.2% |
| Redis GET 操作 QPS | 85,000 | 82,000 | 3.5% |
| SpringBoot API QPS | 3,200 | 3,100 | 3.1% |
关键发现:
- 网络密集型操作损耗较高(约 5-7%)
- CPU 密集型操作几乎无差别
- 内存消耗增加约 10-15%
10. 实际踩坑记录
10.1 时区问题
现象:日志时间比实际晚 8 小时
解决方案:
dockerfile复制ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
10.2 文件描述符限制
现象:Nginx 报 "too many open files"
解决方法:
bash复制docker run --ulimit nofile=65535:65535 nginx
10.3 内存溢出
现象:Java 容器被 OOM killed
调整方案:
bash复制docker run -m 2g --memory-swap 2g myapp
11. 扩展架构建议
11.1 微服务化改造
当单体应用达到 50+ API 接口时,建议拆分为:
- 用户服务
- 商品服务
- 订单服务
- 支付服务
使用 Spring Cloud 组件:
- Nacos 服务发现
- Sentinel 流量控制
- Seata 分布式事务
11.2 高可用方案
关键组件冗余部署:
- Redis Sentinel 集群
- Nginx + Keepalived 双活
- MySQL 主从复制
12. 本地开发环境配置
12.1 IDE 集成技巧
IntelliJ IDEA 配置:
- 安装 Docker 插件
- 配置远程解释器:
- 选择 Docker Daemon
- 映射端口 8080:8080
- 启用 Live Reload
12.2 本地调试方案
启动 Redis 和 Nginx:
bash复制docker-compose -f docker-compose-dev.yml up
调试配置(application.properties):
properties复制spring.redis.host=localhost
server.servlet.context-path=/api
13. 日志收集方案
13.1 ELK 栈部署
docker-compose.yml 示例:
yaml复制version: '3'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
environment:
- discovery.type=single-node
kibana:
image: docker.elastic.co/kibana/kibana:7.14.0
ports:
- "5601:5601"
logstash:
image: docker.elastic.co/logstash/logstash:7.14.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
13.2 日志规范建议
推荐日志格式:
java复制@Slf4j
@RestController
public class UserController {
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
log.info("Get user request received, id: {}", id);
// ...
}
}
14. 成本优化策略
14.1 镜像瘦身技巧
对比不同基础镜像大小:
| 基础镜像 | 大小 | 适用场景 |
|---|---|---|
| openjdk:17-jdk | 471MB | 开发环境 |
| openjdk:17-jre | 237MB | 生产环境 |
| eclipse-temurin:17-jre-alpine | 89MB | 资源受限环境 |
14.2 资源配额管理
按业务峰谷调整:
bash复制# 业务高峰时
docker update --cpus 2 --memory 4g myapp
# 夜间低谷时
docker update --cpus 0.5 --memory 1g myapp
15. 版本升级指南
15.1 滚动更新策略
使用 Docker Swarm 或 Kubernetes:
bash复制docker service update \
--image myapp:v2 \
--update-parallelism 2 \
--update-delay 10s \
myapp_service
15.2 回滚方案
快速回退到上一版本:
bash复制docker run -d --name myapp_rollback \
--net app-net \
-p 8080:8080 \
myapp:previous_stable
