• 自动秒收录
  • 软件:1973
  • 资讯:58002|
  • 收录网站:278291|

IT精英团

了解更多关于k8s中Pod的详细信息

了解更多关于k8s中Pod的详细信息

浏览次数:
评论次数:
编辑: 乐咏
信息来源: ITPUB
更新日期: 2022-09-24 01:08:57
摘要

k8s中Pod的理解基本概念k8s为什么使用Pod作为最小的管理单元如何使用Pod1、自主式Pod2、控制器管理的Pod静态PodPod的生命周期Pod如何直接暴露服务hostNetw

  • 正文开始
  • 相关阅读
  • 推荐作品

对k8s中Pod基本概念的理解k8s为什么使用Pod作为最小的管理单元以及如何使用Pod1、自治Pod2、控制器管理的Pod静态PodPod生命周期Pod如何直接公开服务hostNetworkhostPorthostNetwork和hostPort比较标签亲和调度什么是亲和和反亲和调度节点亲和调度策略Pod亲和调度Nod ESelector定向调度资源限制持久存储Pod 1、emptyDir2、hostPath3、 利用HPA实现Pod自动扩展的Pod持久存储探索HPA工作原理总结

k8s中Pod的理解

基本概念

Pod是Kubernetes集群中可以创建和管理的最小部署单元,它是虚拟存在的。 Pod是容器的集合,部署在同一个Pod中的容器是一组亲密度很强的容器。Pod中的容器共享网络和存储空间,并且Pod是短命的。

k8s中的Pod可以通过以下两种方式使用

1.在Pod中运行容器是最常见的用法。一个Pod封装一个容器,k8s可以直接管理Pod;

2.多个容器同时在一个Pod中运行,通常在我们将它们放在一起之前是紧密耦合的。同一个Pod中的多个容器可以使用localhost进行通信,它们共享网络和存储卷。但这种用法并不常见,只能在特定场合使用。

为什么不直接操作00-1010K8s的集装箱而是用Pod作为最小的部署单位?

为了管理容器,k8s需要更多的信息,比如重启策略,定义了容器终止后要采用的策略;或者它是一个可用性探测器,从应用程序的角度检测一个进程是否还活着。基于这些原因,k8s架构师决定使用一种新的实体,即Pod,而不是重载容器的信息来添加更多的属性,以逻辑地包装管理一个或多个容器所需的信息。

00-1010

k8s 为什么使用 Pod 作为最小的管理单元

我们可以简单快速地创建一个类似如下的Pod:

$ cat pod.yaml

API版本: v1

kind: Pod

元数据:

名称: nginx

spec:

集装箱:

-名称: nginx

图片: nginx:1.14.2

端口:

-集装箱港口: 80

建立

$ kubectl apply -f pod.yaml -n研究-k8s

$ kubectl获取pod -n研究-k8s

名称就绪状态重新开始老化

nginx 1/1运行2m

自创的Pod,因为不受控制器管理,被删除,或者因为意外退出,不会重启自愈,直接删除。所以在商业上,我们在创建Pod的时候都加入了控制器。

00-1010由于我们长期业务场景的需要,我们需要Pod能够在集群级别进行滚动升级、拷贝管理和自我修复。这个时候,我们不能单独创建Pod。我们需要通过相应的控制器来创建Pod,实现Pod的滚动升级和自愈能力。

对于Pod的使用,我们最常用的是通过部署来管理。

部署提供了一种管理Pod和复制集的方法。部署可用于创建新服务、更新新服务或通过滚动升级服务。ReplicaSet还可以实现Pod的复制管理功能。

升级一个服务实际上是创建一个新RS,然后将新RS中的副本数逐渐增加到理想状态,旧RS中的副本数减少到0的复合操作;RS不能很好地描述这样的复合操作,所以用更一般的部署来描述。

$ vi deployment.yaml

阿皮韦

rsion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80

运行

$ kubectl apply -f deployment.yaml -n study-k8s$ kubectl get pods -n study-k8sNAME                                READY   STATUS    RESTARTS   AGEnginx                               1/1     Running             67mnginx-deployment-66b6c48dd5-24sbd   1/1     Running             59snginx-deployment-66b6c48dd5-wxkln   1/1     Running             59snginx-deployment-66b6c48dd5-xgzgh   1/1     Running             59s

因为上面定义了 replicas: 3 也就是副本数为3,当我们删除一个 Pod 的时候,马上就会有一个新的 Pod 被创建。

同样经常使用的到的控制器还有 DaemonSet 和 StatefulSet

DaemonSet:DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

StatefulSet:用来管理有状态应用的工作负载,和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

静态 Pod

静态 Pod 是由 kubelet 进行管理的仅存在与特定 node 上的 Pod,他们不能通过 api server 进行管理,无法与 rc,deployment,ds 进行关联,并且 kubelet 无法对他们进行健康检查。

静态 Pod 始终绑定在某一个kubelet,并且始终运行在同一个节点上。 kubelet会自动为每一个静态 Pod 在 Kubernetes 的 apiserver 上创建一个镜像 Pod(Mirror Pod),因此我们可以在 apiserver 中查询到该 Pod,但是不能通过 apiserver 进行控制(例如不能删除)。

为什么需要静态 Pod ?

主要是用来对集群中的组件进行容器化操作,例如 etcd kube-apiserver kube-controller-manager kube-scheduler 这些都是静态 Pod 资源。

因为这些 Pod 不受 apiserver 的控制,就不会不小心被删掉的情况,同时 kube-apiserver 也不能自己去控制自己。静态 Pod 的存在将集群中的容器化操作提供了可能。

静态 Pod 的创建有两种方式,配置文件和 HTTP 两种方式,具体参见。静态 Pod 的创建

Pod的生命周期

Pod 在运行的过程中会被定义为各种状态,了解一些状态能帮助我们了解 Pod 的调度策略。当 Pod 被创建之后,就会进入健康检查状态,当 Kubernetes 确定当前 Pod 已经能够接受外部的请求时,才会将流量打到新的 Pod 上并继续对外提供服务,在这期间如果发生了错误就可能会触发重启机制。

