当前位置: 首页 > news >正文

k8s java程序实现kubernetes Controller Operator 使用CRD 学习总结

k8s java程序实现kubernetes Controller & Operator 使用CRD 学习总结

大纲

  • 原理
  • Controller 与 Operator
  • 自定义资源定义 CRD ( CustomResourceDefinition)
  • kubernetes-client
  • 使用java fabric8io/kubernetes-client操作k8s 原生资源
  • 使用java abric8io/kubernetes-clientt操作CRD watch状态变更
  • 权限处理
  • 实例:用java开发一个数据库表监控Operator
  • 数据库表监控CRD 创建
  • springboot k8s Operator 程序开发
  • 部署springboot k8s Operator到k8s集群
  • 创建自定义资源 程序实现监控

原文地址 https://blog.csdn.net/liuyij3430448/article/details/129534732

原理

k8s中 “Pod Service Deployment”等都是一种资源,k8s的作用就是管理这些资源。(当资源创建,更新,删除后会有对应的操作)

单纯的资源是没有任何意义的,需要配合对应的Controller[控制器] 来管理资源

例如
Pod 的扩容 就是使用ReplicationController等实现的,单纯的Pod只是一个存储在Etcd中的数据

当k8s 内置的资源无法满足我们的需求时,可以使用k8s提供的CustomResourceDefinition + 自定义controller实现自己的资源与资源控制

有了自定义的资源(CRD),但是没有相应的Controller对其进行操作,那这些资源也就只能简单的存储到k8s集群中了(etcd)。
因此还需要开发相应的Controller来对相应的CRD进行监听、处理业务逻辑

Controller & Operator

Controller就是一遵循k8s相关规范,然后连接到k8s master API 并监听CRD事件的进程(CRD的事件一般就是指:Add, Update, Delete)

Operator是一个更加复杂的Controller,还可以实现一些运维操作

Operator 官方资料 https://kubernetes.io/zh-cn/docs/concepts/extend-kubernetes/operator/

Operator 就是一种 Controller

Kubernetes 的 Operator 模式概念允许你在不修改 Kubernetes 自身代码的情况下, 
通过为一个或多个自定义资源关联控制器来扩展集群的能力。

简单讲 Operator = 资源(可以是k8s内置资源或者自定义的CRD) + controller + 一些运维操作

例如本文中最后的实例

会创建一个数据库表监控CRD资源,在创建一个自己的controller,监控表的创建,保持指定数量行,删除表。 这一系列操作就是一个 Operator

CRD ( CustomResourceDefinition)

要使用自定义资源,就需要先在k8s集群中定义这个资源,定义资源就需要使用CustomResourceDefinition

注意:要使用CustomResourceDefinition, Kubernetes 服务器版本必须不低于版本 1.16.

创建CRD

官方文档 https://kubernetes.io/zh-cn/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/

以一个自定义的MyCrdTest 资源为例 CustomResourceDefinition.yaml文件中需要定 资源的名称,资源的组,资源的版本 以及spec等内容

# 定义自定义的 MyCrdTest 资源
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:# 名字必需与下面的 spec 字段匹配,并且格式为 '<名称的复数形式>.<组名>'name: mycrdtests.liuyjiang.mycrdtest.com
spec:   # 组名称,用于 REST API: /apis/<组>/<版本>group: liuyjiang.mycrdtest.comnames:# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>plural: mycrdtests# 名称的单数形式,作为命令行使用时和显示时的别名singular: mycrdtest# kind 通常是单数形式的驼峰命名(CamelCased)形式。你的资源清单会使用这一形式。kind: MyCrdTest# shortNames 允许你在命令行使用较短的字符串来匹配资源shortNames:- mct# 可以是 Namespaced 或 Cluster   scope: Namespaced       versions:- name: v1# 每个版本都可以通过服务标志启用/禁用。served: true# 必须将一个且只有一个版本标记为存储版本。storage: trueschema:openAPIV3Schema:type: objectproperties:  #自定义CRD中的specspec:type: objectproperties:# 自定义的资源spec 中的属性 mymsgmymsg: type: string# 自定义的资源spec 中的属性 myarray  myarray:    type: arrayitems:type: string # 自定义的资源spec 中的属性 mynumber         mynumber:  type: integer#自定义CRD中的status    status:type: object    properties:  mystatus: type: stringmyip: type: string  

