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

kubernetes(k8s)知识总结(第3期)

1. PV 与 PVC

PV 是持久卷(Persistent Volume)的首字母缩写。通常情况下,可以事先在 k8s 集群创建 PV 对象:

apiVersion: v1
kind: PersistentVolume
metadata:name: nfs
spec:storageClassName: manualcapacity:storage: 1GiaccessModes:- ReadWriteManynfs:server: 10.244.1.4path: "/"

PVC 是持久卷声明(PersistentVolumeClaim)的首字母缩写,描述的是 Pod 所希望使用的持久化存储的属性。PVC 对象通常由平台的用户创建,或者以 PVC 模板的方式成为 StatefulSet 的一部分,然后由 StatefulSet 控制器负责创建带编号的 PVC。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: nfs
spec:accessModes:- ReadWriteManystorageClassName: manualresources:requests:storage: 1Gi

用户创建的 PVC 要真正被容器使用,就必须先和某个符合条件的 PV 进行绑定,要检查一下两个条件:

(1)PV 和 PVC 的 spec 字段,PV 的存储(storage)大小必须满足 PVC 的要求。

(2)PV 和 PVC 的 storageClassName 字段必须一样。

在成功地将 PVC 和 PV 进行绑定之后,Pod 就能够像使用 hostPath 等常规类型的 Volume 一样,在自己的 YAML 文件里声明使用这个 PVC 了。

apiVersion: v1
kind: Pod
metadata:labels:role: web-frontend
spec:containers:- name: webimage: nginxports:- name: webcontainerPort: 80volumeMounts:- name: nfsmountPath: "/usr/share/nginx/html"volumes:- name: nfspersistentVolumeClaim:claimName: nfs

 可以看到,Pod 需要做的,就是在 volumes 字段里声明自己要使用的 PVC 的名字。接下来,等这个 Pod 创建之后,kubelet 就会把该 PVC 所对应的 PV 挂载在这个 Pod 容器内的目录上。

在 k8s 中实际上存在着一个专门处理持久化存储的控制器 Volume Controller。它维护着多个控制循环,其中一个就是将 PV 和 PVC 进行关联的 Persistent Volume Controller。它会不断查看当前每一个 PVC 是否已经处于已绑定(Bound)状态。如果不是,它就会遍历所有可用的 PV,并尝试将其与这个 PVC 进行绑定。所谓的绑定,其实就是将这个 PV 对象的名字填在了 PVC 的 spec.volumeName 字段上。

那么,这个 PV 是如何变成容器里的一个持久化存储的呢?所谓容器的 Volume,就是将一个宿主机上的目录跟一个容器里的目录绑定在了一起。所谓的持久化,指的就是该宿主机上的目录具备持久性,该目录里的文件既不会因为容器的删除而被清理,也不会跟当前的宿主机绑定。所以,大多数情况下,持久化 Volume 的实现往往以来一个远程存储服务。k8s 需要做的,就是使用这些存储服务来为容器准备一个持久化的宿主机目录,以供将来进行绑定挂载时使用。

准备宿主机目录的过程分为两个阶段:

(1)第一阶段(Attach)

当一个 Pod 调度到一个节点上之后,kubelet 就要负责为这个 Pod 创建它的 Volume 目录,默认是宿主机上的一个路径:

/var/lib/kubelet/pods/<Pod 的 ID>/volumes/kubernetes.io~<Volume 类型>/<Volume 名字>

接下来,kubelet 就要调用 Volume 所在平台的 API,将目标存储盘挂载到 Pod 所在的宿主机上。

(2)第二阶段(Mount)

为了能够使用该远程磁盘,kubelet 还要格式化这个磁盘设备,然后把它挂载到宿主机指定的挂载点上。

经过了两阶段处理,就得到了一个持久化的 Volume 宿主机目录。接下来 kubelet 只要把这个 Volume 目录通过 CRI 里的 Mounts 参数传递给 Docker,然后就可以为 Pod 里的容器挂载这个 Volume 了。

2. K8s 网络原理

1. 单机容器网络的实现原理

Linux 容器能看见的网络栈,是隔离在它自己的 Network Namespace 中的。

网络栈包括了网卡、回环设备、路由表和 iptables 规则。对于一个进程来说,这些要素构成了它发起和相应网络请求的基本环境。

作为容器,它可以声明直接使用宿主机的网络栈(-net=host),即不开启 Network Namespace。

$ docker run -d -net=host --name nginx-host nginx

在这种情况下,容器启动后直接监听的就是宿主机的 80 端口。像这样直接使用宿主机的网络栈的方式,虽然可以为容器提供良好的网络性能,但会不可避免地带来共享网络资源的问题,比如端口冲突。所以,我们希望容器进程能使用自己 Network Namespace 里的网络栈,即拥有自己的 IP 地址和端口。

