全流程搞清楚 Kubernetes API 的使用,可进行业务二次开发对接 k8s 调用,详细图文说明以及常见问题整理

news2025/1/10 23:25:31

全流程搞清楚 Kubernetes API 的使用,可进行业务二次开发对接 k8s 调用,详细图文说明以及常见问题整理。

使用CLI(如curl)或GUI(如postman)HTTP客户端调用Kubernetes API有很多理由。例如,你可能需要对Kubernetes对象进行比kubectl提供的更细粒度的控制,或者只是想在尝试从代码访问API之前探索它。

本文不仅仅是一个方便的命令列表,还是一个深思熟虑的演练,揭示了一些你在从命令行调用Kubernetes API时可能会偶然发现的有趣问题。它涵盖以下主题:

如何获取Kubernetes API服务器地址

如何向客户端验证API服务器

如何使用证书向API服务器验证客户端

如何使用令牌向API服务器验证客户端

奖励:如何从Pod内部调用Kubernetes API

如何使用curl对Kubernetes对象执行基本的CRUD操作

如何使用kubectl的raw模式直接访问Kubernetes API

如何查看哪些API请求kubectl命令(如apply发送)

在这里插入图片描述

1 —
设置Kubernetes游乐场

如果你没有Kubernetes集群可以玩,下面是使用arkade[1]快速创建本地游乐场的方法:

$ curl -sLS https://get.arkade.dev | sudo sh
$ arkade get minikube kubectl
$ minikube start --profile cluster1

curl | sudo sh模式很吓人。从Internet获取软件包并在笔记本电脑上运行它们的想法也是如此。由于我没有时间检查我使用的每一段开源代码,所以我更喜欢隔离和一次性的开发环境。你可以在此处[2]阅读有关我的开发程序的更多信息。

— 2 —
如何获取Kubernetes API主机和端口

要调用任何API,你首先需要知道其服务器地址。对于Kubernetes,每个集群都有一个API服务器。因此,查找API主机和端口的最简单方法是查看kubectl cluster-info输出。例如,在我的Vagrant盒子上,它会产生以下几行:

$ kubectl cluster-info
Kubernetes control plane is running at https://192.168.58.2:8443
...

该cluster-info命令显示在当前上下文中选择的集群的API地址。但是,如果你有多个集群怎么办?

查找Kubernetes API服务器地址的另一种方法是查看kubeconfig内容:

$ kubectl config view
apiVersion: v1
clusters:
- name: cluster1
  cluster:
    ...
    server: https://192.168.58.2:8443
- name: cluster2
  cluster:
    ...
    server: https://192.168.59.2:8443
...

默认情况下,kubectl查找目录中命名config的$HOME/.kube文件。那么,为什么不直接从这个文件中获取API地址呢?

原因是潜在的配置合并。KUBECONFIG通过将env var设置为以冒号分隔的位置列表,可以指定多个kubeconfig文件。kubectl在访问集群之前,会尝试将所有 kubeconfig文件的内容合并到一个配置中。

从上面的列表中选择正确的集群,让我们尝试向其API服务器发送请求:

$ KUBE_API=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')


— 3 —
如何使用curl调用Kubernetes API

实际上,任何HTTP客户端(curl、httpie、wget甚至postman)都可以,但我将在本节中坚持使用curl,因为我已经习惯了。

向客户端验证API服务器

让我们从查询API的/version端点开始:

$ curl $KUBE_API/version
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

第一次偶然发现类似的错误时,我真的很困惑。但仔细想想,上述错误实际上是有道理的。默认情况下,Kubernetes通过HTTPS公开其API,特别是为了向客户端保证API服务器的强身份。

但是,minikube使用自签名证书引导我的本地集群。因此,Kubernetes API服务器的TLS证书原来是由curl未知的证书颁发机构 (CA) minikubeCA签名的。由于curl无法信任它,因此请求失败。

默认情况下,curl信任底层操作系统所信任的同一组CA。例如,在Ubuntu或Debian上,受信任的CA列表可以在/etc/ssl/certs/ca-certificates.crt。显然,minikube不会将其证书添加到此文件中。

幸运的是,minikube周到地将CA证书保存到了~/.minikube/ca.crt:

$ cat ~/.minikube/ca.crt | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = minikubeCA
        Validity
            Not Before: Dec 15 20:46:36 2021 GMT
            Not After : Dec 14 20:46:36 2031 GMT
        Subject: CN = minikubeCA
        Subject Public Key Info:

因此,要修复该GET/version请求,我只需要通过手动将其指向minikube CA证书来使curl信任API服务器证书的颁发者:

$ curl --cacert ~/.minikube/ca.crt $KUBE_API/version
{
  "major": "1",
  "minor": "22",
  "gitVersion": "v1.22.3",
  "gitCommit": "c92036820499fedefec0f847e2054d824aea6cd1",
  "gitTreeState": "clean",
  "buildDate": "2021-10-27T18:35:25Z",
  "goVersion": "go1.16.9",
  "compiler": "gc",
  "platform": "linux/amd64"
}

可以通过使用–insecure标志或其短别名-k来使用curl。在安全的环境中,我更喜欢不安全模式——它比试图找到颁发者证书更简单。

使用证书向API服务器验证客户端

列出集群中的所有部署

$ curl --cacert ~/.minikube/ca.crt $KUBE_API/apis/apps/v1/deployments
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "deployments.apps is forbidden: User \"system:anonymous\" cannot list resource \"deployments\" in API group \"apps\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "group": "apps",
    "kind": "deployments"
  },
  "code": 403
}

与明显未受保护的/version端点不同,Kubernetes通常会限制对其API端点的访问。

从错误消息中可以清楚地看出,该请求已通过身份验证User “system:anonymous”,并且显然,该用户未授权列出部署资源。

失败的请求不包括任何身份验证方式(尽管如此,它已经过身份验证,但作为匿名用户),所以我需要提供一些额外的信息来获得所需的访问级别。

Kubernetes支持多种身份验证机制,我将从使用客户端证书对请求进行身份验证开始。

但是等一下!什么是客户证书?

当minikube引导集群时,它还创建了一个user。该用户获得了由同一个minikube CA颁发机构签署的证书。由于Kubernetes API服务器信任此CA,因此在请求中提供此证书将使其作为所述用户进行身份验证。

Kubernetes没有代表用户的对象。即,不能通过API调用将用户添加到集群中。但是,任何提供由集群的证书颁发机构签名的有效证书的用户都被视为已通过身份验证。Kubernetes从证书主题中的通用名称字段中获取用户名(例如,CN = minikube-user)。然后,Kubernetes RBAC子系统判断用户是否有权对资源执行特定操作。

用户证书通常可以在我们已经熟悉的kubectl config view输出中找到:

$ kubectl config view -o jsonpath='{.users[0]}' | python -m json.tool
{
  "name": "cluster1",
  "user": {
    "client-certificate": "/home/vagrant/.minikube/profiles/cluster1/client.crt",
    "client-key": "/home/vagrant/.minikube/profiles/cluster1/client.key"
  }
}

让我们快速检查证书内容以确保它是由同一个CA签名的:

$ cat ~/.minikube/profiles/cluster1/client.crt | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2 (0x2)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = minikubeCA
        Validity
            Not Before: Dec 26 06:35:56 2021 GMT
            Not After : Dec 26 06:35:56 2024 GMT
        Subject: O = system:masters, CN = minikube-user

以下是如何使用curl向Kubernetes API服务器发送由该证书认证的请求:

$ curl $KUBE_API/apis/apps/v1/deployments \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "resourceVersion": "654514"
  },
  "items": [...]
}

使用服务帐户令牌向API服务器验证客户端

另一种验证API请求的方法是使用包含有效服务帐户JWT令牌的不记名标头。

与用户非常相似,不同的服务帐户将具有不同级别的访问权限。让我们看看使用默认命名空间中的默认服务帐户可以实现什么:

$ JWT_TOKEN_DEFAULT_DEFAULT=$(kubectl get secrets \
    $(kubectl get serviceaccounts/default -o jsonpath='{.secrets[0].name}') \
    -o jsonpath='{.data.token}' | base64 --decode)

从一个简单的任务开始——列出apps/v1组中已知的API资源类型:

$ curl $KUBE_API/apis/apps/v1/ \
  --cacert ~/.minikube/ca.crt  \
  --header "Authorization: Bearer $JWT_TOKEN_DEFAULT_DEFAULT"
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "apps/v1",
  "resources": [...]
}