使用命令kubectl apply -f crd-simple.yaml 创建CRD 相关文件见 《/yaml/crd-simple.yaml》

在这里插入图片描述

这样自定义资源的定义就有了,接下来就可以创建自定义资源MyCrdTest

创建CRD定义的资源

上一步中创建了自定义资源定义CustomResourceDefinition 这样就可以基于定义的内容创建自定义资源MyCrdTest

my-crd-test.yaml 文件内容如下

# 这个就是对应crd-simple.yaml 中定义的
# api使用 crd中定义的组名称(group)+ 版本号(versions name)
apiVersion: "liuyjiang.mycrdtest.com/v1"
#  kind使用 crd中定义的kind名称
kind: MyCrdTest
metadata:name: test-001
# 对应 crd-simple.yaml  schema中的spec 配置
spec:mymsg: "hello world"mynumber: 3myarray: - aaabbbccc
#  对应 crd-simple.yaml  schema中的status 配置
status:mystatus: "running"myip: "192.168.0.211"   

使用kubectl apply -f my-crd-test.yaml 创建自定义资源MyCrdTest

查看CRD定义的资源

使用kubectl get 【资源】查看创建的资源

在这里插入图片描述

可以自定义 kubectl get 显示字段

自定义kubectl get 显示字段各式如下

kubectl get [资源类型] [资源名称] -o custom-columns=【显示的的字段】:【.资源配置】

例如yaml中配置
metadata:name: test-001
spec:mymsg: "hello world"
status:mystatus: "running"myip: "192.168.0.211" 

使用以下命令查看内容 注意.号

kubectl get mct  -o custom-columns=NAME:.metadata.name,MSG:.spec.mymsg,IP:.status.myip,STATUS:.status.mystatus

也可以使用模板文件

kubectl get mct  -o custom-columns-file=tpl.txt模板文件tpl.txt内容为
NAME	        MSG          IP            STATUS
metadata.name   spec.mymsg   status.myip   status.mystatus

在这里插入图片描述

这样一个自定义的资源就创建完成了,注意此时资源只存在Etcd中并没有对应的控制器来管理资源

kubernetes-client

k8s 提供了大量的 client端库来操作集群,官方资料: https://kubernetes.io/zh-cn/docs/reference/using-api/client-libraries/

这里使用fabric8io/kubernetes-client来操作k8s集群,quarkus中就是使用fabric8io/kubernetes-client这个库

fabric8io/kubernetes-client 官方地址 https://github.com/fabric8io/kubernetes-client

关于quarkus可以参考
《quarkus 搭建与基础开发环境配置总结》

《quarkus 生产环境与k8s集成总结》

使用fabric8io/kubernetes-client操作k8s 原生资源

使用fabric8io/kubernetes-client 需要在项目中添加依赖

<dependency><groupId>io.fabric8</groupId><artifactId>kubernetes-client</artifactId><version>6.4.1</version>
</dependency>

在maven pom.xml中加入依赖,就可以使用kubernetes-client 注意:可能还需要引入 jackson相关的依赖

以下方式是在集群外(程序未部署到k8s集群中)创建KubernetesClient 
这样就可以拿到KubernetesClient,然后对Pod Service Deployment进行操作private String caCertData = "LS0tLS1C***=";
private String clientCertData = "LS0tLS****LQo=";
private String clientKeyData = "LS0tLS****=";
private String host = "https://192.168.0.160:6443";Config config = new ConfigBuilder().withMasterUrl(host).withCaCertData(caCertData).withClientCertData(clientCertData).withClientKeyData(clientKeyData).withDefaultNamespace().build();
//集群外创建client 需要指定 host 证书 私钥等				
KubernetesClient client = new KubernetesClientBuilder().withConfig(config).build();