不过 Pod 本身不具有自愈能力,如果 Pod 因为 Node 故障,或者是调度器本身故障,这个 Pod 就会被删除。所以 Pod 中一般使用控制器来管理 Pod ,来实现 Pod 的自愈能力和滚动更新的能力。

Pod的重启策略包括

  • Always 只要失败,就会重启;

  • OnFile 当容器终止运行,且退出码不是0,就会重启;

  • Never 从来不会重启。

重启的时间,是以2n来算。比如(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行 重置操作。

管理Pod的重启策略是靠控制器来完成的。

Pod 的几种状态

使用的过程中,会经常遇到下面几种 Pod 的状态。

Pending:Pod 创建已经提交给 k8s,但有一个或者多个容器尚未创建亦未运行,此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。这个状态可能就是在下载镜像;

Running:Pod 已经绑定到一个节点上了,并且已经创建了所有容器。至少有一个容器仍在运行,或者正处于启动或重启状态;

Secceeded:Pod 中的所有容器都已经成功终止,并且不会再重启;

Failed:Pod 中所有的容器均已经终止,并且至少有一个容器已经在故障中终止;

Unkown:因为某些原因无法取得 Pod 的状态。这种情况通常是因为与 Pod 所在主机通信失败。

当 pod 一直处于 Pending 状态,可通过 kubectl describe pods <node_name> -n namespace 来获取出错的信息

Pod 如何直接暴露服务

Pod 一般不直接对外暴露服务,一个 Pod 只是一个运行服务的实例,随时可能在节点上停止,然后再新的节点上用一个新的 IP 启动一个新的 Pod,因此不能使用确定的 IP 和端口号提供服务。这对于业务来说,就不能根据 Pod 的 IP 作为业务调度。kubernetes 就引入了 Service 的概 念,它为 Pod 提供一个入口,主要通过 Labels 标签来选择后端Pod,这时候不论后端 Pod 的 IP 地址如何变更,只要 Pod 的 Labels 标签没变,那么 业务通过 service 调度就不会存在问题。

不过使用 hostNetwork 和 hostPort,可以直接暴露 node 的 ip 地址。

hostNetwork

这是一种直接定义 Pod 网络的方式,使用 hostNetwork 配置网络,Pod 中的所有容器就直接暴露在宿主机的网络环境中,这时候,Pod 的 PodIP 就是其所在 Node 的 IP。从原理上来说,当设定 Pod 的网络为 Host 时,是设定了 Pod 中 pod-infrastructure(或pause)容器的网络为 Host,Pod 内部其他容器的网络指向该容器。

cat <<EOF >./pod-host.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80      hostNetwork: trueEOF

运行

$ kubectl apply -f pod-host.yaml -n study-k8s$ kubectl get pods -n study-k8s -o wideNAME                                READY   STATUS    RESTARTS   AGE     IP             NODE              NOMINATED NODE   READINESS GATESnginx-deployment-6d47cff9fd-5bzjq   1/1     Running   0          6m25s   192.168.56.111   kube-server8.zs   <none>           <none>$ curl http://192.168.56.111/<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>    body {        width: 35em;        margin: 0 auto;        font-family: Tahoma, Verdana, Arial, sans-serif;    }</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p><p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p></body></html>

一般情况下除非知道需要某个特定应用占用特定宿主机上的特定端口时才使用 hostNetwork: true 的方式。

hostPort

这是一种直接定义Pod网络的方式。

hostPort 是直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过宿主机的 IP 加上端口来访问 Pod。

cat <<EOF >./pod-hostPort.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 1  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80          hostPort: 8000EOF

运行

$ kubectl apply -f pod-hostPort.yaml -n study-k8s$ kubectl get pods -n study-k8s -o wideNAME                                READY   STATUS    RESTARTS   AGE     IP             NODE              NOMINATED NODE   READINESS GATESnginx-deployment-6d47cff9fd-5bzjq   1/1     Running   0          3m25s   192.168.56.111   kube-server8.zs   <none>           <none>$ curl http://192.168.56.111:8000/<!DOCTYPE html><html><head><title>Welcome to nginx!</title><style>    body {        width: 35em;        margin: 0 auto;        font-family: Tahoma, Verdana, Arial, sans-serif;    }</style></head><body><h1>Welcome to nginx!</h1><p>If you see this page, the nginx web server is successfully installed andworking. Further configuration is required.</p><p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p></body></html>

这种网络方式可以用来做 nginx [Ingress controller]。外部流量都需要通过 kubenretes node 节点的 80 和 443 端口。

hostNetwork 和 hostPort 的对比

相同点

hostNetwork 和 hostPort 的本质都是暴露 Pod 所在的节点 IP 给终端用户。因为 Pod 的生命周期并不固定,随时都有被重构的可能。可以使用 DaemonSet 或者非亲缘性策略,来保证每个 node 节点只有一个Pod 被部署。

不同点

使用 hostNetwork,pod 实际上用的是 pod 宿主机的网络地址空间;

使用 hostPort,pod IP 并非宿主机 IP,而是 cni 分配的 pod IP,跟其他普通的 pod 使用一样的 ip 分配*方式,端口并非宿主机网络监听端口,只是使用了 DNAT 机制将 hostPort 指定的端口映射到了容器的端口之上。

Label

Label 是 kubernetes 系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。

Label 可以添加到各种资源对象上,如 Node、Pod、Service、RC 等。Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。当我们给一个对象打了标签之后,随后就可以通过 Label Selector(标签选择器)查询和筛选拥有某些 Label 的资源对象。通过使用 Label 就能实现多维度的资源分组管理功能。

Label Selector 在 Kubernetes 中的重要使用场景如下:

1、Kube-controller 进程通过资源对象RC上定义的 Label Selector 来筛选要监控的 Pod 副本的数量,从而实现 Pod 副本的数量始终符合预期设定的全自动控制流程;

2、Kube-proxy 进程通过 Service 的 Label Selector 来选择对应的 Pod,自动建立起每个 Service 到对应 Pod 的请求转发路由表,从而实现 Service 的智能负载均衡机制;

3、通过对某些 Node 定义特定的 Label,并且在 Pod 定义文件中使用 NodeSelector 这种标签调度策略,kube-scheduler 进程可以实现 Pod “定向调度”的特性。

同时借助于 Label,k8s 中可以实现亲和(affinity)与反亲和(anti-affinity)调度。

亲和性调度

什么是亲和(affinity)与反亲和(anti-affinity)调度

Kubernetes 支持节点和 Pod 两个层级的亲和与反亲和。通过配置亲和与反亲和规则,可以允许您指定硬性限制或者偏好,例如将前台 Pod 和后台 Pod 部署在一起、某类应用部署到某些特定的节点、不同应用部署到不同的节点等等。

在学习亲和性调度之前,首先来看下如何进行打标签的操作

查看节点及其标签

$ kubectl get nodes --show-labels

给节点添加标签

$ kubectl label nodes <your-node-name> nodeName=node9

删除节点的标签

$ kubectl label nodes <your-node-name> nodeName-

查看某个标签的的分布情况

$ kubectl get node -L nodeNameNAME              STATUS   ROLES    AGE    VERSION   NODENAMEkube-server7.zs   Ready    <none>   485d   v1.19.9   node7kube-server8.zs   Ready    <none>   485d   v1.19.9   node8kube-server9.zs   Ready    master   485d   v1.19.9   node9
Node 亲和性调度策略
cat <<EOF >./pod-affinity.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 5  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80      affinity:        nodeAffinity:          requiredDuringSchedulingIgnoredDuringExecution:            nodeSelectorTerms:            - matchExpressions:              - key: nodeName                operator: In                values:                - node7                - node8EOF

重点看下下面的

affinity: // 表示亲和        nodeAffinity: // 表示节点亲和          requiredDuringSchedulingIgnoredDuringExecution:             nodeSelectorTerms:            - matchExpressions:              - key: nodeName                operator: In                values:                - node7                - node8

分析下具体的规则

requiredDuringSchedulingIgnoredDuringExecution 非常长,不过可以将这个分作两段来看:

前半段 requiredDuringScheduling 表示下面定义的规则必须强制满足(require)才会调度Pod到节点上;

后半段 IgnoredDuringExecution 表示已经在节点上运行的 Pod 不需要满足下面定义的规则,即去除节点上的某个标签,那些需要节点包含该标签的 Pod 不会被重新调度。

operator 有下面几种取值:

  • In:标签的值在某个列表中;

  • NotIn:标签的值不在某个列表中;

  • Exists:某个标签存在;

  • DoesNotExist:某个标签不存在;

  • Gt:标签的值大于某个值(字符串比较);

  • Lt:标签的值小于某个值(字符串比较)。

需要说明的是并没有 nodeAntiAffinity(节点反亲和),通过 NotIn 和 DoesNotExist 即可实现反亲和性地调度。

requiredDuringSchedulingIgnoredDuringExecution 是一种强制选择的规则。

preferredDuringSchedulingIgnoredDuringExecution 是优先选择规则,表示根据规则优先选择那些节点。

使用 preferredDuringSchedulingIgnoredDuringExecution 规则的时候,我们可以给 label 添加权重,这样 Pod 就能按照设计的规则调度到不同的节点中了。

cat <<EOF >./pod-affinity-weight.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 5  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80      affinity:        nodeAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - weight: 80             preference:               matchExpressions:               - key: nodeName                operator: In                 values:                 - node7                - node9          - weight: 20             preference:               matchExpressions:               - key: nodeName                operator: In                 values:                 - node8EOF

上面的栗子可以看到,可以给 label 添加 weight 权重,在 preferredDuringSchedulingIgnoredDuringExecution 的规则下,就能按照我们设计的权重,部署到 label 对应的节点中。

Pod 亲和性调度

除了支持 Node 的亲和性调度,k8s 中还支持 Pod 和 Pod 之间的亲和。

栗如:将应用的前端和后端部署在同一个节点中,从而减少访问延迟。

Pod 亲和同样有 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 两种规则。

模拟后端的 Pod 部署

cat <<EOF >./pod-affinity-backend.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: backend  labels:    app: backendspec:  replicas: 1  selector:    matchLabels:      app: backend  template:    metadata:      labels:        app: backend    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80EOF

模拟前端的 Pod 部署,使得前端对应的业务使用 Pod 亲和性调度和后端 Pod 部署到一起

cat <<EOF >./pod-affinity-frontend.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: frontend  labels:    app: frontendspec:  replicas: 5  selector:    matchLabels:      app: frontend  template:    metadata:      labels:        app: frontend    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80      affinity:        podAffinity:          requiredDuringSchedulingIgnoredDuringExecution:          - topologyKey: kubernetes.io/hostname            labelSelector:              matchExpressions:               - key: app                operator: In                 values:                 - backendEOF

这里把 backend 的 Pod 数量设置成 1,然后 frontend 的 Pod 数量设置成 5。这样来演示 frontend 向 backend 的亲和调度。

$ kubectl get pods -n study-k8s -o wideNAME                        READY   STATUS    RESTARTS   AGE   IP              NODE              NOMINATED NODE   READINESS GATESbackend-5f489d5d4f-xcv4d    1/1     Running             22s   10.233.67.179   kube-server8.zs   <none>           <none>frontend-64846f7fbf-6nsmd   1/1     Running             33s   10.233.67.181   kube-server8.zs   <none>           <none>frontend-64846f7fbf-7pfq7   1/1     Running             33s   10.233.67.182   kube-server8.zs   <none>           <none>frontend-64846f7fbf-dg7wx   1/1     Running             33s   10.233.67.178   kube-server8.zs   <none>           <none>frontend-64846f7fbf-q7jd5   1/1     Running             33s   10.233.67.177   kube-server8.zs   <none>           <none>frontend-64846f7fbf-v4hf9   1/1     Running             33s   10.233.67.180   kube-server8.zs   <none>           <none>

这里有两个点需要注意下

1、topologyKey 表示的指定的范围,指定的也是一个 label,通过指定这个 label 来确定安装的范围;

2、matchExpressions 指定亲和的 Pod,例如上面的栗子就是 app=frontend

不过这里有个先后顺序,首先匹配 topologyKey,然后匹配下面的 matchExpressions 规则。

Pod 的反亲和性调度

有时候我们希望 Pod 部署到一起,那么我们就会也有希望 Pod 不部署在一起的场景,这时候就需要用到反亲和性调度。

cat <<EOF >./pod-affinity-frontend.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: frontend  labels:    app: frontendspec:  replicas: 5  selector:    matchLabels:      app: frontend  template:    metadata:      labels:        app: frontend    spec:      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80      affinity:        podAntiAffinity:          requiredDuringSchedulingIgnoredDuringExecution:          - topologyKey: kubernetes.io/hostname            labelSelector:              matchExpressions:               - key: app                operator: In                 values:                 - backendEOF

使用 podAntiAffinity 即可定义反亲和性调度的策略

$ kubectl get pods -n study-k8s -o wideNAME                        READY   STATUS    RESTARTS   AGE    IP               NODE              NOMINATED NODE   READINESS GATESbackend-5f489d5d4f-xcv4d    1/1     Running             108m   10.233.67.179    kube-server8.zs   <none>           <none>frontend-567ddb4c45-6mf87   1/1     Running             23s    10.233.111.125   kube-server7.zs   <none>           <none>frontend-567ddb4c45-fbj6j   1/1     Running             23s    10.233.111.124   kube-server7.zs   <none>           <none>frontend-567ddb4c45-j5qpb   1/1     Running             21s    10.233.72.25     kube-server9.zs   <none>           <none>frontend-567ddb4c45-qsc8m   1/1     Running             21s    10.233.111.126   kube-server7.zs   <none>           <none>frontend-567ddb4c45-sfwjn   1/1     Running             23s    10.233.72.24     kube-server9.zs   <none>           <none>

NodeSelector 定向调度

kubernetes 中 kube-scheduler 负责实现 Pod 的调度,内部系统通过一系列算法最终计算出最佳的目标节点。如果需要将 Pod 调度到指定 Node 上,则可以通过 Node 的标签(Label)和 Pod 的 nodeSelector 属性相匹配来达到目的。

栗如:DaemonSet 中使用到了 NodeSelector 定向调度。

DaemonSet(守护进程),会在每一个节点中运行一个 Pod,同时也能保证只有一个 Pod 运行。

如果有新节点加入集群,Daemonset 会自动的在该节点上运行我们需要部署的 Pod 副本,如果有节点退出集群,Daemonset 也会移除掉部署在旧节点的 Pod 副本。

DaemonSet 适合一些系统层面的应用,例如日志收集,资源监控等,等这类需要每个节点都运行,且不需要太多的实例。

cat <<EOF >./pod-daemonset.yamlapiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-daemonset  labels:    app: nginx-daemonsetspec:  selector:    matchLabels:      app: nginx-daemonset  template:    metadata:      labels:        app: nginx-daemonset    spec:      nodeSelector: # 节点选择,当节点拥有nodeName=node7时才在节点上创建Pod        nodeName: node7      containers:      - name: nginx        image: nginx:1.14.2        ports:        - containerPort: 80EOF

可以看到 DaemonSet 也是通过 label 来选择部署的目标节点

nodeSelector: # 节点选择,当节点拥有nodeName=node7时才在节点上创建Pod        nodeName: node7

如果不添加目标节点,那么就是在所有节点中进行部署了。

资源限制

每个 Pod 都可以对其能使用的服务器上的计算资源设置限额,当前可以设置限额的计算资源有 CPU 和 Memory 两种,其中 CPU 的资源单位为 CPU(Core)的数量,是一个绝对值。

对于容器来说一个 CPU 的配额已经是相当大的资源配额了,所以在 Kubernetes 里,通常以千分之一的 CPU 配额为最小单位,用 m 来表示。通常一个容器的CPU配额被 定义为 100-300m,即占用0.1-0.3个CPU。与 CPU 配额类似,Memory 配额也是一个绝对值,它的单位是内存字节数。

对计算资源进行配额限定需要设定以下两个参数:

  • Requests:该资源的最小申请量,系统必须满足要求。

  • Limits:该资源最大允许使用的量,不能超过这个使用限制,当容器试图使用超过这个量的资源时,可能会被Kubernetes Kill并重启。

通常我们应该把 Requests 设置为一个比较小的数值,满足容器平时的工作负载情况下的资源需求,而把 Limits 设置为峰值负载情况下资源占用的最大量。下面是一个资源配额的简单定义:

spec:  containers:  - name: db    image: mysql    resources:      requests:        memory: "64Mi"        cpu: "250m"      limits:        memory: "128Mi"        cpu: "500m"

最小0.25个CPU及64MB内存,最大0.5个CPU及128MB内存。

当然 CPU 的指定也可以不使用 m。cpu: "2",就表示 2 个 cpu。

添加资源限制的目的

在业务流量请求较低的时候,释放多余的资源。当有一些突发性的活动,就能根据资源占用情况,申请合理的资源。

Pod 的持久化存储

volume 是 kubernetes Pod 中多个容器访问的共享目录。volume 被定义在 pod 上,被这个 pod 的多个容器挂载到相同或不同的路径下。volume 的生命周期与 pod 的生命周期相同,pod 内的容器停止和重启时一般不会影响 volume 中的数据。所以一般 volume 被用于持久化 pod 产生的数据。Kubernetes 提供了众多的 volume 类型,包括 emptyDir、hostPath、nfs、glusterfs、cephfs、ceph rbd 等。

1、emptyDir

emptyDir 类型的 volume 在 pod 分配到 node 上时被创建,kubernetes 会在 node 上自动分配 一个目录,因此无需指定宿主机 node 上对应的目录文件。这个目录的初始内容为空,当 Pod 从 node 上移除时,emptyDir 中的数据会被永久删除。emptyDir Volume 主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等。

容器的 crashing 事件并不会导致 emptyDir 中的数据被删除。

配置示例

cat <<EOF >./pod-emptyDir.yamlapiVersion: v1kind: Podmetadata:  name: test-pdspec:  containers:  - image: liz2019/test-webserver    name: test-container    volumeMounts:    - mountPath: /cache      name: cache-volume  volumes:  - name: cache-volume    emptyDir: {}EOF

2、hostPath

hostPath Volume 为 pod 挂载宿主机上的目录或文件,使得容器可以使用宿主机的高速文件系统进行存储。缺点是,在 k8s 中,pod 都是动态在各 node 节点上调度。当一个 pod 在当前 node 节点上启动并通过 hostPath 存储了文件到本地以后,下次调度到另一个节点上启动时,就无法使用在之前节点上存储的文件。

配置示例

cat <<EOF >./pod-hostPath.yamlapiVersion: v1kind: Podmetadata:  name: test-pdspec:  containers:  - image: liz2019/test-webserver    name: test-container    volumeMounts:    - mountPath: /cache      name: test-volume  volumes:  - name: test-volume    hostPath:      # directory location on host      path: /data-testEOF

3、Pod 持久化存储

1、 pod直接挂载nfs-server

我们能将 NFS (网络文件系统) 挂载到Pod 中,不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享,NFS 卷可以由多个pod同时挂载。

cat <<EOF >./pod-nfs.yamlapiVersion: v1kind: Podmetadata:  name: test-pdspec:  containers:  - image: liz2019/test-webserver    name: test-container    volumeMounts:    - mountPath: /cache      name: test-nfs  volumes:  - name: test-nfs    nfs:      path: /data-test      server: 192.268.56.111EOF

2、pv 和 pvc

具体什么是 pv 和 pvc,可参见 pv和pvc

创建 pv

cat <<EOF >./pv-demp.yamlapiVersion: v1kind: PersistentVolumemetadata:  name: pv001  labels:    name: pv001spec:  nfs:    path: /data/volumes/v1    server: nfs  accessModes: ["ReadWriteMany","ReadWriteOnce"]  capacity:    storage: 2Gi---apiVersion: v1kind: PersistentVolumemetadata:  name: pv002  labels:    name: pv002spec:  nfs:    path: /data/volumes/v2    server: nfs  accessModes: ["ReadWriteOnce"]  capacity:    storage: 1GiEOF

创建 pvc

cat <<EOF >./pvc-demp.yamlapiVersion: v1kind: PersistentVolumeClaimmetadata:  name: testpvc  namespace: defaultspec:  accessModes: ["ReadWriteMany"]  resources:    requests:      storage: 1GiEOF

业务绑定 pvc

cat <<EOF >./pod-pvc-cache.yamlapiVersion: v1kind: Podmetadata:  name: test-pdspec:  containers:  - image: liz2019/test-webserver    name: test-container    volumeMounts:    - mountPath: /cache      name: test-pvc-cache  volumes:  - name: test-pvc-cache    persistentVolumeClaim:      claimName: testpvcEOF

Pod 的探针

k8s 中当 Pod 的运行出现异常的时候,需要能够检测到 Pod 的这种状态,将流量路由到其他正常的 Pod 中,同时去恢复损坏的组件。

默认情况下,Kubernetes 会观察 Pod 生命周期,并在容器从挂起(pending)状态转移到成功(succeeded)状态时,将流量路由到 Pod。Kubelet 会监控崩溃的应用程序,并重新启动 Pod 进行恢复。

但是 Pod 的健康并不代表,Pod 中所有的容器都已经专准备好了,例如,这时候的应用可能正在启动,处于连接数据库的状态中,处于编译的状态中,这时候打进来的流量,得到的返回肯定就是异常的了。

k8s 中引入了活跃(Liveness)、就绪(Readiness)和启动(Startup)探针来解决上面的问题。

存活探针:主要来检测容器中的应用程序是否正常运行,如果检测失败,就会使用 Pod 中设置的 restartPolicy 策略来判断,Pod是否要进行重启, 例如,存活探针可以探测到应用死锁。

就绪探针:可以判断容器已经启动就绪能够接收流量请求了,当一个 Pod 中所有的容器都就绪的时候,才认为该 Pod 已经就绪了。就绪探针就能够用来避免上文中提到的,应用程序未完全就绪,然后就有流量打进来的情况发生。

启动探针:kubelet 使用启动探针来了解应用容器何时启动。启动探针主要是用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。

如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。

如果启动探测失败,kubelet 将杀死容器,而容器依其重启策略进行重启。

在配置探针之前先来看下几个主要的配置

initialDelaySeconds:容器启动后要等待多少秒后才启动存活和就绪探针, 默认是 0 秒,最小值是 0;

periodSeconds:执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1;

timeoutSeconds:探测的超时后等待多少秒。默认值是 1 秒。最小值是 1;

successThreshold:探针在失败后,被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1;

failureThreshold:将探针标记为失败之前的重试次数。对于 liveness 探针,这将导致 Pod 重新启动。对于 readiness 探针,将标记 Pod 为未就绪(unready)。

目前 ReadinessProbe 和 LivenessProbe 都支持下面三种探测方法

ExecAction:在容器中执行指定的命令,如果能成功执行,则探测成功;

HTTPGetAction:通过容器的IP地址、端口号及路径调用HTTP Get方法,如果响应的状态码200-400,则认为容器探测成功;

TCPSocketAction:通过容器IP地址和端口号执行TCP检查,如果能建立TCP连接,则探测成功;

gRPC 活跃探针:在 Kubernetes v1.24 [beta]中引入了,gRPC 活跃探针,如果应用实现了 gRPC 健康检查协议 ,kubelet 可以配置为使用该协议来执行应用活跃性检查。不过使用的时候需要先开启。

这里来看下使用 HTTPGetAction 的方式,来看下存活探针和就绪探针的配置,其他的可参考配置存活、就绪和启动探针

cat <<EOF >./pod-test-go-liveness.yamlapiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: test-go-liveness  name: test-go-liveness  namespace: study-k8sspec:  replicas: 5  selector:    matchLabels:      app: go-web  strategy: {}  template:    metadata:      creationTimestamp: null      labels:        app: go-web    spec:      containers:      - image: liz2019/test-go-liveness        name: test-go-liveness        livenessProbe: # 活跃探针          httpGet:            path: /healthz            port: 8001          initialDelaySeconds: 15          periodSeconds: 10          timeoutSeconds: 5        readinessProbe: # 存活探针          httpGet:            path: /healthz            port: 8001          initialDelaySeconds: 5 # 容器启动后多少秒启动探针          periodSeconds: 10 # 执行探针检测的时间建个间隔          timeoutSeconds: 5 # 探测的超时后等待多少秒status: {}EOF

可以看到上面同时设置了存活探针和就绪探针;

对于镜像中的代码设置了超过十秒即返回错误,这样上面的示例就能模拟探针检测失败,然后重启的效果了

func healthz(w http.ResponseWriter, r *http.Request) {	duration := time.Now().Sub(started)	w.Header().Set("Content-Type", "application/json; charset=utf-8")	if duration.Seconds() > 10 {		w.WriteHeader(500)		w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))	} else {		w.WriteHeader(200)		w.Write([]byte("ok"))	}}