那么,这个被隔离的容器进程跟其他 Network Namespace 里的容器进程交互就是接下来要介绍的。可以把每个容器看作一台主机,如果要实现网络通信,最直接的办法就是用网线把他们连接到一台交换机上。在 Linux 中,能起到虚拟交换机作用的网络设备就是网桥。它是一个在数据链路层工作的设备,主要功能是根据 MAC 地址学习将数据包转发到网桥的不同端口上。为了实现这个目的,Docker 会默认在宿主机上创建一个名叫 docker0 的网桥,凡是与 docker0 网桥连接的容器,都可以通过他来进行通信。将容器连接到 docker0 网桥的虚拟设备是 Veth Pair。Veth Pair 被创建出来后,总是以两张虚拟网卡的形式成对出现。从其中一张“网卡”发出的数据可以直接出现在对应的“网卡”上,哪怕这两张“网卡”在不同的 Network Namespace 里。

2. 容器跨主机网络的实现原理

(1)VXLAN

VXLAN(virtual extensible LAN,虚拟可扩展局域网)是 Linux 内核本身就支持的一种网络虚拟化技术。VXLAN 覆盖网络的设计思想是,在现有的三层网络之上“覆盖”一层虚拟的、由内核 VXLAN 模块负责维护的二层网络,使得这个二层网络上的“主机”之间可以像在同一个局域网里那样自由通信。为了能够在二层网络上打通“隧道”,VXLAN 会在宿主机上设置一个特殊的网络设备作为“隧道”的两端。这个设备叫做 VTEP(VXLAN tunnel end point,虚拟隧道端点)。在进行通信的流程中,VTEP 设备既有 IP 地址,也有 MAC 地址。

比如现在宿主机A Node1 的 container-1 要访问在不同主机上的 Node2 的 container-2。当 container-1 发出请求之后,这个 IP 包会先出现在 docker0 网桥,然后被路由到本机的 VTEP 设备进行处理,也就是来到了“隧道的入口”。为了能将 IP 包封装并发送到正确的宿主机,VXLAN 就需要找到这条隧道的出口,即目的宿主机的 VTEP 设备。而这个设备信息是由每台宿主机上的 flanneld 进程负责维护的,每个节点被添加到 Flannel 网络之后,在其他已加入的网络节点上的 flanneld 就会添加一条路由规则。这些 VTEP 设备之间需要想办法组成一个虚拟的二层网络,即通过二层数据帧进行通信。可以根据 IP 地址通过 ARP 记录查到 MAC 地址,这个 ARP 记录也是在新节点启动时自动添加到其他节点的。现在得到了一个二层数据帧,需要注意的是,以上封包过程只是加一个二层头,不会改变 IP 包的内容。接下来 Linux 内核还要把二层数据帧进一步封装成为宿主机网络里的一个普通的数据帧,也叫“外部数据帧”,好让它通过宿主机的 eth0 网卡进行传输。首先,Linux 内核会在二层数据帧前面加上一个特殊的 VXLAN 头,这个 VXLAN 头里有一个重要的标志,叫做 VNI,它是 VTEP 设备识别某个数据帧是否应该归自己处理的重要标识。然后, Linux 内核会把这个数据帧封装进一个 UDP 包里发出去。但是,这个 VTEP 设备只知道另一端的 MAC 地址,不知道 IP 地址。在这种场景中,VTEP 设备要扮演一个“网桥”的角色,在二层网络进行 UDP 包的转发。在 Linux 内核中,“网桥”设备进行转发的依据来自一个叫做 FDB (forwarding database)的转发数据库。接下来的流程就是正常宿主机网络上的封包工作。在前面加上一个 IP 头,组成一个 IP 包,这个 IP 头里会填上之前通过 FDB 查询出来的 IP 地址。然后,Linux 内核再在这个 IP 包前面加上二层数据帧头,并把 MAC 地址填进去。这样,封包工作就完成了。

接下来,Node1 上的 VTEP 设备就可以把这个数据帧从 Node1 的 eth0 网卡发出去,这个帧会经过宿主机网络来到 Node2 的 eth0 网卡。Node2 的内核网络栈会发现这个数据帧里有 VXLAN 头,所以 Linux 内核会对它进行拆包,获取里面的数据帧,然后根据 VNI 值把它交给 Node2 上的 VTEP 设备。VTEP 设备会进一步拆包,取出里面的 IP 包。接下来就到了单机容器网络的处理流程。最终,IP 包就进入了 container-2 的 Network Namespace 里。

(2)host-gw

假设现在 Node1 上的 container-1 要访问 Node2 上的 container-2,使用 host-gw 模式之后,flanneld 会在宿主机上创建这样一条规则,以 Node1 为例:

10.244.1.0/24 via 10.168.0.3 dev eth0

这条路由规则的含义是,目的 IP 地址属于 10.244.1.0/24 网段的 IP 包应该经过本机的 eth0 设备发出,它的下一跳地址是 10.168.0.3,这个下一跳地址对应的正是目的宿主机 Node2。配置了下一跳地址,接下来当 IP 包从网络层进入链路层封装成帧时,eth0 设备就会使用下一跳地址对应的 MAC 地址,作为该数据帧的目的 MAC 地址。这样,这个数据帧就会从 Node1 通过宿主机的二层网络顺利到达 Node2 上。

Node2 的内核网络栈从二层数据帧里获取 IP 包后,会“看到”这个 IP 包的目的 IP 地址是 10.244.1.3,即 container-2 的 IP 地址。此时,根据 Node2 上的路由表,IP 包会进入 cni0 网桥,进而进入 container-2 当中。

