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

从零开始的云计算生活——激流勇进,kubernetes模块之Pod资源对象

目录

一.故事背景

二.Pod概述

三.K8S-组件介绍

1.概述

K8S的由来

K8S的功能

K8S解决的问题

K8S的特性

2.K8S架构与组件

K8S架构

K8S组件

master 节点组件

Kube-apiserver

Kube-controller-manager

Kube-scheduler

etcd

node节点组件

Kubelet

Kube-Proxy

Controller Runtime

Pod

四.POD创建过程(重要)

五.Pod资源清单详解

5.1 Pod资源清单介绍

5.1.1 资源清单必须存在的属性

5.1.2 主要对象

5.1.3 额外的参数项

5.2 POD YAML文件示例

5.3 标签

5.3.1 什么是标签?

5.3.2 给pod资源打标签

通过yaml文件修改

通过命令修改

5.3.3 查看资源标签

5.4 资源限制

5.4.1 节点资源不足,导致调度失败

5.4.2 所在命名空间资源不足

5.5 Pod探针

5.5.1 kubelet检查机制

5.5.2 探针返回结果

5.5.3 探针的类型

5.5.4 探针属性

5.5.5 livenessProbe探针案例

5.5.5.1 livenessProbe和kubelet-exec

5.5.5.2 livenessProbe和kubelet-httpGet

5.5.5.3 livenessProbe和kubelet-tcpSocket

5.5.6 readinessProbe探针案例

5.5.6.1 readinessProbe和kubelet-exec

5.5.6.3 readinessProbe和kubelet-tcpSocket

5.6 Pod案例

5.6.1 生成YAML文件

5.6.2 创建Pod

六.Pod常用命令

七.Pod状态

7.1 常用的排障命令

7.2 常见故障归类

八.总结


一.故事背景

结束上两个模块的内容之后,接下来学习Pod资源对象

二.Pod概述

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元

Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个) 容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。 Pod 中的容器总是并置(colocated)的并且一同调度,在共享的上下文中运行。 Pod 所建模的是特定于应用的 “逻辑主机”,其中包含一个或多个应用容器, 这些容器相对紧密地耦合在一起。 在非云环境中,在相同的物理机或虚拟机上运行的应用类似于在同一逻辑主机上运行的云应用。

除了应用容器,Pod 还可以包含在 Pod 启动期间运行的 Init 容器。 你也可以在集群支持临时性容器的情况下, 为调试的目的注入临时性容器。

Pod 的共享上下文包括一组 Linux 名字空间、控制组(cgroup)和可能一些其他的隔离方面, 即用来隔离容器的技术。 在 Pod 的上下文中,每个独立的应用可能会进一步实施隔离。

Pod 类似于共享名字空间并共享文件系统卷的一组容器。

三.K8S-组件介绍

1.概述

Kubernetes 简称 k8s,是支持云原生部署的一个平台,起源于谷歌。谷歌早在十几年之前就对其应用,通过容器方式进行部署。

k8s 本质上就是用来简化微服务的开发和部署的,关注点包括自愈和自动伸缩、调度和发布、调用链监控、配置管理、Metrics 监控、日志监控、弹性和容错、API 管理、服务安全等,k8s 将这些微服务的公共关注点以组件形式封装打包到 k8s 这个大平台中,让开发人员在开发微服务时专注于业务逻辑的实现,而不需要去特别关心微服务底层的这些公共关注点,大大简化了微服务应用的开发和部署,提高了开发效率。

K8S的由来

  • K8S由google的Borg系统(博格系统,google内部使用的大规模容器编排工具)作为原型,后经GO语言延用Borg的思路重写并捐献给CNCF基金会开源。

  • 云原生基金会(CNCF)于2015年12月成立,隶属于Linux基金会。CNCF孵化的第一个项目就是Kubernetes,随着容器的广泛使用,Kubernetes已经成为容器编排工具的事实标准。

K8S的功能

  • 跨主机编排容器。

  • 更充分地利用硬件资源来最大化地满足企业应用的需求。

  • 控制与自动化应用的部署与升级。

  • 为有状态的应用程序挂载和添加存储器。

  • 线上扩展或缩减容器化应用程序与它们的资源。

  • 声明式的容器管理,保证所部署的应用按照我们部署的方式运作。

  • 通过自动布局、自动重启、自动复制、自动伸缩实现应用的状态检查与自我修复。

  • 为多个容器提供服务发现和负载均衡,使得用户无需考虑容器IP问题。

K8S解决的问题

K8S 解决了裸跑 Docker 的若干痛点:

  • 单机使用,无法有效集群

  • 随着容器数量的上升,管理成本攀升

  • 没有有效的容灾、自愈机制

  • 没有预设编排模板,无法实现快速、大规模容器调度

  • 没有统一的配置管理中心工具

  • 没有容器生命周期的管理工具

  • 没有图形化运维管理工具

K8S 提供了容器编排,资源调度,弹性伸缩,部署管理,服务发现等一系列功能。

K8S的特性

  • 弹性伸缩

  使用命令、UI 或者基于 CPU 使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性;业务低峰时回收资源,以最小成本运行服务。

  • 自我修复

  在节点故障时重新启动失败的容器,替换和重新部署,保证预期的副本数量;杀死健康检查失败的容器,并且在未准备好之前不会处理客户端请求,确保线上服务不中断。

  • 自动发布(默认滚动发布模式)和回滚

  K8S 采用滚动更新策略更新应用,一次更新一个 Pod,而不是同时删除所有 Pod,如果更新过程中出现问题,将回滚更改,确保升级不影响业务。

  • 集中化配置管理和密钥管理

  管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在 K8S 中,方便应用程序使用。

  • 存储编排,支持外挂存储并对外挂存储资源进行编排

  挂载外部存储系统,无论是来自本地存储,公有云(如 AWS),还是网络存储(如 NFS、GlusterFS、Ceph)都作为集群资源的一部分使用,极大提高存储使用灵活性。

  • 任务批处理运行

  提供一次性任务,定时任务;满足批量数据处理和分析的场景。