以上代码中的caCertData clientCertData clientKeyData host
可以使用k8s集群master节点 /root/.kube/config中的配置

在这里插入图片描述

//以下方式是在集群内(程序部署在k8s集群中)创建KubernetesClient
KubernetesClient client = new KubernetesClientBuilder().build();
不需要配置 host 证书 私钥等		

然后就可以使用client

client.pods()..
client.services()..
来操作k8s集群中的资源了

在这里插入图片描述

使用abric8io/kubernetes-clientt操作CRD watch状态变更

此时我们只需要在自己的java springboot项目中,使用kubernetes-client 去监听自定义的资源的状态并对状态做对应的响应操作即可

对应的就是watch操作

在这里插入图片描述

后续实例中会详解讲解 watch操作 监控资源状态变更

权限处理

把java项目部署到k8s集群中,是一个很好的选择。但是对于我们自定义的资源默认的ServiceAccount中是没有对应的定义的,所以需要创建ServiceAccount,并让ServiceAccount与ClusterRole 绑定。这样java程序能够在集群内部访问k8s api接口

参考资料《快速上手k8s权限管理 立即掌握User Role RoleBinding kubeconfig 实战教程》

相关的权限配置如下

	# 创建ServiceAccountapiVersion: v1kind: ServiceAccountmetadata:name: crdtest-serviceaccountnamespace: crd-tm-testlabels:myk8s.crd-test.com: crd-tm-test---# 需要操作自定义的 CRD TableMonitor  需要配置对TableMonitor资源的操作权限apiVersion: rbac.authorization.k8s.io/v1beta1kind: ClusterRolemetadata:name: crdtest-clusterrolerules:- apiGroups:- "myk8s.crd-test.com"resources: - tablemonitorsverbs:- list- watch---# 让ServiceAccount 与 ClusterRole绑定
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: crdtest-cluster-role-binding
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: crdtest-clusterrole
subjects:- kind: ServiceAccountname: crdtest-serviceaccountnamespace: crd-tm-test 

实例:用java开发一个数据库表监控Operator

本例子为了简洁并利于理解,使用数据库中的表作为一个需要管理的资源。

类似Pod管理的是容器,我们创建一个TableMonitor资源来管理表

架构设计入下图

在这里插入图片描述

数据库表监控Operator的业务逻辑是

  • 1 管理k8s集群中定义的TableMonitor资源
  • 2 如果发现新建了TableMonitor资源就新建表 (类似Pod新建一个容器)
  • 3 如果发现删除了TableMonitor资源就删除表
  • 4 循环的监控TableMonitor资源定义的表行数,保证行数在指定范围内 (类似Deployment replicas)

Step1 数据库表监控CRD 创建

创建一个TableMonitor资源的定义 CRD yaml文件 crd-table-monitor.yaml 内容如下 (见my-docker-demo-k8s-operator/yaml/crd-table-monitor.yaml)

# 定义自定义的TableMonitor 资源
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:# 名字必需与下面的 spec 字段匹配,并且格式为 '<名称的复数形式>.<组名>'name: tablemonitors.liuyijiang.crd-tm.comspec:   # 组名称,用于 REST API: /apis/<组>/<版本>group: liuyijiang.crd-tm.comnames:# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>plural: tablemonitors# 名称的单数形式,作为命令行使用时和显示时的别名singular: tablemonitor# kind 通常是单数形式的驼峰命名(CamelCased)形式。你的资源清单会使用这一形式。kind: TableMonitor# shortNames 允许你在命令行使用较短的字符串来匹配资源shortNames:- tmscope: Namespaced       versions:- name: v1# 每个版本都可以通过服务标志启用/禁用。served: true# 必须将一个且只有一个版本标记为存储版本。storage: trueschema:openAPIV3Schema:type: objectproperties:  spec:type: objectproperties:# 自定义的资源spec 中的属性 dbUserName 需要连接的数据库的账户名dbUserName: type: string# 自定义的资源spec 中的属性 dbUserPassword    需要连接的数据库的密码dbUserPassword: type: string# 自定义的资源spec 中的属性 dbUrl   需要连接的数据库的urldbUrl:  type: string# 自定义的资源spec 中的属性 tableName  需要操作的表名称tableName:  type:  string # 自定义的资源spec 中的属性 tableColumns 注意类型是  array 表中的字段tableColumns:    type: arrayitems:type: string # 自定义的资源spec 中的属性 dataNum   表中保存的数据行数      dataNum:  type: integerstatus:type: object    properties:  # 恢复次数  每调整一次表行数就加1recoverNum: type: integer# 运行数据库ip  hostIp: type: string# 运行状态  runingStatus: type: string  	