由此可见,host-gw 模式的工作原理其实就是将每个 Flannel 子网的下一跳设置成了该子网对应的宿主机的 IP 地址。

(3) Calico 项目

Calico 项目提供的网络解决方案与 Flannel 的 host-gw 几乎完全一样。Calico 也会在每台宿主机上添加一条格式如下的路由规则:

<目的容器 IP 地址段> via <网关的 IP 地址> dev eth0

其中,网关的 IP 地址正是目的容器所在宿主机的 IP 地址。这个三层网络方案得以正常工作的核心是为每个容器的 IP 地址找到对应的下一跳的网关。不同于 Flannel 通过 etcd 和宿主机上的 flanneld 来维护路由信息的做法,Calico 使用 BGP(border gateway protocol,边界网关协议) 来自动地在整个集群中分发路由信息。

Calico 项目的架构由以下三个部分组成:

(1)Calico 的 CNI 插件。

(2)Felix。这是一个 DaemonSet,负责在宿主机上插入路由规则,以及维护 Calico 所需的网络设备等工作。

(3)BIRD。BGP 的客户端,专门负责在集群里分发路由规则信息。

下面介绍一下 Calico 的工作原理:

Calico 的 CNI 插件会为每个容器设置一个 Veth Pair 设备,然后把其中的一端放置在宿主机上。此外,由于 Calico 没有使用 CNI 的网桥模式,因此 Calico 的 CNI 插件还需要在宿主机上为每个容器的 Veth Pair 设备配置一条路由规则,用于接收传入的 IP 包。有了这样的 Veth Pair 设备之后,容器发出的 IP 包就会经过 Veth Pair 设备出现在宿主机上。然后,宿主机网络栈就会根据路由规则的下一跳 IP 地址,把它们转发给正确的网关。接下来的流程就跟 Flannel 的 host-gw 模式完全一致了。 

3. 网络隔离:Network Policy

在 K8s 里,网络隔离能力是依靠一种专门的 API 对象来描述的,它就是 NetworkPolicy。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: test-network-policynamespace: default
spec:podSelector:matchLabels:role: dbpolicyTypes:- Ingress- Egressingress:- from:- ipBlock:cidr: 172.17.0.0/16except:- 172.17.1.0/24- namespaceSelector:matchLabels:project: myproject- podSelector:matchLabels:role: frontendports:- protocol: TCPport: 6379egress:- to:- ipBlock:cidr: 10.0.0.0/24ports:- protocol: TCPport: 5978

在这个例子中, 首先会看到 podSelector 字段。它的作用是定义这个 NetworkPolicy 的限制范围,比如当前 Namespace 里携带了 role=db 标签的 Pod。

如果把 podSelector 字段留空:

spec:podSelector: {}

那么这个 NetworkPolicy 就会作用于当前 Namespace 下的所有 Pod。

NetworkPolicy 定义的规则其实就是“白名单”。例如,上面的例子里,在 policyTypes 字段定义了这个 NetworkPolicy 的类型是 ingress 和 egress,即它既会影响流入请求,也会影响流出请求。然后在 ingress 字段定义了 from 和 ports,即允许流入的“白名单”和端口。在这个“白名单”里指定了 3 种并列的情况,分别是 ipBlock、namespaceSelector 和 podSelector。在 egress 字段定义了 to 和 ports,即允许流出的“白名单”和端口。这里的定义方法与 ingress 类似,只是 ipBlock 字段指定的是目的地址和网段。

综上所述,这个 NetworkPolicy 对象指定的隔离规则如下所示:

(1)该隔离规则只对 default Namespace 下携带了 role=db 标签的 Pod 有效。限制的请求类型包括 ingress 和 egress。

(2)K8s 会拒绝任何对被隔离 Pod 的访问请求,除非请求来自以下“白名单”里的对象,并且访问的是被隔离 Pod 的 6379 端口。这些“白名单”对象包括:

        1)default Namespace 里携带了 role=fronted 标签的 Pod

        2)任何 Namespace 里携带了 project=myproject 标签的 Pod

        3)任何源地址属于 172.17.0.0/16 网段,且不属于 172.17.1.0/24 网段的请求

(3)K8s 会拒绝被隔离 Pod 对外发起任何请求,除非请求的目的地属于 10.0.0.0/24 网段,并且访问的是该网段地址的 5978 端口。

3. Service

K8s 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另一方面是因为一组 Pod 实例之间总会有负载均衡的需求。

apiVersion: v1
kind: Service
metadata:name: hostnames
spec:selector:app: hostnamesports:- name: defaultprotocol: TCPport: 80targetPort: 9376

这个例子中,使用了 selector 字段来声明这个 Service 只携带 app: hostnames 标签的 Pod。 并且,这个 Service 的 80 端口代理的是 Pod 的 9376 端口。

应用的 Deployment 如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:name: hostnames
spec:selector:matchLabels:app: hostnamesreplicas: 3template:metadata:labels:app: hostnamesspec:containers:- name: hostnamesimage: k8s.gcr.io/serve_hostnameports:- containerPort: 9376protocol: TCP

被 selector 选中的 Pod 称为 Service 的 Endpoint,可以使用 kubectl get ep 查看。只有处于 Running 状态,且 readinessProbe 检查通过的 Pod,才会出现在 Service 的 Endpoints 列表里。当某个 Pod 出现问题时,K8s 会自动从 Service 里将其移除。