2.K8S架构与组件

K8S架构

k8s 总体架构采用了经典的 maste/slave 架构模式,分 master 节点和 worker 节点,节点可以是虚拟机也可以是物理机。

K8S组件

master 节点组件
Kube-apiserver
  • 用于暴露 Kubernetes API,任何资源请求或调用操作都是通过 kube-apiserver 提供的接口进行。以 HTTPRestful API 提供接口服务,所有对象资源的增删改查和监听操作都交给 API Server 处理后再提交给 Etcd 存储。

  • 可以理解成 API Server 是 K8S 的请求入口服务。API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI命令行工具), 然后根据用户的具体请求,去通知其他组件干活。可以说 API Server 是 K8S 集群架构的大脑。

Kube-controller-manager
  • 运行管理控制器,是 K8S 集群中处理常规任务的后台线程,是 K8S 集群里所有资源对象的自动化控制中心。在 K8S 集群中,一个资源对应一个控制器,而 Controller manager 就是负责管理这些控制器的。

  • 由一系列控制器组成,通过 API Server 监控整个集群的状态,并确保集群处于预期的工作状态,比如当某个 Node意外宕机时,Controller Manager 会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。

控制器类型作用
Node Controller(节点控制器)负责在节点出现故障时发现和响应。
Replication Controller(副本控制器)负责保证集群中一个 RC(资源对象 Replication Controller)所关联的 Pod 副本数始终保持预设值。可以理解成确保集群中有且仅有 N 个 Pod 实例,N 是 RC 中定义的 Pod 副本数量。
EndpointsController(端点控制器)填充端点对象(即连接 Services 和 Pods),负责监听 Service 和对应的 Pod副本的变化。 可以理解端点是一个服务暴露出来的访问点,如果需要访问一个服务,则必须知道它的 endpoint。
Service Account & Token Controllers(服务帐户和令牌控制器)为新的命名空间创建默认帐户和 API 访问令牌。
ResourceQuota Controller(资源配额控制器)确保指定的资源对象在任何时候都不会超量占用系统物理资源。
Namespace Controller(命名空间控制器)管理 namespace 的生命周期。
Service Controller(服务控制器)属于 K8S 集群与外部的云平台之间的一个接口控制器。
Kube-scheduler
  • 是负责资源调度的进程,根据调度算法为新创建的 Pod 选择一个合适的 Node 节点。

  • 可以理解成 K8S 所有 Node 节点的调度器。当用户要部署服务时,Scheduler 会根据调度算法选择最合适的 Node 节点来部署 Pod。

  • 预选策略(predicate)

  • 优选策略(priorities)

etcd
  • K8S 的存储服务。etcd 是分布式键值存储系统,存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据。

node节点组件

在 Kubernetes 集群中,在每个 Node(又称 Worker Node)上都会启动一个 kubelet 服务进程。该进程用于处理 Master 下发到本节点的任务,管理 Pod 及 Pod 中的容器。每个 kubelet 进程都会在 API Server 上注册节点自身的信息,定期向 Master 汇报节点资源的使用情况,并通过 cAdvisor 监控容器和节点资源。

Kubelet
  • Node 节点的监视器,以及与 Master 节点的通讯器。Kubelet 是 Master 节点安插在 Node 节点上的“眼线”,它会定时向 API Server 汇报自己 Node 节点上运行的服务的状态,并接受来自 Master 节点的指示采取调整措施。

  • 从 Master 节点获取自己节点上 Pod 的期望状态(比如运行什么容器、运行的副本数量、网络或者存储如何配置等), 直接跟容器引擎交互实现容器的生命周期管理,如果自己节点上 Pod 的状态与期望状态不一致,则调用对应的容器平台接口(即 docker 的接口)达到这个状态。

  • 管理镜像和容器的清理工作,保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源。

Kube-Proxy
  • 在每个 Node 节点上实现 Pod 网络代理,是 Kubernetes Service 资源的载体,负责维护网络规则和四层负载均衡工作。 负责写入规则至iptables、ipvs实现服务映射访问的。

  • Kube-Proxy 本身不是直接给 Pod 提供网络,Pod 的网络是由 Kubelet 提供的,Kube-Proxy 实际上维护的是虚拟的 Pod 集群网络。

  • Kube-apiserver 通过监控 Kube-Proxy 进行对 Kubernetes Service 的更新和端点的维护。

  • 在 K8S 集群中微服务的负载均衡是由 Kube-proxy 实现的。Kube-proxy 是 K8S 集群内部的负载均衡器。它是一个分布式代理服务器,在 K8S 的每个节点上都会运行一个 Kube-proxy 组件。

Controller Runtime
  • 容器引擎,如:docker、containerd,运行容器,负责本机的容器创建和管理工作。

  • 当 kubernetes 把 pod 调度到节点上,节点上的 kubelet会指示 docker 启动特定的容器。接着,kubelet 会通过 docker 持续地收集容器的信息, 然后提交到主节点上。docker 会如往常一样拉取容器镜像、启动或停止容器。不同点仅仅在于这是由自动化系统控制而非管理员在每个节点上手动操作的。

Pod

k8s 中特有的一个概念,可以理解为对容器的包装,是 k8s 的基本调度单位,一个 Pod 代表集群上正在运行的一个进程,实际的容器是运行在 Pod 中的, 可以把 Pod 理解成豌豆荚,而同一 Pod 内的每个容器是一颗颗豌豆。一个节点可以启动一个或多个 Pod。生产环境中一般都是单个容器或者具有强关联互补的多个容器组成一个 Pod。

