用户中心项目部署上线
- 宝塔 Linux
- Docuker 容器
- 容器平台
@
目录- 用户中心项目部署上线
- 多环境
- 前端环境识别-区别-dev-test-不同的环境-使用不同的域名和环境
- 前端页面“静态化”
- 后端多环境:
- 项目部署
- 原始部署
- 宝塔 Linux 部署
- Docker 容器部署
- Docker 平台部署
- 域名设置
- 绑定域名
- 跨域问题(Allow CORS)解决(3 种方法)
- 补充:SpringBoot设置Cors跨域的四种方式
- 方式1:返回新的CorsFilter
- 方式2:重写WebMvcConfigurer
- 方式3:使用注解(@CrossOrigin)
- 方式4:手工设置响应头(HttpServletResponse )
- 最后:
多环境
多环境:是指同一个套项目代码在不同的阶段需要根据实际情况来部署到不同的机器上,并且部署到不同的机器上。
比如:
- 测试:部署到一个机器上
- 开发:部署到一个服务器上,配置也是可能不同的。
为什么需要多环境:
- 每个环境互不影响。不需要,改动已经发布到线上的项目,影响用户。
- 为了区分不同的阶段:开发,测试
- 对项目进行优化:
- 本地日志:
- 精简依赖,节省项目体积
- 项目的环境/参数可以调整,比如 JVM 参数
- 针对不同环境做不同的事情。
多环境分类:
- 本地环境(自己的电脑)localhost
- 开发环境(远程开发)大家连同一台机器,为了大家开发。
- 测试环境(测试)——> 开发 / 测试 / 产品,性能测试 / 功能测试 / 系统集成测试 / 单元测试。注意:测试的数据库时单独的数据库。
- 预发布环境(体验服),这里可能就是利用了,正式的数据库。基本和正式环境是一致的。
- 正式环境(线上,公开对外访问的项目):尽量不要改动,保证上线前的代码时“完美”运行
- 沙箱环境(实验环境):为了对某个功能进行测试实验之类的。
前端环境识别-区别-dev-test-不同的环境-使用不同的域名和环境
startFront(env) { if(env === 'prod') { // 不输出注释 // 项目优化 // 修改请求地址 } else {用了umi 框架,build 时会自动传入 NODE_ENV == production 参数,start NODE_ENV 参数为 development ·启动方式 ○开发环境:npm run start(本地启动,监听端口、自动更新) 。线上环境:npm run build(项目构建打包),可以使用 serve 工具启动(npmi-g serve) ·项目的配置 不同的项目(框架)都有不同的配置文件,umi的配置文件是config,可以在配置文件后添加对应的环境名称后缀来区 分开发环境和生产环境。参考文档:https://umijs.org/zh-CN/docs/deployment ·开发环境:config.dev.ts ·生产环境:config.prod.ts ·公共配置:config.ts 不带后缀 // 保持本地开发逻辑 } }
const isDev = process.env.NODE_ENV === 'development';
用了umi 框架,build 时会自动传入 NODE_ENV == production 参数,start NODE_ENV 参数为 development
- 启动方式
- 开发环境:npm run start(本地启动,监听端口、自动更新)
- 线上环境:npm run build(项目构建打包),可以使用 serve 工具启动(npmi-g serve)
const request = extend ({ credentials:'include', // 默认请求是否带上 cookie preifx : process.env.NODE_EDV = "dev" ? 'https://rainbowsea.cn' : undefined // undefined 默认的值 })
项目的配置
不同的项目(框架)都有不同的配置文件,umi的配置文件是config,可以在配置文件后添加对应的环境名称后缀来区分开发环境和生产环境。参考文档:https://umijs.org/zh-CN/docs/deployment
- 开发环境:config.dev.ts
- 生产环境:config.prod.ts
- 公共配置:config.ts 不带后缀
前端页面“静态化”
为每个路由都配置了一个 index.html
静态页面。
后端多环境:
Spring Boot 项目,通过 application.yaml
添加不同的后缀来区分配置文件。比如这里:可以添加一个 application-prod.yaml
。其中配置连接的信息,是需要的生产环境的远程的数据库,而生产环境的配置
习惯:可以将创建的数据库的脚本语句,保存到项目当中(用一个目录保存起来)
可以在启动项目时,启动环境变量。
java -jar .\user-center-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
主要是改:
。数据库地址
。缓存地址
。消息队列地址
。项目端口号
服务器配置
项目部署
需要 Linux服务器(建议大家用CentOS 8+ / 7.6 以上)
原始部署
什么都自己在服务器当中自己安装。
前端:
需要 web 服务器:nginx、apache、tomcat
安装 nginx服务器:
1.用系统自带的软件包管理器快速安装,比如centos的yum
2.自己到官网安装 (参考文章)
ll -ah # Linux 查看文件大小
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 查看启动情况
curl -o nginx-1.21.6.tar.gz http://nginx.org/download/nginx-1.21.6.tar.gz # Linux 下载文件
netstat -ntlp 查看启动情况
注意:nginx 权限
ps -ef | grep 'nignx'
后端:
Java ,maven
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
jps 查看运行所有Java程序
宝塔 Linux 部署
Linux 运维面板
方便管理服务器,方便安装软件。
Docker 容器部署
docker是容器,可以将项目的环境(比如 java、nginx)和项目的代码一起打包成镜像,所有同学都能下载镜像,更容易分发和移植。
再启动项目时,不需要敲一大堆命令,而是直接下载镜像、启动镜像就可以了。
docker 可以理解为软件安装包。
Docker 安装:https://www.docker.com/get-started/或者宝塔安装
Dockerfile 用于指定构建 Docker 镜像的方法
Dockerfile
一般情况下不需要完全从O自己写,建议去 github、gitee 等托管平台参考同类项目(比如 springboot)
后端项目打包 Docker 容器镜像
Dockerfile 的编写
- FROM 依赖的基础镜像
- WORKDIR 工作目录 一般为 app
- COPY 从本机复制文件
- RUN 执行命令
- CMD / ENTRYPOINT(它可以附加额外的参数) 指定运行容器时默认执行的命令
Dockerfile 的编写 不用记,网上找
FROM mave:3.5-jdk-8-alpine as WORKDIR /app # 表示一个工作目录 COPY pom.xml . # 将本地的 pom.xml 复制到当前目录下后作为镜像,上传到 DOCKer容器当中 COPY src ./src RUN mvn package -DskipTests CMD ["java","/app/target/xxxxx.jar","--spring.profiles.active=prod"] # 配置启动运行参数,之类的
根据 Dockerfile 构建镜像(将自己的项目打包成镜像文件上传,让 Docker 使用):
# 后端 docker build -t user-center-backend:v0.0.1 . # 注意:这里有一个 . 表示当前路径,注意要在可以看到 Dockerfile 路径下执行该 docker 命令 # 前端 docker build -t user-center-front:v0.0.1 . # 注意提示没权限要用: sudo # 注意要在可以看到 Dockerfile 路径下执行该 docker 命令
前端项目打包 Docker 镜像
基于 Nginx 打包
FROM nginx WORKDIR /usr/share/nginx/html/ USER root COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf COPY ./dist /user/share/nginx/html/ EXPOSE 80 CMD ["nginx","-g","daemon off;] # 注意提示没权限要用: sudo # 注意要在可以看到 Dockerfile 路径下执行该 docker 命令
# 后端 docker build -t user-center-backend:v0.0.1 . # 注意:这里有一个 . 表示当前路径,注意要在可以看到 Dockerfile 路径下执行该 docker 命令 # 前端 docker build -t user-center-front:v0.0.1 . # 注意提示没权限要用: sudo # 注意要在可以看到 Dockerfile 路径下执行该 docker 命令
补充:
Nginx 降级:就是当我们的某个页面找不到的时候,防止报一个 404 错误,让其降级找我们下面配置的,这个 index.html 页面。使页面更加友好
location / { try_files $uri /index.html } // 就是当我们的某个页面找不到的时候,防止报一个 404 错误, // 让其降级找我们下面配置的,这个 index.html 页面。使页面更加友好
补充:Docker 构建优化:减少尺寸,减少构建时间(比如多阶段构建,可以丢弃之前阶段不需要的内容,比如:这里我们让 maven 使用完了,就可以该内容从镜像当中移除了)
docker run
Docker 容器启动 。
# 前端 docker run -p 80:80 -d user-center-frontend:v0.0.1 # 后端 docker run -p 8080:8080 user-center-backend:v0.0.1
虚拟化:
- 端口映射:把本机的资源(实际访问地址)和容器内部的资源(应用启动端口)进行关联
- 目录映射:把本机的端口和容器应用的端口进行关联
进入容器
docker exec -i -t fee2bbb7c9ee /bin/bash
补充:
查看容器日志sudo pocker ps sudo docker logs [上面查询到的 container ID] 的哪个你所需的日志
进入容器:
docker exec -i -t fee2bbb7c9ee /bin/bash
查看进程:
docker ps
查看日志:
docker logs -f [container-id]
杀死容器:
docker kill
强制删除镜像:
docker rmi -f
Docker 平台部署
Docker 容器平台:
- 云服务商的容器平台(腾讯云,阿里云)
- 面向某个领域的容器平台(前端 webify,后端微信云托管)要米。
容器平台的好处:
- 可视化操作,不用输入命令来操作,更方便省事
- 不用在控制台操作,更傻瓜式,更简单。
- 大厂运维,比自己运维更省心
- 额外的能力:比如:监控,警告,其他(存储,负载均衡,自动扩容缩,流水线)
webfiy (Web 应用托管 比容器化更傻瓜式,不需要自己写构建应用的命令,就能启动前端项目),目前缺点:需要将代码放到代码托管平台上,才能部署上去,不能从本地 copy 上去。优势:不用写命令,代码更新时,会被实时更新部署上。
鱼皮用的:
微信云托管
域名设置
绑定域名
前端项目访问流程:用户输入网址=>域名解析服务器(把网址解析为ip地址/交给其他的域名解析服务)=>服务器:〉(防火墙)=> nginx接收请求(这里需要请求处理,要不然 Nginx 不认识这个域名),找到对应的文件,返回文件给前端=>前端加载文件到浏览器中(js、css)=>渲染页面
后端项目访问流程:用户输入网址=>域名解析服务器=>服务器=>nginx接收请求(这里需要请求处理,要不然 Nginx 不认识这个域名)=>后端项目(比如 8080端口)
nginx反向代理的作用:替服务器接收请求,转发请求
跨域问题(Allow CORS)解决(3 种方法)
跨域问题:
浏览器为了用户的安全,仅允许向同域,同端口
的服务器发送请求。浏览器在发送请求的时候,会发送一个
预检请求(一般请求方法是: options)
。作用:提前探探路,是否符合同域策略什么的
解决方式:
- 把域名,端口改为相同
- 网关支持
让服务器告诉浏览器:允许跨域(返回 cross-orign-allow 响应头),就是在请求头当中,告诉浏览器这个是安全的,可以跨域:
Nginx 网关的支持
尽量不要用 add_header Acess-Control-Allow-origin *
有个缺陷,cookice 可能无法处理。
# 跨域配置 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'; # 允许后端带上 cookie add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers '*'; if ($request_method = 'OPTIONS') { # 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; '; add_header 'Content-Length' 0; return 204; } }
# 跨域配置 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'; # 允许后端带上 cookie add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers '*'; if ($request_method = 'OPTIONS') { # 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; } }
- 修改后端服务
- 配置
@ CrossOrigin
注解
- 配置
@CrossOrigin(origins = {"http://你想支持跨域的域名"}, allowCreadentials = "true") public class UserController { }
b. 添加 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); } }
c. 定义新的 corsFilter Bean,参考:https://www.jianshu.com/p/b02099a435bd
补充:SpringBoot设置Cors跨域的四种方式
前言:CorsFilter / WebMvcConfigurer / @CrossOrigin 需要SpringMVC 4.2 以上的版本才支持,对应SpringBoot 1.3 版本以上都支持这些CORS特性。不过,使用SpringMVC4.2 以下版本的小伙伴也不用慌,直接使用方式4通过手工添加响应头来授权CORS跨域访问也是可以的。
链接:https://www.jianshu.com/p/b02099a435bd
首先一点:跨域问题,后端解决,有如下四种方式。
方式1:返回新的CorsFilter
@Configuration public class CorsConfig { private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.setMaxAge(3600L); corsConfiguration.setAllowCredentials(true); return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } }
方式2:重写WebMvcConfigurer
@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:使用注解(@CrossOrigin)
@Controller @RequestMapping("/admin/sysLog") @CrossOrigin public class SysLogController { }
方式4:手工设置响应头(HttpServletResponse )
这种方式,可以自己手工加到,具体的controller,inteceptor,filter等逻辑里。
@RequestMapping("/test") @ResponseBody public String test(){ response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080"); return "success"; }
总结
:以上是设置cors跨域后端解决的四种方式,本质都是类似最后一种设置响应头,不过都是各自包实现了不同的封装逻辑。最后:
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”
这一切,似未曾拥有