查看 Pod 的重启情况

kubectl get pods -n study-k8sNAME                                READY   STATUS             RESTARTS   AGEtest-go-liveness-66755487cd-ck4mz   /1     CrashLoopBackOff   6          11mtest-go-liveness-66755487cd-f54lz   /1     CrashLoopBackOff   6          11mtest-go-liveness-66755487cd-hts8k   /1     CrashLoopBackOff   7          11mtest-go-liveness-66755487cd-jzsmb   /1     Running            7          11mtest-go-liveness-66755487cd-k9hdk   1/1     Running            7          11m

下面在简单看下启动探针的配置

ports:- name: liveness-port  containerPort: 8080  hostPort: 8080livenessProbe:  httpGet:    path: /healthz    port: liveness-port  failureThreshold: 1  periodSeconds: 10startupProbe:  httpGet:    path: /healthz    port: liveness-port  failureThreshold: 30 # 将探针标记为失败之前的重试次数  periodSeconds: 10 # 执行探测的时间间隔(单位是秒)

上面配置了启动探针,那么程序就会有 30 * 10 = 300s 来完成启动过程。 一旦启动探测成功一次,存活探测任务就会接管对容器的探测,对容器死锁作出快速响应。 如果启动探测一直没有成功,容器会在 300 秒后被杀死,并且根据 restartPolicy 来 执行进一步处置。

