k8s whereabouts 使用

Whereabouts简介

whereabouts是一个cluster-wide(集群级别)的IPAM插件,非常适合用在NetworkAttachment的场景。之前我们描述过k8s为分配地址使用的是ipam,常见的ipam类型为host-local,calico-ipam。whereabouts是一款用于替换host-local的ipam。记录本地或者k8s已经分配的pool和ip地址。通常以 NAD 为地址段设定的模式,一个 nad 中描述 该 地址段的 ip 范围,网关等信息。一般和cni bridge,ipvlan,macvlan 等相结合使用,负责分配和管理 IP 的功能。

一、部署whereabouts

  • 下载安装包
1:克隆代码
[root@node1 ~]# git clone https://github.com/k8snetworkplumbingwg/whereabouts
Cloning into 'whereabouts'...
remote: Enumerating objects: 23528, done.
remote: Counting objects: 100% (3556/3556), done.
remote: Compressing objects: 100% (1875/1875), done.
remote: Total 23528 (delta 1811), reused 2957 (delta 1580), pack-reused 19972
Receiving objects: 100% (23528/23528), 36.48 MiB | 9.56 MiB/s, done.
Resolving deltas: 100% (11207/11207), done.#################################
2;查看文件
[root@node1 ~]# cd whereabouts/doc/crds/
[root@node1 crds]# ll
total 12
-rw-r--r-- 1 root root 2662 Nov 29 14:27 daemonset-install.yaml
-rw-r--r-- 1 root root 2566 Nov 29 14:27 whereabouts.cni.cncf.io_ippools.yaml
-rw-r--r-- 1 root root 2039 Nov 29 14:27 whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml##########################################
3:执行以下命令开始部署whereabouts
[root@node1 crds]# kubectl apply -f daemonset-install.yaml 
serviceaccount/whereabouts created
clusterrolebinding.rbac.authorization.k8s.io/whereabouts created
clusterrole.rbac.authorization.k8s.io/whereabouts-cni created
daemonset.apps/whereabouts created
[root@node1 crds]# kubectl apply -f whereabouts.cni.cncf.io_ippools.yaml 
customresourcedefinition.apiextensions.k8s.io/ippools.whereabouts.cni.cncf.io created
[root@node1 crds]# kubectl apply -f whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml 
customresourcedefinition.apiextensions.k8s.io/overlappingrangeipreservations.whereabouts.cni.cncf.io created
  • 查看生成的crd
1:查看生成的crd
[root@node1 crds]# kubectl get crd | grep whereabouts
ippools.whereabouts.cni.cncf.io                          2023-11-29T06:50:47Z
overlappingrangeipreservations.whereabouts.cni.cncf.io   2023-11-29T06:50:52Z
[root@node1 crds]# ################解释:
overlappingrangeipreservations 所有分配的 IP
Ippool  已经分配的ip的地址池
  • 查看服务
1;查看whereabouts服务运行状态,以daemonset形式在每个节点运行
[root@node1 ~]# kubectl get po -A -o wide | grep whereabouts
kube-system            whereabouts-4sjpf                            1/1     Running     0              19m     192.168.5.27    node3   <none>           <none>
kube-system            whereabouts-rw5d5                            1/1     Running     0              19m     192.168.5.126   node2   <none>           <none>
kube-system            whereabouts-v8nxd                            1/1     Running     0              19m     192.168.5.79    node1   <none>  ##########################################
2:会在每个节点的/opt/cni/bin 目录下生成一个二进制文件
[root@node1 ~]# cd /opt/cni/bin/
[root@node1 bin]# ll  | grep where
-rwxr-xr-x 1 root root 45792495 Nov 29 15:03 whereabouts
[root@node1 bin]# ##########解释
daemonset服务 负责维护地址池
whereabouts插件负责申请地址

二、实验

以下测试皆是基于生产环境来配置。

实验环境基于kube-ovn + multus + ipvlan给容器设置双网卡,ipvlan使用whereabouts来分配置IP

  • 网络规划
在我的环境中,ipvlan使用的是两块网卡做的bond,每个子接口走不同的业务,本次测试使用的是ipvl1720
[root@node1 ~]# ip a | grep bond_ipvl
2: enp35s0f0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond_ipvl state UP group default qlen 1000
9: enp97s0f1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond_ipvl state UP group default qlen 1000
77: bond_ipvl: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
78: bond_ipvl.1520@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
79: bond_ipvl.1511@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
80: bond_ipvl.1510@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
81: bond_ipvl.1521@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
82: bond_ipvl.1522@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
207: bond_ipvl.1720@bond_ipvl: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
  • 创建NAD
