📖 前言
容器化技术已经成为现代软件部署的标准实践。作为一名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: false
spring:
application:
name: my-spring-app
# 数据库配置(容器环境)
datasource:
url: jdbc:mysql://mysql:3306/app_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: ${
DB_USERNAME:root}
password: ${
DB_PASSWORD:123456}
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接池配置
hikari:
minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 300000
connection-timeout: 20000
max-lifetime: 1200000
# JPA配置
jpa:
hibernate:
ddl-auto: validate
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: false
# 批量处理优化
jdbc:
batch_size: 20
order_inserts: true
order_updates: true
# Redis配置(如果需要)
redis:
host: redis
port: 6379
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# 监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
health:
redis:
enabled: false
# 日志配置
logging:
level:
com.example: INFO
org.springframework.web: WARN
org.hibernate.SQL: WARN
pattern:
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.log
max-size: 100MB
max-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