使用 HPA 实现 Pod 的自动扩容

我们通过手动更改 RS 副本集的大小就能实现 Pod 的扩容,但是这是我们手动操作的,人工不可能24小时不间断的检测业务的复杂变化。所以需要自动扩容的机制,能够根据业务的变化,自动的实现 Pod 的扩容和缩容。

Kubernetes 提供 Horizontal Pod Autoscaling(Pod 水平自动伸缩),简称 HPA。通过使用 HPA 可以自动缩放在 Replication Controller,Deployment 或者 Replica Set 中的 Pod。HPA 将自动缩放正在运行的 Pod 的数量,以实现最高效率。

HPA 中影响 Pod 数量的因素包括:

  • 用户定义的允许运行的 Pod 的最小和最大数量;

  • 资源指标中报告的观察到的 CPU 或内存使用情况;

  • 第三方指标应用程序(例如 Prometheus,Datadog 等)提供的自定义指标。

HPA 是如何工作的


HPA 是用来控制 Pod 水平伸缩的控制器,基于设定的扩缩容规则,实时采集监控指标数据,根据用户设定的指标阈值计算副本数,进而调整目标资源的副本数量,完成扩缩容操作。

算法的细节

Pod 水平自动扩缩控制器根据当前指标和期望指标来计算扩缩比例

