《Kubernetes Service 进阶、kube-proxy 与 Ingress 实战精要》

《Kubernetes Service 进阶、kube-proxy 与 Ingress 实战精要》

本总结覆盖 Service 高级类型(NodePort / LoadBalancer / ExternalName / Headless)会话保持金丝雀发布 ,以及 kube-proxy 三种模式原理与切换 ,最后深入 Ingress-Nginx 控制器部署与核心规则 ,全部知识点配有带详细注释的 YAML 代码和命令示例,可直接用于生产环境参考。


一、Service 高级类型详解

1.1 环境准备(通用)

bash 复制代码
kubectl create ns services
kubectl config set-context --current --namespace services
kubectl create deployment web --image=httpd --replicas=2   # 后端应用

1.2 ClusterIP(默认)

  • 仅在集群内部可访问,分配一个虚拟 IP(ClusterIP)。
  • 其他类型(NodePort、LoadBalancer)都基于 ClusterIP 构建。

YAML 示例(不带注释,简单):

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-clusterip
spec:
  type: ClusterIP           # 可省略,默认
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80

1.3 NodePort

  • 在每个节点开放一个静态端口(默认 30000-32767),集群外部可通过 NodeIP:NodePort 访问。
  • 内部仍然分配 ClusterIP,kube-proxy 负责转发。

带注释的 YAML:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort                      # 指定类型
  selector:
    app: web
  ports:
  - port: 8080                        # ClusterIP 监听的端口
    targetPort: 80                    # Pod 容器端口
    nodePort: 30080                   # 可选,固定节点端口(范围 30000-32767)

创建命令:

bash 复制代码
kubectl expose deployment web --type=NodePort --port=8080 --target-port=80

访问测试(集群内任一节点 IP + nodePort):

bash 复制代码
curl http://<任意节点IP>:30080

1.4 LoadBalancer

  • 需要外部负载均衡器支持(云厂商或 MetalLB)。
  • 为 Service 分配一个独立的外部 IP,外部客户端可直接通过该 IP 访问。

部署 MetalLB(裸机 K8s 负载均衡实现):

bash 复制代码
# 下载并部署 metallb(需按环境替换镜像源)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.8/config/manifests/metallb-native.yaml

# 配置 IP 地址池(IPAddressPool)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 10.1.8.40-10.1.8.80          # 可用的外部 IP 范围
EOF

# 配置 L2 宣告(L2Advertisement)
cat <<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: example
  namespace: metallb-system
EOF

LoadBalancer Service YAML(带注释):

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-lb
spec:
  type: LoadBalancer                # 关键类型
  selector:
    app: web
  ports:
  - port: 80                        # 外部访问端口
    targetPort: 80

创建后,Kubernetes 会自动分配一个 EXTERNAL-IP(如 10.1.8.40)。

流量路径: 客户端 → LB IP:80 → 节点 kube-proxy → Service 转发 → Pod。


1.5 ExternalName

  • 通过 CNAME 记录将 Service 映射到外部域名,不提供代理。
  • 适用于集群内应用访问外部服务(如数据库)时统一使用 Service 名称。

示例:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: my-external-service
spec:
  type: ExternalName
  externalName: database.example.com    # 实际外部域名

集群内访问 my-external-service.namespace.svc.cluster.local 会解析为 database.example.com


1.6 Headless Service(无头服务)

  • clusterIP: None,不分配 ClusterIP,kube-proxy 不处理。
  • DNS 直接返回后端 Pod IP 列表(带选择器)或 CNAME(无选择器 + ExternalName)。
  • 适用于 StatefulSet、自定义服务发现。

YAML:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web-headless
spec:
  clusterIP: None          # 关键,设为 None
  selector:
    app: web
  ports:
  - port: 80
    targetPort: 80

二、Service 会话保持(Session Affinity)

2.1 概念

  • 默认 sessionAffinity: None,请求随机转发。
  • 设置为 ClientIP 后,基于源 IP 哈希,同一客户端始终转发到同一 Pod(适合有状态服务)。

2.2 配置与验证

bash 复制代码
# 创建 Deployment 和 Service(普通)
kubectl create deployment web --image=httpd --replicas=2
kubectl expose deployment web --port=80

# 修改每个 Pod 主页为 Pod 名称(用于观察)
for pod in $(kubectl get pods -o name | cut -d/ -f2); do
  kubectl exec $pod -- bash -c "echo $pod > htdocs/index.html"
done

# 验证默认分发(轮询)
for i in {1..10}; do curl -s 10.111.90.183; done | sort | uniq -c
# 输出会看到两个 Pod 各约 5 次

# 开启会话保持(使用 patch 命令)
kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'