kubectl apply -f crd-table-monitor.yaml 创建CRD

在这里插入图片描述

Step2 springboot k8s Operator 程序开发

程序就是一个简单的springboot 其中fabric8/kubernetes-client版本号6.4.1 项目主要结构如下

在这里插入图片描述

自定义资源相关类

TableMonitorSpec.java TableMonitorStatus.java 都是一个实现了KubernetesResource接口的POJO类
对应crd-table-monitor.yaml中配置的spec 和 status 相关字段

TableMonitorSpec.java

在这里插入图片描述

TableMonitorStatus.java

在这里插入图片描述

TableMonitor.java 则是对应的TableMonitor资源 注意组和版本号

在这里插入图片描述

TableMonitorList.java 是一个继承了DefaultKubernetesResourceList的类,用于保存多个TableMonitor

在这里插入图片描述

数据库操作类

TableService.java的作用就是一个数据库操作的类,用于创建表,删表,加数据,删数据等

在这里插入图片描述

使用spring提供的jdbctemplate来操作数据库,例如以下是一个建表操作

在这里插入图片描述

数据库操作的类很简单 就不多赘述

监听自定义资源类

TableMonitorListener.java 是本Operator 程序的核心类

代码如下:

package com.k8s.operator.listener;import java.util.List;
import java.util.concurrent.ConcurrentHashMap;import javax.annotation.PostConstruct;import org.springframework.stereotype.Component;import com.k8s.operator.crd.TableMonitor;
import com.k8s.operator.crd.TableMonitorList;
import com.k8s.operator.crd.TableMonitorStatus;
import com.k8s.operator.database.DataTable;
import com.k8s.operator.database.TableService;import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.Resource;/*** 核心就是这个TableMonitorListener* * TableMonitorListener watch 自定义的TableMonitor资源 处理 1 新建 2 删除 3 数据是否满足指定* * @author liuyijiang**/
@Component
public class TableMonitorListener {/*** TableMonitor 控制器*/private MixedOperation<TableMonitor, TableMonitorList, Resource<TableMonitor>> tableMonitor;/*** 数据库操作类*/private TableService tableService = new TableService();/*** 保存所有的k8s集中部署的TableMonitor*/private ConcurrentHashMap<String, TableMonitor> CRDS = new ConcurrentHashMap<>();/*** 初始化*/@PostConstructpublic void initListerner() {System.out.println("start TableMonitorListener");/*** 初始化客户端*/init();/*** 监听表的状态变化*/watchTable();/*** 监听资源的变化*/watchCRD();}/*** 初始化KubernetesClient 客户端*/private void init() {System.out.println("init   KubernetesClientBuilder !!!!!!!!!!!!!!!!");KubernetesClient client = new KubernetesClientBuilder().build();/*** 获取自定义资源的客户端*/NonNamespaceOperation<TableMonitor, TableMonitorList, Resource<TableMonitor>> tableMonitorNonNamespace = client.resources(TableMonitor.class, TableMonitorList.class);//使用default 命名空间tableMonitorNonNamespace = ((MixedOperation<TableMonitor, TableMonitorList, Resource<TableMonitor>>) tableMonitorNonNamespace).inNamespace("default");tableMonitor = (MixedOperation<TableMonitor, TableMonitorList, Resource<TableMonitor>> ) tableMonitorNonNamespace;}/*** 监控表 保证表中的数据始终保持在 dataNum配置的值*/private void watchTable() {new Thread(() -> {System.out.println("start watchTable ");while (true) {for (String id : CRDS.keySet()) {TableMonitor tm = CRDS.get(id);/*** 检查是否存在表*/System.out.println("check if table is not EXISTS");tableService.createTable(tm);/*** 查询出TableMonitor 表中存在的数据*/int num = tableService.getTableDataCount(tm);if (num != tm.getSpec().getDataNum()) {// 小于定义的值if (num < tm.getSpec().getDataNum()) {System.out.println("### data  too  little  !!!!!!!!!!!!!!!!");int flag = tm.getSpec().getDataNum() - num; // 获得少了的量for (int i = 0; i < flag; i++) {tableService.insertTableData(tm); // 创建少的数据}} else { // 大于定义的值System.out.println("### data  too  more  !!!!!!!!!!!!!!!!");int flag = num - tm.getSpec().getDataNum(); // 获得多了的量List<DataTable> list = tableService.listTableData(tm);for (int i = 0; i < flag; i++) {tableService.deleteTableData(tm, list.get(i)); // 删除多的数据}}//更新资源状态 添加一次恢复次数tm.getStatus().setRecoverNum(tm.getStatus().getRecoverNum() + 1);tableMonitor.resource(tm).createOrReplace();}}// 10秒钟监控一次try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}public void watchCRD() {/*** 监控资源*/Watch watch = tableMonitor.watch(new Watcher<TableMonitor>() {@Overridepublic void eventReceived(Action action, TableMonitor resource) {// 新增if (action.equals(Action.ADDED)) { // 新增资源System.out.println("===============create kind=================" + resource);// 建表tableService.createTable(resource);CRDS.put(resource.getMetadata().getName(), resource); // 资源放入到map中//添加资源状态resource.setStatus(new TableMonitorStatus());resource.getStatus().setRuningStatus("running");resource.getStatus().setRecoverNum(0);String ip = resource.getSpec().getDbUrl().substring(13,26);resource.getStatus().setHostIp(ip);//更新资源状态tableMonitor.resource(resource).createOrReplace();} else if (action.equals(Action.DELETED)) { // 删除资源System.out.println("===============delete kind=================" + resource);tableService.dropTable(resource);CRDS.remove(resource.getMetadata().getName());}}@Overridepublic void onClose(WatcherException cause) {System.out.println(cause);}});}}

以上便是 java实现Operator 的基本代码

Step3 部署springboot k8s Operator到k8s集群

主要事项

