namespace介绍

Namespace提供了一种将集群资源逻辑上隔离的方式,允许在同一个集群中划分多个虚拟的、逻辑上独立的集群环境,相当于集群的"虚拟化"。

命名空间namespace是k8s集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的命名空间,例如,可以为test、devlopment、production环境分别创建各自的命名空间。

命名空间适用于存在很多跨多个团队或项目的用户的场景。对于只有几到几十个用户的集群,根本不需要创建或考虑命名空间。

创建ns:

kubectl create ns test

合理的资源划分

资源限制的重要性:如果没有,可能会产生节点资源被异常耗尽的问题。

pod数量限制的重要性:应对异常pod激增的问题。举个例子,对某个deployment下的pod,进行了内核修改配置(securityContext里面添加sysctl命令),但是如果集群没有允许更改内核参数,可能会报错sysctl forbidden,但是pod资源已经有了,这样的后果是RS会不断的创建pod,可能会直接创建上万个垃圾pod,严重的时候会直接把集群拖垮。

生产环境一定针对每个ns,对pod数量和RS数量做限制,因为这两个资源是不受管控的资源,防止异常激增。比如限制ns级别的pod数量为512,RS数量为1024。

以租户为单位

是针对ns去限制的。

  1. 基于节点去划分:比如一个团队申请了5台8C16G机器加入集群,那么就限制这个团队的ns资源limit为40C80G。
  2. 基于现有资源:利用现有资源,直接划分给这个团队固定的cpu和memory

以环境为单位

比如有dev、uat、prod等环境,需要预估每个环境的所有微服务情况,留一些冗余。

ResourceQuota资源

ResourceQuota是k8s中用于资源管理的对象,限制ns中的资源使用量。可以:

  • 限制资源使用量
  • 限制对象数量
apiVersion: v1
kind: ResourceQuota
metadata: name: customer1-quota
namespace: customer1
spec:
  hard:
    # 下面的限制建议都打开
    count/pods: "100"
    requests.cpu: "2"
    requests.memory: 4Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    count/replicasets.apps: 1k
    count/persistentvolumeclaims: "10"
    requests.storage: 400Gi
    count/services: "40"

CPU的单位解释:为 Pod 和容器管理资源 | Kubernetes

CPU 资源的限制和请求以 "cpu" 为单位。 在 Kubernetes 中,一个 CPU 等于 1 个物理 CPU 核 或者 1 个虚拟核, 取决于节点是一台物理主机还是运行在某物理主机上的虚拟机。

  • 如果是request.cpu: 0.5 --> 那就是请求0.5个核
  • 如果是request.cpu: 500m --> 那是500毫核 --> 也就是0.5核

注意

  • ns指定了ResourceQuota之后,如果创建的deployment没有显式指定requests和limits,那么pod会创建不出来。此时的状态就是deployment正常,但是pod实际数量为0,可以describe rs来看,也可以get events来看。
  • 新创建的resourceQuota,不会影响已经在运行的服务,但是一旦出发更新或者删除,那么就会产生影响,超过的就创建不出来了

LimitRange资源

只配置了resourceQuota是不够的,想象这样一种例子:有一个pod设置request是1m/1Mi,有一个节点已经资源马上满了,但是还是可以接受这个pod,但是这个pod随着运行吃了更多资源,这个节点就满了。

这样是不行的,需要:

  1. 对requests和limits的值也进行合理性的约束,不符合约束的就禁止创建;
  2. 对于没有显式声明requests和limits的资源,添加上一个默认值。

在Kubernetes集群中部署任何的服务,都建议添加resources参数,也就是配置内存和CPU资源的请求和限制。如果不想给每个容器都手动添加资源配置,此时可以使用limitRange实现给每个容器自动添加资源配置(不会覆盖已经配置的值)。

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-mem-limit-range
spec:
  limits:
  - type: Container # 可以写container、pod
    default: # default就是limit的默认值
      cpu: 1
      memory: 512Mi
    defaultRequest: # request的默认值
      cpu: 0.5
      memory: 256Mi
    min: # requests不能小于这里的值
      memory: 32Mi
      cpu: 100m
    max: # limits不能大于这里的值
      memory: 1Gi
      cpu: 1
  - type: PersistentVolumeClaim # 限制PVC的存储大小范围(创建太多很小的PVC,可能会产生过多的存储碎片)
    max:
      storage: 3Gi
    min:
      storage: 1Gi

注意

  1. limitRange是针对pod去修改的,deployment的yaml不会被修改。

QoS

想象这样一个场景:节点上面的pod由于流量高峰,资源使用量上升,超出节点资源量。这时候节点会启动一些OOM Kill的机制,杀掉pod。如果有一些重要的pod不希望被杀掉,或者尽量在最后被杀掉,怎么去保护?

QoS:Quality of Service,表示程序的服务质量,K8s集群每一个pod,都会有对应的QoS级别,可以决定pod在资源紧张时候的处理顺序。同时可以确保关键服务的稳定性和可靠性。(QoS不是K8s的特性,Linux里面的程序也有服务质量的概念)