四.POD创建过程(重要)

第一步: ​ 客户端提交创建Pod的请求,可以通过调用API Server的Rest API接口,也可以通过kubectl命令行工具。如kubectl apply -f filename.yaml(资源清单文件) ​

第二步: ​ apiserver接收到pod创建请求后,会将yaml中的属性信息(metadata)写入etcd。

第三步: ​ apiserver触发watch机制准备创建pod,信息转发给调度器scheduler,调度器用一组规则过滤掉不符合要求的主机,比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。调度器使用调度算法选择node,调度器将node信息给apiserver,apiserver将绑定的node信息写入etcd。 ​

第四步: ​ apiserver又通过watch机制,调用kubelet,指定pod信息,调用Docker API创建并启动pod内的容器。 ​

第五步: ​ worker创建完成之后反馈给自身的kubelet, 再反馈给控制器的kubelet,然后将pod的状态信息给apiserver,apiserver又将pod的状态信息写入etcd

五.Pod资源清单详解

5.1 Pod资源清单介绍

#查看对象中包含哪些字段

[root@k8s-master ~]# kubectl explain pod.spec.containers
KIND:       Pod
VERSION:    v1FIELD: containers <[]Container>DESCRIPTION:List of containers belonging to the pod. Containers cannot currently beadded or removed. There must be at least one container in a Pod. Cannot beupdated.A single application container that you want to run within a pod.FIELDS:args  <[]string>Arguments to the entrypoint. The container image's CMD is used if this isnot provided. Variable references $(VAR_NAME) are expanded using thecontainer's environment. If a variable cannot be resolved, the reference inthe input string will be unchanged. Double $$ are reduced to a single $,which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" willproduce the string literal "$(VAR_NAME)". Escaped references will never beexpanded, regardless of whether the variable exists or not. Cannot beupdated. More info:https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shellcommand       <[]string>Entrypoint array. Not executed within a shell. The container image'sENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME)are expanded using the container's environment. If a variable cannot beresolved, the reference in the input string will be unchanged. Double $$ arereduced to a single $, which allows for escaping the $(VAR_NAME) syntax:i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escapedreferences will never be expanded, regardless of whether the variable existsor not. Cannot be updated. More info:https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shellenv   <[]EnvVar>List of environment variables to set in the container. Cannot be updated.envFrom       <[]EnvFromSource>List of sources to populate environment variables in the container. The keysdefined within a source must be a C_IDENTIFIER. All invalid keys will bereported as an event when the container is starting. When a key exists inmultiple sources, the value associated with the last source will takeprecedence. Values defined by an Env with a duplicate key will takeprecedence. Cannot be updated.image <string>Container image name. More info:https://kubernetes.io/docs/concepts/containers/images This field is optionalto allow higher level config management to default or override containerimages in workload controllers like Deployments and StatefulSets.imagePullPolicy       <string>Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if:latest tag is specified, or IfNotPresent otherwise. Cannot be updated. Moreinfo: https://kubernetes.io/docs/concepts/containers/images#updating-imagesPossible enum values:- `"Always"` means that kubelet always attempts to pull the latest image.Container will fail If the pull fails.- `"IfNotPresent"` means that kubelet pulls if the image isn't present ondisk. Container will fail if the image isn't present and the pull fails.- `"Never"` means that kubelet never pulls an image, but only uses a localimage. Container will fail if the image isn't presentlifecycle     <Lifecycle>Actions that the management system should take in response to containerlifecycle events. Cannot be updated.livenessProbe <Probe>Periodic probe of container liveness. Container will be restarted if theprobe fails. Cannot be updated. More info:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probesname  <string> -required-Name of the container specified as a DNS_LABEL. Each container in a pod musthave a unique name (DNS_LABEL). Cannot be updated.ports <[]ContainerPort>List of ports to expose from the container. Not specifying a port here DOESNOT prevent that port from being exposed. Any port which is listening on thedefault "0.0.0.0" address inside a container will be accessible from thenetwork. Modifying this array with strategic merge patch may corrupt thedata. For more information Seehttps://github.com/kubernetes/kubernetes/issues/108255. Cannot be updated.readinessProbe        <Probe>Periodic probe of container service readiness. Container will be removedfrom service endpoints if the probe fails. Cannot be updated. More info:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probesresizePolicy  <[]ContainerResizePolicy>Resources resize policy for the container.resources     <ResourceRequirements>Compute Resources required by this container. Cannot be updated. More info:https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/restartPolicy <string>RestartPolicy defines the restart behavior of individual containers in apod. This field may only be set for init containers, and the only allowedvalue is "Always". For non-init containers or when this field is notspecified, the restart behavior is defined by the Pod's restart policy andthe container type. Setting the RestartPolicy as "Always" for the initcontainer will have the following effect: this init container will becontinually restarted on exit until all regular containers have terminated.Once all regular containers have completed, all init containers withrestartPolicy "Always" will be shut down. This lifecycle differs from normalinit containers and is often referred to as a "sidecar" container. Althoughthis init container still starts in the init container sequence, it does notwait for the container to complete before proceeding to the next initcontainer. Instead, the next init container starts immediately after thisinit container is started, or after any startupProbe has successfullycompleted.securityContext       <SecurityContext>SecurityContext defines the security options the container should be runwith. If set, the fields of SecurityContext override the equivalent fieldsof PodSecurityContext. More info:https://kubernetes.io/docs/tasks/configure-pod-container/security-context/startupProbe  <Probe>StartupProbe indicates that the Pod has successfully initialized. Ifspecified, no other probes are executed until this completes successfully.If this probe fails, the Pod will be restarted, just as if the livenessProbefailed. This can be used to provide different probe parameters at thebeginning of a Pod's lifecycle, when it might take a long time to load dataor warm a cache, than during steady-state operation. This cannot be updated.More info:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probesstdin <boolean>Whether this container should allocate a buffer for stdin in the containerruntime. If this is not set, reads from stdin in the container will alwaysresult in EOF. Default is false.stdinOnce     <boolean>Whether the container runtime should close the stdin channel after it hasbeen opened by a single attach. When stdin is true the stdin stream willremain open across multiple attach sessions. If stdinOnce is set to true,stdin is opened on container start, is empty until the first client attachesto stdin, and then remains open and accepts data until the clientdisconnects, at which time stdin is closed and remains closed until thecontainer is restarted. If this flag is false, a container processes thatreads from stdin will never receive an EOF. Default is falseterminationMessagePath        <string>Optional: Path at which the file to which the container's terminationmessage will be written is mounted into the container's filesystem. Messagewritten is intended to be brief final status, such as an assertion failuremessage. Will be truncated by the node if greater than 4096 bytes. The totalmessage length across all containers will be limited to 12kb. Defaults to/dev/termination-log. Cannot be updated.terminationMessagePolicy      <string>Indicate how the termination message should be populated. File will use thecontents of terminationMessagePath to populate the container status messageon both success and failure. FallbackToLogsOnError will use the last chunkof container log output if the termination message file is empty and thecontainer exited with an error. The log output is limited to 2048 bytes or80 lines, whichever is smaller. Defaults to File. Cannot be updated.Possible enum values:- `"FallbackToLogsOnError"` will read the most recent contents of thecontainer logs for the container status message when the container exitswith an error and the terminationMessagePath has no contents.- `"File"` is the default behavior and will set the container statusmessage to the contents of the container's terminationMessagePath when thecontainer exits.tty   <boolean>Whether this container should allocate a TTY for itself, also requires'stdin' to be true. Default is false.volumeDevices <[]VolumeDevice>volumeDevices is the list of block devices to be used by the container.volumeMounts  <[]VolumeMount>Pod volumes to mount into the container's filesystem. Cannot be updated.workingDir    <string>Container's working directory. If not specified, the container runtime'sdefault will be used, which might be configured in the container image.Cannot be updated.

