Bootstrap

项目部署与上线

  1. 多环境

  2. 项目部署上线

    1. 原始前端/后端
    2. 宝塔Linux
    3. 容器
    4. 容器平台

多环境

同一套项目代码,在不同阶段,根据不同情况,调整部署并部署到不同的机器上

为什么需要?

  1. 每个环境互不影响
  2. 区分不同的阶段:开发、测试、生产
  3. 项目的环境、参数可调整

分类:

  1. 本地环境
  2. 开发环境(远程开发)
  3. 测试环境(测试):性能测试、功能测试、系统集成测试=>独立的数据库
  4. 预发布环境(体验、内测):正式环境数据库
  5. 正式环境:尽量不要改动
  6. 沙箱环境(实验环境):为了做实验

前端

1、请求地址

  1. 开发环境:localhost:8000
  2. 线上环境:xxx(域名)

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

/**
* 配置request请求时的默认参数,区分不同的环境
*/
const request = extend({
  credentials: 'include', // 默认请求是否带上cookie
  prefix: process.env.NODE_ENV === 'production' ? 'http://xxx(自己的域名)' : undefined
  // requestType: 'form',
});

2、启动方式

  1. 开发环境:nmp run start(本地启动、监听端口、自动更新)
  2. 线上环境:npm run build(项目构建打包)

3、项目配置

不同的项目(框架)都有不同的配置文件,umi 的配置文件是config,可以在配置文件后添加对应的环境名称后缀来区分开发环境和生产环境

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

后端

1、依赖的环境地址

  1. 数据库地址
  2. 缓存地址
  3. 消息队列地址
  4. 端口号

2、服务器配置

spring:
  application:
    name: user-center-backend
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://数据库地址:3306/usercenter
    username: root
    password: 123456
  session:
    timeout: 86400
server:
  port: 8080
  servlet:
    context-path: /api
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false
  global-config:
    db-config:
      logic-delete-field: isDelete # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

3、启动项目

java -jar .\xxx-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

原始部署

安装nginx

# 下载 nginx
curl -o nginx-1.21.6.tar.gz http://nginx.org/download/nginx-1.21.6.tar.gz
# 解压 nginx
tar -zxvf nginx-1.21.6.tar.gz
# 进入 nginx 目录
cd nginx-1.21.6
# 安装 nginx 需要的环境
yum install pcre pcre-devel -y
yum install openssl openssl-devel -y
yum -y install gcc-c++
# 配置文件检查
./configure --with-http_ssl_module --with-http_v2_module --with-stream
# 编译
make
make install
# 查看是否有 nginx 的可执行文件
ls /usr/local/nginx/sbin/nginx
# 配置全局环境变量, shift+g 定位到最后一行,再按 o 在最后一行插入
vim /etc/profile
在最后一行添加:export PATH=$PATH:/usr/local/nginx/sbin
修改环境变量后执行:source /etc/profile
# 启动nginx
nginx
# 查看启动情况
netstat -ntlp 查看启动情况
# 备份nginx.conf
cd 
cp nginx.conf nginx.default.conf

部署前端

# 前端项目打包
npm run build
# 打包完成之后,出现dist目录,压缩dist.zip
# 上传dist到服务器——使用xshell,直接将dist.zip拖到上传的目录
# 解压缩
unzip dist
# 改文件名
mv dist front
# 最终front的地址
/root/services/usercenter/front

# 找到nginx文配置文件夹(注意是系统生成的文件,不是services下的,编译时系统提示文件路径)
cd /usr/local/nginx/conf
# 修改nginx.config
vim nginx.config
1、第一行改:user root,指定用户
2、改server的运行路径,server-location下:root /root/services/usercenter/front,前端项目的地址
# 修改 nginx 配置后,需要运行如下命令,才生效
nginx -s reload
# 访问,输入服务器ip地址,搞定!

部署后端

Java、maven

# 安装 java8
yum install -y java-1.8.0-openjdk*
# 验证(yum安装,不需要配环境变量)
java -version
# 安装 maven
官网下载 https://maven.apache.org/download.cgi
拖到服务器,或者使用curl -o命令也可
# 解压 
tar -zxvf apache-maven-3.8.5-bin.tar.gz
# 配置环境变量
# 进入bin目录,复制文件地址
pwd
# /root/services/apache-maven-3.9.5/bin
# 编辑文件
vim /etc/profile
将/root/services/apache-maven-3.9.5/bin地址添加到最后一行的环境变量,在nginx地址后添加:并输入地址:
:/root/services/apache-maven-3.9.5/bin
# 文件生效
source /etc/profile
# 验证mvn是否生效
mvn -v