Guaranteed

Guaranteed级别的Pod具有最高的优先级,Kubernetes会确保这些Pod获得足够的资源,也就是Kubernetes调度器会确保这些Pod调度到能够提供所需资源的节点上。

配置Guaranteed级别的Pod,需要满足如下条件:

  1. Pod中的每个容器必须指定limits.memory和requests.memory,并且两者需要相等
  2. Pod中的每个容器必须指定limits.cpu和requests.cpu,并且两者需要相等
limits:
  cpu: 200m
  memory: 512Mi
requests:
  cpu: 200m
  memory: 512Mi

一般mysql、redis等基础组件,需要尽量配成Guaranteed,预估好资源,直接给他requests、limits配成一样的(给冗余多一点)

Burstable

Burstable级别的Pod具有中等优先级,Kubernetes会尽量满足其资源请求,但在资源紧张时可能会被驱逐,Kubernetes调度器会确保这些Pod调度到能够提供所需资源的节点上,如果节点上有额外的资源,这些Pod可以使用超过其请求的资源。

配置Burstable级别的Pod,需要满足如下条件:

  1. Pod不符合Guaranteed的配置要求
  2. Pod中至少有一个容器配置了requests.cpu或requests.memory。(即这类服务知道最小用量,但是机器资源充足时会占用更多)
requests:
  memory: 128Mi
  cpu: 100m
  • 一般自己开发的无状态微服务,允许漂移的,可以设置成Burstable。
  • 而且一般微服务CPU使用量低,所以CPU一般设置成小requests,可变得更大,这种模式就是Burstable。
  • 对于Java,Xms和Xmx如果设置了,建议requests设成Xmx+128Mi,保证进程能起来,也给容器一些冗余。

BestEffort

BestEffort级别的Pod是最低优先级,Kubernetes不保证这些Pod获得任何资源,在资源紧张时,这些Pod最先被驱逐。同时Kubernetes调度器会尝试将这些Pod调度到任何节点上,但不保证节点上有足够的资源。

配置BestEffort级别的Pod,不配置resources字段即可。

生产环境不推荐使用,因为没有配置任何资源声明,可能会被调度到资源紧张的节点上,造成一些问题。

ns删除后卡在Terminating状态

删除命名空间时,可能因为残留资源或 finalizer 未完成,导致 namespace 一直卡在 Terminating 状态,重启 K8s 或节点都无效。

注意

强制删除前建议先排查并清理 namespace 中的残留资源,确认无法自然释放后再使用强制手段。

原理

Namespace 卡在 Terminating 通常是因为 spec.finalizers 未被清空。解决思路:通过 API 将 namespace 的 spec.finalizers 置空,绕过等待。

手动方式

# 1. 开启 API 代理(新窗口保持运行)
kubectl proxy
# Starting to serve on 127.0.0.1:8001

# 2. 新开终端,导出 namespace JSON 并清空 finalizers
kubectl get namespace $NAMESPACE -o json | jq '.spec = {"finalizers":[]}' > temp.json

# 3. 发送 PUT 请求完成删除
curl -k -H "Content-Type: application/json" -X PUT --data-binary @temp.json \
  127.0.0.1:8001/api/v1/namespaces/$NAMESPACE/finalize

自动化脚本

来源:实用脚本:强制删除K8s命名空间(Terminating状态)

前置条件:需要先在另一个终端执行 kubectl proxy 保持运行,且需安装 jq

#!/bin/bash
# deleteNameSpace.sh - 强制删除 Terminating 状态的 namespace
# 用法: sh deleteNameSpace.sh <namespace-name>

NAMESPACE="$1"

if [ -z "$NAMESPACE" ]; then
    echo "请传入要删除的 namespace 名称:"
    read NAMESPACE
fi

echo "您将要删除的 namespace 名称是:$NAMESPACE"

# 导出 JSON 并清空 finalizers
kubectl get namespace "$NAMESPACE" -o json | jq '.spec = {"finalizers":[]}' > temp.json

# 通过 API 发送 PUT 请求完成删除
curl -k -H "Content-Type: application/json" -X PUT \
  --data-binary @temp.json \
  "127.0.0.1:8001/api/v1/namespaces/$NAMESPACE/finalize"

# 验证结果
if kubectl get namespace "$NAMESPACE" &>/dev/null; then
    echo "删除 namespace 失败:命名空间 '$NAMESPACE' 仍然存在"
    exit 1
else
    echo "删除 namespace 成功:命名空间 '$NAMESPACE' 已不存在"
    exit 0
fi

使用

# 终端 1:开启代理
kubectl proxy

# 终端 2:执行脚本
sh deleteNameSpace.sh knative-eventing

特殊namespace

kube-node-lease

  • 节点的心跳信息会存放在其中,api server去里面查看心跳信息,获取node状态。