[root@node1 ~]# cat ipvlan1720.yaml 
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:name: ipvlan1720namespace: devops
spec:config: '{ "cniVersion": "0.3.1", "LogFile": "/var/log/multus.log", "LogLevel": "debug", "name": "ipvlan1720", "type": "ipvlan", "master": "bond_ipvl.1720",    ##使用的接口"mtu": 1500, "ipam": { "type": "whereabouts",   ###指定ipam类型"datastore": "kubernetes", "range": "10.11.88.96/28",   ###cidr"range_start": "10.11.88.98",  ###起始地址"range_end": "10.11.88.98",   ###终止地址"gateway": "10.11.8.97",   ###网关"log_file" : "/tmp/whereabouts.log", "log_level" : "debug" } }'[root@node1 ~]# kubectl apply -f  ipvl1720.yaml 
networkattachmentdefinition.k8s.cni.cncf.io/ipvlan1720 created
[root@node1 ~]# 
[root@node1 ~]# 
[root@node1 ~]# kubectl get network-attachment-definition -n devops
NAME         AGE
ipvlan1720   78s
[root@node1 ~]# 
  • 启动pod
1;pod yaml内容如下
apiVersion: v1
kind: Pod
metadata:name: ipvlnamespace: devopslabels:app: nginxannotations:k8s.v1.cni.cncf.io/networks: ipvlan1720   ###指定使用的NAD
spec:containers:- name: nginximage: registry-1.ict-mec.net:18443/nginx:latestimagePullPolicy: IfNotPresentports:- name: nginx-portcontainerPort: 80####################################
2:查看pod,172.10.4.148为kube-ovn网络的ip地址
[root@node1 ~]# kubectl get po -n devops 
NAME   READY   STATUS    RESTARTS   AGE
ipvl   1/1     Running   0          3s
[root@node1 ~]# kubectl get po -n devops  -o wide 
NAME   READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
ipvl   1/1     Running   0          6s    172.10.4.148   node2   <none>           <none>
[root@node1 ~]# 
  • 查看pod获取的地址