此时,通过该 Service 的 VIP 地址,就可以访问到它所代理的 Pod 了。 这个 VIP 地址是 K8s 自动为 Service 分配的。Service 提供的是轮询方式的负载均衡。这种方式称为 ClusterIP 模式的 Service。

Service 的访问信息在 K8s 集群之外是无效的。所谓的 Service 的访问入口,其实就是每台宿主机上由 kube-proxy 生成的 iptables 规则,以及由 kube-dns 生成的 DNS 记录。一旦离开这个集群,这些信息对用户就没有作用了。如何从外部访问 K8s 集群里的 Service?最常用的方式是 NodePort:

apiVersion: v1
kind: Service
metadata:name: my-nginxlabels:run: my-nginx
spec:type: NodePortports:- nodePort: 8080port: 30080targetPort: 80protocol: TCPname: http- nodePort: 443port: 30443protocol: TCPname: httpsselector:run: my-nginx

在这个 Service 里,它的类型是 type=NodePort。然后在 ports 字段里声明了 Service 的 8080 端口代理 Pod 的 80 端口,Service 的 443 端口代理 Pod 的 443 端口。当然,如果不显式声明 nodePort 字段,K8s 就会为你分配随机的可用端口来设置代理。这个端口的默认范围是 30000~32767,你可以通过 kube-apiserver 的 --service-node-port-range 参数来修改。此时要访问这个 Service,只需要访问:

<K8s集群中任何一台宿主机的IP地址>:8080

 这样就可以访问到某一个被代理的 Pod 的 80 端口了。

从外部访问 Service 的另一种方式适用于公有云上的 K8s 服务,此时可以制定一个 LoadBalancer 类型的 Service:

apiVersion: v1
kind: Service
metadata:name: example-service
spec:ports:- port: 8765targetPort: 9376selector:app: exampletype: LoadBalancer

在公有云提供的 K8s 服务里,都使用了一个叫做 CloudProvider 的转接层来跟公有云本身的 API 进行对接。所以,在上述 LoadBalancer 类型的 Service 提交后,K8s 就会调用 CloudProvider 在公有云上为你创建一个负载均衡服务,并且把被代理的 Pod 的 IP 地址配置给负载均衡服务作为后端。 

4. Ingress

Ingress 是一种全局的、为了代理不同后端 Service 而设置的负载均衡服务。

举个例子,假如有一个站点:https://cafe.example.com,其中 https://cafe.example.com/coffee 对应“咖啡点餐系统”,而 https://cafe.example.com/tea 对应“茶水点餐系统”。这两个系统分别由名叫 coffee 和 tea 的两个 Deployment 来提供服务。下面的 Ingress 可以实现当用户访问不同域名时,能够访问不同的 Deployment:

apiVersion: extensions/vibeta1
kind: Ingress
metadata:name: cafe-ingress
spec:tls:- hosts:- cafe.example.comsecretName: cafe-secretrules:- host: cafe.example.comhttp:paths:- path: /teabackend:serviceName: tea-svcservicePort: 80- path: /coffeebackend:serviceName: coffee-svcservicePort: 80

host 字段定义的值就是这个 Ingress 的入口。这就意味着当用户访问 cafe.example.com 时,实际上访问的是这个 Ingress 对象。这样,K8s 就能使用 IngressRule 来对你的请求进行下一步转发了。接下来 IngressRule 规则的定义则依赖 path 字段。这里的每一个 path 都对应一个后端的 Service。

一个 Ingress 对象的主要内容,实际上就是一个“反向代理”服务的配置文件的描述。而这个代理服务对应的转发规则就是 IngressRule。这就是为什么在每条 IngressRule 里,需要有一个 host 字段作为这条 IngressRule 的入口,还需要有一系列 path 字段来声明具体的转发策略。

在实际使用中,只需要从社区里选择一个具体的 Ingress Controller,把它部署到 K8s 集群中即可。 

5. RBAC(基于角色的权限控制)

这里需要明确 3 个基本概念:

(1)Role:角色,他其实是一组规则,定义了一组对 K8s API 对象的操作权限

(2)Subject:被作用者,既可以是“人”,也可以是“机器”,也可以是在 K8s 里定义的“用户”

(3)RoleBinding:定义了“被作用者”和“角色”间的绑定关系

Role 实际上就是一个 K8s 的 API 对象:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: mynamespacename: example-role
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "watch", "list"]

这个 Role 对象指定了它能产生作用的 Namespace 是 mynamespace。然后,这个 Role 对象的 rules 字段就是它所定义的权限规则。在上面的例子里,这条规则的含义是,允许“被使用者”对 mynamespace 下面的 Pod 对象进行 GET、WATCH 和 LIST 操作。那么,这个“被作用者”是如何制定的呢?通过 RoleBinding 来实现:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: example-rolebindingnamespace: mynamespace
subjects:
- kind: Username: example-userapiGroup: rbac.authorization.k8s.io
roleRef:kind: Rolename: example-roleapiGroup: rbac.authorization.k8s.io