# 再次测试,所有请求都发给同一个 Pod
for i in {1..10}; do curl -s 10.111.90.183; done | sort | uniq -c
# 输出只有 10 次同一条

YAML 中配置:

yaml 复制代码
spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600   # 粘性超时(默认 10800 秒)

注意: 会话保持与 kube-proxy 的 IPVS 模式配合时,会自动采用 sh(源地址哈希)调度算法。


三、金丝雀发布(Canary Deployment)复习

(已在 0810 笔记中详述,这里仅强调实现方式)

  • 同时运行两个 Deployment(稳定版 track: stable,金丝雀版 track: canary),Service 的 selector 只包含公共标签(如 app: web, tier: frontend)。
  • 通过调整两个 Deployment 的副本数比例实现流量灰度。

四、kube-proxy 工作模式详解

kube-proxy 是 K8s 核心网络组件,负责将 Service 的流量负载均衡到后端 Pod。

4.1 三种模式对比

模式 特点 性能 适用场景
iptables(默认) 基于 netfilter 规则链,规则多时性能下降 中(<1000 服务) 小规模、稳定环境
IPVS(推荐) 基于内核哈希表,O(1) 查找,支持多种调度算法 极高(10w+ 服务) 中大规模生产
Userspace(废弃) 用户态代理,性能极低 K8s 1.25+ 已移除

4.2 查看当前模式

bash 复制代码
# 查看 kube-proxy ConfigMap
kubectl get cm -n kube-system kube-proxy -o yaml | grep mode

# 查看 Pod 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using"
# 输出:Using iptables proxy 或 Using ipvs Proxier

4.3 切换到 IPVS 模式

bash 复制代码
# 1. 编辑 ConfigMap
kubectl edit cm -n kube-system kube-proxy
# 将 mode: "" 改为 mode: "ipvs"

# 2. 重启 kube-proxy DaemonSet
kubectl rollout restart ds -n kube-system kube-proxy

# 3. 验证
kubectl logs -n kube-system -l k8s-app=kube-proxy | grep "Using ipvs"

4.4 IPVS 原理验证(重点)

① 创建测试资源

bash 复制代码
kubectl create deployment web --image=nginx --replicas=3
kubectl expose deployment web --port=80

② 查看 IPVS 虚拟服务器

bash 复制代码
# 安装 ipvsadm 工具(节点上)
ipvsadm -L -n | grep -A5 "10.103.143.120:80"   # Service ClusterIP

输出类似:

复制代码
TCP  10.103.143.120:80 rr
  -> 10.224.19.38:80              Masq    1      0          0
  -> 10.224.113.164:80            Masq    1      0          0
  -> 10.224.113.165:80            Masq    1      0          0
  • rr 为调度算法(默认轮询)。
  • 每个后端 Pod 被注册为 Real Server。

③ 验证负载均衡

bash 复制代码
for i in {1..60}; do curl -s 10.103.143.120; done | sort | uniq -c
# 每个 Pod 约 20 次,说明 rr 轮询生效。

④ 修改调度算法(如 wrr)

bash 复制代码
# 编辑 ConfigMap,添加 ipvs.scheduler: "wrr"
kubectl edit cm -n kube-system kube-proxy
# ... 添加 scheduler: "wrr"
# 重启 kube-proxy 后生效

4.5 iptables 模式原理(补充)

  • iptables 规则链:KUBE-SERVICESKUBE-SVC-XXX(SNAT + 概率负载均衡) → KUBE-SEP-XXX(DNAT) → Pod。
  • 概率负载均衡通过 --probability 实现,规则数量随后端增加而线性增长。

五、Ingress 控制器与核心规则

5.1 Ingress 是什么

  • 为集群外部访问提供 7 层 HTTP/HTTPS 路由(域名、路径分流)。
  • 需要部署 Ingress 控制器(如 ingress-nginx)才能生效。

5.2 部署 ingress-nginx(使用 LoadBalancer 类型)

bash 复制代码
# 下载部署文件(已替换镜像源)
wget http://example.com/ingress-nginx-controller-v1.11.2.tar.gz
tar -xf ingress-nginx-controller-v1.11.2.tar.gz
# 修改镜像为私有仓库(如需)
sed -i 's#registry.k8s.io#hub.laoma.cloud#g' deploy.yaml
kubectl apply -f deploy.yaml

# 查看控制器资源
kubectl get all -n ingress-nginx
# 会看到 LoadBalancer Service 分配了外部 IP(如 10.1.8.40)

5.3 环境准备(两个后端服务)

bash 复制代码
# webapp01
kubectl create deployment webapp01 --image=httpd --replicas=2
kubectl expose deployment webapp01 --port=80

# webapp02
kubectl create deployment webapp02 --image=httpd --replicas=2
kubectl expose deployment webapp02 --port=80
# 设置各自主页内容(略)

