章
目
录
今天,咱们来深入探讨一下基于Qiankun实现的微前端中台的前后端部署上线流程,这可是我在2023年初组内技术分享的内容,现在整理出来给大家详细讲讲。跟着我的思路,你将全面了解整个部署过程的关键技术和核心步骤。
一、前期技术储备
要搭建整个微前端部署发布流程,需要掌握一系列技术,不过在这篇文章里,咱们先对这些技术有个大概的了解就行,具体深入学习还得查阅相关资料。下面来看看都涉及哪些技术:
- 前端:QianKun、TypeScript、React、Webpack5。其中,QianKun用于实现微前端架构,让多个前端应用能够协同工作;TypeScript为JavaScript添加了类型系统,提高代码的可读性和可维护性;React是当下流行的前端框架,用于构建用户界面;Webpack5则是强大的模块打包工具,帮助管理前端资源。
- 后端:Mysql8、NestJs。Mysql8是常用的关系型数据库,用于存储数据;NestJs基于Node.js,提供了一套高效的后端开发框架。
- 运维:Nginx、Docker、K8s。Nginx是高性能的Web服务器,能做正向代理和反向代理;Docker是开源的应用容器引擎,让应用可以在不同环境中轻松部署;K8s(Kubernetes)则是容器编排系统,自动管理和部署容器。
二、请求访问流程详解
这部分是整个微前端部署的关键,了解请求如何在各个组件间流转,对理解后续的部署过程很有帮助。请求访问流程主要分三个步骤:
- 页面请求:当我们在浏览器中输入网址发起请求时,请求会先到达服务器。例如,常见的页面请求地址类型有前端主应用(
www.demo.com/console/
)、前端子应用(www.demo.com/console/app
)和后端服务(www.demo.com/home/api
)。这里你可能会好奇,为什么子应用地址和主应用前缀都是/console
呢?其实,主应用这样设置没问题,能直接请求到前端网页;而子应用这样做,是为了在主应用页面(
/console
)下发起对子应用(/app
)的请求,这样主、子应用就能共存了。要是子应用前缀和主应用不一致,Nginx就会直接把请求转发到子应用或主应用,主、子应用就没办法同时展示了。 - Nginx转发:Nginx接收到请求后,会根据域名进行转发操作。它可以将请求转发到私有gitlab、私有docker镜像源和K8s集群(用来部署应用容器)。这里简单介绍下Nginx的代理概念:正向代理是代理客户端,就像我们常用的Vpn;反向代理则是代理服务端,比如负载均衡。
在实际配置中,Nginx会根据不同域名转发到不同的端口服务。
下面是一段Nginx的配置示例:
# 完整nginx配置文档参考地址:
# https://zhuanlan.zhihu.com/p/619165119
server {
listen 80; # 监听80端口
server_name www.demo.com; #监听域名
location / { # 代理路径。匹配前缀为 / 的地址
# 转发到 k8s 的 GateWay 服务
proxy_pass http://192.168.49.2:30001/;
}
}
server {
listen 80;
server_name git.demo.com;
location / {
proxy_pass http://www.demo.com:9000/;
}
}
server {
listen 80;
server_name jenkins.demo.com;
location / {
proxy_pass http://www.demo.com:8080/;
}
}
server {
listen 80;
server_name registry.demo.com;
client_max_body_size 0; # 设置不限制请求内容大小,因为docker镜像很大。
location / {
proxy_pass http://www.demo.com:5000/;
}
}
这段配置代码根据不同的域名(www.demo.com
、git.demo.com
、jenkins.demo.com
、registry.demo.com
),将请求转发到不同的后端服务端口。
3. K8s内部转发:K8s集群内部部署了两类应用:gateway(网关)和service(服务)。gateway内部又部署了一个Nginx,它负责把K8s外部的请求转发到K8s内部的服务。而服务其实是K8s的一个节点,每个节点里面部署着一个子应用。通过这样的架构,实现了请求在K8s集群内部的流转和处理。
三、技术原理
(一)Docker技术要点
Docker在整个部署流程中起着重要作用,它基于Go语言开发,是一个开源的应用容器引擎。通过Docker,我们可以在各种操作系统上轻松运行应用,而不用反复配置运行环境。
- Docker组成:Docker主要由镜像(Image)和容器(container)组成。镜像是一个只读的模板,就好比是一个应用的“模具”,通过它可以创建一个又一个容器。每个容器里能运行多个应用,并且容器还能映射到宿主机的端口、文件或目录。
- 构建与使用镜像:构建镜像使用
docker build -t [镜像名称] .
命令,这里的-t
参数是给镜像命名。从镜像创建容器则使用docker run -itd --name [容器名称] -p [本机端口]:[容器端口] -v [本机目录]:[容器目录] [镜像名称]
命令。其中,-itd
参数中,-i
表示保持输入源打开,-t
表示分配控制台,-d
表示让容器在后台运行。如果单独使用-i
或-t
,在容器内输入和打印结果就不完整。此外,-p
用于映射端口,-v
用于挂载目录,实现数据持久化,这样即使删除容器再重新创建,数据也不会丢失。进入容器有两种方式,docker exec -it [容器名称] bash
和docker attach [容器名称]
,不过前者退出容器后容器不会关闭,后者则会关闭容器。另外,还可以使用docker tag [源镜像] [目标镜像]
给镜像创建一个标签。 - 数据持久化:通过
-v [本机目录]:[容器目录]
这种方式,能让容器的指定目录同步挂载到宿主机,确保数据不会因为容器的删除和重建而丢失。
(二)K8s技术要点
K8s是容器管理编排系统,简单来说,它能管理多个应用的启动和访问。K8s通常会搭建一个集群,一个集群里有多台主机,每台主机就是一个Node。Node是服务器节点,上面跑着K8S应用,里面又运行着多个pod。Pod是K8s中最小的计算单元,里面部署着多个docker容器。Service则用来代理网络服务,负责集群内的网络通信。还有Deployment,它能管理pod副本,支持版本回滚、错误重启等强大功能,感兴趣的话可以去官网了解。
- 常用命令:在K8s中,有一些常用的命令。比如
k get all
可以获取所有应用状态;k logs [pod名称]
用于查看pod的运行状态,在排查错误时很有用;k exec -it [pod名称] bash
可以进入某个pod;k delete all --all
能删除全部服务,也可以单独删除某个pod(k delete pod [pod名称]
)或service(k delete service [service名称]
)。 - 部署实战:下面以在K8s内部部署一个Nginx应用并暴露到外界为例,展示具体的部署过程。我们通过编写yaml文件来部署容器,主要创建一个Service和一个Pod。Service负责代理从宿主机访问到Pod,Pod则用来部署容器。注意,K8s yaml文件内部不允许使用下划线。下面是yaml文件的示例:
# port:集群内部访问service端口
# containerPort: pod内部容器端口
# nodePort: 外部访问k8s集群内部service的端口
# targetPod: pod的端口
apiVersion: v1 # api版本号 - v1
kind: Service # 类型 - service
metadata:
name: i-nginx-service
labels:
app: i-nginx-service
spec:
type: NodePort # 指定service类型。nodePort:暴露端口到集群外。默认类型仅集群内访问。
ports:
- port: 80 # 集群内部service的端口,通过 i-nginx-service:80 访问
targetPort: 80 # 匹配pod的端口
nodePort: 30002 # 暴露到集群外部端口(宿主机端口)
selector: # 匹配到pod
app: i-nginx
---
apiVersion: v1
kind: Pod
metadata:
name: i-nginx-pod
labels:
app: i-nginx
spec:
containers:
- name: i-nginx
image: nginx
ports:
- containerPort: 80 # 容器内访问端口
编写好yaml文件后,执行kubectl apply -f k8s.yaml
就能运行这个容器。测试是否成功,可以在宿主机内(即虚拟机内)执行curl [当前k8s - ip地址]:30002
,如果能打印出nginx首页消息,就说明部署成功。也可以在宿主机的nginx配置中进行转发,然后访问www.demo.com:30002
来测试。
四、部署上线流程
(一)前端部署流程
- 把前端代码打包到
/dist
目录。 - 使用
Dockerfile
创建docker镜像,镜像内部会用nginx启动一个服务器,用来代理dist
文件夹。 - 将创建好的镜像上传到私有docker镜像源。
- 通过Jenkins流水线,把yaml文件上传到远程服务器。
- 在远程服务器上使用
kubectl
执行yaml文件,重新创建pod和service。这时,K8s执行yaml文件时会去私有docker镜像源拉取镜像。最后,通过[service名称]:80
就能访问pod中的页面了。
(二)后端部署流程
后端服务和前端有点不同,它依靠启动node服务来提供接口服务,并且需要安装依赖才能运行。部署流程如下:
- 同样先打包到
dist
目录。 - 利用
Dockerfile
创建docker镜像,在创建容器运行时,安装packages.json
中的全部依赖,并执行npm命令启动node服务。 - 后续步骤和前端服务一样,上传镜像到私有docker镜像源,Jenkins上传yaml文件到远程服务器,再用
kubectl
执行yaml文件创建pod,最后通过[service名称]:80
访问页面。
(三)gateway网关转发配置
gateway网关主要负责转发宿主机发送到K8s内部的请求,它本身不涉及业务代码。在K8s中创建一个service和一个pod,在里面运行nginx来实现代理转发。具体配置如下:
# 网关 - 负责转发到子应用
# 每次新增插件,都要在这里注册代理地址,并启动一次构建
APP=micro-gateway # 应用名称
K8S_APP=$APP # K8S应用名称
K8S_NAMESPACE=micro-k8s-front # K8S命名空间(用于资源隔离,常用作区分测试、正式环境)
K8S_YAML=gateway.yaml # K8S的yaml文件
K8S_DIR=/data/k8s # 服务器存放k8s的yaml文件目录
DOCKER_TAG=${BUILD_VERSION} # docker镜像标签
DOCKER_NAME=registry.tjh.com/$APP # docker镜像名称(如果前面有地址,则推送到该地址,而非官方docker hub)
DOCKER_IMAGE=$DOCKER_NAME:$DOCKER_TAG # 最终的完整docker镜像标识
# nginx配置文件创建
cat << EOF > default.conf
server {
listen 80;
# 前端
location =/ {
proxy_pass http://micro-console-front-service:80/;
}
location /console {
proxy_pass http://micro-console-front-service:80/;
}
location /app {
proxy_pass http://micro-app-front-service:80/;
}
location /app-react {
proxy_pass http://micro-app-react-front-service:80/;
}
location /gunboss {
proxy_pass http://micro-gunboss-front-service:80/;
}
# 后端
location /home/api/ {
proxy_pass http://api-back-service/;
}
}
EOF
# 新建gateway docker镜像
cat << EOF > Dockerfile
FROM nginx
COPY default.conf /etc/nginx/conf.d/
EXPOSE 80
EOF
docker build -t ${DOCKER_IMAGE} .
docker push ${DOCKER_IMAGE}
# 执行k8s构建网关
cat << EOF > $K8S_YAML
apiVersion: v1
kind: Service
metadata:
name: $K8S_APP-service
namespace: $K8S_NAMESPACE
labels:
app: $K8S_APP-service
spec:
type: NodePort # 方便集群外访问
ports:
- port: 80
targetPort: 80
nodePort: 30001 # 对外暴露的PORT
selector:
app: $K8S_APP
---
apiVersion: v1
kind: Pod
metadata:
name: $K8S_APP
namespace: $K8S_NAMESPACE
labels:
app: $K8S_APP
spec:
containers:
- name: $K8S_APP
image: $DOCKER_IMAGE
ports:
- containerPort: 80
EOF
# 远程执行 k8s
ssh root@172.16.231.133 mkdir -p $K8S_DIR
scp $K8S_YAML 172.16.231.133:$K8S_DIR
ssh root@172.16.231.133 kubectl apply -f $K8S_DIR/$K8S_YAML
(四)QianKun子应用打包注意事项
QianKun中,子应用打包时publicPath
要加子应用前缀。这是因为子应用不止一个,如果不加前缀,gateway在代理时,所有子应用的资源都会被代理到同一个目录/
下,导致资源访问出错。加上前缀后,比如/app
就能正确代理到子应用的index.html
,/app/main.js
也能正确代理到子应用的main.js
,/app/assets/xxx.icon
能代理到子应用的assets
目录下,保证了子应用资源的正确访问。
五、实战演练:快速部署子应用
最后,咱们来实战一下,快速部署上线一个子应用。具体步骤如下:
- 推送前端项目的git代码。
- 在Jenkins中新建前端service流水线。
- 在Jenkins中修改gateway的转发配置。
- 在gunboss网站注册应用并配置菜单。
- 打开网站,就能看到部署好的子应用了。
文中涉及的完整实现代码(前后端)可以点击获取,希望通过这篇文章,大家能对微前端部署发布流程有更深入的理解,在实际项目中更好地运用这些技术。