K8S 运维额外知识
Zhongjun Qiu 元婴开发者

讲解了K8S集群中运维相关的补充知识,包括网络策略、外部服务暴露、资源限制等内容。

NetworkPolicy

在Kubernetes中,NetworkPolicy是一种API对象,用于定义和控制Pod之间的网络通信策略,可以基于IP地址或端口(OSI第3层或第4层)来管理网络流量。

Kubernetes集群默认情况下,一个名字空间中的所有Pod对入站和出站流量都是非隔离的,即所有连接都是被允许的。NetworkPolicy的作用就是改变这种默认行为,通过定义策略来对Pod间的网络通信进行精细化控制,以实现更高的网络安全性。

NetworkPolicy的局限性

  • 强制集群内部流量经过某个公用网关:这类场景更适合通过服务网格(Service Mesh)或其他代理来实现
  • 与TLS相关的场景:可以考虑使用服务网格或Ingress控制器来解决
  • 特定于节点的策略:虽然可以通过CIDR来表达此需求,但无法使用节点在Kubernetes中的其他标识信息来识别目标节点
  • 基于名字选择服务或名字空间来选择目标Pod
  • 创建或管理由第三方实际完成的“策略请求”
  • 实现适用于所有名字空间或Pods的默认策略
  • 高级的策略查询或可达性相关工具
  • 生成网络安全事件日志的能力(例如,被阻塞或接收的连接请求)
  • 显式地拒绝策略的能力:目前,NetworkPolicy的模型默认采用拒绝操作,其唯一的能力是添加允许策略
  • 禁止本地回路或指向宿主的网络流量:Pod无法阻塞localhost访问,也无法禁止来自所在节点的访问

基本语法

一个典型的NetworkPolicy YAML文件包括以下几个部分:

  • apiVersionnetworking.k8s.io/v1
  • kindNetworkPolicy
  • metadata:包含策略的name和所在的namespace
  • spec:核心部分,用于定义策略规则。
    • podSelector:通过标签选择器(matchLabels)来指定该策略作用于哪些Pod。如果podSelector为空,则选择该名字空间下的所有Pod 。
    • policyTypes:定义策略的类型,可以是Ingress(入站)或Egress(出站)。如果未指定,默认只设置Ingress
    • ingress:入站规则,通过from部分来指定允许哪些来源的流量访问目标Pod。
    • egress:出站规则,通过to部分来指定目标Pod可以访问哪些目的地。 fromto部分可以包含以下四种选择器:
    • podSelector:基于Pod标签。
    • namespaceSelector:基于名字空间标签。
    • namespaceSelectorpodSelector的组合。
    • ipBlock:基于CIDR IP地址块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
# 选择 default 命名空间下 label 为 role=db 的 Pod (规定这些pod的出站和入栈规则)
podSelector:
matchLabels:
role: db

# 明确声明此策略同时控制 Ingress(入站)和 Egress(出站)
policyTypes:
- Ingress
- Egress

# 入站规则(允许哪些来源访问 role=db 的 Pod)
ingress:
- from:
# 允许 172.17.0.0/16 的 IP 段,但排除 172.17.1.0/24
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
# 允许来自 namespace 上带 project=myproject 标签的所有 Pod
- namespaceSelector:
matchLabels:
project: myproject
# 允许同 namespace 下 label=role:frontend 的 Pod
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379 # 只允许访问 TCP 6379 端口

# 出站规则(role=db 的 Pod 可以访问哪些目标)
egress:
- to:
# 允许访问 10.0.0.0/24 网段
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978 # 只能访问 TCP 5978 端口

默认策略

  • 拒绝所有入站流量:创建一个podSelector: {}policyTypes: Ingress的策略,但不包含任何ingress规则
1
2
3
4
5
6
7
8
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress

规定了Ingress规则,但没写任何匹配条目,意思就是没有流量能访问

  • 允许所有入站流量:创建一个podSelector: {}ingress: {}的策略 。
1
2
3
4
5
6
7
8
9
10
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress

规定了Ingress规则,匹配条目为”{}“,代表任意,意思就是任何流量都能访问

Egress的默认策略编写同理

外部服务暴露

Kubernetes 中的 Pod 默认只能在集群内部访问,如果要让外部用户访问,需要通过暴露服务的方式。

Expose

kubectl expose 用来基于已有的 Pod / Deployment / ReplicaSet 创建一个 Service,从而将应用端口暴露出来。

本质上就是用命令帮你快速创建一个Service资源

1
kubectl expose deployment myapp --port=80 --target-port=8080 --type=NodePort

意思是把 deployment myapp 的 8080 容器端口暴露为集群 Service 的 80 端口,同时通过 NodePort 暴露到每个节点。

Port-forward

kubectl port-forward 将本地端口和某个 Pod/Service 的端口建立临时转发。

1
kubectl port-forward pod/myapp-pod 8080:80

本地 http://localhost:8080 的请求会被转发到 Pod 的 80 端口。

  • 仅作用在当前 kubectl 会话,关闭终端/CTRL+C 后失效。
  • 只绑定到 localhost,外部机器无法直接访问。
  • 不依赖 Service、Ingress 等,快速调试用。

如果需要外部访问,则改成

1
kubectl port-forward pod/myapp-pod 8080:80 --address 0.0.0.0

这样它就会监听 0.0.0.0:32222,即所有IP,包括任意外部主机发送到这个节点上的流量

否则它只认127.0.0.1的IP地址

Ingress

前面单独有讲

限制资源