这个 RoleBinding 对象里定义了一个 subjects 字段,即“被作用者”。它的类型是 User,这个用户的名字是 example-user。接下来,可以看到一个 roleRef 字段。通过该字段,RoleBinding 对象可以直接通过名字来引用前面定义的 Role 对象,从而定义了“被作用者”和“角色”之间的绑定关系。

Role 和 RoleBinding 对权限的限制规则仅在它们自己的 Namespace 内有效。如果某个 Role 想作用于所有的 Namespace 时,就必须使用 ClusterRole 和 ClusterRoleBinding 了:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: example-clusterrole
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "watch", "list"]
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: example-clusterrolebinding
subjects:
- kind: Username: example-userapiGroup: rbac.authorization.k8s.io
roleRef:kind: ClusterRolename: example-clusterroleapiGroup: rbac.authorization.k8s.io

这意味着名叫 example-user 的用户拥有对所有 Namespace 的 Pod 进行 GET、WATCH 和 LIST 操作的权限。

相关文章:

kubernetes(k8s)知识总结(第3期)

1. PV 与 PVC PV 是持久卷&#xff08;Persistent Volume&#xff09;的首字母缩写。通常情况下&#xff0c;可以事先在 k8s 集群创建 PV 对象&#xff1a; apiVersion: v1 kind: PersistentVolume metadata:name: nfs spec:storageClassName: manualcapacity:storage: 1Giac…...

浅谈跨境电商运行模式

近些年&#xff0c;由于疫情的原因和人们的消费习惯的改变&#xff0c;线下销售越来越不占优势&#xff0c;电商行业由于这几年的飞速发展&#xff0c;成功地吸引到我国的民众&#xff0c;拼多多、淘宝、京东、天猫等各种各样的国内电商平台涌现&#xff0c;依靠着产品质量好、…...

Memcached

什么是MemcachedMemcached 是一个开源免费的高性能的分布式内存对象缓存系统、就是一个软件Memcached的作用缓存数据提高动态网站的速度Memcached的安装//方法一yum installmemcached//方法二1.安装libevent (memcached依赖包)tar -zvxflibevent-release-1.4.15-stable.tar.gzc…...

Unity UGUI 拖拽组件

效果展示 使用方式 拖到图片上即可用 父节点会约束它的活动范围哦~ 父节点会约束它的活动范围哦~ 父节点会约束它的活动范围哦~ 源码 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems;/// <summary> /…...

面试总结——react生命周期

react生命周期总结 生命周期主要分为以下几个阶段&#xff1a; Mounting:创建虚拟DOM&#xff0c;渲染UI(初始化)Updating&#xff1a;更新虚拟DOM&#xff0c;重新渲染UI&#xff1b;(更新)UnMounting&#xff1a;删除虚拟DOM&#xff0c;移除UI&#xff1b;(销毁) 生命周期…...

初探推荐系统-01

文章目录一、什么是推荐系统是什么为什么长尾理论怎么做二、相似度算法杰卡德相似系数余弦相似度三、基于内容的推荐算法如何获取到用户喜欢的物品如何确定物品的特征四、推荐算法实验方法评测指标推荐效果实验方法1、离线实验2、用户调查3、在线实验评测指标1、预测准确度评分…...

html实现浪漫的爱情日记(附源码)

文章目录1.设计来源1.1 主界面1.2 遇见1.3 相熟1.4 相知1.5 相念2.效果和源码2.1 动态效果2.2 源代码2.3 代码结构源码下载更多爱情表白源码作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/129264757 html实现浪漫的爱情…...

detectron2容器环境安装问题(1)

1为避免后面出现需求python版本低于3.7的情况ERROR: Package detectron2 requires a different Python: 3.6.9 not in >3.7可以第一步就使用 nvidia/cuda:11.1.1-cudnn8-devel-ubuntu20.04镜像2如果使用了18.04的镜像nvidia/cuda:11.1.1-cudnn8-devel-ubuntu18.04可以使用我…...

JAVA线程池原理详解二

JAVA线程池原理详解二 一. Executor框架 Eexecutor作为灵活且强大的异步执行框架&#xff0c;其支持多种不同类型的任务执行策略&#xff0c;提供了一种标准的方法将任务的提交过程和执行过程解耦开发&#xff0c;基于生产者-消费者模式&#xff0c;其提交任务的线程相当于生…...

Java 常用 API

文章目录一、Math二、System三、Object1. toString() 方法2. equals() 方法四、Arrays1. 冒泡排序2. Arrays 常用方法五、基本类型包装类1. Integer2. int 和 String 相互转换3. 字符串中数据排序4. 自动装箱和拆箱六、日期类1. Date2. SimpleDateFormat3. Calendar4. 二月天一…...

记一次分布式环境下TOKEN实现用户登录

背景&#xff1a; ​ 以前的单体项目&#xff0c;使用的是session来保存用户登录状态&#xff0c;控制用户的登录过期时间等信息&#xff0c;但是这个session是只保存在该服务器的这个系统内存中。系统只有一个服务就没关系&#xff0c;但是如果是分布式的服务&#xff0c;每个…...

用cpolar发布本地的论坛网站 1

