当前位置: 首页 > 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&…...

Java for循环嵌套for循环,你需要懂的代码性能优化技巧

前言 本篇分析的技巧点其实是比较常见的&#xff0c;但是最近的几次的代码评审还是发现有不少兄弟没注意到。 所以还是想拿出来说下。 正文 是个什么场景呢&#xff1f; 就是 for循环 里面还有 for循环&#xff0c; 然后做一些数据匹配、处理 这种场景。 我们结合实例代码来…...

关于我拒绝了腾讯测试开发岗offer这件事

2022年刚开始有了向要跳槽的想法&#xff0c;之前的公司不能算大厂但在重庆也算是数一数二。开始跳槽的的时候我其实挺犹豫的 其实说是有跳槽的想法在2022年过年的时候就有了&#xff0c;因为每年公司3月会有涨薪的机会&#xff0c;所以想着看看那能不能涨&#xff08;其实还是…...

从GPT到GPT-3:自然语言处理领域的prompt方法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

Git代码提交规范

Git 代码规范Git 每次提交代码&#xff0c;都是需要写 Commit message&#xff08;提交说明&#xff09;&#xff0c;否则就不允许提交。Commit message 的格式 (三部分)&#xff1a;Heaher ----- 必填type ---必需scope --- 可选subject --- 必需Body ---- 可省略Footer ---- …...

【JavaScript速成之路】JavaScript内置对象--Math和Date对象

&#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f525;系列专栏&#xff1a;【JavaScript速成之路】 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 文章目录前言1&#xff0c;Math对象1.1&#xff0c;常用属性方法1.1.1&#xff0c;获取x的…...

(自用POC)Fortinet-CVE-2022-40684

本文转载于&#xff1a;https://mp.weixin.qq.com/s?__bizMzIzNDU5Mzk2OQ&mid2247485332&idx1&sn85931aa474f1ae2c23a66bf6486eec63&chksme8f54c4adf82c55c44bc7b1ea919d44d377e35a18c74f83a15e6e20ec6c7bc65965dbc70130d&mpshare1&scene23&srcid…...

ConvNeXt V2实战:使用ConvNeXt V2实现图像分类任务(二)

文章目录训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整算法设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法运行以及结果查看测试热力图可视化展示完…...

【人工智能与深度学习】基于正则化潜在可变能量的模型

【人工智能与深度学习】基于正则化潜在可变能量的模型 正则化潜变量能量基础模型稀疏编码FISTALISTA稀疏编码示例卷积稀疏编码自然图像上的卷积稀疏编码可变自动编码器正则化潜变量能量基础模型 具有潜在变量的模型能够生成预测分布 y ‾ \overline{y}...

【Leetcode——排序的循环链表】

&#x1f60a;&#x1f60a;&#x1f60a; 文章目录一、力扣题之排序循环链表二、解题思路1. 使用双指针法2、找出最大节点&#xff0c;最大节点的下一个节点是最小节点&#xff0c;由此展开讨论总结一、力扣题之排序循环链表 题目如下&#xff1a;航班直达&#xff01;&#…...

ChatGPT研究分享:机器第一次开始理解人类世界目录

0、为什么会对ChatGPT感兴趣一开始&#xff0c;我对ChatGPT是没什么关注的&#xff0c;无非就是有更大的数据集&#xff0c;完成了更大规模的计算&#xff0c;所以能够回答更多的问题。但后来了解到几个案例&#xff0c;开始觉得这个事情并不简单。我先分别列举出来&#xff0c…...

男女做啊免费视频网站/网站技术制作

来自&#xff1a;http://kakajw.iteye.com/blog/1063843&#xff0c;感谢作者解决问题。 Tomcat 5.5使EL表达式不被解析。 现象 代码${userSession.user_name}是JSP中的一个代码片段&#xff1b; 如果部署到tomcat5.5中&#xff0c;不会显示出session中的变量user用户名,而只会…...

代办网站/宁波网站推广优化哪家正规

应用发布简单的流程&#xff1a;1.集群节点应用下线&#xff08;下面会介绍为什么将这个放在第一位.&#xff09;2.获取最新代码3.编译打包4.推送到应用机器5.差异复制6.重启7.测试8.加入集群 我公司都是使用nginx完成负载均衡的...当我们后端应用python,java,nodejs需要升级上…...

网站做流量怎么赚钱的/开封seo推广

前天我去一个客户那里装系统&#xff0c;那里的环境是这样的&#xff1a;他们那里是两台邮件服务器&#xff0c;同时用&#xff0c;数据同步&#xff0c;就算是备份和冗余&#xff0c;现在正常的叫A&#xff0c;我要装系统的是B&#xff0c;B有两个盘&#xff0c;一个盘为一个分…...

网站手机端排名怎么做/个人网站制作

文章目录前言一、依赖关系是什么&#xff1f;二、支持的功能总结前言 终于更新一个小的python项目来一起动手学习了&#xff0c;今天想看看Redis源码&#xff0c;可惜太慢太多&#xff0c;思维太乱&#xff0c;于是想到看是否用Python可以分析出这个源码直接的依赖关系。 一、…...

网站闭站保护/seo关键词排名网络公司

1. 马哈鱼数据血缘分析工具简介 马哈鱼数据血缘分析工具&#xff08;英文名称为 Gudu SQLFlow &#xff09;是一款用于分析 SQL 语句&#xff0c;并发现其中数据血缘关系的分析软件&#xff0c;经常和元数据管理工具一起使用&#xff0c;是企业数据治理的基础工具。 如果你对 …...

淄博市人民政府门户网站建设工作调研报告/建网站的流程

目录 - - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - -- - - - - 1. 基础类业务 2. 融资融券业务 3. 投资银行业务 4. 投资管理业务 5. 资产管理业务 6. 券商与商业银行的合作业务 7. 券商与信托公司的合作业务 8. 多金融…...