?? 前言
容器化技術已經成為現代軟件部署的標準實踐。作為一名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