# 下载源码
git clone xxx 下载代码
# 使用 maven 工具打包项目(跳过测试)
打包构建,跳过测试
mvn package -DskipTests
# 运行 jar 包
java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --server.port=8080 --spring.profiles.active=prod
# 后台运行 jar 包
nohup java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --server.port=8080 --spring.profiles.active=prod &
# 使用 jobs 查看用 nohup 运行的项目
jobs

mysql8.0下载安装

wget http://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm
rpm -ivh mysql80-community-release-el7-3.noarch.rpm
yum install mysql-server -y
service mysqld start
service mysqld status
systemctl enable mysqld.service
# 修改密码
mysqladmin -uroot -p password
# 设置远程访问
# 创建用户
CREATE USER 'mys'@'%' IDENTIFIED BY '123456';
# 授权
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
# 刷新生效
FLUSH PRIVILEGES;

创建数据库和数据表(参考create_table.sql)

-- 创建库
create database if not exists usercenter;
-- 切换库
use usercenter;
# 用户表
create table user(......)
# 导入示例用户
INSERT INTO usercenter.user ......

运行后端项目

2、jar包拖到xshell5上传

# 1、上传到代码仓库,使用git在线拉取
git clone xxx
# 使用 maven 工具打包项目(跳过测试)
mvn package -DskipTests
# 设置jar包权限,可执行
chmod a+x user-center-backend-0.0.1-SNAPSHOT.jar 
# 运行 jar 包
java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --server.port=8080 --spring.profiles.active=prod
# 后台运行 jar 包
nohup java -jar ./user-center-backend-0.0.1-SNAPSHOT.jar --server.port=8080 --spring.profiles.active=prod &
# 使用 jobs 查看用 nohup 运行的项目
jobs

netstat -ntlp

防火墙 FirewallD is not running

# 查看防火墙状态
systemctl status firewalld
# 开启防火墙
systemctl start firewalld
# 检查放行端口
firewall-cmd --zone=public --list-ports
# 新增放行端口
firewall-cmd --zone=public --add-port=8080/tcp --permanent
# 刷新
firewall-cmd --reload

宝塔Linux部署

注意云服务器和宝塔的防火墙对应端口都要开启!!!

Linux运维面板

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

前端部署

1、宝塔的软件商店搜索 nignx,并安装

2、在宝塔添加php项目

3、上传前端dist目录下的文件到根目录下

4、输入ip地址/域名即可访问,与原始部署比起来,确实简单不少!

后端部署

MySQL5.7

1、在宝塔软件商店安装MySQL5.7

MySQL5.6之前默认密码为空,5.6之后默认密码由MySQL数据库随机产生

# 查看初始密码
cat /root/.mysql_secret
# 登录成功后,修改密码
set password = password(‘123456’);
# 如果/root/.mysql_secret不存在,跳过权限认证
vim /etc/my.cnf
在[mysqld]下添加skip-grant-tables 
# 重启MySQL
systemctl restart mysqld 
# 登录 
mysql -u root
# 改密码
update mysql.user set authentication_string=PASSWORD('123456') where User='root'; 
# 刷新生效
flush privileges; 
# 退出mysql
exit
# 改文件
vim /etc/my.cnf
注释前面添加的skip-grant-tables 
# 重启mysql

2、远程连接

云服务器需要开放端口3306

# 登录mysql进行授权
GRANT ALL PRIVILEGES ON  *.*  TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
# 刷新生效
flush privileges;

3、创建数据库和新建数据表(参考create_table.sql)

-- 创建库
create database if not exists usercenter;
-- 切换库
use usercenter;
# 用户表
create table user(......)
# 导入示例用户
INSERT INTO usercenter.user ......

创建后端项目

1、在宝塔上传jar包

2、创建Java项目,配置完成即启动项目

# 项目执行命令
/usr/bin/java -jar -Xmx1024M -Xms256M  /www/wwwroot/user-center-backend/user-center-backend-0.0.1-SNAPSHOT.jar --server.port=8080 --spring.profiles.active=prod