提高标准——让我们尝试在默认命名空间中列出实际的部署对象:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
  --cacert ~/.minikube/ca.crt  \
  --header "Authorization: Bearer $JWT_TOKEN_DEFAULT_DEFAULT"
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

  },
  "status": "Failure",
  "message": "deployments.apps is forbidden: User \"system:serviceaccount:default:default\" cannot list resource \"deployments\" in API group \"apps\" in the namespace \"default\"",
  "reason": "Forbidden",
  "details": {
    "group": "apps",
    "kind": "deployments"
  },
  "code": 403
}

显然,用户system:serviceaccount:default:default甚至没有足够的能力在自己的命名空间中列出Kubernetes对象。

让我们尝试一个强大的kube-system服务帐户:

$ JWT_TOKEN_KUBESYSTEM_DEFAULT=$(kubectl -n kube-system get secrets \
    $(kubectl -n kube-system get serviceaccounts/default -o jsonpath='{.secrets[0].name}') \
    -o jsonpath='{.data.token}' | base64 --decode)

强大的帐户值得一项具有挑战性的任务——列出集群级资源:

$ curl $KUBE_API/apis/apps/v1/deployments \
  —cacert ~/.minikube/ca.crt  \
  —header "Authorization: Bearer $JWT_TOKEN_KUBESYSTEM_DEFAULT"
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "resourceVersion": "656580"
  },
  "items": []
}

如何从Pod内部调用Kubernetes API

与任何其他Kubernetes服务非常相似,Kubernetes API服务地址可通过环境变量提供给Pod:

$ kubectl run -it --image curlimages/curl --restart=Never mypod -- sh
$ env | grep KUBERNETES
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1

Pod通常还会将Kubernetes CA证书和服务帐户机密材料安装在/var/run/secrets/kubernetes.io/serviceaccount/。因此,应用以上部分的知识,curl从 Pod调用Kubernetes API服务器的命令如下所示:

$ curl https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/apis/apps/v1 \
  --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"

创建、读取、观看、更新、修补和删除对象

Kubernetes API支持对Kubernetes Objects进行以下操作:

GET    /<resourcePlural>            -  Retrieve a list of type <resourceName>.


POST   /<resourcePlural>            -  Create a new resource from the JSON
                                       object provided by the client.

GET    /<resourcePlural>/<name>     -  Retrieves a single resource with the
                                       given name.

DELETE /<resourcePlural>/<name>     -  Delete the single resource with the
                                       given name.

DELETE /<resourcePlural>            -  Deletes a list of type <resourceName>.


PUT    /<resourcePlural>/<name>     -  Update or create the resource with the given
                                       name with the JSON object provided by client.

PATCH  /<resourcePlural>/<name>     -  Selectively modify the specified fields of
                                       the resource.

GET    /<resourcePlural>?watch=true -  Receive a stream of JSON objects 
                                       corresponding to changes made to any
                                       resource of the given kind over time.

API是RESTful的,因此上述HTTP方法在资源操作上的映射应该看起来很熟悉。

即使文档仅提及JSON对象,如果Content-Type标头设置为application/yaml,则支持提交YAML有效负载。

以下是使用curl和YAML清单创建新对象的方法:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key \
  -X POST \
  -H 'Content-Type: application/yaml' \
  -d '---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep", "365d"]
'
以下是如何获取默认命名空间中的所有对象:
$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key

以及如何通过名称和命名空间获取对象:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key

一种更高级的检索Kubernetes资源的方法是持续观察它们的变化:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments?watch=true \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key

请注意,只能监视一组资源。但是,你可以通过提供标签或字段选择器将结果集缩小到单个资源。

以下是更新现有对象的方法:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key \
  -X PUT \
  -H 'Content-Type: application/yaml' \
  -d '---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep", "730d"]  # <-- Making it sleep twice longer
'

以下是如何修补现有对象:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key \
  -X PATCH \
  -H 'Content-Type: application/merge-patch+json' \
  -d '{
  "spec": {
    "template": {
      "spec": {
        "containers": [
          {
            "name": "sleep",
            "image": "curlimages/curl",
            "command": ["/bin/sleep", "1d"]
          }
        ]
      }
    }
  }
}'

请注意UPDATE和PATCH是相当棘手的操作。第一个受到各种版本冲突的影响,第二个的行为因使用的补丁策略而异。

