docker-compose进阶实战 docker-compose学习案例
·
案例2:进阶版 - SpringBoot + MySQL + Redis(企业级常用)
目录结构
springboot-demo/
├── docker-compose.yml
├── .env
└── mysql/
└── init.sql # MySQL初始化脚本(建库、建表、插数据)
1. .env文件
# MySQL配置
MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=demo_db
MYSQL_USER=demo
MYSQL_PASSWORD=Demo@123!
# 应用配置
SPRING_PORT=8080
REDIS_PORT=6379
2. mysql/init.sql(初始化脚本)
-- 创建表
USE demo_db;
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT
);
-- 插入测试数据
INSERT INTO user (name, age) VALUES ('Tom', 20), ('Jerry', 18);
注意:当同时设置环境变量和挂载 init.sql 时,镜像会先执行环境变量,再执行 init.sql 里的内容
3. docker-compose.yml
volumes:
mysql-data:
redis-data:
卷的路径是在宿主机上面的
[root@jenkins-server ~]# cd /var/lib/docker/volumes/
version: '3.8'
# 自定义网络(服务隔离)
networks:
demo-network:
driver: bridge
# 数据卷(持久化MySQL/Redis数据)
volumes:
mysql-data:
redis-data:
services:
# MySQL服务
mysql:
image: mysql:8.0
container_name: demo-mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql # 持久化数据,容器删除不丢失
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本
networks:
- demo-network
restart: always
# 健康检查:确保MySQL就绪后再启动后端
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u${MYSQL_USER}", "-p${MYSQL_PASSWORD}"]
interval: 5s
timeout: 5s
retries: 5
# Redis服务
redis:
image: redis:alpine
container_name: demo-redis
command: redis-server --requirepass 123456 # 设置Redis密码
volumes:
- redis-data:/data
networks:
- demo-network
restart: always
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 3s
timeout: 3s
retries: 3
# SpringBoot后端服务(替换为自己的镜像,或用build构建)
springboot-app:
#image: springboot-demo:1.0 # 替换为你的SpringBoot镜像
build: ./backend # 若有Dockerfile,用build替代image
container_name: demo-springboot
ports:
- "${SPRING_PORT}:8080"
environment:
# 数据库连接(用服务名作为主机名)
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/${MYSQL_DATABASE}?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
- SPRING_DATASOURCE_USERNAME=${MYSQL_USER}
- SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD}
# Redis配置
- SPRING_REDIS_HOST=redis
- SPRING_REDIS_PORT=${REDIS_PORT}
- SPRING_REDIS_PASSWORD=123456
networks:
- demo-network
restart: on-failure
# 依赖MySQL和Redis,且等待其健康检查通过
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
补充:SpringBoot后端服务完整代码(适配上述Compose配置)
以下代码可直接创建项目、编写,打包后配合Compose启动,完美适配案例2的MySQL、Redis配置,包含实体类、数据库操作、Redis缓存、接口测试,无需额外修改配置。
1. 项目结构(Maven)
backend/
├── src/
│ ├── main/
│ │ ├── java/com/example/demo/
│ │ │ ├── DemoApplication.java # 启动类
│ │ │ ├── config/
│ │ │ │ ├── RedisConfig.java # Redis配置
│ │ │ ├── controller/
│ │ │ │ ├── UserController.java # 接口控制器
│ │ │ ├── entity/
│ │ │ │ ├── User.java # 实体类(对应MySQL user表)
│ │ │ ├── mapper/
│ │ │ │ ├── UserMapper.java # 数据库操作(MyBatis)
│ │ │ ├── service/
│ │ │ │ ├── UserService.java # 业务逻辑
│ │ │ │ └── impl/
│ │ │ │ └── UserServiceImpl.java # 业务实现
│ │ └── resources/
│ │ ├── application.yml # 项目配置(贴合Compose环境变量)
│ │ └── mybatis/
│ │ └── mapper/
│ │ └── UserMapper.xml # MyBatis映射文件
│ └── test/
│ └── java/com/example/demo/
│ └── DemoApplicationTests.java # 测试类
├── pom.xml # Maven依赖
└── Dockerfile # 构建镜像配置
2. Maven依赖(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 https://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>2.7.10</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-demo</artifactId>
<version>1.0</version>
<name>springboot-demo</name>
<description>SpringBoot Demo 适配 Docker Compose</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- SpringBoot Web 核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL 驱动(SpringBoot 父项目自动管理版本) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<!-- MyBatis 整合 SpringBoot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- Redis 整合 SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- SpringBoot 打包插件(生成可执行jar) -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. 核心配置(application.yml)
完全贴合Compose中的环境变量,无需手动修改,启动时自动读取Compose配置的MySQL、Redis信息。
server:
port: 8080 # SpringBoot 端口,与 Compose 映射一致
spring:
# 数据库配置(读取 Compose 环境变量)
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
minimum-idle: 5
# Redis 配置(读取 Compose 环境变量)
redis:
host: ${SPRING_REDIS_HOST}
port: ${SPRING_REDIS_PORT}
password: ${SPRING_REDIS_PASSWORD}
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# MyBatis 核心配置(关键:确保映射文件路径正确)
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml # 匹配 XML 文件路径
type-aliases-package: com.example.demo.entity # 实体类包名
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰(适配数据库字段)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 日志(便于调试)
4. 实体类(User.java)
对应MySQL中的user表(与init.sql中的表结构一致)。
package com.example.demo.entity;
import lombok.Data;
@Data // Lombok注解,自动生成getter、setter、toString等方法
public class User {
private Integer id;
private String name;
private Integer age;
}
5. 数据库操作(UserMapper.java + UserMapper.xml)
// UserMapper.java(接口)
package com.example.demo.mapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {
// 查询所有用户
List<User> findAll();
// 根据ID查询用户
User findById(Integer id);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 必须与 Mapper 接口全类名完全一致 -->
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 结果映射(可选,建议添加,避免字段映射问题) -->
<resultMap id="UserResultMap" type="com.example.demo.entity.User">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</resultMap>
<!-- findAll 方法:id 必须与接口方法名完全一致 -->
<select id="findAll" resultMap="UserResultMap">
SELECT id, name, age FROM user
</select>
<!-- findById 方法:适配接口的 findById 方法 -->
<select id="findById" parameterType="java.lang.Integer" resultMap="UserResultMap">
SELECT id, name, age FROM user WHERE id = #{id}
</select>
</mapper>
6. 业务逻辑(UserService.java + UserServiceImpl.java)
// UserService.java(接口)
package com.example.demo.service;
import com.example.demo.entity.User;
import java.util.List;
public interface UserService {
// 查询所有用户(从Redis缓存,无缓存则查数据库)
List<User> findAll();
// 根据ID查询用户
User findById(Integer id);
}
// UserServiceImpl.java(实现类)
package com.example.demo.service.impl;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
// 缓存key前缀
private static final String USER_KEY = "user:";
@Override
public List<User> findAll() {
// 先查Redis缓存
String key = USER_KEY + "all";
List<User> userList = (List<User>) redisTemplate.opsForValue().get(key);
if (userList == null || userList.isEmpty()) {
// 缓存不存在,查数据库
userList = userMapper.findAll();
// 存入Redis,设置过期时间1小时
redisTemplate.opsForValue().set(key, userList, 1, TimeUnit.HOURS);
}
return userList;
}
@Override
public User findById(Integer id) {
String key = USER_KEY + id;
User user = (User) redisTemplate.opsForValue().get(key);
if (user == null) {
user = userMapper.findById(id);
if (user != null) {
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
}
}
return user;
}
}
7. 接口控制器(UserController.java)
提供HTTP接口,可通过curl或浏览器访问,验证服务是否正常。
package com.example.demo.controller;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/user") // 接口前缀
public class UserController {
@Resource
private UserService userService;
// 查询所有用户:GET http://localhost:8080/user
@GetMapping
public List<User> findAll() {
return userService.findAll();
}
// 根据ID查询用户:GET http://localhost:8080/user/1
@GetMapping("/{id}")
public User findById(@PathVariable Integer id) {
return userService.findById(id);
}
}
8. 启动类(DemoApplication.java)
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 扫描MyBatis接口
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
9. Redis配置(RedisConfig.java)
解决Redis序列化问题,避免存入缓存的数据乱码。
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 字符串序列化器
StringRedisSerializer stringSerializer = new StringRedisSerializer();
// JSON序列化器
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
// key使用字符串序列化
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// value使用JSON序列化
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
10. Dockerfile(构建SpringBoot镜像)
放在backend目录下,配合Compose的build字段构建镜像(替代image字段)。
# 基础镜像(Java 8)
FROM registry.cn-hangzhou.aliyuncs.com/testpm-k8s/openjdk:8-jre-slim
# 工作目录
WORKDIR /app
# 复制打包后的jar包(maven打包后在target目录下)
COPY target/springboot-demo-1.0.jar app.jar
# 暴露端口(与SpringBoot端口、Compose端口映射一致)
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
11. 打包与启动说明
-
打包SpringBoot项目:进入backend目录,执行
mvn clean package,生成target目录下的jar包。 -
修改Compose中的springboot-app服务:将
image: springboot-demo:1.0注释,启用build: ./backend。 -
启动Compose:执行
docker-compose up -d,Compose会自动构建SpringBoot镜像并启动所有服务。 -
验证接口:
查询所有用户:curl http://localhost:8080/user,返回init.sql中的测试数据(Tom、Jerry)。 -
根据ID查询:
curl http://localhost:8080/user/1,返回ID为1的用户信息。
4. 启动与验证
# 进入目录
cd springboot-demo
# 验证配置文件语法
docker-compose config
# 启动服务
docker-compose up -d
# 查看后端日志(排查启动问题)
docker-compose logs -f springboot-app
# 验证MySQL数据(进入容器)
docker-compose exec mysql mysql -u demo_user -p demo_db
# 执行SQL:SELECT * FROM user; 查看测试数据
# 验证接口(假设后端有/user接口)
curl http://localhost:8080/user
# 停止服务(保留数据)
docker-compose down
更多推荐




所有评论(0)