期望副本数 = ceil[当前副本数 * (当前指标 / 期望指标)]

例如,如果当前指标值为 200m,而期望值为 100m,则副本数将加倍, 因为 200.0 / 100.0 == 2.0 如果当前值为 50m,则副本数将减半, 因为 50.0 / 100.0 == 0.5。如果比率足够接近 1.0(在全局可配置的容差范围内,默认为 0.1), 则控制平面会跳过扩缩操作。

如果 HorizontalPodAutoscaler 指定的是 targetAverageValue 或 targetAverageUtilization, 那么将会把指定 Pod 度量值的平均值做为当前指标。

HPA 控制器执行扩缩操作并不是马上完成的,会有一个扩缩操作的时间窗口。首先每次的扩缩操作建议会被记录,在扩缩操作的时间窗口内,会根据规则选出一个缩容的策略。这样就能让系统更平滑的进行扩缩操作,消除短时间内指标波动带来的影响。时间窗口的值可通过 kube-controller-manager 服务的启动参数 --horizontal-pod-autoscaler-downscale-stabilization 进行配置, 默认值为 5 分钟。

来个栗子实践下

cat <<EOF >./pod-hpa.yamlapiVersion: apps/v1kind: Deploymentmetadata:  creationTimestamp: null  labels:    app: go-web  name: go-web  namespace: study-k8sspec:  replicas: 5  selector:    matchLabels:      app: go-web  strategy: {}  template:    metadata:      creationTimestamp: null      labels:        app: go-web    spec:      containers:      - image: liz2019/test-docker-go-hub        name: go-app-container        resources:           requests:            cpu: 0.1            memory: 50Mi          limits:            cpu: 0.2            memory: 100Mistatus: {}---apiVersion: v1kind: Servicemetadata:  name: go-web-svc  labels:    run: go-web-svcspec:  selector:    app: go-web  type: NodePort # 服务类型  ports:    - protocol: TCP      port: 8000      targetPort: 8000      nodePort: 30001  # 对外暴露的端口      name: go-web-httpEOF