网页论坛向来是个很神奇的地方&#xff0c;曾经的天涯论坛和各种BBS&#xff0c;大家聚在在一起讨论某个问题&#xff0c;也能通过论坛发布想法&#xff0c;各种思维碰撞在一起&#xff0c;发生很多有趣的故事&#xff0c;也产生了很多流传一时的流行语录。当然&#xff0c;如果…...

CSS的4种引入方式

CSS的4种引入方式 目录CSS的4种引入方式一、内嵌式&#xff1a;CSS写在style标签中二、外联式&#xff1a;CSS写在一个单独的.css文件中三、行内式&#xff1a;CSS写在标签的style属性中四、导入外部样式五、css引用的优先级六、link和import的区别一、内嵌式&#xff1a;CSS写…...

Shell高级——Linux中的文件描述符(本质是数组的下标)

以下内容源于C语言中文网的学习与整理&#xff0c;非原创&#xff0c;如有侵权请告知删除。 前言 Linux中一切接文件&#xff0c;比如 C 源文件、视频文件、Shell脚本、可执行文件等&#xff0c;就连键盘、显示器、鼠标等硬件设备也都是文件。 一个 Linux 进程可以打开成百上…...

Nvidia jetson nano硬件架构

资料来源 官方文档中心 https://developer.nvidia.com/embedded/downloads -> 选jetson -> Jetson Nano Product Design Guide //产品设计指导(入口) //-> 1.1 References 列出了相关的文档 -> Jetson Nano Developer Kit Carrier Board Specification //板子标注…...

ffmpeg多路同时推流

一、ffmpeg常见使用方法1.1利用FFMPEG命令进行文件分割1.2转换格式1.3推流配置方法一&#xff1a;ngnix&#xff08;不推荐&#xff0c;推流不好使&#xff09;方法二&#xff1a;srs&#xff08;强烈推荐&#xff09;1.4查看nginx启动是否成功二、ffmpeg推流——>ngnix单路…...

一次性搞定 `SHOW SLAVE STATUS` 的解读

一次性搞定 SHOW SLAVE STATUS 的解读 解析日志文件的位置 诚然, GTID(全局事务标识符)已经在 MySQL 5.6中得到支持, 此外,还可以通过 Tungsten replicator 软件来实现(2009年以后一直有谷歌在维护,不是吗?)。 但有一部分人还在使用MySQL 5.5的标准副本方式, 那么这些二进制日…...

【代码随想录训练营】【Day25】第七章|回溯算法 |216.组合总和III|17.电话号码的字母组合

组合总和III 题目详细&#xff1a;LeetCode.216 做过上一题组合后&#xff0c;再来写这道题就显得得心应手了&#xff0c;通过理解回溯算法的模版&#xff0c;也总结出了算法中的一些特点&#xff1a; 回溯算法与递归算法类似&#xff0c;同样需要参数、结束条件和主体逻辑回…...

docker使用

https://blog.csdn.net/u012563853/article/details/125295985http://www.ppmy.cn/news/11249.html启动 docker服务并设置开机自动启动dockersudo systemctl start docker sudo systemctl enable dockerdocker 常见启动失败问题:https://blog.csdn.net/zhulianseu/article/deta…...

手把手docker registry配置登录名/密码

我们的Docker私有仓库Registry服务只有加了认证机制之后我们的Registry服务才会更加的安全可靠。赶快跟随以下步骤来增加认证机制吧。 创建docker registry工作目录 mkdir -p /data/docker.registry 创建将保存凭据的文件夹 mkdir -p /data/docker.registry/etc/registry/auth…...

一步打通多渠道服务场景 中电金信源启移动开发平台MADP功能“上新”

日前&#xff0c;中电金信源启移动开发平台MADP功能迭代升级&#xff0c;“上新”源启小程序开发平台。定位“为金融业定制”的移动PaaS平台&#xff0c;源启小程序开发平台为银行、互联网金融、保险、证券客户提供一站式小程序的开发、运营、营销全生命周期管理技术支撑&#…...

Kubernetes06:Controller (Deployment无状态应用)

Kubernetes06:Controller 1、什么是controller 管理和运行容器的对象&#xff0c;是一个物理概念 在集群上管理和运行容器的对象 2、Pod和Controller之间的关系 Pod是通过controller来实现应用的运维 比如伸缩、滚动升级等等操作Pod和Controller之间通过 label 标签建立关系…...

低代码开发平台选型必看指南

低代码开发是近年来逐渐兴起的一种新型软件开发方式。它通过封装常见的软件开发流程和代码&#xff0c;使得非专业的开发者也能够轻松创建复杂的应用程序。这种开发方式已经受到了许多企业的青睐&#xff0c;成为提高生产效率、降低开发成本的一种有效途径。 低代码开发的核心…...

OVN:ovn20.03.1/ovs2.13.0编译rpm过程

操作系统openeuler22.0&#xff0c;x86架构分别下载ovn和ovs的源码https://github.com/openvswitch/ovs/tree/v2.13.0https://github.com/ovn-org/ovn/tree/v20.03.1安装必要工具&#xff1a;yum install -y unzip tar make autoconf automake libtool rpm-build gcc libuuid-d…...

Shell管道

