项目部署上线-用户中心示例

多环境

参考文章:https://blog.csdn.net/weixin_41701290/article/details/120173283

本地开发:localhost(127.0.0.1)

多环境:指同一套项目代码在不同的阶段需要根据实际情况来调整配置并且部署到不同的机器上。

为什么需要?

  1. 每个环境互不影响
  2. 区分不同的阶段:开发 / 测试 / 生产
  3. 对项目进行优化:
    1. 本地日志级别
    2. 精简依赖,节省项目体积
    3. 项目的环境 / 参数可以调整,比如 JVM 参数

针对不同环境做不同的事情。

多环境分类:

  1. 本地环境(自己的电脑)localhost
  2. 开发环境(远程开发)大家连同一台机器,为了大家开发方便
  3. 测试环境(测试)开发 / 测试 / 产品,单元测试 / 性能测试 / 功能测试 / 系统集成测试,独立的数据库、独立的服务器
  4. 预发布环境(体验服):和正式环境一致,正式数据库,更严谨,查出更多问题
  5. 正式环境(线上,公开对外访问的项目):尽量不要改动,保证上线前的代码是 “完美” 运行
  6. 沙箱环境(实验环境):为了做实验

前端多环境实战

  • 请求地址

    • 开发环境:localhost:8000

    • 线上环境:user-backend.code-nav.cn

    1
    2
    3
    4
    5
    6
    7
    8
    9
    startFront(env) {
    if(env === 'prod') {
    // 不输出注释
    // 项目优化
    // 修改请求地址
    } else {
    // 保持本地开发逻辑
    }
    }

    用了 umi 框架,build 时会自动传入 NODE_ENV == production 参数,start NODE_ENV 参数为 development

  • 启动方式

    • 开发环境:npm run start(本地启动,监听端口、自动更新)
    • 线上环境:npm run build(项目构建打包),可以使用 serve 工具启动(npm i -g serve)
  • 项目的配置

    不同的项目(框架)都有不同的配置文件,umi 的配置文件是 config,可以在配置文件后添加对应的环境名称后缀来区分开发环境和生产环境。参考文档:https://umijs.org/zh-CN/docs/deployment

    • 开发环境:config.dev.ts
    • 生产环境:config.prod.ts
    • 公共配置:config.ts 不带后缀

后端多环境实战

SpringBoot 项目,通过 application.yml 添加不同的后缀来区分配置文件

可以在启动项目时传入环境变量:

1
java -jar .\user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

主要是改:

  • 依赖的环境地址

    • 数据库地址

    • 缓存地址

    • 消息队列地址

    • 项目端口号

  • 服务器配置

项目部署

参考文章:https://www.bilibili.com/read/cv16179200

需要 Linux 服务器(建议大家用 CentOS 8+ / 7.6 以上)

原始部署

什么都自己装

前端

需要 web 服务器:nginx 、apache、tomcat

安装 nginx 服务器:

  1. 用系统自带的软件包管理器快速安装,比如 centos 的 yum

  2. 自己到官网安装(参考文章)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    curl -o nginx-1.21.6.tar.gz http://nginx.org/download/nginx-1.21.6.tar.gz

    tar -zxvf nginx-1.21.6.tar.gz

    cd nginx-1.21.6

    37 2022-04-17 23:30:09 yum install pcre pcre-devel -y
    39 2022-04-17 23:30:59 yum install openssl openssl-devel -y
    41 2022-04-17 23:31:57 ./configure --with-http_ssl_module --with-http_v2_module --with-stream
    42 2022-04-17 23:32:13 make
    43 2022-04-17 23:32:54 make install
    48 2022-04-17 23:33:40 ls /usr/local/nginx/sbin/nginx
    vim /etc/profile
    在最后一行添加:export PATH=$PATH:/usr/local/nginx/sbin

    nginx

    netstat -ntlp 查看启动情况

    注意 nginx 权限

后端