  • 1 需要创建对应的ServiceAccount 让程序可以访问自定义的TableMonitor资源
  • 2 由于镜像仓库是阿里云私库,需要创建对应的Secret便于拉取镜像

关于k8s权限 角色 可以参考《快速上手k8s权限管理 立即掌握User Role RoleBinding kubeconfig 实战教程》

注意:所有相关配置文件保存在 /my-docker-demo-k8s-operator/yaml/operrator相关 Docker相关

创建镜像

Dockerfile内容如下

FROM ascdc/jdk8
VOLUME ["/data/service/logs","/data/service/tmp"] 
WORKDIR "/data/service"
EXPOSE 5533
COPY my-docker-demo-k8s-operator.jar my-docker-demo-k8s-operator.jar
ENTRYPOINT ["nohup","java","-jar","my-docker-demo-k8s-operator.jar","&"]

Dockerfile参考 《Dockerfile文件总结》

docker build -t tm-controller .
docker tag tm-controller registry.cn-hangzhou.aliyuncs.com/jimliu/tm-controller
docker push registry.cn-hangzhou.aliyuncs.com/jimliu/tm-controller

在这里插入图片描述

此时镜像创建完毕

创建k8s部署文件

springboot k8s Operator部署文件deploy.yml如下 (也可以不部署在k8s中 注意kubernetes-clinet的创建方式)

# 创建命名空间
apiVersion: v1
kind: Namespace
metadata:name: crd-tm-testlabels:liuyijiang.crd-tm.com: crd-tm-test---# 创建阿里云私库秘钥
apiVersion: v1
kind: Secret
metadata:name: myaliyunsecret-crdtmtestnamespace: crd-tm-test labels:liuyijiang.crd-tm.com: crd-tm-test 
data:.dockerconfigjson: eyJhdXRocyI6eyJyZWdpc3RyeS5.....省略换成自己的
type: kubernetes.io/dockerconfigjson---# 创建ServiceAccount 用于 程序中访问自定义资源
apiVersion: v1
kind: ServiceAccount
metadata:name: crdtest-serviceaccountnamespace: crd-tm-testlabels:liuyijiang.crd-tm.com: crd-tm-test
imagePullSecrets:- name: myaliyunsecret-crdtmtest---# 需要操作自定义的 CRD TableMonitor  需要配置对TableMonitor资源的操作权限
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:name: crdtest-clusterrolelabels:liuyijiang.crd-tm.com: crd-tm-test
rules:- apiGroups:- "liuyijiang.crd-tm.com"  #apiGroups crd-table-monitor.yaml中定义的 groupresources: - tablemonitors  #只操作TableMonitor资源  注意为crd-table-monitor.yaml中配置的复数名称verbs:   #可以操作的类型- list- watch- get- create- delete - update - edit - exec---# 让ServiceAccount 与 ClusterRole绑定
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:name: crdtest-cluster-role-bindinglabels:liuyijiang.crd-tm.com: crd-tm-test
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: crdtest-clusterrole
subjects:- kind: ServiceAccountname: crdtest-serviceaccount  namespace: crd-tm-test ---# 创建项目容器pod 
apiVersion: v1
kind: Pod
metadata: name: tm-controller-podnamespace: crd-tm-test labels: liuyijiang.crd-tm.com: crd-tm-testspec: # 注意指定serviceAccountserviceAccountName: crdtest-serviceaccountrestartPolicy: Alwayscontainers: - image:  registry.cn-hangzhou.aliyuncs.com/jimliu/tm-controller:latestname: tm-controller-runtime  

执行 kubectl apply -f deploy.yml 部署operator

在这里插入图片描述

执行 kubectl logs -f tm-controller-pod -n crd-tm-test 查看日志 注意-n 命名空间

在这里插入图片描述

到此 springboot k8s Operator部署完成

创建自定义资源 程序实现监控

测试创建TableMonitor资源

现在创建一个资源来测试 springboot k8s Operator

资源创建文件 tm1.yaml 内容如下

# api使用 crd中定义的组名称
apiVersion: "liuyijiang.crd-tm.com/v1"
#  kind使用 crd中定义的kind名称
kind: TableMonitor
metadata:name: test-001
spec:dbUserName: "root"dbUserPassword: "123456"dbUrl: "jdbc:mysql://192.168.0.206:3306/t0003"tableName: "tb_my_test"dataNum: 3tableColumns: - aaabbbccc

首先可以看到t0003数据库中目前还没有tb_my_test 这张表

在这里插入图片描述

kubectl apply -f tm1.yaml 创建资源

kubectl apply -f  tm1.yaml
kubectl get tm -o custom-columns-file=tpl.txt

在这里插入图片描述

springboot k8s Operator 日志出现建表操作

在这里插入图片描述
在这里插入图片描述

测试表数据始终保持为 dataNum

删除表中的一条数据

在这里插入图片描述

10秒后 表数据恢复到dataNum指定的值3

在这里插入图片描述

同时恢复次数增加1次
在这里插入图片描述

测试删除TableMonitor资源

执行 kubectl delete -f tm1.yaml 删除TableMonitor资源

在这里插入图片描述
原文地址 https://blog.csdn.net/liuyij3430448/article/details/129534732

相关文章:

k8s java程序实现kubernetes Controller Operator 使用CRD 学习总结

k8s java程序实现kubernetes Controller & Operator 使用CRD 学习总结 大纲 原理Controller 与 Operator自定义资源定义 CRD ( CustomResourceDefinition)kubernetes-client使用java fabric8io/kubernetes-client操作k8s 原生资源使用java abric8io/kubernetes-clientt操…...

Unity笔记:修改代码执行的默认打开方式

使用 External Tools 偏好设置可设置用于编写脚本、处理图像和进行源代码控制的外部应用程序。 External Script Editor&#xff1a;选择 Unity 应使用哪个应用程序来打开脚本文件。Unity 会自动将正确的参数传递给内置支持的脚本编辑器。Unity 内置支持 Visual Studio Commun…...

Linux IPC:匿名管道 与 命名管道

目录一、管道的理解二、匿名管道三、命名管道四、管道的通信流程五、管道的特性进程间通信方式有多种&#xff0c;本文介绍的是管道&#xff0c;管道分为匿名管道和命名管道。 一、管道的理解 生活中的管道用来传输资源&#xff0c;例如水、石油之类的资源。而进程间通信的管道…...

阿里研发工程师JAVA暑期实习一面

文章目录先说一下我自己的情况面试过程总结先说一下我自己的情况 我就读于湖南大学&#xff0c;软件工程专业&#xff0c;现在大三下 很巧的是&#xff0c;我在大二的时候就在相同的时间面过相同的部门和相同的岗位&#xff0c;所以我没有做笔试就直接让我去面试了。我当时还纳…...

第十四届蓝桥杯三月真题刷题训练——第 11 天

目录 第 1 题&#xff1a;卡片 题目描述 运行限制 第 2 题&#xff1a;路径_dpgcd 运行限制 第 3 题&#xff1a;字符统计 问题描述 输入格式 输出格式 样例输入 样例输出 评测用例规模与约定 运行限制 第 4 题&#xff1a;费用报销 第 1 题&#xff1a;卡片 题…...

机器学习入门——线性回归

线性回归什么是线性回归&#xff1f;回归分析&#xff1a;线性回归&#xff1a;回归问题求解单因子线性回归简单实例评估模型表现可视化模型展示多因子线性回归什么是线性回归&#xff1f; 回归分析&#xff1a; 根据数据&#xff0c;确定两种或两种以上变量间相互依赖的定量…...

Microsoft Word 远程代码执行漏洞(CVE-2023-21716)

本文转载于&#xff1a; https://mp.weixin.qq.com/s?__bizMzI5NTUzNzY3Ng&mid2247485476&idx1&sneee5c7fd1c4855be6441b8933b10051e&chksmec535547db24dc516d013d3d76097e985aaad7f10f82f15b4e355a97af75fd333acdab6232af&mpshare1&scene23&srci…...

Android kotlin 系列讲解(数据篇)SharedPreferences存储及测试

文章目录 一、什么是SharedPreferences1、将数据存储到SharedPreferences中2、从SharedPreferences中读取数据二、登录使用SharedPreferences一、什么是SharedPreferences SharedPreferences是使用键值对的方式来存储数据的。也就是说,当保存一条数据的时候,需要给这条数据提…...

一文了解Web Worker

一、概述 众所周知&#xff0c;JavaScript最初设计是运行在浏览器中的&#xff0c;为了防止多个线程同时操作DOM带来的渲染冲突问题&#xff0c;所以JavaScript执行器被设计成单线程。但是随着前端技术的发展&#xff0c;JavaScript要处理的工作也越来越复杂&#xff0c;当我们…...

接口文档包含哪些内容?怎么才能写好接口文档?十年测试老司机来告诉你

目录 接口文档结构 参数说明 示例 错误码说明 语言基调通俗易懂 及时更新与维护 总结 那么我们该如何写好一份优秀的接口文档呢&#xff1f; 接口文档结构 首先我们要知道文档结构是什么样子的。接口文档应该有清晰明确的结构&#xff0c;以便开发人员能快速定位自己需…...

java面试八股文之------Java并发夺命23问

java面试八股文之------Java并发夺命23问&#x1f468;‍&#x1f393;1.java中线程的真正实现方式&#x1f468;‍&#x1f393;2.java中线程的真正状态&#x1f468;‍&#x1f393;3.如何正确停止线程&#x1f468;‍&#x1f393;4.java中sleep和wait的区别&#x1f468;‍…...

CANoe中使用CAPL刷写流程详解(Trace图解)(CAN总线)

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…...

【MySQL】002 -- 日志系统:一条SQL更新语句是如何执行的

此文章为《MySQL 实战 45 讲》的学习笔记&#xff0c;其课程链接可参见&#xff1a;MySQL实战45讲_MySQL_数据库-极客时间 目录 一、日志系统 1、重做日志&#xff1a;redo log&#xff08;引擎层&#xff09; 2、归档日记&#xff1a;binlog&#xff08;Server层&#xff09; …...

C++---背包模型---数字组合(每日一道算法2023.3.14)

注意事项&#xff1a; 本题是"动态规划—01背包"的扩展题&#xff0c;优化思路不多赘述&#xff0c;dp思路会稍有不同&#xff0c;下面详细讲解。 题目&#xff1a; 给定 N个正整数 A1,A2,…,AN&#xff0c;从中选出若干个数&#xff0c;使它们的和为 M&#xff0c;…...

并查集(不相交集)详解

目录 一.并查集 1.什么是并查集 2.并查集的基本操作 3.并查集的应用 4.力扣上的题目 二.三大操作 1.初始化 2.查找 3.合并 三.省份数量 1.题目描述 2.问题分析 3.代码实现 四.冗余连接 1.题目描述 2.问题分析 3.代码实现 一.并查集 1.什么是并查集 并查集&…...

10个最频繁用于解释机器学习模型的 Python 库

文章目录什么是XAI&#xff1f;可解释性实践的步骤技术交流1、SHAP2、LIME3、Eli54、Shapash5、Anchors6、BreakDown7、Interpret-Text8、aix360 (AI Explainability 360)9、OmniXAI10、XAI (eXplainable AI)XAI的目标是为模型的行为和决定提供有意义的解释&#xff0c;本文整理…...

final关键字:我偏不让你继承

哈喽&#xff0c;小伙伴们大家好&#xff0c;我是兔哥呀&#xff0c;今天就让我们继续这个JavaSE成神之路&#xff01; 这一节啊&#xff0c;咱们要学习的内容是Java所有final关键字。 之前呢&#xff0c;我们学习了继承&#xff0c;这大大提高了代码的灵活性和复用性。但是总…...

8大主流编程语言的适用领域,你可能选错了语言

很多人学编程经常是脑子一热然后就去网上一搜资源就开始学习了&#xff0c;但学到了后面发现目前所学的东西并不是自己最喜欢的&#xff0c;好像自己更喜欢另一个技术&#xff0c;感觉自己学错了&#xff0c;于是乎又去学习别的东西。 结果竹篮打水一场空&#xff0c;前面所付…...

关于Python库的问题

关于Python库的问题 问题1&#xff1a; ModuleNotFoundError: No module named ‘requests’ Python库 Pycharm使用Requests库时报错&#xff1a; No module named requests’解决方法 未安装requests库&#xff0c;使用"pip install requests"命令安装 依然提示P…...

好记性不如烂笔头(2)

概述&#xff1a;用来记录一些小技巧。 1.查看MyBatis执行的sql 类&#xff1a;org.apache.ibatis.mapping.MappedStatement方法&#xff1a;getBoundSql(Object parameterObject)在IDEA的Evaluate Expression查看sql&#xff1a;boundSql.getSql() 2.maven仓库地址为https&…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

短视频矩阵系统文案创作功能开发实践,定制化开发

在短视频行业迅猛发展的当下&#xff0c;企业和个人创作者为了扩大影响力、提升传播效果&#xff0c;纷纷采用短视频矩阵运营策略&#xff0c;同时管理多个平台、多个账号的内容发布。然而&#xff0c;频繁的文案创作需求让运营者疲于应对&#xff0c;如何高效产出高质量文案成…...