5.1.1 资源清单必须存在的属性

参数名字段类型说明
apiversionString指的是K8S API的版本,目前基本上是v1,可以用kubectl api-versions命令查询
kindString这里指的是yaml文件定义的资源类型和角色,比如:Pod
metadataObject元数据对象,固定值就写metadata
metadata.nameString元数据对象的名称,这里由我们编写,比如命名Pod的名字
metadata.namespaceString元数据对象的命名空间,由我们自定义
specObject详细定义对象,固定值就是Spec
spec.containers[]list这是是spec对象的容器列表定义,是个列表
spec.containers[].nameString这里定义容器的名称
spec.containers[].imageString这里定义要用到的镜像名称

5.1.2 主要对象

参数名字段类型说明
spec.containers[].nameString这里定义容器的名称,- name
spec.containers[].imageString这里定义要用到的镜像名称
spec.containers[].imagePullPolicyString定义镜像拉取策略,有Always、Never、IfNotPresent三个值可选(1) Always:意思是每次都尝试重新拉取镜像(2)Never:表示仅使用本地镜像(3)IfNotPresent:如果本地有镜像就使用本地镜像,没有就拉取在线镜像。上面三个值都没设置的话,默认是Always.
spec.containers[].command[]List指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令。
spec.containers[].args[]List指定容器启动命令参数,因为是数组可以指定多个
spec.containers[].workingDirString指定容器的工作目录
spec.containers[].volumeMounts[]List指定容器内部的存储卷配置
spec.containers[].volumeMounts[].nameString指定可以被容器挂载的存储卷名称
spec.containers[].volumeMounts[].mountPathString指定可以被容器挂载的存储卷的路径
spec.containers[].volumeMounts[].readOnlyString设置存储卷路径的读写模式,ture或者false,默认为读写模式
spec.containers[].ports[]List指定容器需要用到的端口列表
spec.containers[].ports[].nameString指定端口名称
spec.containers[].ports[].containerPortString指定容器需要监听的端口号
spec.containers[].ports[].hostPortString指定容器所在主机需要监听的端口号,默认跟上面containerPort相同,注意设置了hostPort同一台主机无法启动该容器相同的副本(因为主机的端口号不能相同,这样会冲突)
spec.containers[].ports[].protocolString指定端口协议,支持TCP和UDP,默认为TCP
spec.containers[].env[]List指定容器运行前需要设置的环境变量列表

5.1.3 额外的参数项

参数名字段类型说明
spec.restartPolicyString定义Pod的重启策略,可选值为Always、OnFailure,Never;默认值为Always。1.Always: Pod—旦终止运行,则无论容器是如何终止的,kubelet服务都将重启它。2.OnFailure:只有Pod以非零退出码终止时,kubelet才会重启该容器。如果容器正常结束(退出码为0),则kubelet将不会重启它。3.Never: Pod终止后,kubelet将退出码报告给Master,不会重启该Pod。
spec.nodeSelectorObject定义Node的Label过滤标签,以key:value格式指定
spec.nodeNameObject以worker节点的主机名指定pod在哪个worker节点上工作
spect.imagePullSecretsObject定义pull镜像时使用secret名称,以name:secretkey格式指定
spec.hostNetworkBoolean定义是否使用主机网络模式,默认值为false。设置true标识使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本

5.2 POD YAML文件示例