1:describe 查看pod信息
[root@node1 ~]# kubectl describe  po ipvl -n devops
Name:         ipvl
Namespace:    devops
Priority:     0
Node:         cmu52/23.1.1.36
Start Time:   Thu, 30 Nov 2023 15:45:33 +0800
Labels:       app=nginx
Annotations:  io.kubernetes.pod.sandbox.uid: aa3576c85e9b699a8bbe5360edd5d84cccffdfc2e1c017b6b6e52c77c0308dcdk8s.v1.cni.cncf.io/network-status:[{"name": "kube-ovn","ips": ["172.10.4.148","fd00:10:16::494"],"default": true,"dns": {}},{"name": "devops/ipvlan1720","interface": "net1","ips": ["10.11.88.98"],"mac": "40:a6:b7:37:29:3c","dns": {}}]k8s.v1.cni.cncf.io/networks: ipvlan1720   ###使用的NADk8s.v1.cni.cncf.io/networks-status:[{"name": "kube-ovn","ips": ["172.10.4.148","fd00:10:16::494"],"default": true,"dns": {}},{"name": "devops/ipvlan1720","interface": "net1",  ####pod内部的网卡"ips": ["10.11.88.98"       ####可以看到获取的地址],"mac": "40:a6:b7:37:29:3c","dns": {}}]###############################
2:进入pod的宿主机的网络ns 中查看
[root@node2 ~]# crictl  ps| grep nginx
38a9298403eda       12766a6745eea       About a minute ago   Running             nginx                       0                   aa3576c85e9b6       ipvl
[root@node2 ~]# crictl  inspect 38a9298403eda| grep -i pid"pid": 505586,"pid": 1"type": "pid"
[root@node2 ~]# nsenter -t 505586 -n bash
[root@node2 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000link/ipip 0.0.0.0 brd 0.0.0.0
3: net1@if248: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default link/ether 40:a6:b7:37:29:3c brd ff:ff:ff:ff:ff:ffinet 10.11.88.98/28 brd 10.11.88.111 scope global net1valid_lft forever preferred_lft foreverinet6 fe80::40a6:b700:137:293c/64 scope link valid_lft forever preferred_lft forever
259: eth0@if260: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP group default link/ether 00:00:00:20:4f:93 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.10.4.148/16 brd 172.10.255.255 scope global eth0valid_lft forever preferred_lft foreverinet6 fd00:10:16::494/64 scope global valid_lft forever preferred_lft foreverinet6 fe80::200:ff:fe20:4f93/64 scope link valid_lft forever preferred_lft forever
[root@node2 ~]# ip r
default via 172.10.0.1 dev eth0 
10.11.88.96/28 dev net1 proto kernel scope link src 10.11.88.98 
172.10.0.0/16 dev eth0 proto kernel scope link src 172.10.4.148 
  • 查看分配的ip地址
1:查看已经分配的地址
[root@node1 ~]# kubectl get  overlappingrangeipreservations.whereabouts.cni.cncf.io  -n kube-system
NAME           AGE
10.11.88.98    79m################
2:查看已经分配的地址池,因为我在上面的NAD中定义的网络为10.11.88.96/28,所以pool的名称规则是网络+掩码位数
[root@node1 ~]# kubectl get ippools.whereabouts.cni.cncf.io -n kube-system
NAME              AGE
10.11.88.96-28    80m####################################
3:查看分配的ip地址信息
[root@node1 ~]# kubectl describe   overlappingrangeipreservations.whereabouts.cni.cncf.io 10.11.88.98 -n kube-system
Name:         10.11.88.98
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>
API Version:  whereabouts.cni.cncf.io/v1alpha1
Kind:         OverlappingRangeIPReservation
Metadata:Creation Timestamp:  2023-11-30T07:45:34ZGeneration:          1Managed Fields:API Version:  whereabouts.cni.cncf.io/v1alpha1Fields Type:  FieldsV1fieldsV1:f:spec:.:f:containerid:f:podref:Manager:         whereaboutsOperation:       UpdateTime:            2023-11-30T07:45:34ZResource Version:  25214006UID:               d1565403-02e1-45ff-b09f-a26710d7bb7d
Spec:Containerid:  aa3576c85e9b699a8bbe5360edd5d84cccffdfc2e1c017b6b6e52c77c0308dcd  ####可以看到绑定的容器idPodref:       devops/ipvl
Events:         <none>
[root@node1 ~]# ##############################
4:查看地址池的信息
[root@node1 ~]# kubectl describe  ippools.whereabouts.cni.cncf.io 10.11.88.96-28 -n kube-system
Name:         10.11.88.96-28
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>
API Version:  whereabouts.cni.cncf.io/v1alpha1
Kind:         IPPool
Metadata:Creation Timestamp:  2023-11-30T07:44:44ZGeneration:          4Managed Fields:API Version:  whereabouts.cni.cncf.io/v1alpha1Fields Type:  FieldsV1fieldsV1:f:spec:.:f:allocations:.:f:2:.:f:id:f:podref:f:range:Manager:         whereaboutsOperation:       UpdateTime:            2023-11-30T07:45:34ZResource Version:  25214005UID:               10544b9b-9ad3-43a9-b747-d46293a54ebb
Spec:Allocations:2:Id:      aa3576c85e9b699a8bbe5360edd5d84cccffdfc2e1c017b6b6e52c77c0308dcdPodref:  devops/ipvl    ###pod的名称Range:       10.11.88.96/28
Events:        <none>
[root@node1 ~]# 
  • pod删除
1:测试多启动一个pod,发现在ippool 中会自动把发分配的ip更新进去
[root@node1 ~]# kubectl get ippool 10.11.88.96-28 -o yaml  -n kube-system
apiVersion: whereabouts.cni.cncf.io/v1alpha1
kind: IPPool
metadata:creationTimestamp: "2023-11-30T09:38:48Z"generation: 3name: 10.11.88.96-28namespace: kube-systemresourceVersion: "25262851"uid: d00b0b1c-f848-461b-9e98-e4512307a485
spec:allocations:"2":id: cc4d323c718f08effc22ff05f4a7727a9b648e5bd4849ab0143c5439337209d1podref: devops/ipvl"3":id: 7a8bbfed7f98586779ac089358102078bca0f1946fe131c6abd8bd66e685688apodref: devops/ipvl2range: 10.11.88.96/28########################################
2:删除两个pod,查看ippool的变化
[root@node1 ~]# kubectl delete  po  ipvl -n devops
pod "ipvl" deleted
[root@cmu51 ~]# kubectl delete  po  ipvl2 -n devops
pod "ipvl2" deleted如下ippool中已经将分配到ip地址进行删除。
[root@node1 ~]# kubectl get ippool 10.11.88.96-28 -o yaml  -n kube-system
apiVersion: whereabouts.cni.cncf.io/v1alpha1
kind: IPPool
metadata:creationTimestamp: "2023-11-30T09:38:48Z"generation: 5name: 10.11.88.96-28namespace: kube-systemresourceVersion: "25263222"uid: d00b0b1c-f848-461b-9e98-e4512307a485
spec:allocations: {}range: 10.11.88.96/28

三、原理总结

1:创建一个NAD,内部定义一个IP range

2:创建pod,调度到宿主机时,本机的二进制文件whereabouts读取ip range

3:获取ippool,如果不存在就创建一个新的ippool,比如NAD中定义的IP range为10.11.88.96/28,ippool的名称为10.11.88.96-28

4:获取到 ippool 之后,根据NAD.ipam 地址段里的 IP range 里分配一个可用 ip,将 ip 更新到 ippool 里。

5:创建 OverlappingRangeIPReservation,名称以IP地址命名。

6:cni将结果返回给cri

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/2001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PCL】教程global_hypothesis_verification 通过验证模型假设来实现 3D 对象识别与位姿估计...

测试程序1 milk.pcd milk_cartoon_all_small_clorox.pcd 终端输出1&#xff1a; Model total points: 12575; Selected Keypoints: 193 Scene total points: 307200; Selected Keypoints: 7739 [pcl::SHOTEstimation::computeFeature] The local reference frame is not valid!…

初入单元测试

单元测试&#xff1a;针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试 Junit可以用来对方法进行测试&#xff0c;虽然是有第三方公司开发&#xff0c;但是很多开发工具已经集成了&#xff0c;如IDEA。 Junit 优点&#xff1a;可以灵活的编写测试代码&am…

【C++】类和对象初探:类的实例化与对象生命周期管理,解析this指针的奥秘

欢迎来到CILMY23的博客 本篇主题为&#xff1a; 类和对象初探&#xff1a;类的实例化与对象生命周期管理&#xff0c;解析this指针的奥秘 个人主页&#xff1a;CILMY23-CSDN博客 系列专栏&#xff1a;Python | C | C语言 | 数据结构与算法 感谢观看&#xff0c;支持的可以给…

医学影像图像去噪:滤波器方法、频域方法、小波变换、非局部均值去噪、深度学习与稀疏表示和字典学习

医学影像图像去噪是指使用各种算法从医学成像数据中去除噪声,以提高图像质量和对疾病的诊断准确性。MRI(磁共振成像)和CT(计算机断层扫描)是两种常见的医学成像技术,它们都会受到不同类型噪声的影响。 在医学影像中,噪声可能来源于多个方面,包括成像设备的电子系统、患…

[RTOS 学习记录] 工程管理工具make及makefile

[RTOS 学习记录] 工程管理工具make及makefile 这篇文章是我阅读《嵌入式实时操作系统μCOS-II原理及应用》后的读书笔记&#xff0c;记录目的是为了个人后续回顾复习使用。 前置内容&#xff1a; 开发工具 Borland C/C 3.1 精简版 文章目录 1 make 工具2 makefile 的内容结构3…

MLLM | InternLM-XComposer2-4KHD: 支持336 像素到 4K 高清的分辨率的大视觉语言模型

上海AI Lab&#xff0c;香港中文大学等 论文标题:InternLM-XComposer2-4KHD: A Pioneering Large Vision-Language Model Handling Resolutions from 336 Pixels to 4K HD 论文地址:https://arxiv.org/abs/2404.06512 Code and models are publicly available at https://gi…

PyCharm Professional 安装

文章目录 下载PyCharm 2022.3 Professional使用‘第一种【推荐】’即可记得要是要使用Activation Code激活&#xff01; 破解方法&#xff1a; https://www.exception.site/essay/pycharm-pojie-jihuoma 下载PyCharm 2022.3 Professional [https://www.jetbrains.com/pycharm/…

使用 ollama 部署最新的Llama 3 70B本地模型

一、ollama是什么? 在本地启动并运行大型语言模型。运行Llama 3&#xff0c;Mistral, Gemma, Code Llama和其他模型。自定义并创建您自己的。 综合优点&#xff1a; 快速下载容器自动运行大模型&#xff0c;现在下载&#xff0c;马上上手。本地利用 cpu 运行大模型&#xff0c…

【Hadoop】-Apache Hive概述 Hive架构[11]

目录 Apache Hive概述 一、分布式SQL计算-Hive 二、为什么使用Hive Hive架构 一、Hive组件 Apache Hive概述 Apache Hive是一个在Hadoop上构建的数据仓库基础设施&#xff0c;它提供了一个SQL-Like查询语言来分析和查询大规模的数据集。Hive将结构化查询语言&#xff08;…

视频教程下载:ChatGPT驱动的SEO、网络营销、生产力提升

用户遇到的一个常见问题是在ChatGPT对话过程中难以保持清晰的目的和专注。这可能导致互动无效和浪费时间。这门课程将教给各种创意人士——艺术家、制造者、博主、讲师和内容创作者——如何制定理想的提示配方&#xff0c;从而产生更有成效的对话和更高的回报。 这是一门关于如…

小程序前端调用接口(getAccessToken)获取调用凭据,调用接口(msgSecCheck)检测文本内容是否安全--最终版

序言: 集合百家之所长,方著此篇文章,废话少说,直接上代码,找好你的小程序APPID,AppSecret(小程序密钥),进行配置,然后复制粘贴代码,就可以了。 第一步:小程序前端调用接口(getAccessToken)获取调用凭据 wx.request({method: GET,url: "https://api.weixin.qq.…

【入门篇】本章包括创建云项目、数据库的使用、云存储管理、云函数的基本使用、实战举例(小程序之云函数开发入门到使用发布上线实操)

云函数 云函数相当于服务器接口的概念,它并属于小程序端代码。它是以函数的形式运行后端代码来响应事件以及调用其他服务。运行环境是Node.js。 一、基创建云函数项目 打开微信开发者工具: 打开微信开发者工具,并登录你的微信开发者账号。 创建项目: 如果还没有创建项目,你…

7. Django 模型与数据库

第7章 模型与数据库 Django对各种数据库提供了很好的支持, 包括PostgreSQL, MySQL, SQLite和Oracle, 而且为这些数据库提供了统一的API方法, 这些API统称为ORM框架. 通过使用Django内置的ORM框架可以实现数据库连接和读写操作. 本章以SQLite数据库为例, 分别讲述Django的模型…

Ai-WB2 系列模组SDK接入亚马逊云

文章目录 前言一、准备二、亚马逊云物模型建立1. 注册亚马逊账号&#xff0c;登录AWS IoT控制台&#xff0c;[注册地址](https://aws.amazon.com/cn/)2. 创建好之后点击登录3. 创建物品以及下载证书 三、连接亚马逊云demo获取以及配置1. 下载源码2. 按照顺序执行下面指令3. 修改…

用友U8-Cloud api/hr接口存在SQL注入漏洞

声明&#xff1a; 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 简介 U8 Cloud是由用友推出的新一代云ERP系统&#xff0…

20240331-1-基于深度学习的模型

基于深度学习的模型 知识体系 主要包括深度学习相关的特征抽取模型&#xff0c;包括卷积网络、循环网络、注意力机制、预训练模型等。 CNN TextCNN 是 CNN 的 NLP 版本&#xff0c;来自 Kim 的 [1408.5882] Convolutional Neural Networks for Sentence Classification 结…

hadoop安装记录

零、版本说明 centos [rootnode1 ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)jdk [rootnode1 ~]# java -version java version "1.8.0_311" Java(TM) SE Runtime Environment (build 1.8.0_311-b11) Java HotSpot(TM) 64-Bit Server VM (…

Node.js数电票、全电票查验接口示例、发票查验、票据OCR API

何为数电票&#xff1a;数电票全称为全面数字化的电子发票&#xff0c;是一种全新的发票形式&#xff0c;与传统的纸质发票具有同等的法律效力&#xff0c;以数字形式存在&#xff0c;不依赖于纸质介质&#xff0c;而数电票的推行旨在提高发票管理效率&#xff0c;降低企业成本…

【LeetCode热题100】【图论】腐烂的橘子

题目描述&#xff1a;994. 腐烂的橘子 - 力扣&#xff08;LeetCode&#xff09; 腐烂的橘子会污染周围的橘子&#xff0c;要求多少轮扩散才能把全部橘子污染&#xff0c;这就相当于滴墨水入清水&#xff0c;会扩散&#xff0c;其实就是广度遍历&#xff0c;看看遍历多少层可以…

编写一款2D CAD/CAM软件(十六)交互绘制图形

绘制步骤 以交互绘制圆形为例&#xff1a; 点击鼠标左键&#xff0c;确定圆心位置&#xff1b;抬起鼠标&#xff0c;移动鼠标&#xff0c;半径随鼠标位置变化&#xff1b;点击左键确定半径&#xff0c;完成圆的绘制。 绘制结果 Code /// j-operator-create-circle.h#pragma…