单个Pod中对特定容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: resource-limited-pod
spec:
containers:
- name: my-container
image: nginx
resources: # 容器资源限制和请求配置
limits: # 最大资源限制
cpu: "500m" # CPU 最大使用量为 500 milliCPU(0.5 CPU)
memory: "256Mi" # 内存最大使用量为 256MiB
requests: # 容器启动时请求的资源(保证调度)
cpu: "200m" # CPU 最小保证 200 milliCPU(0.2 CPU)
memory: "128Mi" # 内存最小保证 128MiB

特性 requests limits
调度决策 用于调度 Pod 到节点(Scheduler 根据 requests 判断节点是否有足够资源) 不影响调度,运行时才生效
保证资源 Pod 至少能使用 requests 的资源 Pod 不会超过 limits 的资源
超过时处理 不会超额 CPU 超额限速,内存超额 OOMKill
  • requests = 调度门槛
  • limits = 运行上限

HPA

HPA 的核心目标是 根据负载自动增加或减少 Pod 数量,保证应用在流量高峰时有足够的资源,同时在流量低时节省资源。

例如:

  • 当 CPU 使用率超过 80% 时,HPA 会增加 Pod 副本。
  • 当 CPU 使用率降到 30% 时,HPA 会减少 Pod 副本。

HPA 工作原理

  1. 指标采集:

    HPA 通过 Kubernetes 的 Metrics Server 获取 Pod 的实时指标,如 CPU、内存使用率,或者自定义指标(通过 Prometheus Adapter 等)。

  2. 计算副本数:

    HPA 根据公式计算所需副本数:

    例如:

    • 当前 Pod 副本数:3

    • CPU 使用率:90%

    • 目标 CPU 使用率:50%

    • 那么:

  3. 调整副本:

    • HPA 会修改对应 Deployment/ReplicaSet 的副本数,使集群资源动态适配负载。

HPA 配置示例

假设有一个 Deployment 名为 my-app,希望基于 CPU 使用率自动扩缩:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
  • minReplicas: 最少 2 个 Pod
  • maxReplicas: 最多 10 个 Pod
  • target.averageUtilization: CPU 目标利用率 50%

Pod QoS (服务质量等级)

Kubernetes 根据 Pod 的 requests/limits 配置,分配不同 QoS 等级:

BestEffort(最低优先级)

  • 没有设置任何 requests/limits(该pod可以使用任意多的资源)。
  • 容易被驱逐。

Burstable(中优先级)

  • 设置了 requests或limits,或者两个都设置了但不相等。
  • 在资源紧张时,可能被驱逐。

Guaranteed(最高优先级)

  • 设置了 requests == limits。
  • 不会轻易被驱逐,保障性最好。

LimitRange

用于 命名空间级别下单独每个pod 的资源限制,避免用户随意配置。

可以指定每个容器可申请的最小/最大 CPU、内存。

还可以设置默认的 requests/limits,简化配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: v1
kind: LimitRange # LimitRange 资源类型,用于在命名空间中对 Pod/容器设置默认资源限制和约束
metadata:
name: example-limit-range # LimitRange 对象名称
spec:
limits: # 定义限制规则列表
- type: Pod # 限制类型为 Pod 级别
max: # Pod 最大可用资源
cpu: "1" # CPU 最大 1 核
memory: 1Gi # 内存最大 1Gi
min: # Pod 最小资源
cpu: "200m" # CPU 最小 0.2 核
memory: 100Mi # 内存最小 100Mi
- type: Container # 限制类型为容器级别
max: # 容器最大资源
cpu: "500m" # CPU 最大 0.5 核
memory: 512Mi # 内存最大 512Mi
min: # 容器最小资源
cpu: "100m" # CPU 最小 0.1 核
memory: 64Mi # 内存最小 64Mi
defaultRequest: # 如果 容器 未指定 requests,则使用默认值
cpu: "200m" # 默认请求 CPU 0.2 核
memory: 128Mi # 默认请求内存 128Mi
default: # 如果 容器 未指定 limits,则使用默认限制
cpu: "300m" # 默认限制 CPU 0.3 核
memory: 200Mi # 默认限制内存 200Mi

ResourceQuota

用于 限制整个命名空间 的资源总量。

控制一个 namespace 内的 Pod 数量、总 CPU、总内存、PVC 使用量等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: ResourceQuota # 资源配额资源类型
metadata:
name: test-resources-rq # ResourceQuota 对象名称
namespace: test # 所在命名空间(ResourceQuota 作用域是命名空间级)
spec:
hard: # 定义硬限制(Hard Limit),超过就不能再创建资源
requests.cpu: "20" # 所有 Pod 请求的 CPU 总和最大 20 核
requests.memory: 100Gi # 所有 Pod 请求的内存总和最大 100Gi
limits.cpu: "40" # 所有 Pod 限制的 CPU 总和最大 40 核
limits.memory: 200Gi # 所有 Pod 限制的内存总和最大 200Gi
pods: "1" # 命名空间中最多允许 1 个 Pod
configmaps: "10" # 命名空间中最多允许 10 个 ConfigMap
persistentvolumeclaims: "4" # 命名空间中最多允许 4 个 PVC
replicationcontrollers: "20" # 命名空间中最多允许 20 个 ReplicationController
secrets: "10" # 命名空间中最多允许 10 个 Secret
services: "10" # 命名空间中最多允许 10 个 Service
services.loadbalancers: "2" # 命名空间中最多允许 2 个 LoadBalancer 类型 Service
 REWARD AUTHOR
 Comments
Comment plugin failed to load
Loading comment plugin