我们在开发做软件的时候,一般是微服务框架,那么怎么实现将微服务各个模块部署到服务器呢,今天就写一个小案例实现,看完之后类别工作中的项目部署就差不多理解了
1.创建数据库,开发本质就是对数据进行操作,数据库创建很重要,怎么保证查询等不需要多张表进行关联查询提高速度呢,可以根据mybatis的一对多和多对多加上业务需求配置字段
2.编写主逻辑,根据对数据库的操作编写逻辑,这些需要java后端自己编写接口操作数据库
3.打包部署,将程序打包为jar包制作成镜像运行在多台服务器上,前端部署在nginx中,处理发送的请求操作数据库
参考文章:SQL的逻辑和优化(面试必知)_sql实现逻辑差-CSDN博客
创建微服务项目和单体配置需要改一下,如下
首先固定springcloud服务版本,在最外层pom.xml文件如下
<!-- 锁定SpringBoot版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- 这是一个空元素,表示Maven应该从哪里查找父项目的配置信息。当它为空时,Maven会从仓库中查找父项目。如果你将此元素设置为具体的路径,Maven将从指定的相对路径中查找父项目的pom.xml文件 -->
</parent>
<groupId>com.dabalmao</groupId>
<artifactId>Dabalmao-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Dabalmao-cloud</name>
<description>Dabalmao-cloud</description>
<packaging>pom</packaging>
<!-- 锁定SpringCloud、SpringCloudAlibaba 版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.7.RELEASE</version>
<type>pom</type>
<scope>import</scope><!--这两个表示是微服务的pom导入子类模块中-->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope><!--这两个表示是微服务的pom导入子类模块中-->
</dependency>
</dependencies>
</dependencyManagement>
以上规定版本为2.3.12,接下来在子模块中pom文件继承最外层pom文件,如下
<parent>
<!--最外层父类pom文件地址,名称版本等-->
<groupId>com.dabalmao</groupId>
<artifactId>Dabalmao-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--指向最外层父类文件进行打包-->
<relativePath>../pom.xml</relativePath>
</parent>
<packaging>jar</packaging>
最外层pom文件为pom形式,模块为jar包形式
怎么写我就不过多解释了,在每个模块依赖配置写代码即可,博客上都有,不会也可以gpt查询即可(省略......)
3.接下来写接口,我在服务Module1和服务Module2两个微服务模块分别向同一个redis添加数据
测试如下
redis中dabalmao1键添加成功
redis中dabalmao2键添加成功
测试成功后进行打包
打包成功,java-jar测试
现在服务如下,Module1:8081; Module2:8082 接下来将jar包上传部署到服务器
参考Java微服务轻松部署服务器_java 微服务项目 怎么快速在单机部署?-CSDN博客即可
现在工作中一般可视化即可如下1Panel - 现代化、开源的 Linux 服务器运维管理面板官网查看即可,今天从零部署
将两个服务jar包制作成镜像的Dockerfile分别为
项目1:
FROM openjdk:8
# 将jar1.jar复制到镜像中的工作目录
COPY Module1-0.0.1-SNAPSHOT.jar /dabaimao/module1/Module1-0.0.1-SNAPSHOT.jar
# 设置工作目录
WORKDIR /dabaimao/module1
# 暴露端口
EXPOSE 8081
#定义时区参数
ENV TZ=Asia/Shanghai
# 设置时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 运行jar文件
CMD java -jar Module1-0.0.1-SNAPSHOT.jar
项目2:
FROM openjdk:8
# 将jar1.jar复制到镜像中的工作目录
COPY Module2-0.0.1-SNAPSHOT.jar /dabaimao/module2/Module2-0.0.1-SNAPSHOT.jar
# 设置工作目录
WORKDIR /dabaimao/module2
# 暴露端口
EXPOSE 8082#定义时区参数
#定义时区参数
ENV TZ=Asia/Shanghai
# 设置时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 运行jar文件
CMD java -jar Module2-0.0.1-SNAPSHOT.jar
将两个服务制作成镜像之后如下
启动访问测试一下,测试成功
先启动依赖容器,比如中间件redis,mq,我这边只用到了redis
version: '3'
services:
redis:
image: daocloud.io/library/redis:5.0.7
ports:
- "6379:6379"
environment:
- REDIS_PASSWORD=123456
启动成功
接下来使用docker-compose同时启动两个服务:
version: '3.3'
services:
# my-module1 服务配置
my-module1:
image: my-module1:1.0
ports:
- "18081:8081"
networks:
- my-network
# my-module2 服务配置
my-module2:
image: my-module2:1.0
ports:
- "18082:8082"
networks:
- my-network
# Nginx 服务配置
my-nginx:
image: daocloud.io/library/nginx:latest
ports:
- "8080:80"
networks:
- my-network
networks:
my-network:
driver: bridge
启动成功
测试如下
redis中dabalmao1键添加成功
redis中dabalmao2键添加成功
脚本为
cd /dabaimao/redis #redis的docker-compose.yml文件路径
docker-compose up -d #启动redis镜像
cd /dabaimao #module1和module2两个服务的docker-compose.yml文件路径
docker-compose up -d #启动两个服务
#####################没有docker可以使用脚本java-jar启动
这样就可以了,但是再次之前一般需要两个docker-compose.yml文件,先启动比如mysql,redis,mq之类的依赖服务,在启动逻辑服务,可以网络进行连接
3.nginx部署前端代码
我这边用gpt自动生成另一个前端网页,localhost表示同一个网络,127.0.0.1表示本地主机,一般使用内网ip即可,这里连的是同一个网络所以用localhost
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Redis 接口测试</title>
<style>
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
<!--'把bg1.jpg放到/usr/share/nginx/html容器路径下即可访问!'-->
background: url('/bg1.jpg') center/cover no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
color: #333;
}
h1 {
margin-bottom: 20px;
text-align: center;
}
button {
margin: 10px;
padding: 10px 20px;
background-color: #3498db;
color: #fff;
border: none;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background-color: #2980b9;
}
#result1, #result2 {
margin-top: 20px;
max-width: 400px;
padding: 10px;
background-color: rgba(255,255,255,0.7);
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<h1>Redis 接口测试</h1>
<button id="button1">获取接口1结果</button>
<button id="button2">获取接口2结果</button>
<div id="result1"></div>
<div id="result2"></div>
<script>
document.getElementById('button1').addEventListener('click', function() {
// 创建一个新的 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 配置请求
xhr.open('GET', 'localhost:18081/dabalmao/toRedis', true);
// 设置请求完成后的回调函数
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功时,将返回的数据插入到页面上
document.getElementById('result1').innerHTML = xhr.responseText;
} else {
// 请求失败时,显示错误信息
document.getElementById('result1').innerHTML = 'Error: ' + xhr.statusText;
}
};
// 设置请求失败时的回调函数
xhr.onerror = function() {
// 请求失败时,显示错误信息
document.getElementById('result1').innerHTML = 'Network error';
};
// 发送请求
xhr.send();
});
document.getElementById('button2').addEventListener('click', function() {
// 创建一个新的 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 配置请求
xhr.open('GET', 'localhost:18082/dabalmao/toRedis', true);
// 设置请求完成后的回调函数
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功时,将返回的数据插入到页面上
document.getElementById('result2').innerHTML = xhr.responseText;
} else {
// 请求失败时,显示错误信息
document.getElementById('result2').innerHTML = 'Error: ' + xhr.statusText;
}
};
// 设置请求失败时的回调函数
xhr.onerror = function() {
// 请求失败时,显示错误信息
document.getElementById('result2').innerHTML = 'Network error';
};
// 发送请求
xhr.send();
});
</script>
</body>
</html>
启动nginx指令
docker run -d -p 8080:80 --name my-nginx daocloud.io/library/nginx:latest
进入nginx指令
docker exec -it ae6fe44888f9 /bin/bash
找到nginx配置文件`/etc/nginx/conf.d/default.conf`,修改配置
静态文件把bg1.jpg放到/usr/share/nginx/html容器路径下即可访问
server {
# 前端程序运行端口
# 注释:前端程序运行端口
listen 80;
# 前端程序运行ip
# 注释:前端程序运行ip
server_name localhost;
# 前端代码,vue使用dist,需要index.html会开头
# 注释:前端代码,vue使用dist,需要index.html会开头
root /usr/share/nginx/html;
# 加载配置文件以使用默认服务器块。
# Load configuration files for the default server block.
# 注释:加载配置文件以使用默认服务器块。
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://jar;
#通过代理转到jar进行负载均衡
}
location / {
#动静分离
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~* \.(gif|jpg|png|js|css|html)$ {
# 匹配以gif|jpg|png|js|css|html为结尾的路径 静态资源
root /usr/share/nginx/statics;
}
error_page 404 /404.html;
location = /40x.html {
# 如果请求的错误页面是404,则返回404.html文件。
# 如果请求的错误页面是40x.html,则不做任何处理。
# 注释:如果请求的错误页面是404,则返回40x.html文件。
# 如果请求的错误页面是50x.html,则不做任何处理。
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
# 如果发生5xx错误,例如500内部服务器错误,则返回50x.html文件。
# 如果请求的错误页面是50x.html,则不做任何处理。
# 注释:如果发生错误,例如内部服务器错误,则返回5xx.html文件。
}
}
Upstream jar{
#负载均衡
# server 192.168.30.137:18080
# server 192.168.30.137:18081
}
修改完成后重新加载配置
nginx -s reload
访问Nginx本地8080端口http://192.168.30.137:8080,展示前端页面如下(一般这种情况放置网关)
查看redis数据库
redis中dabalmao1键添加成功
redis中dabalmao2键添加成功,最后访问成功
在工作中部署项目到服务器一般分为以下几步
1. 将前端代码部署在公网IP的服务器上,并通过域名或公网IP来访问前端应用
2. 将后端代码部署在内网IP的服务器上,服务器之间通过内网IP进行通信,以减少网络延迟和提高数据传输速度
3. 为了使前端能够使用后端的内网IP地址进行通信,通常需要在两者之间设置一个代理服务器(也称为反向代理),这个代理服务器位于公网和内网之间,具有公网IP地址,并且能够访问内网中的后端服务器,前端服务器通过这个代理服务器来与后端服务器进行通信
3. 在前端代码中,可以使用代理服务器,将请求发送给后端, 以实现前后端的通信
这样就完成了