# yaml格式的pod定义文件完整内容:
apiVersion: v1       #必选,版本号,例如v1
kind: Pod       #必选,Pod
metadata:       #必选,元数据name: string       #必选,Pod名称namespace: string    #必选,Pod所属的命名空间labels:      #自定义标签name: string     #自定义标签名字annotations:       #自定义注释列表- name: string
spec:         #必选,Pod中容器的详细定义containers:      #必选,Pod中容器列表- name: string     #必选,容器名称image: string    #必选,容器的镜像名称imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令args: [string]     #容器的启动命令参数列表workingDir: string     #容器的工作目录volumeMounts:    #挂载到容器内部的存储卷配置- name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符readOnly: boolean    #是否为只读模式ports:       #需要暴露的端口库号列表- name: string     #端口号名称containerPort: int   #容器需要监听的端口号hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同protocol: string     #端口协议,支持TCP和UDP,默认TCPenv:       #容器运行前需设置的环境变量列表- name: string     #环境变量名称value: string    #环境变量的值resources:       #资源限制和请求的设置limits:      #资源限制的设置cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数requests:      #资源请求的设置cpu: string    #Cpu请求,容器启动的初始可用数量memory: string     #内存清楚,容器启动的初始可用数量livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可exec:      #对Pod容器内检查方式设置为exec方式command: [string]  #exec方式需要制定的命令或脚本httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、portpath: stringport: numberhost: stringscheme: stringHttpHeaders:- name: stringvalue: stringtcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式port: numberinitialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次successThreshold: 0failureThreshold: 0securityContext:privileged: falserestartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该PodnodeSelector: obeject  #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定- name: stringhostNetwork: false      #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络volumes:       #在该pod上定义共享存储卷列表- name: string     #共享存储卷名称 (volumes类型有很多种)emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录secret:      #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部scretname: string items:    - key: stringpath: stringconfigMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部name: stringitems:- key: stringpath: string

5.3 标签

5.3.1 什么是标签?

标签其实就一对 key/value ,被关联到对象上,比如Pod,标签的使用我们倾向于能够表示对象的特殊特点,就是一眼就看出了这个Pod是干什么的,标签可以用来划分特定的对象(比如版本,服务类型等),标签可以在创建一个对象的时候直接定义,也可以在后期随时修改,每一个对象可以拥有多个标签,但是,key值必须是唯一的。创建标签之后也可以方便我们对资源进行分组管理。如果对pod打标签之后就可以使用标签来查看、删除指定的pod。(慎重!!!)

在k8s中,大部分资源都可以打标签。

5.3.2 给pod资源打标签

通过yaml文件修改

通过命令修改

5.3.3 查看资源标签

查看默认名称空间下所有pod资源的标签

查看默认名称空间下指定pod具有的所有标签

列出默认名称空间下标签key是app的pod,不显示标签

列出默认名称空间下标签key是app、值是nginx129的pod,不显示标签

列出默认名称空间下标签key是app2的所有pod,并打印对应的标签值

查看所有名称空间下的所有pod的标签

5.4 资源限制

5.4.1 节点资源不足,导致调度失败

apiVersion: v1
kind: Pod
metadata:name: nginx-pod2
spec:containers:- name: nginx2image: nginximagePullPolicy: IfNotPresentresources:limits:cpu: '8'memory: '8Gi'requests:cpu: '6'

5.4.2 所在命名空间资源不足

##创建命名空间并设置资源限制
[root@k8s-master ~]# vim c2505.txt
apiVersion: v1
kind: Namespace
metadata:name: c2505
---
apiVersion: v1
kind: ResourceQuota
metadata:name: mem-cpu-quotanamespace: c2505
spec:hard:requests.cpu: '2'requests.memory: '2Gi'limits.cpu: '4'limits.memory: '4Gi'
###创建pod
[root@k8s-master ~]# vim nginx.yaml 
apiVersion: v1
kind: Pod
metadata:name: nginx-pod2namespace: c2505
spec:containers:- name: nginx2image: nginximagePullPolicy: IfNotPresentresources:limits:cpu: '8'memory: '8Gi'requests:cpu: '6'memory: '2Gi'##提交后的报错信息
[root@k8s-master ~]# kubectl apply -f nginx.yaml 
Error from server (Forbidden): error when creating "nginx.yaml": pods "nginx-pod2" is forbidden: exceeded quota: mem-cpu-quota, requested: limits.cpu=8,limits.memory=8Gi,requests.cpu=6, used: limits.cpu=0,limits.memory=0,requests.cpu=0, limited: limits.cpu=4,limits.memory=4Gi,requests.cpu=2

5.5 Pod探针

在K8S集群中,为了测试pod是否正常运行,可以通过kubelet定期对pod进行健康检查,从而保证服务正常运行。

5.5.1 kubelet检查机制

  • exec: 在容器内执行指定命令,当返回码为0表示检测成功。在 Kubernetes 1.20 版本之前,exec 探针会忽略 timeoutSeconds: 探针会无限期地持续运行,甚至可能超过所配置的限期,直到返回结果为止。

  • httpGet:对容器的IP和URL进行HTTP的GET请求,当响应码(状态码)为大于等于200且小于400,表示容器正常运行。

  • tcpSocket:对容器内的端口或socket进行TCP检查,如果端口成功打开,证明容器正常运行。

5.5.2 探针返回结果

  • Success:表示通过检测。

  • Failure:表示未通过检测。

  • Unknown:表示检测没有正常进行。