配置 HPA 策略

cat <<EOF >./pod-hpa-config.yamlapiVersion: autoscaling/v2beta2kind: HorizontalPodAutoscalermetadata:  name: go-web-hpa  namespace: study-k8sspec:  scaleTargetRef:    apiVersion: apps/v1    kind: Deployment    name: go-web  minReplicas: 1  maxReplicas: 10  metrics:  - type: Resource    resource:      name: cpu      target:              type: Utilization        averageUtilization: 50EOF

关于 HPA 的版本支持

autoscaling/v1只支持CPU一个指标的弹性伸缩;

autoscaling/v2beta1支持自定义指标;

autoscaling/v2beta2支持外部指标;

总结

1、Pod 是 Kubernetes 集群中能够被创建和管理的最小部署单元;

2、通常使用控制起来管理 Pod,来实现 Pod 的滚动升级,副本管理,集群级别的自愈能力;

3、Deployment 可以用来创建一个新的服务,更新一个新的服务,也可以用来滚动升级一个服务。借助于 ReplicaSet 也可以实现 Pod 的副本管理功能;

4、静态 Pod 是由 kubelet 进行管理的仅存在与特定 node 上的 Pod,他们不能通过 api server 进行管理,无法与 rc,deployment,ds 进行关联,并且 kubelet 无法对他们进行健康检查;