一、管道是什么 英文是pipe。 把一个命令的标准输出作为下一个命令的标准输入&#xff0c;以这种方式连接的两个或者多个命令就形成了管道 使用竖线|连接多个命令&#xff0c;称为管道符。 语法格式如下&#xff1a; command1 | command2 [ | commandN... ] command1的标准…...

Zynq UltraScale系列使用MIPI CSI-2 RX Subsystem 解码MIPI视频PD输出 提供2套工程源码和技术支持

目录1、前言2、设计思路和架构3、vivado工程详解4、上板调试验证5、福利&#xff1a;工程代码的获取1、前言 本设计采用OV5640摄像头MIPI模式作为输入&#xff0c;分辨率为1280x72060Hz&#xff0c;MIPI解码方案采用Xilinx官方提供的MIPI CSI-2 RX Subsystem IP解码MIPI视频&a…...

C++:详解C++11 线程休眠函数

休眠函数简介1: 让线程休眠一段时间1.1&#xff1a;std::chrono 的时钟 clock简介 C11 之前并未提供专门的休眠函数&#xff0c;C语言的 sleep、usleep函数其实是系统提供的函数&#xff0c;不同的系统函数的功能还要些差异。 在Windows系统中&#xff0c;sleep的参数是毫秒 …...

TryHackMe-The Great Escape(Docker)

The Great Escape 我们的开发人员创建了一个很棒的新网站。你能冲出沙盒吗&#xff1f; 端口扫描 循例 nmap Web信息收集 robots.txt: /exif-util是文件上传点&#xff0c;但是绕过之后貌似没啥用 在robots.txt当中披露了可能存在.bak.txt&#xff0c;现在我们已知的文件就是…...

这么强才给我28k,我头都不回,转身拿下40k~

时间真的过得很快&#xff0c;眨眼就从校园刚出来的帅气小伙变成了油腻大叔&#xff0c;给各位刚入道的测试朋友一点小建议&#xff0c;希望你们直通罗马吧&#xff01; 如何选择自己合适的方向 关于选择测试管理&#xff1a; 第一&#xff0c;你一定不会是一个喜欢技术&…...

【Python学习笔记】第二十一节 Python Lambda 函数

Python 提供了非常多的库和内置函数。有不同的方法可以执行相同的任务&#xff0c;而在 Python 中&#xff0c;有个万能之王函数&#xff1a;lambda 函数&#xff0c;它以不同的方式在任何地方使用。一、Lambda 函数简介在 Python 中&#xff0c;函数可以接受一个或多个位置参数…...

Nginx学习整理

Nginx学习第一章 Nginx概述1.1、Nginx概述1.2、Nginx官网1.3、Nginx用处第二章 Nginx单实例安装2.1、环境说明2.2、安装依赖2.3、Nginx下载2.4、Nginx解压2.5、Nginx安装2.6、Nginx命令2.7、开放防火墙2.8、启动后效果第三章 Nginx正向代理、反向代理3.1、概述3.2、反向代理配置…...

阿里面试之Hr面,这个套路把我坑惨了......

作为技术类的测试工程师面试&#xff0c;往往要经过多次面试才能拿到心仪的offer&#xff0c;这里面有技术一面、二面…&#xff0c;甚至总监面等&#xff0c;还有一个必不可少的就是HR面&#xff0c;一般HR会出现在你面试的最前面和最后面&#xff0c;前面是了解你的基本情况&…...

域基础和基本环境搭建

1.1 名词解释 域和工作组的区别&#xff1a; 工作组中所有的计算机都是对等的&#xff0c;也就是没有服务器和客户机的之分&#xff0c;所以工作组并不存在真正的集中管理作用&#xff1b;域是一个有安全边界的计算机集合&#xff0c;安全边界指的是一个域中的用户无法访问到另…...

Java Map集合体系(HashMap、LinkedHashMap、TreeMap、集合嵌套)

目录Map集合体系一、Map集合的概述二、Map集合体系特点三、Map集合常用API四、Map集合的遍历4.1 Map集合的遍历方式一&#xff1a;键找值4.2 Map集合的遍历方式二&#xff1a;键值对4.3 Map集合的遍历方式三&#xff1a;lambda表达式五、Map集合案例-统计投票人数六、Map集合的…...

使用邮箱验证实现登录功能(发送邮件,redis)

目录 概述 前端搭建 后端搭建 生成验证码-存入redis&#xff08;主要过程代码&#xff09; 发送邮件&#xff08;主要过程代码&#xff09; 登录验证-取出redis中数据进行验证&#xff08;主要代码&#xff09; 完整代码一-LoginController 完整代码二-LoginService 完…...

【Linux】网卡的7种bond模式

网卡的7种bond模式 一、bond模式 Mode0(balance-rr) 表示负载分担round-robin&#xff0c;和交换机的聚合强制不协商的方式配合 Mode1(active-backup) 表示主备模式&#xff0c;只有一块网卡是active,另外一块是备的standby&#xff0c;这时如果交换机配的是捆绑&#xff0c…...

AQS抽象队列同步器

aqs 抽象队列同步器&#xff0c;内部存储了一个valitail修饰的status 和内部类node &#xff0c;来实现对共享变量并发同步队列机制,以reentrantLock为例&#xff0c;lock底层实际上调用的是sync的lock&#xff0c;会调用cas对status的状态进行修改&#xff0c;来确定是否获得锁…...