5.5.3 探针的类型

  • livenessProbe(存活探针):判断容器是否正常运行。如果存活探测失败,那么kubelet就会把老的容器删除,然后根据重启策略对容器做操作。如果容器没有存活探针,默认状态为Success。

  • readinessProbe(就绪探针):判断容器的是否就绪。比如:应用在启动时可能需要加载大量的数据或配置文件,或是启动后要依赖等待外部服务。在这种情况下,既不想杀死应用,也不想给它发送请求。这个时候就需要用到这个探针。当就绪探测失败,端点控制器将从与 Pod匹配的所有服务的端点列表中删除该 Pod 的 IP 地址(如果是用nodeport映射端口到外网,这个时候就不能访问网站了,但是容器不会被删除),初始延迟之前的就绪态的状态值默认为 Failure。 如果容器不提供就绪态探针,则默认状态为 Success。

  • startupProbe(启动探针):指示容器中的应用是否已经启动。如果提供了启动探针,则所有其他探针都会被禁用,直到此探针成功为止。如果启动探测失败,kubelet 将删除容器,而容器依其重启策略进行重启。如果容器没有提供启动探测,则默认状态为 Success。

    注意:startupProbe 和 livenessProbe 最大的区别就是startupProbe在探测成功之后就不会继续探测了,而livenessProbe在pod的生命周期中一直在探测!

5.5.4 探针属性

  • (initialDelaySeconds: 5):初始化延迟时间,主要是告诉kubelet,容器启动需要的时间,当过了这个时间再进行探测,要不然容器可能还没启动就会删除了。

  • (periodSeconds: 5):探测周期间隔时间,主要是指定kubelet对容器进行探针的时间周期,也就是第一次探测结束后,等待多少时间后对容器进行探测。默认值为10秒,最小值为1秒。

  • (timeoutSeconds: 5):单次探测超时时间,指定kubelet对容器探测的最大时间,超过这个时间证明容器探测失败。默认为1秒,最小为1秒。

  • (successThreshold: 5):探测失败到成功的重试次数,当kubelet对某个容器第一次探测失败后,重新进行探测的次数,比如指定为1,那么就会直接将容器删除。如果使用的探针是livenessProbe,那么只能配置为1,最小值为1次。

  • (failureThreshold: 5):探测成功到失败的重试次数,当kubelet对某个容器进行探测过程中,允许失败的次数,当用于readinessProbe探针,默认是3次,最小值为1次。也就是说当3次探测失败后,容器会被删除。当用于startupProbe探针,如果还设置了periodSeconds时间,那么等待容器启动的时间为failureThreshold的时间乘以periodSeconds时间的值,在这段时间内,容器没有启动,那么就会删除容器。

5.5.5 livenessProbe探针案例

5.5.5.1 livenessProbe和kubelet-exec
apiVersion: v1
kind: Pod
metadata:name: nginx-podsnamespace: myns1labels:app: nginx
spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentlivenessProbe:exec:                    #定义探测方式command:               #不断查看文件是否存在,文件必须是镜像原本存在的文件- cat- /usr/share/nginx/html/index.htmlinitialDelaySeconds: 5   #指定探针多少秒后启动periodSeconds: 5         #指定探针探测周期时间

删除测试文件,触发探针,发现重启一次

 kubectl -n myns1 exec pods/nginx-pods -- rm -rf /usr/share/nginx/html/index.html

5.5.5.2 livenessProbe和kubelet-httpGet
apiVersion: v1
kind: Pod
metadata:name: nginx1-podslabels:app: nginx
spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentlivenessProbe:httpGet:                  #指定探针探测方式path: /index.html       #定义请求的URLport: 80                #定义GET的端口initialDelaySeconds: 3    #指定探针多少秒后启动periodSeconds: 3          #指定探针的探测周期

触发探针

看后发现重启了1次

再次进入容器,发现文件重建了

5.5.5.3 livenessProbe和kubelet-tcpSocket
apiVersion: v1
kind: Pod
metadata:name: nginx2-podslabels:app: nginx
spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentlivenessProbe:tcpSocket:                  #指定探针探测方式port: 80                #定义GET的端口initialDelaySeconds: 3    #指定探针多少秒后启动periodSeconds: 3          #指定探针的探测周期

#把80都改为8080

nginx -s reload                          #重新加载配置文件

查看pod,可以看到RESTARTS,证明容器重启过

5.5.6 readinessProbe探针案例

5.5.6.1 readinessProbe和kubelet-exec
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginx0v0namespace: default
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80readinessProbe:  #指定探针exec:          #指定探针探测方式command:- cat- /usr/share/nginx/html/index.htmlinitialDelaySeconds: 5periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:labels:svc: nginx-svc-nodeportname: nginx-svc-nodeport
spec:type: NodePortports:- port: 8000   ##pod的端口targetPort: 80  ##容器内部暴露的端口nodePort: 30080 ##对外访问端口selector:app: nginx

名字不需要定义,它会自己定义,如下图,会自动继承pod控制器名称

都可以登录nginx

此时,进入容器空间echo一个值后,再次刷新会进行伪轮询