java、maven

安装:

1
2
3
4
5
6
7
8
9
10
yum install -y java-1.8.0-openjdk*

curl -o apache-maven-3.8.5-bin.tar.gz https://dlcdn.apache.org/maven/maven-3/3.8.5/binaries/apache-maven-3.8.5-bin.tar.gz

git clone xxx 下载代码

打包构建,跳过测试
mvn package -DskipTests

java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

宝塔 Linux 部署

Linux 运维面板

官方安装教程:https://www.bt.cn/new/download.html

方便管理服务器、方便安装软件

前端托管

前端腾讯云 web 应用托管(比容器化更傻瓜式,不需要自己写构建应用的命令,就能启动前端项目)

https://console.cloud.tencent.com/webify/new

  • 小缺点:需要将代码放到代码托管平台上
  • 优势:不用写命令、代码更新时自动构建

Docker 部署

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 构建镜像:

一定要进入到对应的目录

1
2
3
4
# 前端
docker build -t user-center-frontend:v0.0.1 .
# 后端
docker build -t user-center-backend:v0.0.1 .

Docker 构建优化:减少尺寸、减少构建时间(比如多阶段构建,可以丢弃之前阶段不需要的内容)

  • -d: 后台运行容器,并返回容器ID;
  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

docker run 启动:

1
2
3
4
5
# 前端
docker run -p 80:80 -d user-center-frontend:v0.0.1

# 后端
docker run -p 8080:8080 user-center-backend:v0.0.1

虚拟化

  1. 端口映射:把本机的资源(实际访问地址)和容器内部的资源(应用启动端口)进行关联
  2. 目录映射:把本机的端口和容器应用的端口进行关联

进入容器:

1
2
docker exec -i -t  fee2bbb7c9ee /bin/bash
# fee2bbb7c9ee 为容器 Id,docker ps 进行查询 id

查看进程:

1
docker ps 

查看日志:

1
2
docker logs -f [container-id]
# 添加 -f 跟踪日志输出

杀死容器:

1
2
3
docker kill 
# docker kill abf5c6ebe2fe
# 指定镜像 Id

强制删除镜像:

1
2
3
docker rmi -f 
# docker rmi -f repository 名称
# -f 为强制删除

Docker 平台部署

  1. 云服务商的容器平台(腾讯云、阿里云)
  2. 面向某个领域的容器平台(前端 / 后端微信云托管)要花钱!

容器平台的好处:

  1. 不用输命令来操作,更方便省事
  2. 不用在控制台操作,更傻瓜式、更简单
  3. 大厂运维,比自己运维更省心
  4. 额外的能力,比如监控、告警、其他(存储、负载均衡、自动扩缩容、流水线)

绑定域名

用户中心(上线)1.mp4 时间:01:05:00

前端项目访问流程:用户输入网址 => 域名解析服务器(把网址解析为 ip 地址 / 交给其他的域名解析服务) => 服务器 =>(防火墙)=> nginx 接收请求,找到对应的文件,返回文件给前端 => 前端加载文件到浏览器中(js、css) => 渲染页面

后端项目访问流程:用户输入网址 => 域名解析服务器 => 服务器 => nginx 接收请求 => 后端项目(比如 8080端口)

nginx 反向代理的作用:替服务器接收请求,转发请求

跨域问题解决

浏览器为了用户的安全,仅允许向 同域名、同端口 的服务器发送请求。

如何解决跨域?

最直接的方式:把域名、端口改成相同的

添加跨域头

让服务器告诉浏览器:允许跨域(返回 cross-origin-allow 响应头)

1. 网关支持(Nginx)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 跨域配置
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. 修改后端服务–用户中心上线(2) 00:32:00

  1. 配置 @CrossOrigin 注解

  2. 添加 web 全局请求拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @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);
    }
    }
  3. 定义新的 corsFilter Bean,参考:https://www.jianshu.com/p/b02099a435bd