5、静态 Pod 主要是用来对集群中的组件进行容器化操作,例如 etcd kube-apiserver kube-controller-manager kube-scheduler 这些都是静态 Pod 资源;

6、Pod 一般不直接对外暴露服务,一个 Pod 只是一个运行服务的实例,随时可能在节点上停止,然后再新的节点上用一个新的 IP 启动一个新的 Pod,因此不能使用确定的 IP 和端口号提供服务;

7、Pod 中可以使用 hostNetwork 和 hostPort,可以直接暴露 node 的 ip 地址;

8、Label 是 kubernetes 系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择;

9、Kubernetes 支持节点和 Pod 两个层级的亲和与反亲和。通过配置亲和与反亲和规则,可以允许您指定硬性限制或者偏好,例如将前台 Pod 和后台 Pod 部署在一起、某类应用部署到某些特定的节点、不同应用部署到不同的节点等等;

10、为了合理的利用 k8s 中的资源,一般会对 Pod 添加资源限制;

11、k8s 中当 Pod 的运行出现异常的时候,需要能够检测到 Pod 的这种状态,将流量路由到其他正常的 Pod 中,同时去恢复损坏的组件,这种情况可以通过 K8s 中的探针去解决;

12、面对业务情况的变化,使用 HPA 实现 Pod 的自动扩容;

参考

【初识Kubernetes(K8s):各种资源对象的理解和定义】https://blog.51cto.com/andyxu/2329257
【Kubernetes系列学习文章 - Pod的深入理解(四)】https://cloud.tencent.com/developer/article/1443520
【详解 Kubernetes Pod 的实现原理】https://draveness.me/kubernetes-pod/
【Kubernetes 之Pod学习】https://www.cnblogs.com/kevingrace/p/11309409.html
【亲和与反亲和调度】https://support.huaweicloud.com/intl/zh-cn/basics-cce/kubernetes_0018.html
【hpa】https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/
【k8s中的Pod细节了解】https://boilingfrog.github.io/2022/09/23/k8s中的Pod细节了解/