5.4 核心 Ingress 规则(带完整注释)

(1)多域名虚拟主机

场景: 不同域名 webapp01.laoma.cloudwebapp02.laoma.cloud 分别路由到不同服务。

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx          # 指定控制器
  rules:
  - host: webapp01.laoma.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80
  - host: webapp02.laoma.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp02
            port:
              number: 80
(2)同一域名多路径

场景: www.laoma.cloud/ 走 webapp01,www.laoma.cloud/games 走 webapp02。

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-path-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: www.laoma.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80
      - path: /games
        pathType: Prefix
        backend:
          service:
            name: webapp02
            port:
              number: 80
(3)路径重写(裁剪前缀)------生产核心

场景: 前端访问 /webapp01/api/xxx,后端实际只认 /api/xxx,需要去掉 /webapp01 前缀。

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-trimming-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"          # 启用正则
    nginx.ingress.kubernetes.io/rewrite-target: /$1        # 重写目标,$1 捕获第一个括号内容
spec:
  ingressClassName: nginx
  rules:
  - host: www.laoma.cloud
    http:
      paths:
      - path: /webapp01/(.*)
        pathType: ImplementationSpecific   # 必须用 ImplementationSpecific 以支持正则
        backend:
          service:
            name: webapp01
            port:
              number: 80
      - path: /webapp02/(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: webapp02
            port:
              number: 80
  • 访问 www.laoma.cloud/webapp01/hello 会转发到 webapp01 服务的 /hello
(4)HTTPS + TLS 证书 + 强制跳转

准备证书并创建 Secret:

bash 复制代码
openssl genrsa -out www.key 2048
openssl req -new -key www.key -out www.csr -subj "/CN=www.laoma.cloud"
openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
kubectl create secret tls www-tls --cert=www.crt --key=www.key

Ingress 配置:

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"        # 强制 HTTPS 重定向
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - www.laoma.cloud
    secretName: www-tls            # 引用证书 Secret
  rules:
  - host: www.laoma.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80

5.5 生产级常用注解速查(带说明)

注解 作用 示例值
nginx.ingress.kubernetes.io/rewrite-target 路径重写 /$1(裁剪前缀)
nginx.ingress.kubernetes.io/ssl-redirect 80 端口自动跳转 443 "true"
nginx.ingress.kubernetes.io/whitelist-source-range IP 白名单(逗号分隔 CIDR) "10.1.8.0/24,192.168.1.0/24"
nginx.ingress.kubernetes.io/limit-rps 每秒请求数限流(单 IP) "20"
nginx.ingress.kubernetes.io/limit-connections 单 IP 最大并发连接数 "50"
nginx.ingress.kubernetes.io/enable-cors 开启跨域 "true"
nginx.ingress.kubernetes.io/proxy-read-timeout 后端读取超时(秒) "60"
nginx.ingress.kubernetes.io/x-forwarded-for 透传真实客户端 IP "true"
nginx.ingress.kubernetes.io/canary 启用灰度(金丝雀) "true"
nginx.ingress.kubernetes.io/canary-weight 灰度流量权重(0-100) "10"

示例(限流 + 白名单 + 超时):

yaml 复制代码
metadata:
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24"
    nginx.ingress.kubernetes.io/limit-rps: "30"
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "5"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "120"

六、环境清理

bash 复制代码
kubectl delete ns services   # 删除 Service 实验命名空间
kubectl delete ns ingress    # 删除 Ingress 实验命名空间

以上内容涵盖了 Service 高级类型kube-proxy 模式切换与验证Ingress 控制器部署和 10+ 核心规则,可直接用于生产环境配置。

相关推荐
Crazy________3 小时前
Redis03:持久化存储,大key分析,主从复制及哨兵模式
数据库·redis·容器
Zhu7583 小时前
使用helm在k8s集群部署MySQL单实例,支持当前所有主版本的最新子版本
mysql·adb·kubernetes
2401_834636993 小时前
从零吃透 K8s 网络:ServiceIngressMetalLB 实操手册
网络·容器·kubernetes
SLD_Allen4 小时前
HxApisix 云原生 API 网关的架构设计与 AI 集成实践(THS)
人工智能·网关·云原生·apisix
云烟成雨TD5 小时前
Micrometer 系列【39】链路追踪:入门案例 | 环境准备
java·云原生·链路追踪
Zhu7586 小时前
在docker环境部署frp
运维·docker·容器
掉鱼的猫7 小时前
Solon AOT & Native:三段式编译,从 Java 到原生可执行文件
java·云原生
x-cmd10 小时前
用 Rust 打造 AI 时代的 SQL:把重复任务变成可执行文件
数据库·人工智能·sql·ai·容器·rust·workflow