5.5.6.2 readinessProbe和kubelet-httpGet

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80readinessProbe:             #指定探针httpGet:                  #指定探针方式path: /index.html       port: 80                initialDelaySeconds: 5periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:labels:svc: nginx-svc-nodeportname: nginx-svc-nodeport
spec:type: NodePortports:- port: 80targetPort: 80nodePort: 30080selector:app: nginx
[root@k8s-master01 ~]# kubectl apply -f nginx-re-httpGet.yml        #创建容器
[root@k8s-master01 ~]# curl -I http://192.168.116.132:30080      #和上面一样,访问网站成功
[root@k8s-master01 ~]# kubectl get pod -A -o wide     #查看容器名字,可以看到原本READY是1/1
###测试####
[root@k8s-master01 ~]# kubectl exec -it nginx-75f8cfd9d-6x8jz -- bash  #连接容器
#cd /usr/share/nginx/html/   #修改探针指定探测的文件名字,让探针触发
#ls
#mv index.html index1.html 
#exit
[root@k8s-master01 ~]# kubectl get pod -A -o wide  #可以看到READY变成了0/1,证明探针被触发了,容器没有被删除,也没有重建
NAME                                READY   STATUS    RESTARTS      AGE   IP              NODE           NOMINATED NODE   READINESS GATES
nginx-556bcf764d-7qpjh              0/1     Running   0             29m   172.16.79.76    k8s-worker01   <none>           <none>[root@k8s-master01 ~]# curl -I http://192.168.116.132:30080  #可以看到网站访问不了 (等待5分钟)
[root@k8s-master01 ~]# kubectl describe svc nginx-svc-nodeport  #可以看到Endpoints没有值,证明探针把service和pod解除绑定了
Name:                     nginx-svc-nodeport
Namespace:                default
Labels:                   svc=nginx-svc-nodeport
Annotations:              <none>
Selector:                 app=nginx
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.10.166.16
IPs:                      10.10.166.16
Port:                     <unset>  8000/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30080/TCP
Endpoints:                
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
5.5.6.3 readinessProbe和kubelet-tcpSocket
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80readinessProbe:                 #指定探针tcpSocket:                    #指定探测方式port: 80initialDelaySeconds: 5periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:labels:svc: nginx-svc-nodeportname: nginx-svc-nodeport
spec:type: NodePortports:- port: 80targetPort: 80nodePort: 30080selector:app: nginx
[root@k8s-master01 ~]# kubectl apply -f nginx-re-tcpSocket.yml        #创建容器
[root@k8s-master01 ~]# curl -I http://192.168.116.132:30080      #和上面一样,访问网站成功[root@k8s-master01 ~]# kubectl get pod -A                       #查看pod
####测试####
[root@k8s-master01 ~]# kubectl exec -it nginx-6bf8bf8577-9skvn -- bash  #连接容器#vi /etc/nginx/conf.d/default.conf        #修改配置文件server {listen       8080;    #把80都改为8080listen  [::]:8080;#nginx -s reload                          #重新加载配置文件[root@k8s-master01 ~]# kubectl get pod -A  可以看到READY变成了0/1,证明探针被触发了,容器没有被删除,也没有重建
[root@k8s-master01 ~]# curl -I http://192.168.71.128:30080  可以看到因为探针触发,外网是访问不了容器了

就绪探针不会影响pod和pod之间的访问,新建测试容器测试

[root@k8s-master01 ~]# kubectl run net-test1 --image=alpine sleep 360000  #创建容器
[root@k8s-master01 ~]# kubectl get pod -A -o wide              #查看pod的IP
[root@k8s-master01 ~]# kubectl exec -it net-test1 -- bash      #连接容器
#可以看到只要指定改过的pod的端口,pod和pod之间还是可以访问的
#wget http://10.10.1.36:8080    
#ls

5.6 Pod案例

5.6.1 生成YAML文件

kubectl run  pod --image=nginx --dry-run=client -o yaml > my-pod.yaml  #生成Pod模版

5.6.2 创建Pod

 kubectl apply -f /root/nginx/nginx_pod.yaml

六.Pod常用命令

命令作用
kubectl create -f ymal文件创建pod
kubectl get pod [-n 名称空间] kubectl get pod -o wide查看pod
kubectl apply -f yaml文件更新pod
kubectl delete pod pod名称删除pod
kubectl exec -it pod名称 -- shell进入pod中的容器
kubectl logs pod名称 -c 容器名查看pod中容器日志
kubectl get pod pod名称 --show-labels查看pod标签
kubectl label pod pod名称 newkey=newvalue修改pod标签
kubectl get pod -l app查看标签为app的pod
kubectl get pod -l app --all-namespaces查看所有名称空间标签为app的pod
kubectl get pod -l app=myapp kubectl get pod -l app=myapp --all-namespaces查看标签为app,值为myapp的pod
kubectl describe pod pod名称查看详细信息

七.Pod状态

  • 挂起(Pending):我们在请求创建pod时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了pod但是没有适合它运行的节点叫做挂起,调度没有完成,处于pending的状态会持续一段时间:包括调度Pod的时间和通过网络下载镜像的时间。

  • 运行中(Running):Pod已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行。

  • 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。

  • 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。

  • 未知(Unknown):未知状态,所谓pod是什么状态是apiserver和运行在pod节点的kubelet进行通信获取状态信息的,如果节点之上的kubelet本身出故障,那么apiserver就连不上kubelet,得不到信息了,就会看Unknown

7.1 常用的排障命令

##查看 Pod 的配置是否正确kubectl get pod <pod-name> -o yaml ##查看 Pod 的事件kubectl describe pod <pod-name> ##查看容器日志
kubectl logs <pod-name> [-c <container-name>] ##进入容器查看
kubectl exec -it <pod-name>  -- /bin/bash

7.2 常见故障归类

  • Pod状态 一直处于 Pending

Pending 说明 Pod 还没有调度到某个 Node 上面。可以通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件,进而判断为什么没有调度。可能的原因包括:
资源不足,集群内所有的 Node 都不满足该 Pod 请求的 CPU、内存、GPU 等资源
HostPort 已被占用,通常推荐使用 Service 对外开放服务端口
  • Pod状态 一直处于 Waiting或者Pod状态 一直处于 ContainerCreating

首先还是通过 kubectl describe pod <pod-name> 命令查看到当前 Pod 的事件。可能的原因包括:镜像拉取失败,比如配置了镜像错误、Kubelet 无法访问镜像、私有镜像的密钥配置错误、镜像太大,拉取超时等CNI 网络错误,一般需要检查 CNI 网络插件的配置,比如无法配置 Pod 、无法分配 IP 地址
容器无法启动,需要检查是否打包了正确的镜像或者是否配置了正确的容器参数
  • Pod状态 处于 ImagePullBackOff

这也是我们测试环境常见的,通常是镜像拉取失败。这种情况可以使用 docker pull <image> 来验证镜像是否可以正常拉取。
或者docker images | grep <images>查看镜像是否存在(系统有时会因为资源问题自动删除一部分镜像)
  • Pod状态 处于 CrashLoopBackOff