最后但同样重要的是——以下是如何删除对象集合:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key \
  -X DELETE

以下是如何删除单个对象:

$ curl $KUBE_API/apis/apps/v1/namespaces/default/deployments/sleep \
  --cacert ~/.minikube/ca.crt \
  --cert ~/.minikube/profiles/cluster1/client.crt \
  --key ~/.minikube/profiles/cluster1/client.key \
  -X DELETE

使用kubectl调用Kubernetes API
上面带有证书和令牌的诡计很有趣。至少经历一次是一个很好的练习,可以巩固对客户端和服务器移动部件的理解。但是,当你有一个可以使用的kubectl时,每天都这样做可能会有点矫枉过正。

使用kubectl代理调用Kubernetes API

使用正确配置的kubectl工具,你可以通过使用kubectl proxy命令大大简化API访问。

如果你已经使用可工作的kubectl,为什么还要直接调用Kubernetes API呢?

原因有很多。例如,你可能正在开发一个控制器并希望在不编写额外代码的情况下使用API查询。或者,你可能对kubectl操纵资源时的幕后操作不满意,这使你希望对Kubernetes对象上的操作进行更细粒度的控制。

该命令在你的localhost和Kubernetes API服务器kubectl proxy之间创建一个代理服务器(或应用程序级网关)。但它必须不止于此。不然怎么会这么方便?

代理kubectl从调用者那里卸载了相互的客户端-服务器身份验证责任。由于调用者和代理之间的通信是通过localhost进行的,因此它被认为是安全的。代理本身使用kubeconfig文件中选择的当前上下文中的信息来处理客户端-服务器身份验证。

$ kubectl config current-context
cluster1

$ kubectl proxy --port=8080 &

启动代理服务器后,调用Kubernetes API服务器就变得简单多了:

$ curl localhost:8080/apis/apps/v1/deployments
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "resourceVersion": "660883"
  },
  "items": [...]
}

使用kubectl raw模式调用Kubernetes API我最近学到的另一个很酷的技巧是一些kubectl命令支持的原始模式:

# Sends HTTP GET request
$ kubectl get --raw /api/v1/namespaces/default/pods

# Sends HTTP POST request
$ kubectl create --raw /api/v1/namespaces/default/pods -f file.yaml

# Sends HTTP PUT request
$ kubectl replace --raw /api/v1/namespaces/default/pods/mypod -f file.json

# Sends HTTP DELETE request
$ kubectl delete --raw /api/v1/namespaces/default/pods

kubectl是一个非常先进的工具,即使是简单的命令,比如kubectl get背后也有大量的代码。但是,当使用该–raw标志时,实现归结为将唯一的参数转换为API端点URL并调用原始REST API客户端。

这种方法的一些优点是:

原始REST API客户端使用相同的身份验证意味着baked command将使用(在kubeconfig文件中配置的任何内容)

-f这些命令通过标志支持传统的基于文件的清单输入。

但也有一个缺点——我找不到任何PATCH或WATCH支持,因此curl访问为你提供了更多功能。

— 4 —
奖励:Kubernetes API调用等效于kubectl命令

我已经多次提到你可能对特定kubectl命令发出的请求的实际顺序不满意。但是你不读代码怎么能知道这个序列呢?

这是一个不错的技巧——你可以将-v 6标志添加到任何kubectl命令,日志将变得如此冗长,以至于你将开始看到向Kubernetes API服务器发出的HTTP请求。

例如,你可以通过这种方式了解到该kubectl scale deployment命令是通过对子资源的PATCH请求实现的/deployments//scale:

$ kubectl scale deployment sleep --replicas=2 -v 6
I0116 ... loader.go:372] Config loaded from file:  /home/vagrant/.kube/config
I0116 ... cert_rotation.go:137] Starting client certificate rotation controller
I0116 ... round_trippers.go:454] GET https://192.168.58.2:8443/apis/apps/v1/namespaces/default/deployments/sleep 200 OK in 14 milliseconds
I0116 ... round_trippers.go:454] PATCH https://192.168.58.2:8443/apis/apps/v1/namespaces/default/deployments/sleep/scale 200 OK in 12 milliseconds
deployment.apps/sleep scaled

看看kubectl apply -v 6,结果可能非常有见地!

