DEVOPS: 认证与调度
概述
- 不知道大家有没有意识到一个现实,就是大部分时候,我们已经不像以前一样
- 通过命令行,或者可视窗口来使用一个系统了
- 现在我们上微博、或者网购,操作的其实不是眼前这台设备,而是一个又一个集群
- 通常,这样的集群拥有成百上千个节点,每个节点是一台物理机或虚拟机,集群一般远离用户,坐落在数据中心
- 为了让这些节点互相协作,对外提供一致且高效的服务,集群需要操作系统,Kubernetes 就是这样的操作系统
- 比较 Kubernetes 和单机操作系统,Kubernetes 相当于内核,它负责集群软硬件资源管理
- 并对外提供统一的入口,用户可以通过这个入口来使用集群,和集群沟通
- 而运行在集群之上的程序,与普通程序有很大的不同,这样的程序,是“关在笼子里”的程序
- 它们从被制作,到被部署,再到被使用,都不寻常。我们只有深挖根源,才能理解其本质
“关在笼子里”的程序
1 ) 代码
- 我们使用 go 语言写了一个简单的 web 服务器程序 app.go,这个程序监听在 2580 这个端口
- 通过 http 协议访问这个服务的根路径,服务会返回“This is a small app for kubernetes…”字符串
package main
import ("github.com/gorilla/mux""log""net/http"
)func about(w http.ResponseWriter, r *http.Request) {w.Write([]byte("This is a small app for kubernetes...\n"))
}func main() {r := mux.NewRouter()r.HandleFunc("/", about)log.Fatal(http.ListenAndServe("0.0.0.0:2580", r))
}
-
使用 go build 命令编译这个程序,产生 app 可执行文件
-
这是一个普通的可执行文件,它在操作系统里运行,会依赖系统里的库文件
# ldd app linux-vdso.so.1 => (0x00007ffd1f7a3000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f554fd4a000) libc.so.6 => /lib64/libc.so.6 (0x00007f554f97d000) /lib64/ld-linux-x86-64.so.2 (0x00007f554ff66000)
2 ) “笼子”
-
为了让这个程序不依赖于操作系统自身的库文件,我们需要制作容器镜像,即隔离的运行环境, Dockerfile 是制作容器镜像的“菜谱”
-
我们的菜谱就只有两个步骤,下载一个 centos 的基础镜像,把 app 这个可执行文件放到镜像中 /usr/local/bin 目录中去
FROM centos ADD app /usr/local/bin
3 ) 地址
- 制作好的镜像存再本地,我们需要把这个镜像上传到镜像仓库里去
- 这里的镜像仓库,相当于应用商店
- 我们使用阿里云的镜像仓库,上传之后镜像地址是 :
registry.cn-hangzhou.aliyuncs.com/kube-easy/app:latest- 镜像地址可以拆分成四个部分:仓库地址 / 命名空间 / 镜像名称 : 镜像版本
- 显然,镜像上边的镜像,在阿里云杭州镜像仓库,使用的命名空间是 kube-easy
- 镜像名 : 版本是 app:latest
- 至此,我们有了一个可以在 Kubernetes 集群上运行的,“关在笼子里”的小程序
得其门而入
1 ) 入口
- Kubernetes 作为操作系统,和普通的操作系统一样,有 API 的概念
- 有了API,集群就有了入口;有了 API,我们使用集群,才能得其门而入
- Kubernetes 的 API 被实现为运行在集群节点上的组件 API Server
- 这个组件是典型的 web 服务器程序,通过对外暴露 http(s) 接口来提供服务
- 这里我们创建一个阿里云 Kubernetes 集群
- 登录集群管理页面,我们可以看到API Server 的公网入口
- API Server 内网连接端点: https://xx.xxx.xxx.xxx:6443
2 ) 双向数字证书验证
- 阿里云 Kubernetes 集群 API Server 组件,使用基于 CA 签名的双向数字证书
认证来保证客户端与 api server 之间的安全通信。 - 这句话很绕口,对于初学者不太好理解,我们来深入解释一下。
- 从概念上来讲,数字证书是用来验证网络通信参与者的一个文件
- 这和学校颁发给学生的毕业证书类似
- 在学校和学生之间,学校是可信第三方 CA,而学生是通信参与者
- 如果社会普遍信任一个学校的声誉的话,那么这个学校颁发的毕业证书,也会得到社会认可
- 参与者证书和 CA 证书可以类比毕业证和学校的办学许可证
- 这里我们有两类参与者,CA 和普通参与者
- 与此对应,我们有两种证书,CA 证书和参与者证书
- 另外我们还有两种关系,证书签发关系,以及信任关系
- 这两种关系至关重要,我们先看签发关系
- 如下图,我们有两张 CA 证书,三个参与者证书
- 其中最上边的 CA 证书,签发了两张证书
- 一张是中间的 CA 证书
- 另一张是右边的参与者证书
- 中间的 CA 证书,签发了下边两张参与者证书
- 这六张证书以签发关系为联系,形成了树状的证书签发关系图
- 然而,证书以及签发关系本身,并不能保证可信的通信可以在参与者之间进行
- 以上图为例,假设最右边的参与者是一个网站,最左边的参与者是一个浏览器,浏览器相信网站的数据
- 不是因为网站有证书,也不是因为网站的证书是 CA 签发的,而是因为浏览器相信最上边的 CA,也就是信任关系
- 理解了 CA(证书),参与者(证书),签发关系,以及信任关系之后,我们回过头来看“基于 CA 签名的双向数字证书认证”
- 客户端和 API Server 作为通信的普通参与者,各有一张证书
- 而这两张证书,都是由 CA 签发,我们简单称它们为集群CA 和客户端 CA
- 客户端信任集群 CA,所以它信任拥有集群 CA 签发证书的 API Server
- 反过来 API Server 需要信任客户端 CA,它才愿意与客户端通信
- 阿里云 Kubernetes 集群,集群 CA 证书,和客户端 CA 证书,实现上其实是一张证书,所以我们有这样的关系图
3 )KubeConfig 文件
-
登录集群管理控制台,我们可以拿到 KubeConfig 文件
-
这个文件包括了客户端证书,集群 CA 证书,以及其他
-
证书使用 base64 编码,所以我们可以使用base64 工具解码证书,并使用 openssl 查看证书文本。
-
首先,客户端证书的签发者 CN 是集群 id c0256a3b8e4b948bb9c21e66b0e-1d9a72
-
而证书本身的 CN 是子账号 252771643302762862
Certificate:Data:Version: 3 (0x2)Serial Number: 787224 (0xc0318)Signature Algorithm: sha256WithRSAEncryptionIssuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72ValidityNot Before: Nov 29 06:03:00 2018 GMTNot After : Nov 28 06:08:39 2021 GMTSubject: O=system:users, OU=, CN=252771643302762862 -
其次,只有在 API Server 信任客户端 CA 证书的情况下,上边的客户端证书
才能通过 API Server 的验证 -
kube-apiserver 进程通过 client-ca-file 这个参数指定其信任的客户端 CA 证书,其指定的证书是 /etc/kubernetes/pki/apiserver-ca.crt
-
这个文件实际上包含了两张客户端 CA 证书,其中一张和集群管控有关系
-
这里不做解释,另外一张如下,它的 CN 与客户端证书的签发者 CN 一致
Certificate:Data:Version: 3 (0x2)Serial Number: 787224 (0xc0318)Signature Algorithm: sha256WithRSAEncryptionIssuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72ValidityNot Before: Nov 29 06:03:00 2018 GMTNot After : Nov 28 06:08:39 2021 GMTSubject: O=system:users, OU=, CN=252771643302762862
-
再 次,API Server 使 用 的 证 书, 由 kube-apiserver 的 参 数 tls-cert-file决定
-
这个参数指向证书 /etc/kubernetes/pki/apiserver.crt。这个证书的CN 是 kube-apiserver
-
签 发 者 是 c0256a3b8e4b948bb9c21e66b0e-1d9a72,即集群 CA 证书
Certificate:Data:Version: 3 (0x2)Serial Number: 2184578451551960857 (0x1e512e86fcba3f19)Signature Algorithm: sha256WithRSAEncryptionIssuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72ValidityNot Before: Nov 29 03:59:00 2018 GMTNot After : Nov 29 04:14:23 2019 GMTSubject: CN=kube-apiserver -
最后,客户端需要验证上边这张 API Server 的证书,因而 KubeConfig 文件里包含了其签发者,即集群 CA 证书
-
对比集群 CA 证书和客户端 CA 证书,发现两张证书完全一样,这符合我们的预期
Certificate:Data:Version: 3 (0x2)Serial Number: 786974 (0xc021e)Signature Algorithm: sha256WithRSAEncryptionIssuer: C=CN, ST=ZheJiang, L=HangZhou, O=Alibaba, OU=ACS, CN=rootValidityNot Before: Nov 29 03:59:00 2018 GMTNot After : Nov 24 04:04:00 2038 GMTSubject: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72
4 )访问
-
理解了原理之后,我们可以做一个简单的测试
-
我们以证书作为参数,使用 curl访问 api server,并得到预期结果
# curl --cert ./client.crt --cacert ./ca.crt --key ./client.key https://xx.xx.xx.xxx:6443/api/ {"kind": "APIVersions","versions": ["v1"],"serverAddressByClientCIDRs": [{"clientCIDR": "0.0.0.0/0","serverAddress": "192.168.0.222:6443"}] }
择优而居
1 ) 两种节点,一种任务
- 如开始所讲,Kubernetes 是管理集群多个节点的操作系统
- 这些节点在集群中的角色,却不必完全一样
- Kubernetes 集群有两种节点,master 节点和 worker 节点
- 这种角色的区分,实际上就是一种分工:master 负责整个集群的管理
- 其上运行的以集群管理组件为主,这些组件包括实现集群入口的 api server
- 而 worker 节点主要负责承载普通任务
- 在 Kubernetes 集群中,任务被定义为 pod 这个概念
- pod 是集群可承载任务的原子单元
- pod 被翻译成容器组,其实是意译,因为一个 pod 实际上封装了多个容器化的应用
- 原则上来讲,被封装在一个 pod 里边的容器,应该是存在相当程度的耦合关系
2 ) 择优而居
- 调度算法需要解决的问题,是替 pod 选择一个舒适的“居所”,让 pod 所定义的任务可以在这个节点上顺利地完成
- 为了实现“择优而居”的目标,Kubernetes 集群调度算法采用了两步走的策略:
- 第一步,从所有节点中排除不满足条件的节点,即预选;
- 第二步,给剩余的节点打分,最后得分高者胜出,即优选
- 下边,我们使用文章开始的时候制作的镜像,创建一个 pod,并通过日志来具体分析一下,这个 pod 怎么样被调度到某一个集群节点
3 ) Pod 配置
- 首先,我们创建 pod 的配置文件,配置文件格式是 json
- 这个配置文件有三个地方比较关键,分别是镜像地址,命令以及容器的端口
{"apiVersion": "v1","kind": "Pod","metadata": {"name": "app"},"spec": {"containers": [{"name": "app","image": "registry.cn-hangzhou.aliyuncs.com/kube-easy/app:latest","command": ["app"],"ports": [{"containerPort": 2580}]}]}
}
4 ) 日志级别
-
集群调度算法被实现为运行在 master 节点上的系统组件,这一点和 api server类似
-
其对应的进程名是 kube-scheduler。kube-scheduler 支持多个级别的日志输出
-
但社区并没有提供详细的日志级别说明文档。查看调度算法对节点进行筛选、打分的过程
-
我们需要把日志级别提高到 10,即加入参数 --v=10
kube-scheduler --address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=true --v=10
5 ) 创建 Pod
-
使用 curl,以证书和 pod 配置文件等作为参数,通过 POST 请求访问 api server 的接口
-
我们可以在集群里创建对应的 pod
# curl -X POST -H 'Content-Type: application/json;charset=utf-8' --cert ./ client.crt --cacert ./ca.crt --key ./client.key https://47.110.197.238:6443/api/v1/namespaces/default/pods -d@ app.json
6 ) 预选
- 预选是 Kubernetes 调度的第一步,这一步要做的事情,是根据预先定义的规则,把不符合条件的节点过滤掉
- 不同版本的 Kubernetes 所实现的预选规则有很大的不同,但基本的趋势,是预选规则会越来越丰富
- 比较常见的两个预选规则是 PodFitsResourcesPred 和 PodFitsHostPortsPred
- 前一个规则用来判断,一个节点上的剩余资源,是不是能够满足 pod 的需求
- 而后一个规则,检查一个节点上某一个端口是不是已经被其他 pod 所使用了
- 下图是调度算法在处理测试 pod 的时候,输出的预选规则的日志
- 这段日志记录了预选规则 CheckVolumeBindingPred 的执行情况
- 某些类型的存储卷(PV),只能挂载到一个节点上
- 这个规则可以过滤掉不满足 pod 对 PV 需求的节点
- 从 app 的编排文件里可以看到,pod 对存储卷并没有什么需求
- 所以这个条件并没有过滤掉节点
7 ) 优选
- 调度算法的第二个阶段是优选阶段
- 这个阶段,kube-scheduler 会根据节点可用资源及其他一些规则,给剩余节点打分
- 目前,CPU 和内存是调度算法考量的两种主要资源,但考量的方式并不是简单的,剩余 CPU、内存资源越多,得分就越高
- 日志记录了两种计算方式:
- LeastResourceAllocation
- BalancedResourceAllocation
- 前一种方式计算 pod 调度到节点之后,节点剩余 CPU 和内存占总 CPU 和内存的比例,比例越高得分就越高
- 第二种方式计算节点上 CPU 和内存使用比例之差的绝对值,绝对值越大,得分越少
-
这两种方式,一种倾向于选出资源使用率较低的节点,第二种希望选出两种资源使用比例接近的节点
-
这两种方式有一些矛盾,最终依靠一定的权重来平衡这两个因素
-
除了资源之外,优选算法会考虑其他一些因素
- 比如 pod 与节点的亲和性,或者如果一个服务有多个相同 pod 组成的情况下
- 多个 pod 在不同节点上的分散程度
-
这是保证高可用的一种策略
8 ) 得分
- 最后,调度算法会给所有的得分项乘以它们的权重,然后求和得到每个节点最终的得分
- 因为测试集群使用的是默认调度算法
- 而默认调度算法把日志中出现的得分项所对应的权重,都设置成了 1
- 所以如果按日志里有记录得分项来计算,最终三个节点的得分应该是 29,28 和 29
- 之所以会出现日志输出的得分和我们自己计算的得分不符的情况
- 是因为日志并没有输出所有的得分项,猜测漏掉的策略应该是 NodePreferAvoidPodsPriority
- 这个策略的权重是 10000,每个节点得分 10,所以才得出最终日志输出的结果
总结
- 我们以一个简单的容器化 web 程序为例
- 着重分析了客户端怎么样通过 Kubernetes 集群 API Server 认证
- 以及容器应用怎么样被分派到合适节点这两件事情
- 在分析过程中,我们弃用了一些便利的工具,比如 kubectl,或者控制台
- 我们用了一些更接近底层的小实验,比如拆解 KubeConfig 文件
- 再比如分析调度器日志来分析认证和调度算法的运作原理
相关文章:
DEVOPS: 认证与调度
概述 不知道大家有没有意识到一个现实,就是大部分时候,我们已经不像以前一样通过命令行,或者可视窗口来使用一个系统了现在我们上微博、或者网购,操作的其实不是眼前这台设备,而是一个又一个集群 通常,这样…...
ICPC区域赛成都站【赛后回顾+总结】
传送门 前言赛后总结赛后回顾赛后感悟 前言 首先,这是本人本赛季第一场XCPC区域赛,也是本人算竞生涯中第一场XCPC区域赛(之前只打过邀请赛和省赛)。 赛后总结 然后赛后总结一下:我队天崩开局,我队出师不利…...
保险大模型革新:全面自动化倒计时
摘 要 大模型于保险业不仅是一个技术升级的过程,更是一种商业模式的变革 未来将会是一切都连接着AI的世界——科技杂志《连线》创始主编凯文凯利(KevinKelly)曾在《5000天后的世界》中预测。 ChatGPT催生大模型热潮已将近两年,…...
《使用Gin框架构建分布式应用》阅读笔记:p212-p233
《用Gin框架构建分布式应用》学习第12天,p212-p233总结,总22页。 一、技术总结 1.JavaScript知识点 (1)class、method (2)function, arrow function, (3)fetch() (4)Promise, then() 2.bootstrap 第5章主要涉及前端技术的运用,作为后…...
点云聚类学习 KMeans/DBSCAN
点云聚类学习--KMeans/DBSCAN OverviewKMeansDBSCAN简单对比 Overview 最近做的东西会处理一些Lidar的点云数据,虽然之前在看Autoware的时候有了解一些聚类的基本原理和实现,但还是稍微再学习一下聚类方法吧,这里就简单记录一下(…...
反悔贪心
Problem - C - Codeforces(初识反悔贪心) 题目: 思路: 代码: #include <bits/stdc.h> #define fi first #define se secondusing namespace std; typedef pair<int,int> PII;string a, b, ans; bool vis…...
汽车软件融合分析
随着汽车智能化、互联化的不断发展,软件在汽车中的重要性日益彰显。从硬件定义汽车,到软件定义汽车,再到AI定义汽车,汽车产业的变革正在加速进行。在这一变革中,软件融合成为了一个重要的趋势。本文将从多个角度对汽车…...
机器人和智能的进化速度远超预期-ROS-AI-
危机 通常,有危险也有机遇才称之为危机。 从2020年启动转型自救,到2021年发现危险迫在眉睫,直到2024年也没有找到自己满意的出路。 共识 中产阶级知识分子共有的特性和一致的推断。 200年前的推断,在如今得到了验证。 机器人…...
5天学习RAG路线图,你信吗?
RAG是"Retrieval Augmented Generation"的缩写,让我们来拆解这个术语,了解RAG的本质: R -> Retrieval(检索) A -> Augmented(增强) G -> Generation(生成&…...
JIME智创:抖音创作者的AI绘画与视频生成创作神器
在短视频和社交内容创作的时代,创意和速度成了成功的关键。无论是视频博主、图文创作者还是品牌推广人,他们都面临着如何快速生成高质量图片与视频素材的挑战。JIME智创正是针对这一需求推出的AI创作工具,专为抖音的图文和视频创作者设计&…...
基于SpringBoot和PostGIS的世界各国邻国可视化实践
目录 前言 一、空间数据查询基础 1、空间数据库基础 2、空间相邻查询 二、SpringBoot后台功能设计 1、后台查询接口的实现 2、业务接口设计 三、Leaflet进行WebGIS开发 1、整体结构介绍 2、相邻国家展示可视化 四、成果展示 1、印度及其邻国 2、乌克兰及其邻国 3、…...
Halcon相机外参自理解
外参描述了相机在世界坐标系中的位置和朝向,即它将世界坐标转换为相机坐标的几何变换。具体来说,外参包括一个 旋转矩阵 R R R 和一个 平移向量 t t t,它们共同构成了将世界坐标变换到相机坐标系的刚体变换 相机标定的Pose0代表了相机在外界…...
C#语言入门:从基础到进阶
C#(发音为"C sharp")是微软公司推出的一种面向对象的编程语言,它由Anders Hejlsberg和他的团队在.NET框架下开发。C#语言结合了C和Java的特性,并添加了新的功能,使其成为当今最流行的编程语言之一。 C#的特…...
网络爬虫的定义
网络爬虫,即Web Spider,是一个很形象的名字。 把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛。 网络蜘蛛是通过网页的链接地址来寻找网页的。 从网站某一个页面(通常是首页)开始,读取网页…...
一个月调研分析标的“英伟达”
放在现在依然成立 一、移动网兴起至今的最佳股票与人工智能时代的目标 9 年移动网兴起至今,若选一只股票长期持有,最佳解是 ARM(涨了 20 倍),因为无论系统层和应用层谁胜出,底层一定是芯片,而…...
Spring Boot 与 EasyExcel 携手:复杂 Excel 表格高效导入导出实战
数据的并行导出与压缩下载:EasyExcel:实现大规模数据的并行导出与压缩下载 构建高效排队导出:解决多人同时导出Excel导致的服务器崩溃 SpringBoot集成EasyExcel 3.x: 前言 在企业级应用开发中,常常需要处理复杂的 …...
什么是严肃游戏,严肃游戏本地化的特点是什么?
“严肃游戏”是一种交互式数字体验,不仅用于娱乐,还用于教育、培训或解决问题。与主要关注乐趣和参与度的传统游戏不同,严肃游戏的目标不仅仅是娱乐,比如教授特定技能、模拟现实生活场景或提高对重要问题的认识。它们用于医疗保健…...
ceph补充介绍
SDS-ceph ceph介绍 crushmap 1、crush算法通过计算数据存储位置来确定如何存储和检索,授权客户端直接连接osd 2、对象通过算法被切分成数据片,分布在不同的osd上 3、提供很多种的bucket,最小的节点是osd # 结构 osd (or device) host #主…...
2024/11/1 408 20题
b d c c a b d c c...
Python相关类库使用问题
文章目录 前言 一、pandas是什么? 二、使用步骤 1.引入库 2.读入数据 总结 前言 在工作中不时遇到新的需求,需要用到新的类库,以此篇专门记录Python类库使用过程中遇到的问题与解决 一、Python是什么? Python是一种高级编…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
