Kubernetes(k8s) 网络策略及排错

文章目录

  • k8s 网络策略
  • k8s 网络故障定位指南
    • IP 转发和桥接
      • IP 转发
      • 桥接
    • hairpin
    • 查看 pod ip 地址
    • 故障排查工具
    • 为什么不推荐使用SNAT

k8s 网络策略

  • k8s 网络策略采用了比较严格的单向控制
  • {} 表示允许所有,[] 表示拒绝所有
# 所有pod允许所有流量进入
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
	podSelector: {}
	ingress:
	- {}
---

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
	# 筛选 pod 应用下面规则
  podSelector:
    matchLabels:
      role: db
  policyTypes:  # 不写,默认为 Ingress
  - Ingress
  - Egress
  # 管理进入流量 下面的规则都是独立的 不是和的关系
  ingress:
  - from:
    - ipBlock: # 在此ip范围,但不包含172.17.1.0/24的ip可与上述筛选的pod的80端口建立连接
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector: # 符合条件的 namespace 可与上述 pod 的 80 端口建立 tcp 连接
        matchLabels:
          project: myproject
    - podSelector: # default namespace 下,满足条件的 pod 可与上述 pod 建立连接 80 tcp
        matchLabels:
          role: frontend
  - ports:
    - protocol: TCP
      port: 80 # 指的是筛选出的 pod 端口
  # 管理出去流量
  egress:
  - to:
    - ipBlock:  # 允许上述筛选出的 pod 访问网段为 10.0.0.0/24 的 5978 端口
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978  # 指的是目的端口

k8s 网络故障定位指南

IP 转发和桥接

linux 内核设置低级别的集群 IP 负载均衡,除了 iptables 和 IPVS,还需要用到两个关键的模块:IP转发(IP forward)和桥接

IP 转发

  • 是一种内核态设置,允许将一个接口的流量转发到另一个接口
  • 该配置是内核将流量从容器路由到外部所必需的
  • 没有启动的话,会出现网络访问失败的情况。如,访问 Pod 服务连接超时
# 检查 ipv4 forwarding 是否开启
sysctl net.ipv4.ip_forward
# 0 意味着未开启
net.ipv4.ip_forward = 0

# 进行修复
sysctl -w net.ipv4.ip_forward=1
echo net.ipv4.ip_forward=1 >> /etc/sysconf.d/10-ipv4-forwarding-on.conf
# 验证并生效
sysctl -p

桥接

  • k8s 通过 bridge-netfilter 配置使 iptables 规则应用在 linux 网桥上
  • 该配置对内核进行宿主机和容器之间数据包的地址转换是必需的
  • 否则,Pod 进行外部服务网络请求使会出现,目标主机不可达或连接拒绝等错误
# 检查 bridge netfilter 是否开启
sysctl net.bridge.bridge-nf-call-iptables
# 0 表示未开启
net.bridge.bridge-nf-call-iptables = 0

# 开启这个 iptables 配置
sysctl -w net.bridge.bridge-nf-call-iptables=1
echo net.bridge.bridge-nf-call-iptables=1 >> /etc/sysconf.d/10-bridhe-nf-call-iptables.conf
sysctl -p

##Pod CIDR 冲突

  • 容器与容器之间通信建立了一层特殊的 overlay 网络(虚拟ip)
  • 若 Pod 子网和宿主机网络出现冲突是,就会产生问题,导致无法访问
  • 将主机 IP 范围和 API Server 中指定的子网进行比较
  • 可在 CNI 插件 或 kubelet 的 pod-cidr 参数中指定 IP 地址范围,避免冲突

hairpin

  • 就是 自己访问自己
  • 有时 Pod 无法通过 Service IP 访问自己,这就有可能是 hairpin 的配置问题了
  • 通常,当 kube-proxy 以 iptables 或 IPVS 模式运行,并且 Pod 与桥接网络连接时,就会发生这种情况
  • kubelet 的启动参数提供了一个 --hairpin-mode 标志,支持的值有 hairpin-veth 和 promiscuous-bridge
  • –hairpin-mode 被 kubelet 设置成 hairpin-veth 并且生效后,底层其实是在修改宿主机 /sys/devices/virtual/net 目录下设备文件 hairpin_mode de 值
# 查看是否修改成功
for intf in /sys/devices/virtual/net/cbr0/brif/; do cat $intf/hairpin_mode; done

查看 pod ip 地址

# 从外面看
kubectl get pod
kubectl describe pod

# 进入容器查看 假设Pod的pause容器名称为abc
# 获得容器 id 假设结果返回32166
docker inspect abc --format '{{ .State.Pid}}'
# 进入容器查看 
nsenter --target 32166 --net
ip addr

故障排查工具

  1. tcpdump 捕获网络流量

  2. 容器镜像内置常用网络工具

    • FROM library/python:3.3
      RUN apt-get update && apt-get -y install iptoute2 net-tools ethtool nano
      

为什么不推荐使用SNAT

  • 因为内核需要修改源地址和端口,并记录到表中,并发多时,会导致记录覆盖,因此产生丢包
  • SNAT导致内核丢包原因在于其conntrack的实现
  • 容器端口映射到主机端口,会从上次分配的主机端口,向下顺次搜索,返回可用端口,当高并发时,可能将一个端口返回给多个容器,并记录到了表中,导致之后的丢包
  • 因此之后产生了随机探测宿主机可用端口,来避免冲突,缓解此问题
    • NF_NAT_RANGE_PROTO_RANDOM 部分随机
    • NF_NAT_RANGE_PROTO_RANDOM_FULLY 完全随机
    • iptables 已经支持 --random-fully 这个 flag
  • 虽然缓解了此问题,但不表示根治,因此不推荐生产环境上使用 NodePort

你可能感兴趣的:(Kubernetes学习笔记,linux,运维,k8s,kubernetes,网络)