想查看实际的请求和响应主体吗?将日志详细程度增加到8。

封装起来

第一次访问Kubernetes API的需求可能很可怕——有很多新概念,如资源、API 组、种类、对象、集群、上下文、证书,哦,天哪!

但是一旦你在构建块上分解它并通过执行一些琐碎的任务(比如找出API服务器地址或使用curl调用一堆端点)获得一些实践经验,你很快就会意识到这个想法集群并不是真的一些新的东西——它只是多年来为我们服务的众所周知的机制的组合——REST架构风格、TLS证书、JWT令牌、对象方案等。

所以,不要害怕并运行一些查询!

相关链接:

https://github.com/alexellis/arkade
https://iximiuz.com/en/posts/how-to-setup-development-environment/

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

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

相关文章

windows11改老版右键显示

右键显示效果&#xff1a;点击右键像windows10一样。方式一使用window的命令行操作&#xff1a;reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve1方式二使用注册表手动操作&#xff1a;win r&#xff1a;…

对话面试官:MySQL自增主键id快用完了怎么办?

前几天有个朋友出去面试&#xff0c;被面试官问到MySQL自增主键id用完了怎么办&#xff1f;由于对这块了解不多&#xff0c;所以回答得不太理想。 本篇文章为大家分享一下&#xff0c;MySQL自增主键达到上限以后会发生什么情况&#xff1f;该如何解决这种情况&#xff1f; 我们…

Python|每日一练|幂函数算法|位运算|>>右移|分析神器pysnooper|日志输出:Pow(x, n)