CrashLoopBackOff 状态说明容器曾经启动了,但可能又异常退出了。此时可以先查看一下容器的日志
kubectl logs --previous这里可以发现一些容器退出的原因,比如:容器进程退出健康检查失败退出
  • Pod状态 处于 Error

通常处于 Error 状态说明 Pod 启动过程中发生了错误。常见的原因包括依赖的 ConfigMap、Secret 或者 PV 等不存在请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等违反集群的安全策略,比如违反了 PodSecurityPolicy 等容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定
  • Pod状态 一直处于 Terminating或者Pod状态 处于 Unknown

从 v1.5 开始,Kubernetes 不会因为 Node 失联而删除其上正在运行的 Pod,而是将其标记为 Terminating 或 Unknown 状态。想要删除这些状态的 Pod 有三种方法:1)从集群中删除该 Node。使用公有云时,kube-controller-manager 会在 VM 删除后自动删除对应的 Node。而在物理机部署的集群中,需要管理员手动删除 Node(如 kubectl delete node <node-name>。2)Node 恢复正常。Kubelet 会重新跟 kube-apiserver 通信确认这些 Pod 的期待状态,进而再决定删除或者继续运行这些 Pod。3)用户强制删除。用户可以执行 kubectl delete pods <pod> --grace-period=0 --force 强制删除 Pod。除非明确知道 Pod 的确处于停止状态(比如 Node 所在 VM 或物理机已经关机),否则不建议使用该方法。特别是 StatefulSet 管理的 Pod,强制删除容易导致脑裂或者数据丢失等问题。
  • Pod状态 处于 Evicted

出现这种情况,多见于系统内存或硬盘资源不足,可df-h查看docker存储所在目录的资源使用情况,如果百分比大于85%,就要及时清理下资源,尤其是一些大文件、docker镜像。清除状态为Evicted的pod:
kubectl get pods | grep Evicted | awk '{print $1}' | xargs kubectl delete pod删除所有状态异常的pod:
kubectl delete pods $(kubectl get pods | grep -v Running | cut -d ' ' -f 1)删除集群中没有在使用的docker镜像(慎用):
docker system prune -a查看pod对应的服务(镜像)版本:
kubectl --server=127.0.0.1:8888 get rc -o yaml | grep image: |uniq | sort | grep ecs-core附:
删除某类历史镜像(仅保留当前使用的)
docker images | grep ecs-core | grep -v `docker images | grep ecs-core -m 1 | awk '{print $2}'` | awk '{print $3}' | xargs docker rmi -f
状态含义
CrashLoopBackOff          容器退出,kubelet正在将它重启
InvalidImageName无法解析镜像名称
ImageInspectError无法校验镜像
ErrImageNeverPul策略禁止拉取镜像
ImagePullBackOff  正在重试拉取
RegistryUnavailable连接不到镜像中心
ErrImagePull通用的拉取镜像出错
CreateContainerConfigError  不能创建kubelet使用的容器配置
CreateContainerError    创建容器失败
m.internalLifecycle.PreStartContainer 执行hook报错
RunContainerError      启动容器失败
PostStartHookError    执行hook报错
ContainersNotInitialized  容器没有初始化完毕
ContainersNotReady         容器没有准备完毕
ContainerCreating     容器创建中
PodInitializing          pod 初始化中
DockerDaemonNotReady   docker还没有完全启动
NetworkPluginNotReady   网络插件还没有完全启动
Evicted    即驱赶的意思,意思是当节点出现异常时,kubernetes将有相应的机制驱赶该节点上的
 Pod多见于资源不足时导致的驱赶。

八.总结

以上是本次pod相关内容,后续会更新更多内容。

http://www.dtcms.com/a/330501.html

相关文章:

  • 使用 Rust 进行 Web 自动化入门
  • npm删除包
  • 基于Redisson的分布式锁原理深度解析与优化实践
  • OpenCV图像处理2:边界填充与平滑滤波实战
  • VSC遇到的问题:无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。
  • QT+Yolov8 推理部署,ONNX模型 ,实例分割+目标检测
  • 计算机视觉CS231n学习(9)
  • VLMs开发——基于Qwen2.5-VL 实现视觉语言模型在目标检测中的层级结构与实现方法
  • 【CV 目标检测】R-CNN①——Overfeat
  • PyCharm性能优化与大型项目管理指南
  • Linux 路由表建立过程分析
  • 开疆智能Ethernet转ModbusTCP网关连接UR机器人配置案例
  • LeetCode 面试经典 150_数组/字符串_最后一个单词的长度(19_58_C++_简单)(反向遍历)
  • 百川开源大模型Baichuan-M2的医疗能力登顶第一?
  • 【机器人-开发工具】ROS 2 (4)Jetson Nano 系统Ubuntu22.04安装ROS 2 Humble版本
  • OpenBMC中C++策略模式架构、原理与应用
  • AI数据仓库的核心优势解析
  • 设计模式基础概念(行为模式):策略模式
  • 【java实现一个接口多个实现类通用策略模式】
  • [Oracle数据库] ORACLE基本DML操作
  • 【软件测试】自动化测试 — selenium快速上手
  • Java设计模式之《策略模式》
  • STM32L051C8与STM32L151C8的主要区别
  • visual studio调试cmake项目记录
  • 用飞算JavaAI一键生成电商平台项目:从需求到落地的高效实践
  • 远程影音访问:通过 cpolar 内网穿透服务使用 LibreTV
  • Mybatis学习笔记(九)
  • Spring Boot + Redis + 布隆过滤器防止缓存穿透
  • [已解决]当启动 Spring Boot 应用时出现 Using generated security password xxx提示
  • OpenCV 视频处理全解析