揭秘项目部署上线之路:流程、挑战与解决方案

本文最后更新于:6 个月前

每一片落叶都承载着岁月的痕迹,而飘落的瞬间,也是新生的开始。

前言

  • 本文介绍部署项目的常用方法,以及详细的实操流程
  • 均以我个人开发的伙伴匹配系统为例,体验如何快速部署项目

实操

本地 IDEA 部署

使用 maven 打个 war 包,报了一连串的错误:(2024/03/26 早)

  1. IDEA maven 未配置好,配置一下就行
  2. 有依赖下载失败,换了新的版本解决了
  3. 测试用例有错误,打包时直接忽略掉测试用例就行
  4. Cannot access defaults field of Properties 问题,看下面

Cannot access defaults field of Properties 问题的解决-CSDN 博客

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.3.1</version>
        </plugin>
    </plugins>
</build>

有必要图文总结下这方面的经验了。

maven 打包、本地起 tomcat 服务器

多环境配置

  • 要部署项目到线上,首先就要配置多环境:测试环境(test)、开发环境(development)、生产环境(production)等

前端

  • 在使用 vite 构建工具构建的前端框架中,项目的启动环境是由启动命令来区分的
  • 我们在全局请求拦截器下,输出打印变量:import.meta.env.MODE,如下:
