概述此案例为使用docker来部署springboot集群且用nginx来做负载均衡。springboot项目里面引入了mysql8.0和mybatis-plus和druid等框架。环境jdk11 gradle-7.5.1 DockerVersion:20.10.12DocerkComposeVersion:1.23.2。一、准备工作1.新建一个springboot的项目使用gradle或者maven来添加依赖都行我用的gradle。1项目的结构2gradle-wrapper.properties文件distributionBaseGRADLE_USER_HOMEdistributionPathwrapper/distsdistributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.5.1-bin.zipnetworkTimeout10000retries0retryBackOffMs500validateDistributionUrltruezipStoreBaseGRADLE_USER_HOMEzipStorePathwrapper/dists3build.gradle依赖plugins{idorg.springframework.bootversion2.3.7.RELEASEidio.spring.dependency-managementversion1.0.10.RELEASEidjava}grouporg.exampleversion0.0.1-SNAPSHOTdescriptionSpringBootDemoapply plugin:warjava{toolchain{languageVersionJavaLanguageVersion.of(11)}}repositories{maven{urlhttps://maven.aliyun.com/repository/public/}}dependencies{// Spring Boot 核心依赖 implementationorg.springframework.boot:spring-boot-starterimplementationorg.springframework.boot:spring-boot-starter-web// MyBatis-Plus Spring Boot Starter implementationcom.baomidou:mybatis-plus-boot-starter:3.5.3.1// Druid 连接池Spring Boot Starter 版本 implementationcom.alibaba:druid-spring-boot-starter:1.2.16// Lombok 依赖配置 compileOnlyorg.projectlombok:lombok:1.18.36annotationProcessororg.projectlombok:lombok:1.18.36// MySQL 驱动 runtimeOnlymysql:mysql-connector-java:8.0.29// 外部 Tomcat 部署打包成 WAR 时需要 providedRuntimeorg.springframework.boot:spring-boot-starter-tomcat// 如果测试代码中也需要使用 Lombok可以添加以下两行可选 testCompileOnlyorg.projectlombok:lombok:1.18.36testAnnotationProcessororg.projectlombok:lombok:1.18.36// 测试依赖 testImplementation(org.springframework.boot:spring-boot-starter-test){exclude group:org.junit.vintage, module:junit-vintage-engine}}tasks.named(test){useJUnitPlatform()}// WAR 包配置 war{enabledtruearchiveNamedemo.war}4application.yaml# 服务器配置server:port:8080servlet:context-path:/# Spring Boot 核心配置spring:application:name:springboot-cluster-demo# 数据源配置使用 Druid 连接池datasource:# 驱动类名MySQL 8driver-class-name:com.mysql.cj.jdbc.Driver# 数据库连接 URL通过环境变量覆盖适配 Docker 部署url:${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8}username:${SPRING_DATASOURCE_USERNAME:testuser}password:${SPRING_DATASOURCE_PASSWORD:user123}# Druid 连接池配置druid:# ---------- 连接池核心配置 ----------# 初始化连接数initial-size:5# 最小空闲连接数min-idle:5# 最大活跃连接数max-active:20# 获取连接超时时间毫秒max-wait:60000# 连接保持空闲而不被回收的最小时间毫秒min-evictable-idle-time-millis:300000# 连接保持空闲而不被回收的最大时间毫秒max-evictable-idle-time-millis:600000# 连接池中连接空闲多久后进行空闲连接检测毫秒time-between-eviction-runs-millis:60000# ---------- 连接有效性检测 ----------# 检测连接是否有效的 SQLMySQLvalidation-query:SELECT 1# 是否在获取连接前检测连接有效性test-on-borrow:false# 是否在归还连接时检测连接有效性test-on-return:false# 是否在连接空闲时检测连接有效性test-while-idle:true# ---------- 连接泄漏监控 ----------# 是否开启连接泄漏监控remove-abandoned:true# 连接超过多少秒被认为泄漏秒remove-abandoned-timeout:180# 是否打印连接泄漏日志log-abandoned:true# ---------- 统计与监控Druid 控制台 ----------# 开启 Druid 监控页面stat-view-servlet:# 是否启用enabled:true# 访问路径url-pattern:/druid/*# 登录用户名login-username:admin# 登录密码login-password:admin123# 是否允许重置数据reset-enable:false# ---------- Web 监控配置 ----------web-stat-filter:enabled:true# 拦截路径url-pattern:/*# 排除静态资源exclusions:*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*# 开启 Session 监控session-stat-enable:true# Session 统计最大数量session-stat-max-count:1000# ---------- 过滤器配置 ----------filter:# 统计过滤器stat:enabled:true# 慢查询记录毫秒slow-sql-millis:1000# 是否记录慢查询日志log-slow-sql:true# 是否合并 SQLmerge-sql:true# 日志过滤器记录 SQL 执行日志slf4j:enabled:true# 日志级别statement-log-enabled:truestatement-executable-sql-log-enable:true# Jackson 配置jackson:time-zone:Asia/Shanghaidate-format:yyyy-MM-dd HH:mm:ssserialization:write-dates-as-timestamps:false# MyBatis-Plus 配置替换 mybatis 配置mybatis-plus:# Mapper XML 文件位置mapper-locations:classpath:mapper/*.xml# 实体类包路径用于别名type-aliases-package:org.example.bean# 全局配置global-config:db-config:# 主键生成策略自增id-type:auto# 表名前缀可选# table-prefix: t_# 逻辑删除字段可选# logic-delete-field: deleted# 逻辑已删除值# logic-delete-value: 1# 逻辑未删除值# logic-not-delete-value: 0# 配置信息configuration:# 开启驼峰命名自动映射map-underscore-to-camel-case:false# 开启日志输出log-impl:org.apache.ibatis.logging.slf4j.Slf4jImpl# 开启缓存cache-enabled:true# 懒加载lazy-loading-enabled:true# 超时时间default-statement-timeout:30# 日志配置logging:file:path:/app/logsname:/app/logs/application.loglevel:root:INFOorg.example.springbootdemo:DEBUGorg.example.springbootdemo.mapper:DEBUGorg.mybatis:DEBUG# Druid 日志com.alibaba.druid:DEBUG# 连接池日志com.alibaba.druid.pool:INFO5UserController.java文件packageorg.example.controller;importorg.example.biz.BizUser;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;importjava.util.HashMap;importjava.util.Map;RestControllerRequestMapping(user)publicclassUserController{AutowiredprivateBizUserbizUser;// 从docker-compose中各个实例配置的instanceId来设置值Value(${INSTANCE_ID:default-instance})privateStringinstanceId;Value(${INSTANCE_NAME:Default Instance})privateStringinstanceName;GetMapping(valuegetUserById/{id},producesMediaType.APPLICATION_JSON_VALUE)publicMapString,ObjectgetUserById(PathVariablelongid){MapString,ObjectresponsenewHashMap();response.put(timestamp,LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));response.put(instanceId,instanceId);response.put(instanceName,instanceName);varuserbizUser.getUserById(id);if(user!null){response.put(user,user);}returnresponse;}}6beanbizdaomappermodelservice目录下的文件则比较简单单纯是一个根据用户id查询用户信息接口而已比较简单不再赘述。7 生成war包2.安装好docker和docker-compose使用命令查看是否已安装没安装的话则自行去安装。docker-vdocker-compose-v3.拉取镜像mysql8.0以及nginx到本地为什么要将镜像拉取到本地呢因为拉取镜像到本地后后续再使用镜像的话都是先从本地去拿如果有直接拿来用就不会再去远程仓库拉取了。1拉取mysql8.0镜像方式一dockerpull mysql:8.0方式一多次拉取后仍然不行再试方式二。方式二# 1.安装 EPEL 仓库如果已经安装此步会提示可以忽略yuminstallepel-release-y# 2.安装 skopeoyuminstallskopeo-y# 3.验证是否成功skopeo--version# 清理悬空镜像dockerimage prune-f# 将超时时间设置为5分钟可根据网络情况调整exportSKOPEO_TIMEOUT5m# 执行拉取命令从下面三个备选源选一个去执行# 备选源1使用docker.mirrors.ustc.edu.cn中科大skopeo copy docker://docker.mirrors.ustc.edu.cn/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 备选源2使用 docker.m.daocloud.io道客云skopeo copy docker://docker.m.daocloud.io/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 备选源3使用 hub-mirror.c.163.com网易skopeo copy docker://hub-mirror.c.163.com/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 导入tar文件这里要注意返回的的imageIddockerload-i/tmp/mysql-8.0.tar# 假设你执docker load命令后返回的imageId为6cd09145362dxxx又或者是其他都可以通过前面的部分字符来搜索出来镜像dockerimages|grep6cd09145362d# 给这个镜像打上mysql8.0的标签6cd09145362d 为实际你自己的镜像id的前部分内容或者是完整的镜像iddockertag 6cd09145362d mysql:8.0# 查看镜像dockerimages|grepmysql# 如果能看到 MySQL 的版本号输出比如 mysql Ver 8.0.41 for Linux on x86_64就大功告成了dockerrun-it--rmmysql:8.0--version2拉取nginx镜像# 默认会拉latest版本dockerpull nginx#查看是否拉取成功dockerimages|grepnginx# 问 http://你的服务器IP:8080如果能看到 Nginx 欢迎页就说明一切正常dockerrun-d-p8080:80--namemy-nginx nginx3再查看两个镜像是否都拉取成功docker images4.创建部署项目的目录以及文件1目录结构opt/springboot-clusterappDockerfilecomposeDemo-0.0.1-SNAPSHOT.war(换成你实际的war包)mysqlnginxdocker-compose.yaml2创建目录cd/cdoptmkdirspringboot-clustercdspringboot-clustermkdirappmkdirmysqlmkdirnginx3创建文件3.1创建docker-compose.yaml文件cd/cdopt/springboot-clustervidocker-compose.yaml复制以下代码进去version:3.3services: mysql: image: mysql:8.0 container_name: mysql-db restart: always environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: demo MYSQL_USER: testuser MYSQL_PASSWORD: user123 TZ: Asia/Shanghai ports: -3306:3306volumes: - ./mysql/data:/var/lib/mysql - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro networks: - app-network healthcheck: test:[CMD,mysqladmin,ping,-h,localhost,-u,root,-proot123]interval: 10s timeout: 5s retries:5command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci - --default-authentication-pluginmysql_native_password app1: build: context: ./app dockerfile: Dockerfile container_name: springboot-app1 restart: always environment: -TZAsia/Shanghai -JAVA_OPTS-Xmx512m-Xms256m-XX:UseG1GC-SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 -SPRING_DATASOURCE_USERNAMEtestuser -SPRING_DATASOURCE_PASSWORDuser123 -INSTANCE_IDapp1-instance -INSTANCE_NAMEApp Instance 1depends_on: - mysql ports: -8081:8080networks: - app-network app2: build: context: ./app dockerfile: Dockerfile container_name: springboot-app2 restart: always environment: -TZAsia/Shanghai -JAVA_OPTS-Xmx512m-Xms256m-XX:UseG1GC-SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 -SPRING_DATASOURCE_USERNAMEtestuser -SPRING_DATASOURCE_PASSWORDuser123 -INSTANCE_IDapp2-instance -INSTANCE_NAMEApp Instance 2depends_on: - mysql ports: -8082:8080networks: - app-network nginx: image: nginx:latest container_name: nginx-lb restart: always ports: -80:80volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - app1 - app2 networks: - app-network networks: app-network: driver: bridge3.2创建mysql相关文件cd/cdopt/springboot-cluster/mysqlmkdirdatavimy.cnfmy.cnf[client]default-character-setutf8mb4[mysql]default-character-setutf8mb4[mysqld]character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci init-connectSET NAMES utf8mb4max_connections200max_allowed_packet16M default-time-zone08:00viinit.sqlinit.sqluse demo;create tableifnot exists user(idint(11)primary key AUTO_INCREMENT, name varchar(36)not null defaultcomment姓名, age int(6)not null default0comment年龄, create_time datetime not null default current_timestamp comment创建时间)engineinnodb defaultcharsetutf8mb4collateutf8mb4_unicode_ci comment用户表;insert into user(name,age,create_time)values(tom,18,now()),(york,20,now()),(marry,17,now()),(kerry,16,now()),(mark,15,now());3.3创建nginx的配置文件cd/cdopt/springboot-cluster/nginxvinginx.cnfnginx.cnfevents{worker_connections1024;}http{log_format main$remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for upstream: $upstream_addr;upstream springboot_backend{server app1:8080max_fails3fail_timeout30s;server app2:8080max_fails3fail_timeout30s;}server{listen80;server_name localhost;access_log /var/log/nginx/access.log main;error_log /var/log/nginx/error.log;location /{proxy_pass http://springboot_backend;proxy_set_header Host$host;proxy_set_header X-Real-IP$remote_addr;proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto$scheme;proxy_connect_timeout 30s;proxy_send_timeout 30s;proxy_read_timeout 30s;}}}3.4创建app内的Dockerfile文件cd/cdopt/springboot-cluster/app# 注意得先拉取jdk11的运行时环境镜像dockerpull eclipse-temurin:11-jre-alpineviDockerfileDockerfile文件FROM eclipse-temurin:11-jre-alpine WORKDIR /app# composeDemo-0.0.1-SNAPSHOT.war换成你实际的war包名称COPY composeDemo-0.0.1-SNAPSHOT.war /app/app.jar RUNmkdir-p/app/logs ENVTZAsia/Shanghai RUNln-snf/usr/share/zoneinfo/$TZ/etc/localtimeecho$TZ/etc/timezone ENVJAVA_OPTS-Xmx512m -Xms256m -XX:UseG1GC -Duser.timezoneAsia/ShanghaiEXPOSE8080CMD[sh,-c,java$JAVA_OPTS-jar /app/app.jar]3.5将你的war包放到app目录下二、启动cd/cdopt/springboot-clusterdocker-composebuild --no-cachedocker-composeup-d# 5. 查看所有容器状态如果都为up则代表正常docker-composeps# 6.查看项目的日志信息dockerlogs springboot-app1--tail100dockerlogs springboot-app2--tail100# 查看 mysql-db 容器的所有日志dockerlogs mysql-db# 查看nginx-lb容器的所有日志dockerlogs nginx-lb# 8. 测试接口有返回数据则代表项目启动成功了的curlhttp://localhost/user/getUserById/1三、重启cd/cdopt/springboot-cluster# 1. 停止并删除旧容器和数据卷(重启的情况)docker-composedown-v# 2. 删除旧的 MySQL 数据目录避免权限冲突重启的情况sudorm-rf./mysql/data# 3. 创建新的数据目录重启的情况mkdir-p./mysql/data# 4. 启动或重新启动docker-composeup-d四、测试在物理机器上打开浏览器打开两个窗口分别访问http://xxx(你的虚拟机centos的ip地址)/user/getUserById/1和http://xxx(你的虚拟机centos的ip地址)/user/getUserById/2这里虚拟机设置那里记得要设置为桥接模式结果可以看到有用户数据返回且由instanceName看到确实是有做负载均衡的。
docker部署springboot集群实例,使用nginx做负载均衡
概述此案例为使用docker来部署springboot集群且用nginx来做负载均衡。springboot项目里面引入了mysql8.0和mybatis-plus和druid等框架。环境jdk11 gradle-7.5.1 DockerVersion:20.10.12DocerkComposeVersion:1.23.2。一、准备工作1.新建一个springboot的项目使用gradle或者maven来添加依赖都行我用的gradle。1项目的结构2gradle-wrapper.properties文件distributionBaseGRADLE_USER_HOMEdistributionPathwrapper/distsdistributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-7.5.1-bin.zipnetworkTimeout10000retries0retryBackOffMs500validateDistributionUrltruezipStoreBaseGRADLE_USER_HOMEzipStorePathwrapper/dists3build.gradle依赖plugins{idorg.springframework.bootversion2.3.7.RELEASEidio.spring.dependency-managementversion1.0.10.RELEASEidjava}grouporg.exampleversion0.0.1-SNAPSHOTdescriptionSpringBootDemoapply plugin:warjava{toolchain{languageVersionJavaLanguageVersion.of(11)}}repositories{maven{urlhttps://maven.aliyun.com/repository/public/}}dependencies{// Spring Boot 核心依赖 implementationorg.springframework.boot:spring-boot-starterimplementationorg.springframework.boot:spring-boot-starter-web// MyBatis-Plus Spring Boot Starter implementationcom.baomidou:mybatis-plus-boot-starter:3.5.3.1// Druid 连接池Spring Boot Starter 版本 implementationcom.alibaba:druid-spring-boot-starter:1.2.16// Lombok 依赖配置 compileOnlyorg.projectlombok:lombok:1.18.36annotationProcessororg.projectlombok:lombok:1.18.36// MySQL 驱动 runtimeOnlymysql:mysql-connector-java:8.0.29// 外部 Tomcat 部署打包成 WAR 时需要 providedRuntimeorg.springframework.boot:spring-boot-starter-tomcat// 如果测试代码中也需要使用 Lombok可以添加以下两行可选 testCompileOnlyorg.projectlombok:lombok:1.18.36testAnnotationProcessororg.projectlombok:lombok:1.18.36// 测试依赖 testImplementation(org.springframework.boot:spring-boot-starter-test){exclude group:org.junit.vintage, module:junit-vintage-engine}}tasks.named(test){useJUnitPlatform()}// WAR 包配置 war{enabledtruearchiveNamedemo.war}4application.yaml# 服务器配置server:port:8080servlet:context-path:/# Spring Boot 核心配置spring:application:name:springboot-cluster-demo# 数据源配置使用 Druid 连接池datasource:# 驱动类名MySQL 8driver-class-name:com.mysql.cj.jdbc.Driver# 数据库连接 URL通过环境变量覆盖适配 Docker 部署url:${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8}username:${SPRING_DATASOURCE_USERNAME:testuser}password:${SPRING_DATASOURCE_PASSWORD:user123}# Druid 连接池配置druid:# ---------- 连接池核心配置 ----------# 初始化连接数initial-size:5# 最小空闲连接数min-idle:5# 最大活跃连接数max-active:20# 获取连接超时时间毫秒max-wait:60000# 连接保持空闲而不被回收的最小时间毫秒min-evictable-idle-time-millis:300000# 连接保持空闲而不被回收的最大时间毫秒max-evictable-idle-time-millis:600000# 连接池中连接空闲多久后进行空闲连接检测毫秒time-between-eviction-runs-millis:60000# ---------- 连接有效性检测 ----------# 检测连接是否有效的 SQLMySQLvalidation-query:SELECT 1# 是否在获取连接前检测连接有效性test-on-borrow:false# 是否在归还连接时检测连接有效性test-on-return:false# 是否在连接空闲时检测连接有效性test-while-idle:true# ---------- 连接泄漏监控 ----------# 是否开启连接泄漏监控remove-abandoned:true# 连接超过多少秒被认为泄漏秒remove-abandoned-timeout:180# 是否打印连接泄漏日志log-abandoned:true# ---------- 统计与监控Druid 控制台 ----------# 开启 Druid 监控页面stat-view-servlet:# 是否启用enabled:true# 访问路径url-pattern:/druid/*# 登录用户名login-username:admin# 登录密码login-password:admin123# 是否允许重置数据reset-enable:false# ---------- Web 监控配置 ----------web-stat-filter:enabled:true# 拦截路径url-pattern:/*# 排除静态资源exclusions:*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*# 开启 Session 监控session-stat-enable:true# Session 统计最大数量session-stat-max-count:1000# ---------- 过滤器配置 ----------filter:# 统计过滤器stat:enabled:true# 慢查询记录毫秒slow-sql-millis:1000# 是否记录慢查询日志log-slow-sql:true# 是否合并 SQLmerge-sql:true# 日志过滤器记录 SQL 执行日志slf4j:enabled:true# 日志级别statement-log-enabled:truestatement-executable-sql-log-enable:true# Jackson 配置jackson:time-zone:Asia/Shanghaidate-format:yyyy-MM-dd HH:mm:ssserialization:write-dates-as-timestamps:false# MyBatis-Plus 配置替换 mybatis 配置mybatis-plus:# Mapper XML 文件位置mapper-locations:classpath:mapper/*.xml# 实体类包路径用于别名type-aliases-package:org.example.bean# 全局配置global-config:db-config:# 主键生成策略自增id-type:auto# 表名前缀可选# table-prefix: t_# 逻辑删除字段可选# logic-delete-field: deleted# 逻辑已删除值# logic-delete-value: 1# 逻辑未删除值# logic-not-delete-value: 0# 配置信息configuration:# 开启驼峰命名自动映射map-underscore-to-camel-case:false# 开启日志输出log-impl:org.apache.ibatis.logging.slf4j.Slf4jImpl# 开启缓存cache-enabled:true# 懒加载lazy-loading-enabled:true# 超时时间default-statement-timeout:30# 日志配置logging:file:path:/app/logsname:/app/logs/application.loglevel:root:INFOorg.example.springbootdemo:DEBUGorg.example.springbootdemo.mapper:DEBUGorg.mybatis:DEBUG# Druid 日志com.alibaba.druid:DEBUG# 连接池日志com.alibaba.druid.pool:INFO5UserController.java文件packageorg.example.controller;importorg.example.biz.BizUser;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.http.MediaType;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;importjava.util.HashMap;importjava.util.Map;RestControllerRequestMapping(user)publicclassUserController{AutowiredprivateBizUserbizUser;// 从docker-compose中各个实例配置的instanceId来设置值Value(${INSTANCE_ID:default-instance})privateStringinstanceId;Value(${INSTANCE_NAME:Default Instance})privateStringinstanceName;GetMapping(valuegetUserById/{id},producesMediaType.APPLICATION_JSON_VALUE)publicMapString,ObjectgetUserById(PathVariablelongid){MapString,ObjectresponsenewHashMap();response.put(timestamp,LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));response.put(instanceId,instanceId);response.put(instanceName,instanceName);varuserbizUser.getUserById(id);if(user!null){response.put(user,user);}returnresponse;}}6beanbizdaomappermodelservice目录下的文件则比较简单单纯是一个根据用户id查询用户信息接口而已比较简单不再赘述。7 生成war包2.安装好docker和docker-compose使用命令查看是否已安装没安装的话则自行去安装。docker-vdocker-compose-v3.拉取镜像mysql8.0以及nginx到本地为什么要将镜像拉取到本地呢因为拉取镜像到本地后后续再使用镜像的话都是先从本地去拿如果有直接拿来用就不会再去远程仓库拉取了。1拉取mysql8.0镜像方式一dockerpull mysql:8.0方式一多次拉取后仍然不行再试方式二。方式二# 1.安装 EPEL 仓库如果已经安装此步会提示可以忽略yuminstallepel-release-y# 2.安装 skopeoyuminstallskopeo-y# 3.验证是否成功skopeo--version# 清理悬空镜像dockerimage prune-f# 将超时时间设置为5分钟可根据网络情况调整exportSKOPEO_TIMEOUT5m# 执行拉取命令从下面三个备选源选一个去执行# 备选源1使用docker.mirrors.ustc.edu.cn中科大skopeo copy docker://docker.mirrors.ustc.edu.cn/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 备选源2使用 docker.m.daocloud.io道客云skopeo copy docker://docker.m.daocloud.io/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 备选源3使用 hub-mirror.c.163.com网易skopeo copy docker://hub-mirror.c.163.com/library/mysql:8.0 docker-archive:/tmp/mysql-8.0.tar# 导入tar文件这里要注意返回的的imageIddockerload-i/tmp/mysql-8.0.tar# 假设你执docker load命令后返回的imageId为6cd09145362dxxx又或者是其他都可以通过前面的部分字符来搜索出来镜像dockerimages|grep6cd09145362d# 给这个镜像打上mysql8.0的标签6cd09145362d 为实际你自己的镜像id的前部分内容或者是完整的镜像iddockertag 6cd09145362d mysql:8.0# 查看镜像dockerimages|grepmysql# 如果能看到 MySQL 的版本号输出比如 mysql Ver 8.0.41 for Linux on x86_64就大功告成了dockerrun-it--rmmysql:8.0--version2拉取nginx镜像# 默认会拉latest版本dockerpull nginx#查看是否拉取成功dockerimages|grepnginx# 问 http://你的服务器IP:8080如果能看到 Nginx 欢迎页就说明一切正常dockerrun-d-p8080:80--namemy-nginx nginx3再查看两个镜像是否都拉取成功docker images4.创建部署项目的目录以及文件1目录结构opt/springboot-clusterappDockerfilecomposeDemo-0.0.1-SNAPSHOT.war(换成你实际的war包)mysqlnginxdocker-compose.yaml2创建目录cd/cdoptmkdirspringboot-clustercdspringboot-clustermkdirappmkdirmysqlmkdirnginx3创建文件3.1创建docker-compose.yaml文件cd/cdopt/springboot-clustervidocker-compose.yaml复制以下代码进去version:3.3services: mysql: image: mysql:8.0 container_name: mysql-db restart: always environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: demo MYSQL_USER: testuser MYSQL_PASSWORD: user123 TZ: Asia/Shanghai ports: -3306:3306volumes: - ./mysql/data:/var/lib/mysql - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf:ro networks: - app-network healthcheck: test:[CMD,mysqladmin,ping,-h,localhost,-u,root,-proot123]interval: 10s timeout: 5s retries:5command: - --character-set-serverutf8mb4 - --collation-serverutf8mb4_unicode_ci - --default-authentication-pluginmysql_native_password app1: build: context: ./app dockerfile: Dockerfile container_name: springboot-app1 restart: always environment: -TZAsia/Shanghai -JAVA_OPTS-Xmx512m-Xms256m-XX:UseG1GC-SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 -SPRING_DATASOURCE_USERNAMEtestuser -SPRING_DATASOURCE_PASSWORDuser123 -INSTANCE_IDapp1-instance -INSTANCE_NAMEApp Instance 1depends_on: - mysql ports: -8081:8080networks: - app-network app2: build: context: ./app dockerfile: Dockerfile container_name: springboot-app2 restart: always environment: -TZAsia/Shanghai -JAVA_OPTS-Xmx512m-Xms256m-XX:UseG1GC-SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/demo?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 -SPRING_DATASOURCE_USERNAMEtestuser -SPRING_DATASOURCE_PASSWORDuser123 -INSTANCE_IDapp2-instance -INSTANCE_NAMEApp Instance 2depends_on: - mysql ports: -8082:8080networks: - app-network nginx: image: nginx:latest container_name: nginx-lb restart: always ports: -80:80volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - app1 - app2 networks: - app-network networks: app-network: driver: bridge3.2创建mysql相关文件cd/cdopt/springboot-cluster/mysqlmkdirdatavimy.cnfmy.cnf[client]default-character-setutf8mb4[mysql]default-character-setutf8mb4[mysqld]character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci init-connectSET NAMES utf8mb4max_connections200max_allowed_packet16M default-time-zone08:00viinit.sqlinit.sqluse demo;create tableifnot exists user(idint(11)primary key AUTO_INCREMENT, name varchar(36)not null defaultcomment姓名, age int(6)not null default0comment年龄, create_time datetime not null default current_timestamp comment创建时间)engineinnodb defaultcharsetutf8mb4collateutf8mb4_unicode_ci comment用户表;insert into user(name,age,create_time)values(tom,18,now()),(york,20,now()),(marry,17,now()),(kerry,16,now()),(mark,15,now());3.3创建nginx的配置文件cd/cdopt/springboot-cluster/nginxvinginx.cnfnginx.cnfevents{worker_connections1024;}http{log_format main$remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for upstream: $upstream_addr;upstream springboot_backend{server app1:8080max_fails3fail_timeout30s;server app2:8080max_fails3fail_timeout30s;}server{listen80;server_name localhost;access_log /var/log/nginx/access.log main;error_log /var/log/nginx/error.log;location /{proxy_pass http://springboot_backend;proxy_set_header Host$host;proxy_set_header X-Real-IP$remote_addr;proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto$scheme;proxy_connect_timeout 30s;proxy_send_timeout 30s;proxy_read_timeout 30s;}}}3.4创建app内的Dockerfile文件cd/cdopt/springboot-cluster/app# 注意得先拉取jdk11的运行时环境镜像dockerpull eclipse-temurin:11-jre-alpineviDockerfileDockerfile文件FROM eclipse-temurin:11-jre-alpine WORKDIR /app# composeDemo-0.0.1-SNAPSHOT.war换成你实际的war包名称COPY composeDemo-0.0.1-SNAPSHOT.war /app/app.jar RUNmkdir-p/app/logs ENVTZAsia/Shanghai RUNln-snf/usr/share/zoneinfo/$TZ/etc/localtimeecho$TZ/etc/timezone ENVJAVA_OPTS-Xmx512m -Xms256m -XX:UseG1GC -Duser.timezoneAsia/ShanghaiEXPOSE8080CMD[sh,-c,java$JAVA_OPTS-jar /app/app.jar]3.5将你的war包放到app目录下二、启动cd/cdopt/springboot-clusterdocker-composebuild --no-cachedocker-composeup-d# 5. 查看所有容器状态如果都为up则代表正常docker-composeps# 6.查看项目的日志信息dockerlogs springboot-app1--tail100dockerlogs springboot-app2--tail100# 查看 mysql-db 容器的所有日志dockerlogs mysql-db# 查看nginx-lb容器的所有日志dockerlogs nginx-lb# 8. 测试接口有返回数据则代表项目启动成功了的curlhttp://localhost/user/getUserById/1三、重启cd/cdopt/springboot-cluster# 1. 停止并删除旧容器和数据卷(重启的情况)docker-composedown-v# 2. 删除旧的 MySQL 数据目录避免权限冲突重启的情况sudorm-rf./mysql/data# 3. 创建新的数据目录重启的情况mkdir-p./mysql/data# 4. 启动或重新启动docker-composeup-d四、测试在物理机器上打开浏览器打开两个窗口分别访问http://xxx(你的虚拟机centos的ip地址)/user/getUserById/1和http://xxx(你的虚拟机centos的ip地址)/user/getUserById/2这里虚拟机设置那里记得要设置为桥接模式结果可以看到有用户数据返回且由instanceName看到确实是有做负载均衡的。