📖 前言
容器化技术已经成为现代软件部署的标准实践。作为一名DevOps工程师,我在过去几年中参与了数十个项目的容器化改造,深刻体会到Docker在提升部署效率、环境一致性和运维便利性方面的巨大价值。
今天我将通过一个完整的实战案例,详细展示如何使用Docker部署一个包含Spring Boot后端、MySQL数据库和Nginx反向代理的完整Web应用,让你从零开始掌握容器化部署的核心技能!
🎯 本文你将学到:
- Docker容器化的核心概念和最佳实践
- Dockerfile编写技巧和优化策略
- docker-compose多容器编排
- Spring Boot应用的容器化实践
- MySQL数据库容器化配置
- Nginx反向代理和负载均衡
- 生产环境部署和监控方案
🚀 环境准备
系统要求
# 操作系统:Linux/macOS/Windows
- Docker Engine 20.10+
- Docker Compose 2.0+
- 最少 4GB 内存
- 最少 20GB 可用磁盘空间
安装Docker
Linux (Ubuntu/CentOS):
# 安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker# 添加当前用户到docker组
sudo usermod -aG docker $USER# 安装docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
验证安装:
docker --version
docker-compose --version
🏗️ 项目架构设计
整体架构图
┌─────────────────────────────────────────────┐
│ 用户请求 │
└─────────────────┬───────────────────────────┘│
┌─────────────────▼───────────────────────────┐
│ Nginx (Port 80) │
│ • 反向代理 │
│ • 负载均衡 │
│ • 静态资源服务 │
└─────────────────┬───────────────────────────┘│
┌─────────────────▼───────────────────────────┐
│ Spring Boot App (Port 8080) │
│ • REST API │
│ • 业务逻辑处理 │
│ • 数据库操作 │
└─────────────────┬───────────────────────────┘│
┌─────────────────▼───────────────────────────┐
│ MySQL (Port 3306) │
│ • 数据持久化 │
│ • 数据备份 │
└─────────────────────────────────────────────┘
容器编排策略
# 服务依赖关系
nginx:depends_on: [app]app:depends_on: [mysql]mysql:# 独立启动
📦 Spring Boot应用容器化
项目结构
my-spring-app/
├── src/
│ └── main/
│ ├── java/
│ └── resources/
│ └── application.yml
├── Dockerfile
├── docker-compose.yml
├── nginx/
│ └── nginx.conf
├── mysql/
│ ├── init.sql
│ └── my.cnf
└── scripts/├── deploy.sh└── backup.sh
优化的Dockerfile
多阶段构建Dockerfile:
# 第一阶段:构建阶段
FROM maven:3.8.6-openjdk-17-slim AS builder# 设置工作目录
WORKDIR /app# 复制Maven配置文件,利用Docker缓存
COPY pom.xml .
COPY src ./src# 构建应用
RUN mvn clean package -DskipTests# 第二阶段:运行阶段
FROM openjdk:17-jre-slim# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser# 安装必要的工具
RUN apt-get update && apt-get install -y \curl \jq \&& rm -rf /var/lib/apt/lists/*# 设置工作目录
WORKDIR /app# 从构建阶段复制jar包
COPY --from=builder /app/target/*.jar app.jar# 创建日志目录
RUN mkdir -p /app/logs && chown -R appuser:appuser /app# 切换到非root用户
USER appuser# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \CMD curl -f http://localhost:8080/actuator/health || exit 1# 暴露端口
EXPOSE 8080# JVM优化参数
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:+UseContainerSupport"# 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
应用配置优化
application.yml (容器化配置):
server:port: 8080# 关闭Tomcat访问日志(由容器日志管理)tomcat:accesslog:enabled: falsespring:application:name: my-spring-app# 数据库配置(容器环境)datasource:url: jdbc:mysql://mysql:3306/app_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: ${DB_USERNAME:root}password: ${DB_PASSWORD:123456}driver-class-name: com.mysql.cj.jdbc.Driver# 连接池配置hikari:minimum-idle: 5maximum-pool-size: 20idle-timeout: 300000connection-timeout: 20000max-lifetime: 1200000# JPA配置jpa:hibernate:ddl-auto: validateshow-sql: falseproperties:hibernate:dialect: org.hibernate.dialect.MySQL8Dialectformat_sql: false# 批量处理优化jdbc:batch_size: 20order_inserts: trueorder_updates: true# Redis配置(如果需要)redis:host: redisport: 6379database: 0timeout: 3000mslettuce:pool:max-active: 8max-idle: 8min-idle: 0# 监控配置
management:endpoints:web:exposure:include: health,info,metrics,prometheusendpoint:health:show-details: alwayshealth:redis:enabled: false# 日志配置
logging:level:com.example: INFOorg.springframework.web: WARNorg.hibernate.SQL: WARNpattern:console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"file:name: /app/logs/application.logmax-size: 100MBmax-history: 30
🗄️ MySQL数据库容器化
MySQL配置文件
mysql/my.cnf:
[mysqld]
# 基本配置
user = mysql
default-storage-engine = InnoDB
socket = /var/lib/mysql/mysql.sock
pid-file = /var/lib/mysql/mysql.pid# 字符集配置
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect = 'SET NAMES utf8mb4'# 连接配置
max_connections = 200
max_connect_errors = 6000
open_files_limit = 65535
table_open_cache = 128
max_allowed_packet = 64M
binlog_cache_size = 1M
max_heap_table_size = 8M
tmp_table_size = 16M# 查询缓存配置
query_cache_size = 8M
query_cache_type = 1
query_cache_limit = 2M# InnoDB配置
innodb_additional_mem_pool_size = 4M
innodb_buffer_pool_size = 256M
innodb_data_file_path = ibdata1:10M:autoextend
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_thread_concurrency = 0
innodb_purge_threads = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 2M
innodb_log_file_size = 32M
innodb_log_files_in_group = 3
innodb_max_dirty_pages_pct = 90
innodb_lock_wait_timeout = 120# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/mysql-slow.log
long_query_time = 3# 二进制日志
log-bin = mysql-bin
binlog_format = mixed
expire_logs_days = 7[mysql]
default-character-set = utf8mb4[client]
default-character-set = utf8mb4
数据库初始化脚本
mysql/init.sql:
-- 创建应用数据库
CREATE DATABASE IF NOT EXISTS app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;-- 创建应用用户
CREATE USER IF NOT EXISTS 'app_user'@'%' IDENTIFIED BY 'app_password_2024!';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
FLUSH PRIVILEGES;-- 使用应用数据库
USE app_db;-- 创建用户表
CREATE TABLE IF