坑:

1、不要再单独安装tomcat,会有端口冲突,或者重新设置端口

2、防火墙一定要打开需要的端口号,MySQL3306、宝塔8888、tomcat8080等,并且云服务器上和宝塔上的防火墙都要打开

Docker部署

Docker 是容器,可以将项目的环境(比如 java、nginx)和项目的代码一起打包成镜像,有权限都能下载镜像,更容易分发和移植

好处:再启动项目时,不需要敲一大堆命令,而是直接下载镜像、启动镜像就可以了

Docker 可以理解为软件安装包

1、Docker 安装:https://www.docker.com/get-started/ 或者宝塔安装

2、构建Docker镜像

Dockerfile:用于指定构建 Docker 镜像的方法

Dockerfile 一般情况下不需要完全从 0 自己写,建议去 github、gitee 等托管平台参考同类项目 (比如 springboot)

Dockerfile 编写:

  • FROM 依赖的基础镜像
  • WORKDIR 工作目录
  • COPY 从本机复制文件
  • RUN 执行命令
  • CMD / ENTRYPOINT(附加额外参数)指定运行容器时默认执行的命令

前端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;"]

后端Dockerfile:

# Docker 镜像构建
# 自动按照mvn java8
FROM maven:3.5-jdk-8-alpine as builder

# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# mvn构建,跳过测试
RUN mvn package -DskipTests

# 运行命令时执行
CMD ["java","-jar","/app/target/user-center-backend-0.0.1-SNAPSHOT.jar","--spring.profiles.active=prod"]

3、根据Dockerfile构建镜像

上传代码到Gitee/github,使用git拉取代码,进入对应的目录,运行下面的命令构建镜像

# 后端 
docker build -t user-center-backend:v0.0.1 . 
# 前端 
docker build -t user-center-front:v0.0.1 .

4、docker run 启动

注意启动之前,先看需要的端口是否被占用

# 前端
docker run -p 80:80 -d user-center-front:v0.0.1
# 后端
docker run -p 8080:8080 -d user-center-backend:v0.0.1
dock run命令:https://m.runoob.com/docker/docker-run-command.html
-d:后台运行
-p:指定端口(主机端口:容器端口)

docker常用命令:

# 查看所有镜像
docker images
# 进入容器
docker exec -i -t 容器名/容器id /bin/bash
# 查看进行
docker ps
# 查看日志 -f实时输出
docker logs -f 容器名/容器id
# 杀死容器
docker kill 容器名/容器id
# 强制删除镜像
docker rmi -f 容器名/容器id

镜像优化:

1、镜像大小

2、减小构建时间

比如多阶段构建,可以丢弃之前阶段不需要的内容

虚拟化 :

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

Docker平台部署(√)

Docker 平台分类

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

容器平台的好处

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

绑定域名

域名解析过程

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

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

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

跨域问题解决

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

解决跨域

1、 把域名、端口改成相同的

  1. 前端和后端配置相同的域名以及端口,通过nginx来进行转发。例如当访问xxx/user/login 转发到前端,当访问 xxx/api/user/login 转发到后端
  2. 修改 src/plugins/globalResponseHandler.ts 文件中的请求url
/**
* 配置request请求时的默认参数
*/
const request = extend({
  credentials: 'include', // 默认请求是否带上cookie
  prefix: process.env.NODE_ENV === 'production' ?
  'http://IP地址或域名:80' : undefined,
});
  1. 在 nginx 配置文件中,增加如下配置 (前端的nginx配置)
# 解决跨域问题方式一
location ^~ /api/ {
  proxy_pass http://127.0.0.1:8080/api/;
}
  1. 当用户访问了 http://xxx/user/login 时,后点击了登录按钮,则会请求 http://xxx:80 地址,此时匹配 nginx 中的配置,被转发访问 http://127.0.0.1:8080/api/user/login ,从而解决跨域问题

2、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;
    }
}

参考:https://www.jianshu.com/p/b02099a435bd

3、修改后端代码

  1. 在Controller上配置 @CrossOrigin 注解
  2. 添加 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. 定义新的 corsFilter Bean

参考文章:https://www.jianshu.com/p/b02099a435bd

;