springBoot对REST支持源码解析

一、在配置类中&#xff1a; AutoConfiguration(after { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class }) ConditionalOnWebApplication(type Type.SERVLET) ConditionalOnClass({ Servlet.class, D…...

6 集成学习及Python实现

1 主要思想 集成学习: 三个臭裨将, 顶个诸葛亮 Bagging: 数据随机重抽样, 并行构建分类器, 投票&#xff1b;Boosting: 关注被错分的样本, 串行构建分类器, 加权投票。 2 理论 AdaBoost (Adaptive Boosting)示意图1 错误率: εEN\varepsilon \frac{E}{N}εNE​ 其中NNN为…...

如何编程实现从多数据库操作数据

对于数据量很大的复杂系统&#xff0c;有时候会采用分库或者分表的减轻单台数据库服务器压力&#xff0c;截止目前有一些工具直接支持读写分离等&#xff0c;例如ShardingSphere&#xff0c;如果不采用工具框架&#xff0c;从编码出发&#xff0c;如何实现从多个数据库读写数据…...

LeetCode 147. 对链表进行插入排序 | C/C++版

LeetCode 147. 对链表进行插入排序 | C语言版LeetCode 147. 对链表进行插入排序题目描述解题思路思路一&#xff1a;使用栈代码实现运行结果参考文章&#xff1a;思路二&#xff1a;减少遍历节点数代码实现运行结果参考文章&#xff1a;[]()LeetCode 147. 对链表进行插入排序 …...

【QT进阶】第五章 QT绘图之自定义控件--仪表盘绘制

❤️作者主页:凉开水白菜 ❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步! ❤️专栏目录:【零基础学QT】文章导航篇 ❤️专栏资料:https://pan.baidu.com/s/192A28BTIYFHmixRcQwmaHw 提取码:qtqt ❤️点赞 👍 收藏 ⭐再看,养成习惯 订阅的粉丝可通过…...

Java代码弱点与修复之——URL manipulation(URL操纵)

弱点描述 “URL manipulation” 是指攻击者利用应用程序中的 URL 参数来执行恶意操作的一种攻击技术。 在 URL manipulation 攻击中,攻击者会修改应用程序中的 URL 参数,以便执行不当操作,如访问未授权的页面、修改他人的数据、绕过访问控制等。攻击者通常会使用手动修改 …...

Sharding Sphere学习

一、基本概念 1.什么是Sharding Sphere 2.分库分表3.分库分表的方式 4.分库分表应用和问题 5.功能 5.1数据分片 —核心概念 —使用限制 5.2分布式事务 —核心概念 —使用限制 5.3读写分离 —核心概念 —使用限制 5.4高可用 —核心概念 —使用限制 5.5数据库网关 —核心概念…...

粗心小编被云拯救,那云上数据谁来拯救?

开工第三天      小编已忙的焦头烂额      不是因为工作积压      而是因为自己的疏忽      也许是没有进入工作状态,一大早先经历了自行车钥匙丢失,手机遗落在家,好不容易坐到工位上才发现,备份数据的U盘忘带了。    不过,好在提前将工作文件上传到了云端…...

[git可视化软件]gitkraken平替:GitAhead

日期2023-02-28 gitkraken6.5.1已经不能登陆使用了!! 6.5.1免费版已经无法使用!!! 现在是2023-02-28 这款工具已经废除了6.5.1版本的使用功能了,我直接卡在登陆界面进不去项目了. 要想继续管理私有项目,只能升级最新版的软件,并且开通会员.会员费用高的一批,一年要59.4美元.约…...

CentOS8基础篇8:使用systemctl管理NFS服务

一、服务简介 服务&#xff1a;是指执行指定系统功能的程序、例程或进程&#xff0c;以便支持其他程序&#xff0c;尤其是底层(接近硬件)程序。 例如&#xff1a;打印服务&#xff0c;ftp服务&#xff0c;http服务。 服务就是一个程序&#xff08;正在执行的程序&#xff09…...

Go defer用法

defer概览 defer是go语言里的一个关键字,在 函数内部使用;defer关键字后面跟一个 函数或匿名函数; defer用法 执行一些资源的收尾工作,如 关闭数据库连接,关闭文件描述符,释放资源等等;结合recover()函数使用,防止函数内部的异常导致整个程序停止;defer在遇到panic后,仍然会…...

产地证是什么,主要作用有哪些?

产地证是什么&#xff0c;主要作用有哪些&#xff1f;最近一个客户问我&#xff0c;产地证是什么&#xff0c;主要作用有哪些&#xff1f;今天就来扒拉扒拉这个问题&#xff0c;其实很简单~通俗一点的讲&#xff0c;产地证是货物原产地的证明文件之一&#xff0c;主要用于国外清…...

王道计算机网络课代表 - 考研计算机 第一章 计算机网络体系结构 究极精华总结笔记

本篇博客是考研期间学习王道课程 传送门 的笔记&#xff0c;以及一整年里对 计算机网络 知识点的理解的总结。希望对新一届的计算机考研人提供帮助&#xff01;&#xff01;&#xff01; 关于对 “计算机网络体系结构” 章节知识点总结的十分全面&#xff0c;涵括了《计算机网络…...