标签:节点 容器 探针
2流高手速成记(之二):跳羚之基础网开发
« 上一篇 2022-09-24
  • 2流高手速成记(之二):跳羚之基础网开发
    0阅读 0条评论 个赞
    现在,我们已经能自行完成SpringBoot的初级项目搭建了,接下来看如何实现一些Web开发中的基础功能。先看项目完整的目录结构:1.返回Json数据创建model文件夹,并新建Person类,代码……
  • Lua脚本在Redis交易中的应用实践
    0阅读 0条评论 个赞
    使用过Redis事务的应该清楚,Redis事务实现是通过打包多条命令,单独的隔离操作,事务中的所有命令都会按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。事务中的命令要么全部……
  • IDEA远程部署项目到Docker
    0阅读 0条评论 个赞
    前言最近在写东西部署到服务器,结构是springboot工程配合docker部署。但是每次部署都3个步骤:本地构建jar复制jar到远程服务器用DockerFile构建镜像部署次数一多,我就怀疑人生了……
  • Object.keys的‘怪异’特性 你值得收藏!
    0阅读 0条评论 个赞
    先从‘诡异’的问题入手例1:纯Number类型的属性constobj={1:1,6:6,3:3,2:2}console.log('keys',Object.keys(o……
  • 在Winform开发中 我们使用几个下拉列表来显示字典数据
    0阅读 0条评论 个赞
    在Winform开发中中,我们为了方便客户选择,往往使用系统的字典数据选择,毕竟选择总比输入来的快捷、统一,一般我们都会简单封装一下,以便方便对控件的字典值进行展示处理,本篇随笔介绍DevExpres……
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
  • 谈不可靠的数据库安全扫描
    0阅读 0条评论 个赞
    前阵子就有朋友留言说让我吐槽吐槽数据库安全扫描,此言正合我意。这些年,企业安全事故频发,勒索病毒事故多出,再加上安全对抗演练的进行,让数据库安全在企业里的地位与日俱增,安全扫描也变成了头等大事。也经常……
  • VUE:引入腾讯地图 实现赛道动画
    0阅读 0条评论 个赞
    效果:引入步骤:在html中通过引入script标签加载API服务在一个盒子元素div中预先准备地图容器,并在CSS样式中定义地图(容器)显示大小创建并显示地图的代码创建动画和标记1.在……
  • SQL Server:触发器的详细说明
    0阅读 0条评论 个赞
    1.概述2.触发器的分类3.Inserted和Deleted表4.触发器的执行过程5.创建触发器6.修改触发器:7.删除触发器:8.查看数据库中已有触发器:9.“Insteadof……
  • python入门系列(十)学习Python文件处理
    0阅读 0条评论 个赞
    文件处理在Python中处理文件的关键函数是open()函数。有四种不同的方法(模式)来打开一个文件"r"-读取-默认值。打开一个文件进行读取,如果文件不存在则出错。"a"-Append……
  • 新零售SaaS架构:商品系统架构设计
    6阅读 0条评论 个赞
    SaaS产品就像一座冰山,冰山以上的部分是功能、数据(可见部分)、用户界面,冰山以下是系统架构、完整的数据模型、开放体系、非功能性需求(扩展性、可维护性、性能、安全等)。短期内想要快速上线产品,可能只……
  • 解决ShardingJdbc不支持复杂SQL问题的说明
    18阅读 0条评论 个赞
    背景介绍公司最近做分库分表业务,接入了ShardingJDBC,接入完成后,回归测试时发现好几个SQL执行报错,关键这几个表都还不是分片表。报错如下:这下糟了嘛。熟悉ShardingJDB……
  • 前端必读:如何用JavaScript中的SpreadJS导入导出Excel文件
    0阅读 0条评论 个赞
    JavaScript在前端领域占据着绝对的统治地位,目前更是从浏览器到服务端,移动端,嵌入式,几乎所有的所有的应用领域都可以使用它。技术圈有一句很经典的话“凡是能用JavaScript实现的东西,最后……
  • SQL Server合并(删除)分区的歧义消除
    4阅读 0条评论 个赞
    一、准备在SQLServer2005版本之后就有了表分区的概念与应用,在分区操作里面有一个叫做合并分区的功能,也被称为删除分区。分区所处的文件组和文件是不会被删除的,只会对数据进行转移合并。合并分……
  • 自动化测试选择Python还是Java?
    0阅读 0条评论 个赞
    你好,我是测试蔡坨坨。今天,我们来聊一聊测试人员想要进阶,想要做自动化测试,甚至测试开发,如何选择编程语言。前言自动化测试,这几年行业内的热词,也是测试人员进阶的必备技能,更是软件测试未来发展的趋势。……
  • 面试官:为什么系统不推荐双写?
    0阅读 0条评论 个赞
    某日,阿雄跑去面试!于是有如下情形面试官:"阿雄是吧,做做自我介绍!"阿雄:"我叫阿雄,来自某a国际电商公司!"面试官:"我看你项目里用了elasticsearch,你是怎么同步数据的呢?"阿……
  • 当老板让我从Java8升级到Java11时
    4阅读 0条评论 个赞
    老板让我把一个项目从Java8迁移到Java11,我该怎么办呢?最简单的办法,当然是直接强行升级,遇到一个错就改一个错,别看它low,但是对于一个小型且非核心的项目来说,已经足够了。当然,……
  • MQ系列5:5的发送模式:RocketMQ消息
    0阅读 0条评论 个赞
    在之前的篇章中,我们学习了RocketMQ的原理,以及RocketMQ中命名服务ServiceName的运行流程,本篇从消息的生产、消费来理解一条消息的生命周期。1消息生产在RocketMQ中……
  • 拓扑岭CEO雷鹏:创业不只是技术
    0阅读 0条评论 个赞
    云计算的出现,加速了企业信息技术的发展。数据库是最常用的基础软件之一,它通常能提供计算和存储的能力。虽然分布式数据库也做到了很好的扩展性,但它不能算是「云原生」。「云原生数据库」的核心,是要设计一种更……
  • SQL Server十进制类型(浮点和十进制)
    0阅读 0条评论 个赞
    在SQLServer中,实际上小数数值只有两种数据类型:float和decimal,分别是近似数值和精确数值。其他小数类型,都可以使用float和decimal来替代,例如,双精度(doublep……
  • 转:Java老了 科特林会取而代之吗?
    0阅读 0条评论 个赞
    .css-1yuhvjn{margin-top:16px;}.css-3jt6os.FileLinkCard{-webkit-align-items:center;-webkit-box-align……
  • 在i.MX8MP开发板中移植OpenSSL工具
    0阅读 0条评论 个赞
    飞凌嵌入式OKMX8MP-C开发板采用NXPi.MX8MPlus高性能处理器开发,AI计算能力高达2.3TOPS,可满足轻量级边缘计算需求。同时灵活的I/O接口配置和先进丰富的多媒体资源,方便客户……
  • 谈谈动态线程池的9个场景(改进版)
    0阅读 0条评论 个赞
    大家好,我是小马哥。线程池是一种基于池化思想管理线程的工具,使用线程池可以减少创建销毁线程的开销,避免线程过多导致系统资源耗尽。在高并发以及大批量的任务处理场景,线程池的使用是必不可少的。……
  • 中国台湾的建设:有效登陆中国台湾的六脉神剑
    0阅读 0条评论 个赞
    在数字化时代,数字化体系的建设需要的是系统化的规划和产品化的迭代的模式,基于企业核心业务能力体系,做中台化的持续建设与落地,则是一种不错的选择。所以,企业业务中台的建设和落地,是关系到企业数字化战略成……
  • IDEA远程部署项目到Docker
    0阅读 0条评论 个赞
    前言最近在写东西部署到服务器,结构是springboot工程配合docker部署。但是每次部署都3个步骤:本地构建jar复制jar到远程服务器用DockerFile构建镜像部署次数一多,我就怀疑人生了……
  • 内存泄漏——原因、避免和位置
    0阅读 0条评论 个赞
    .css-1yuhvjn{margin-top:16px;}.css-3jt6os.FileLinkCard{-webkit-align-items:center;-webkit-box-align……
最近发布资讯
更多