1
2
3
4
5
6
7
8
9
10
11
12
myAxios.interceptors.request.use(
function (config) {
console.log(import.meta.env.MODE);
console.log(`我他妈发请求了${config}`);
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
  • 使用如下命令启动项目(本地启动):
1
npm run dev

image-20230729160617495

  • 可以看到在本地启动项目时,项目的启动环境为开发环境(development)
  • 执行以下命令来构建、打包项目,打包完成之后,项目目录下会出现一个 dist 目录,里面就是打包构建完成的项目代码:
1
npm run build

image-20230729161011059

  • 在该目录下,执行以下命令启动项目:
1
serve
  • 注意,serve 是一个启动项目的工具,可以使用以下命令安装:
1
npm i -g serve
  • serve 成功启动打包好的项目之后,如图所示:

image-20230729161424548

  • 可以看到,启动构建好的项目时,项目的启动环境为开发环境(production)
  • 所以我们可以在全局请求拦截器中,可以实现:根据不同的项目环境,去请求不同的后端地址:
1
2
3
4
5
6
7
8
const myAxios = axios.create({
// baseURL: "http://localhost:8082/api",
baseURL:
import.meta.env.MODE === "production"
? "http://120.55.62.195:8081/api"
: "http://localhost:8081/api",
withCredentials: true,
});
  • 这就是前端项目的多环境配置了(2023/07/29 午)
  • 补充:Ant Design Pro 也是我们常用的前端 react 框架,其多环境配置与 vite 构建的 vue 框架十分相似
  • 二者的区别仅在于存储项目启动环境的变量名称不同:
1
2
3
4
5
6
export const errorConfig: RequestConfig = {
baseURL:
process.env.NODE_ENV === 'production' ? 'http://120.55.62.195:8101' : 'http://localhost:8101',
withCredentials: true,
..............
}
  • 这里再附上 Ant Design Vue 的多环境配置:(2023/12/25 早)
1
2
3
4
5
6
7
8
9
const instance = axios.create({
// baseURL: "http://localhost:8081/api",
baseURL:
process.env.NODE_ENV === "production"
? "http://120.55.62.195:8101"
: "http://localhost:8101",
withCredentials: true,
timeout: 10000,
});

后端

配置文件

image-20230725123005384

  • 其中,application.yaml 用来存放各配置文件中的公共配置,其余各环境配置文件中,主要有区别的有以下两点:
    1. 依赖的环境地址
      • 数据库地址
      • 缓存地址
      • 消息队列地址
      • 项目端口号
    2. 服务器配置
  • 下面给出我在不同环境下的配置文件内容:
  • application.yaml(公共配置)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
spring:
# Project name
application:
name: user-center
# DataSource Config
# datasource:
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://localhost:3306/memory
# username: root
# password: Dw990831
# session 失效时间(分钟)
session:
timeout: 86640
store-type: redis
# redis 配置
# redis:
# port: 6379
# host: localhost
# database: 0
# 整合swagger
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
# config:
# activate:
# on-profile: dev

# 端口
server:
port: 8081
servlet:
context-path: /api
# session:
# cookie:
# domain: localhost

mybatis-plus:
global-config:
# 逻辑删除
db-config:
logic-delete-field: isDelete # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
# 开启SQL查询日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • application-dev.yaml(开发环境配置)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
spring:
# Project name
application:
name: user-center
# DataSource Config
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/memory
username: root
password: Dw990831
# session 失效时间(分钟)
session:
timeout: 86640
store-type: redis
# redis 配置
redis:
port: 6379
host: localhost
database: 0
# 整合swagger
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
# config:
# activate:
# on-profile: dev

# 端口
server:
port: 8081
servlet:
context-path: /api
# session:
# cookie:
# domain: localhost
  • application-prod.yaml(生产环境配置)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
spring:
# Project name
application:
name: user-center
# DataSource Config
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/memory
username: root
password: Dw990831
# session 失效时间(分钟)
session:
timeout: 86640
store-type: redis
# redis 配置
redis:
port: 6379
host: localhost
database: 0
# 整合swagger
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
# config:
# activate:
# on-profile: dev

# 端口
server:
port: 8081
servlet:
context-path: /api
# session:
# cookie:
# domain: localhost
  • 有关各个配置文件的加载优先级,可以在这篇博客中详细了解:

直接启动

  • 利用 IDEA 工具,检验在各个环境下能否正确启动项目
  • 这里有个问题,如果配置了多环境,直接 run/debug 项目会报如下错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

Disconnected from the target VM, address: '127.0.0.1:8686', transport: 'socket'

Process finished with exit code 1

  • 这是由于检测到多环境配置文件,需要具体指定项目在那个环境下启动,IDEA 内可以如下操作:

image-20230704001332322

  • 如上图所示,在指定启动环境后,我们的项目在 prod(生产环境)下启动成功了

运行 jar 包

  • 这里我们不在直接运行项目,而是先将项目打包成 jar 包,再运行 jar 包来启动项目
  • 我们借助 ODEA 封装的 Maven 打包工具,一键打包,如下图所示:

image-20230703222202638

  • 项目打包成功后,生成一个 target 目录,jar 包就在该目录下,执行以下命令运行 jar 包来启动项目(IDEA/命令行下均可):
1
java -jar .\user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

image-20230704002107558

  • 如上图所示,项目在 prod(生产环境下)启动成功
  • 至此,后端多环境配置完成(2023/07/04 晚)

项目部署

介绍

  • 我们完成了项目的多环境配置,并在本地检验了配置的正确性,那么接下来就要进行项目的部署上线了
  • 部署上线当然需要服务器了,常见的作法当然是租用一台云服务器了
  • 国内很多提供云服务的厂商:阿里云、腾讯云、百度云、亚马逊云、华为云等等,我们这里选用阿里云的 ECS 云服务器
  • 这台云服务器的相关宝塔面板的安装、云数据库的配置均已完成,详见《宝塔面板:解放手动配置,轻松管理你的服务器》
  • 下面我们正式进行项目的上线、部署

原生部署

  • 这种部署方式很繁琐,从项目的打包到部署,所有的工具、依赖以及相关配置都是纯人工进行的,吃力不讨好
  • 所以不建议使用这种方式进行部署项目,不过日后可以考虑操作一遍,再附上详细教程(2023/07/25 午)

宝塔面板部署

后端部署

  • 还是之前讲过的,部署项目首先要做的,便是正确配置该项目依赖的环境地址,将本地地址改为线上地址:
    • 数据库地址
    • 缓存地址
    • 消息队列地址
    • 项目端口号
  • 打包项目,可以手动打包,也可以利用 IDEA 工具,方便快捷,最终生成一个 jar 包:

image-20230725124235955

  • 成功登录到宝塔面板,在指定路径下上传刚刚打包好的 jar 包:

image-20230725124828787

  • 添加部署 Java 项目:

image-20230725125307600

  • 选择项目的 jar 包路径,设置项目端口、项目 jdk 路径,编写项目执行命令(端口号、启动环境)

image-20230725125535362

  • 点击提交即可看到该项目已经在指定端口处成功运行

image-20230725220040763

  • 这里如果运行不成功的话,检查项目执行命令是否正确(端口号、启动环境),再者就是检查 jdk 是否成功安装、线上资源地址配置是否正确
  • 有关阿里云服务器安装 JDK 和完成相关环境配置的内容,以及线上资源地址的配置流程、注意事项,详见《宝塔面板:解放手动配置,轻松管理你的服务器》
  • 至此,伙伴匹配系统的后端部署成功

前端部署

  • 在宝塔面板中,上传刚刚构建打包好的 dist 目录:

image-20230729163007957

  • 上传成功后,在 PHP 项目下添加站点,填写可访问的服务器公网 IP 及其端口,或者一个可访问的域名,正确设置项目根目录路径:

image-20230729162838485

  • 点击提交即可,宝塔面板已经自动启动了该项目,非常方便快捷高效
  • 注意这里的端口号,一定要在对应服务器和宝塔面板中开放该端口号
  • 至此,前端项目部署完成,一定要注意后端项目中,对新的前端请求地址作允许跨域请求处理:

image-20230729163602095

  • 至此,Memory-伙伴匹配项目部署完成:(2023/07/29 午)

image-20230729163807623

image-20230729163821713

Docker 容器部署

踩坑记录

java 和 javac 版本不一致

  • 项目打包后,运行 jar 包报如下错误:

image-20230703232318658

  • 这个问题很常见,是 java 和 javac 版本不一致导致的
  • 我们可以尝试检查一下 java 和 javac 版本,分别在命令行下输入以下两条命令:
1
java -version
1
javac -version
  • 经查询,发现 java 版本为 8,javac 版本为 11,为什么会这样呢?
  • 我们配置的环境变量是没有问题的,只需要把 path 变量下的%JAVA_HOME%/bin 变量上移到第一行,即可解决这个问题

image-20230703232403934

  • 再次查看 java 和 javac 版本,发现版本一致,效果如下:

image-20230703232639048

  • 到这里本应该结束了,但是我发现命令行下运行 jar 包已经没问题了,项目启动成功,但 IDEA 环境下却仍启动失败
  • 原因是这样的:即使我们成功修改了 jdk 版本,但是在 IDEA 环境下,每个项目使用的 jdk 版本仍可能未改变
  • 如下图所示:
  • 我们可以在此修改项目所使用的 jdk 版本,使之与全局 jdk 版本一致

线上 MySQL 数据库和 Redis 的安装配置

  • 我们一直在反复强调,项目部署中,最重要的当属线上资源地址的配置,而常用的 MySQL 数据库和 Redis 配置则更加重要
  • 我们常用的项目部署经常采用宝塔 Linux 部署方案,所以这部分内容会详细讲解在该方案下的 MySQL 数据库和 Redis 配置的要点
  • 这里的介绍比较冗长和细致,所以我认为将这部分内容同样将收录在《宝塔面板:解放手动配置,轻松管理你的服务器》一文中

宝塔安装配置 MySQL

  • 今天从早到晚,花了整整一天时间,成功部署了伙伴匹配系统的后端,时间大多花在了 MySQL 和 Redis 的安装配置上了
  • 有关项目部署的详细流程,可以在《揭秘项目部署上线之路:流程、挑战与解决方案》一文中了解
  • 宝塔面板安装 MySQL 是很简单的:在软件商店挑选安装对应版本的 MySQL 即可
  • 然后新建数据库:

image-20230725222303061

image-20230725222507233

  • 注意这里新增数据库的选项:数据库名、用户名、密码、访问权限和所属服务器
  • 这里的所属服务器默认只能选本地服务器,即你所使用的这台计算机
  • 那我希望将这个数据库添加至我的这台云服务器上,与项目配置保持一致,保证将来项目部署上线时的正常访问
  • 那我们开始着手添加远程服务器吧:

image-20230725223340042

image-20230725223447990

  • 注意这里的管理员名称和管理员密码,管理员名称默认是 root,而密码是登录 MySQL 时使用的密码:
  • 我们可以在这里查看和修改管理员密码:

image-20230725223657368

  • 就是在这里,我在云服务器和面板都开放了 3306 端口的前提下,添加远程服务器的时候,这玩意儿一直报错:
1
Access denied for user 'root'@'localhost' (using password: YES)
  • 我上网查过很多相关资料,得到了最终解决方案:

image-20230725224215340

  • 上面是这个报错出现的原因,简单来说就是你输入的的用户名、密码无误,但全新安装的 MySQL 默认没有授予给任何用户登录权限
  • 其实这个问题很常见,解决办法很简单,依次执行以下命令:
1
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密规则
1
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; #更新一下用户的密码
1
FLUSH PRIVILEGES; #刷新权限
1
alter user 'root'@'localhost' identified by '123fzw'; #重置密码
  • 这时,就可以顺利添加上远程服务器了
  • 我们在本地使用 SQLyog 工具来尝试连接下该 MySQL 数据库:

image-20230725230240618

  • 这里就不用多讲了吧,填写正确的连接名、服务器地址、用户名、密码、端口号,尝试连接:

image-20230725230421085

  • 连接成功!至此,宝塔安装 MySQL 的全流程已经讲述完毕(2023/07/25 晚)

宝塔安装配置 Redis

  • 宝塔安装 Redis 也很简单,在软件商店里找到对应版本的 Redis 即可一键安装并成功启动
  • 我要讲述的是,在 Java 项目部署过程中,遇到的有关远程服务器 Redis 配置有误而造成的项目部署失败的问题
  • 我在使用宝塔面板的网站服务多次部署 Java 项目无果后,尝试在终端手动部署,结果发现这样的报错:

image-20230725232807932

  • 这里给出项目中的 Redis 配置:
1
2
3
4
5
# redis 配置
redis:
port: 6379
host: 120.55.62.195
database: 0
  • 看报错信息确定,由于项目中的 Redis 配置根本不存在,导致 Redis 访问失败,项目跑不起来,那就在宝塔安装一个 Redis 就行了
  • 在成功安装了 Redis 后,我尝试添加远程服务器:

image-20230725231458585

image-20230725231536404

  • 在输入正确的服务器地址、数据库端口和密码后,尝试连接,却提示这样的报错:
1
[ERR] AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
  • 什么意思呢?当然是全新安装的 Redis 默认是不设置连接密码的,而我正在尝试使用用户名、密码连接 Redis
  • 那就着手进行 Redis 的具体配置了:

image-20230725232027635

image-20230725232127791

  • 如上图所示,配置可访问 Redis 的 IP 限制、绑定端口、设置密码等等,再进行添加远程服务器,成功添加
  • 既然远程服务器配置完成了,此时在宝塔面板再次部署项目肯定会出错:因为我们设置了 Redis 连接密码,而项目中仍未配置
  • 那么回到项目源码中,配置 Redis 和 RedissonConfig:
1
2
3
4
5
6
# redis 配置
redis:
port: 6379
host: 120.55.62.195
database: 0
password: Dw990831
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
**
* @author 邓哈哈
* 2023/4/18 20:36
* Function: Redisson 配置
* Version 1.0
*/
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Data

public class RedissionConfig {
private String host;

private String port;

private String password;

private Integer database;

@Bean
public RedissonClient redissonClient() {
// 1. 创建配置
Config config = new Config();
String redisAddress = String.format("redis://%s:%s", host, port);
// 使用单个Redis,没有开集群 useClusterServers() 设置地址和使用库
config.useSingleServer().setAddress(redisAddress).setDatabase(database).setPassword(password);
// 2. 创建实例
return Redisson.create(config);
}
}
  • 再次打包项目,上传 jar 包,重新部署项目:

image-20230725233621645

  • 成功部署伙伴匹配系统后端!太感动了(2023/07/25 晚)

经验总结

image-20230703223656991

image-20230703223749102

image-20230729144926636

image-20230729144947816

image-20230729145013296


揭秘项目部署上线之路:流程、挑战与解决方案
https://test.atomgit.net/blog/2023/06/04/揭秘项目部署上线之路:流程、挑战与解决方案/
作者
Memory
发布于
2023年6月4日
更新于
2024年3月26日
许可协议