Pow(x, n) 实现 pow(x, n)(https://www.cplusplus.com/reference/valarray/pow/) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10输出&#xff1a;1024.00000 示例 2&#xff1a; …

漫画 | 程序员这次被逼上了绝路!

经过不懈努力&#xff0c;张大胖终于在一个小公司升任经理。张大胖回去翻阅资料&#xff0c;思考了一番&#xff0c;召开会议宣布了一项重要决定。会议室中一阵窃窃私语三天以后&#xff0c;张大胖进行检查&#xff0c;看看自己的第一把火成效如何。张大胖表示很满意&#xff0…

Elasticsearch:轻松处理 CSV 数据

我们知道 CSV 是一种非常流行的数据格式。在 Elastic Stack 中&#xff0c;我们有很多的方式来摄入 CSV 格式的数据。我们可以先看看一个常用的数据摄入数据流&#xff1a; 如上所示&#xff0c;我们可以采取不同的方法来对数据进行摄入。我们可以在不同的地方对数据进行处理。…

【My Electronic Notes系列——逻辑门电路】

目录 序言&#xff1a; &#x1f3c6;&#x1f3c6;人生在世&#xff0c;成功并非易事&#xff0c;他需要破茧而出的决心&#xff0c;他需要永不放弃的信念&#xff0c;他需要水滴石穿的坚持&#xff0c;他需要自强不息的勇气&#xff0c;他需要无畏无惧的凛然。要想成功&…

Java打印流(PrintStream/PrintWriter)

概念 打印流是输出信息最方便的类&#xff0c;注意包含字节打印流PrintStream和字符打印流PrintWriter。打印流提供了非常方便的打印功能&#xff0c;可以打印任何类型的数据信息&#xff0c;例如&#xff1a;小数&#xff0c;整数&#xff0c;字符串。而且永远不会抛出IOExce…

DPDK开发之KNI模块代码实现

DPDK开发之KNI模块代码实现背景KNI实现原理 -- ifreq代码实现总结背景 在DPDK开发的时候&#xff0c;如果有些协议不想处理&#xff0c;只处理关注的协议&#xff0c;可以把其他协议写回内核&#xff0c;让内核处理。此时的DPDK就起到分发的作用&#xff0c;类似一个过滤器。 …

二叉树遍历的C语言实现

1、二叉树 树是n个节点的有限集 每个节点事多有两颗子树的树称为 二叉树 该实验目标实现以下二叉树&#xff1a; 2、二叉树的遍历方案 设&#xff1a; D -- 访问根节点&#xff0c;输出根节点; L -- 递归遍历左二叉树; R -- 递归遍历右二叉树; 二叉树遍历方案…

1145. 二叉树着色游戏

有两位极客玩家参与了一场「二叉树着色」的游戏。游戏中&#xff0c;给出二叉树的根节点 root&#xff0c;树上总共有 n 个节点&#xff0c;且 n 为奇数&#xff0c;其中每个节点上的值从 1 到 n 各不相同。 最开始时&#xff1a; 「一号」玩家从 [1, n] 中取一个值 x&#xff…

软件工程期末考试

软件工程一、简答题&#xff08;5个&#xff09;什么是软件危机&#xff1f;软件危机产生的原因是什么&#xff1f;怎样克服软件危机&#xff1f;你认为摆脱软件危机了吗&#xff1f;软件危机&#xff1a;是指在计算机软件开发、使用与维护过程中遇到的一系列严重问题和难题。它…

QT opencv 学习day01 安装opencv ,

1. 安装opencv 教程 看这个大佬的链接 &#xff08;实测有用&#xff09;&#xff08;操作简单&#xff09; 链接&#xff1a; (1条消息) 【OpenCV】windows Qt环境搭建_logani的博客-CSDN博客 2. 使用opencv 的注意事项 1.首先要在工程文件 .pro 文件里面 加入路径&#x…

Springboot+Echarts实现数据可视化项目

首先,得明白 springboot 需要写什么内容? 先理解下 MVC 模式! bean 层 也称之为 Dao 层 包括XxxMapper.java(数据库访问接口类),XxxMapper.xml(数据库链接实现);mapper 层 也称之为 model层,模型层,entity层,实体层 就是数据库表的映射实体类,存放POJO对象;servi…

Nginx反向代理与负载均衡

一.何为反向代理? 在介绍反向代理之前&#xff0c;先来了解一下正向代理。 正向代理&#xff1a;如果把局域网外的Internet想象成一个巨大的资源库&#xff0c;则局域网中的客户端要访问Internet&#xff0c;则需要通过代理服务器来访问&#xff0c;这种代理服务就称为正向代…

【前端利器炫酷的CodePen】

前言众所周知&#xff0c;前端是一个很容易将自己的劳动成果呈现出来的一个职位&#xff0c;无论是写1行代码还是写100行代码&#xff0c;都可以通过页面来进行呈现&#xff0c;在工作中的劳作成果也是可以一眼就呈现给客户、用户的。比如一些精美的页面&#xff0c;炫酷的特效…

java集合: ArrayList的底层机制和使用方法

文章目录引言一、Arraylist是什么&#xff1f;二、Arraylist的底层扩容机制(面向面试)1.扩容机制2.扩容过程:3步骤3.注意事项三、使用步骤1.ArrayList类引入2.添加元素3.删除元素4.计算大小5.其他的引用类型6.ArrayList 排序7.ArrayList的遍历方法8.Java ArrayList 方法表格引言…

HTML5+CSS3(六)-全面详解(学习总结---从入门到深化)

目录 CSS简介 CSS概念 为什么需要CSS CSS和HTML之间的关系 语法 学习效果反馈 CSS的引入方式 内联样式&#xff08;行内样式&#xff09; 内部样式 外部样式&#xff08;推荐&#xff09; 导入式&#xff08;了解&#xff09; import和link的区别 学习效果反馈 CSS样式…

代码随想录day53 动态规划

代码随想录day53 动态规划 题392 判断是否子序列 1&#xff0c;与最长公共子序列类似&#xff0c;最后公共子序列的长度要等于s的长度。区别在于当遍历元素不想等的时候&#xff0c;对于字符串s&#xff08;子序列&#xff09;不需要删除&#xff0c;对于字符串t&#xff0c;…

Android---CoordinatorLayout原理

目录 CoordinatorLayout 的作用 CoordinatorLayout 的功能 1 处理子控件之间依赖下的交互 2 处理子控件之间的嵌套滑动 3 处理子控件的测量与布局 4 处理子控件的事件拦截与响应 CoordinatorLayout 下的事件传递机制 CoordinatorLayout 协调者布局。 CoordinatorLayout…

Java基础之序列化与反序列化

序列化&#xff1a;将java对象转化为字节序列的过程。 反序列化&#xff1a;将字节序列转化为java对象的过程。 在进行远程通信时&#xff0c;如果需要传输java对象&#xff1a;发送方需要把java对象转换为字节序列(也就是序列化)&#xff0c;接收方需要将字节序列转换为java对…