项目部署
# 项目部署
# 多环境
在项目部署前,先了解一下什么是多环境。
参考文章:https://blog.csdn.net/weixin_41701290/article/details/120173283
本地开发:localhost(127.0.0.1)
多环境:指同一套项目代码在不同的阶段需要根据实际情况来调整配置并且部署到不同的机器上。
为什么需要?
- 每个环境互不影响
- 区分不同的阶段:开发 / 测试 / 生产
- 对项目进行优化:
- 本地日志级别(比如在开发阶段可以在控制台打很多日志来调试,但上线的时候就不可以了,给用户看到这些日志会有风险)
- 精简依赖,节省项目体积
- 项目的环境 / 参数可以调整,比如 JVM 参数
针对不同环境做不同的事情。(可以联想一下 maven 依赖的不同作用域)
多环境分类:
- 本地环境(自己的电脑)localhost
- 开发环境(远程开发)大家连同一台机器,为了大家开发方便
- 测试环境(测试)开发 / 测试 / 产品,单元测试 / 性能测试 / 功能测试 / 系统集成测试,独立的数据库、独立的服务器(测试是测试 bug,产品是体验一下是否符合要求)
- 预发布环境(体验服):和正式环境一致,正式数据库,更严谨,查出更多问题
- 正式环境(线上,公开对外访问的项目):尽量不要改动,保证上线前的代码是 “完美” 运行
- 沙箱环境(实验环境):为了做实验,可以看成是测试环境的一种,单独出来的环境
# 前端多环境实战
请求地址
开发环境:localhost:8000
线上环境:服务器 IP
startFront(env) { if(env === 'prod') { // 不输出注释 // 项目优化 // 修改请求地址 } else { // 保持本地开发逻辑 } }
1
2
3
4
5
6
7
8
9这里用了 umi 框架,build 时会自动传入
NODE_ENV == production
参数,start NODE_ENV
参数为development
启动方式
- 开发环境:npm run start(本地启动,监听端口、自动更新)
- 线上环境:npm run build(项目构建打包),可以使用 serve 工具启动(npm i -g serve 安装)
项目的配置(这里以 Ant design Pro 脚手架搭建的项目为例)
不同的项目(框架)都有不同的配置文件,umi 的配置文件是 config,可以在配置文件后添加对应的环境名称后缀来区分开发环境和生产环境。
部署前建议先看一下框架关于部署方面的官方文档,umi 部署参考文档:https://umijs.org/zh-CN/docs/deployment
- 开发环境:config.dev.ts
- 生产环境:config.prod.ts
- 公共配置:config.ts 不带后缀
# 静态化
在有 exportStatic: {}
的时候根据路由生成的目录下面都是有 index.html
# 操作示例
在 globalRequest.ts 下修改 prefix
const request = extend({
credentials: 'include', // 默认请求是否带上cookie
prefix: process.env.NODE_ENV === 'production' ? 'http://user-backend.code-nav.cn' : undefined
// requestType: 'form',
});
2
3
4
5
修改前:
请求网址: http://localhost:8000/api/user/login
修改后:
请求网址: http://user-backend.code-nav.cn/api/user/login
# 后端多环境实战
SpringBoot 项目,通过 application.yml 添加不同的后缀来区分配置文件
- package 打包项目 jar 包
- 运行 jar 包来启动项目
可以在启动项目时传入环境变量(这是 windows 下执行的命令):
java -jar [jar 包名称] --spring.profiles.active=prod
主要是改:
依赖的环境地址
数据库地址
缓存地址
消息队列地址
项目端口号
服务器配置
# 项目部署
参考文章:https://www.bilibili.com/read/cv16179200
需要 Linux 服务器(建议大家用 CentOS 8+ / 7.6 以上)
# 原始部署
什么都自己装
# 前端
需要 web 服务器:nginx 、apache、tomcat
安装 nginx 服务器:
用系统自带的软件包管理器快速安装,比如 centos 的 yum
自己到官网安装,下载稳定版的
//创建文件夹services并进入 mkdir services cd services //使用命令下载稳定版nginx1.20.2: curl -o nginx-1.20.2.tar.gz https://nginx.org/download/nginx-1.20.2.tar.gz //解压 tar -xzvf nginx-1.20.2.tar.gz cd nginx-1.20.2 //yum安装pcre yum install pcre pcre-devel -y //yum安装openssl yum install openssl openssl-devel -y //设置系统配置参数 ./configure --with-http_ssl_module --with-http_v2_module --with-stream //编译并安装 make make install //添加环境变量 vi /etc/profile 最后一行新增: export PATH=$PATH:/usr/local/nginx/sbin 生效: source /etc/profile //加入system管理 vi /usr/lib/systemd/system/nginx.service 输入: [Unit] Description=nginx - high performance web server Documentation=http://nginx.org/en/docs/ After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s stop [Install] WantedBy=multi-user.target 重载并启动: daemon-reload systemctl start nginx
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
47
48
49
50
51
52
53
54
55注意 nginx 权限(需要将
nobody
改写为root
用户)
部署前端项目: 在 idea 中执行 build,把 dist 文件夹添加到 services 文件夹中并改名为 user-center-front 在 /usr/local/nginx/conf 目录下(真正应用配置的目录)修改配置文件 nginx.conf
将 location 中的 root 目录改成项目文件的目录:
在顶部修改 user 为 root(403 Forbidden 解决方法)
nginx -s reload
重载 nginx访问 云服务器 ip:80 即可
# 后端
java、maven
安装:
# -y 是指不询问
# 安装jdk1.8
yum install -y java-1.8.0-openjdk*
# 在services目录下下载maven
tar -zxvf apache-maven-3.8.8-bin.tar.gz
在/etc/profile最后加上maven文件夹的bin目录
# 打包,跳过测试
mvn package -DskipTests
# 后台启动jar包,nohup
nohup java -jar /root/services/user-center-backend/target/user-center-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod &
2
3
4
5
6
7
8
9
10
11
12
13
14
# 宝塔 Linux 部署
Linux 运维面板
官方安装教程:https://www.bt.cn/new/download.html
方便管理服务器、方便安装软件
查看面板账户信息
sudo /etc/init.d/bt default
这条命令会输出【外网、内网】地址
宝塔装的软件在 /www/server
目录下
- 进入宝塔后,点击【面板设置】,修改用户名和密码
- 点击【软件商店】,下载软件(编译安装可能会慢一些,笔者这里选了快速安装)
- nginx 1.20
- java 项目一键部署 3.4(只是个插件)
- tomcat 9(只是为了安装个 java 环境,装了之后卸载不影响)
- 点击【网站】,添加站点 -> 只输入域名就行
- 点击 根目录 下面的地址,删除所有文件。然后将 前端打包好的 dist 目录里面的文件全部上传到该目录
- 然后将 原本的访问路径 中的 localhost 替换成 服务器IP 即可渲染出前端页面
宝塔部署后端:
左边点击【文件】,新建目录,用来部署后端项目
然后上传后端项目 jar 包到该目录下
参考博客:https://blog.csdn.net/qq_48922459/article/details/121842546 (opens new window)
# 前端托管
前端腾讯云 web 应用托管(比容器化更傻瓜式,不需要自己写构建应用的命令,就能启动前端项目)
https://console.cloud.tencent.com/webify/new
- 小缺点:需要将代码放到代码托管平台上
- 优势:不用写命令、代码更新时自动构建
# Docker 部署
后端:Dockefile 文件
需提前配置好 application-prod.yml
FROM maven:3.5-jdk-8-alpine as builder
# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src
# Build a release artifact.
RUN mvn package -DskipTests
# Run the web service on container startup.
CMD ["java","-jar","/app/target/easy-web-0.0.1-SNAPSHOT.jar","--spring.profiles.active=prod"]
2
3
4
5
6
7
8
9
10
11
12
前端:/docker/nginx.conf
server {
listen 80;
# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location / {
try_files $uri /index.html;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Dockerfile 文件
FROM nginx
WORKDIR /usr/share/nginx/html/
USER root
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY ./dist /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
2
3
4
5
6
7
8
9
10
11
12
docker 是容器,可以将项目的环境(比如 java、nginx)和项目的代码一起打包成镜像,所有同学都能下载镜像,更容易分发和移植。
再启动项目时,不需要敲一大堆命令,而是直接下载镜像、启动镜像就可以了。
docker 可以理解为软件安装包。
Docker 安装:https://www.docker.com/get-started/ 或者宝塔安装
Dockerfile 用于指定构建 Docker 镜像的方法
Dockerfile 一般情况下不需要完全从 0 自己写,建议去 github、gitee 等托管平台参考同类项目(比如 springboot)
Dockerfile 编写:
- FROM 依赖的基础镜像
- WORKDIR 工作目录
- COPY 从本机复制文件
- RUN 执行命令
- CMD / ENTRYPOINT(附加额外参数)指定运行容器时默认执行的命令
根据 Dockerfile 构建镜像:
# 后端
docker build -t user-center-backend:v0.0.1 .
# 前端
docker build -t user-center-front:v0.0.1 .
2
3
4
5
Docker 构建优化:减少尺寸、减少构建时间(比如多阶段构建,可以丢弃之前阶段不需要的内容)
docker run 启动:
# 前端
docker run -p 80:80 -d user-center-frontend:v0.0.1
# 后端
docker run -p 8080:8080 user-center-backend:v0.0.1
2
3
4
5
虚拟化
- 端口映射:把本机的资源(实际访问地址)和容器内部的资源(应用启动端口)进行关联
- 目录映射:把本机的端口和容器应用的端口进行关联
进入容器:
docker exec -i -t fee2bbb7c9ee /bin/bash
查看进程:
docker ps
查看日志:
docker logs -f [container-id]
杀死容器:
docker kill
强制删除镜像:
docker rmi -f
# Docker 平台部署
- 云服务商的容器平台(腾讯云、阿里云)
- 面向某个领域的容器平台(前端 / 后端微信云托管)要花钱!
容器平台的好处:
- 不用输命令来操作,更方便省事
- 不用在控制台操作,更傻瓜式、更简单
- 大厂运维,比自己运维更省心
- 额外的能力,比如监控、告警、其他(存储、负载均衡、自动扩缩容、流水线)
# 绑定域名
前端项目访问流程:用户输入网址 => 域名解析服务器(把网址解析为 ip 地址 / 交给其他的域名解析服务) => 服务器 =>(防火墙)=> nginx 接收请求,找到对应的文件,返回文件给前端 => 前端加载文件到浏览器中(js、css) => 渲染页面
后端项目访问流程:用户输入网址 => 域名解析服务器 => 服务器 => nginx 接收请求 => 后端项目(比如 8080端口)
nginx 反向代理的作用:替服务器接收请求,转发请求
# 跨域问题解决
浏览器为了用户的安全,仅允许向 同域名、同端口 的服务器发送请求。
如何解决跨域?
最直接的方式:把域名、端口改成相同的
# 添加跨域头
让服务器告诉浏览器:允许跨域(返回 cross-origin-allow 响应头)
# 1. 网关支持(Nginx)
# 跨域配置
location ^~ /api/ {
proxy_pass http://127.0.0.1:8080/api/;
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers '*';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. 修改后端服务
配置 @CrossOrigin 注解
添加 web 全局请求拦截器
@Configuration public class WebMvcConfg implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { //设置允许跨域的路径 registry.addMapping("/**") //设置允许跨域请求的域名 //当**Credentials为true时,**Origin不能为星号,需为具体的ip地址【如果接口不带cookie,ip无需设成具体ip】 .allowedOrigins("http://localhost:9527", "http://127.0.0.1:9527", "http://127.0.0.1:8082", "http://127.0.0.1:8083") //是否允许证书 不再默认开启 .allowCredentials(true) //设置允许的方法 .allowedMethods("*") //跨域允许时间 .maxAge(3600); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18定义新的 corsFilter Bean,参考:https://www.jianshu.com/p/b02099a435bd