在K8s集群中部署Traefik并验证Python HTTP服务

一、背景与目标

在个人学习Kubernetes的过程中,我希望搭建一套完整的入口流量管理方案。本文将详细记录在一个3节点的裸金属K8s集群(ubuntu-111/112/113)中,如何部署Traefik作为Ingress Controller(同时运行在ubuntu-111、ubuntu-112节点),并通过一个Python HTTP服务验证整个链路的可用性。

二、环境规划

  • K8s集群:3节点,无MetalLB,使用HAProxy作为外部负载均衡
  • Traefik版本:Helm Chart 39.1.0-ea.2(Traefik 3.x)
  • 核心目标
    1. Traefik仅调度到ubuntu-111、ubuntu-112节点(通过节点亲和性实现)
    2. 启用hostNetwork模式,直接占用节点80/443端口
    3. HAProxy代理两个Traefik节点,增加后端健康检查
    4. 部署Python HTTP服务并通过Traefik Ingress暴露

三、Traefik部署实践

1. 节点标签与亲和性配置

1.1 为多节点打标签

给ubuntu-111、ubuntu-112都打上traefik-work=true标签,作为Traefik调度的目标节点:

bash 复制代码
# 给ubuntu-111打标签
kubectl label nodes ubuntu-111 traefik-work=true
# 给ubuntu-112打标签
kubectl label nodes ubuntu-112 traefik-work=true

# 验证标签是否添加成功
kubectl get nodes ubuntu-111 ubuntu-112 --show-labels | grep traefik-work
1.2 多节点亲和性配置

在Traefik的values.yaml中,配置节点亲和性匹配两个打标签的节点,同时设置Pod反亲和性避免同一节点运行多个Traefik实例:

yaml 复制代码
affinity:
  # 节点亲和性:匹配traefik-work=true的节点(ubuntu-111/112)
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: traefik-work
          operator: In
          values:
          - "true"  # 必须是字符串类型,避免JSON解析错误
  # Pod反亲和性:避免同一节点运行多个Traefik Pod
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchLabels:
          app.kubernetes.io/name: traefik
      topologyKey: kubernetes.io/hostname

# hostNetwork配置(直接使用节点网络)
hostNetwork: true

deployment:
  replicas: 2  # 副本数与目标节点数一致(2个)
  pod:
    securityContext:
      capabilities:
        add:
        - NET_BIND_SERVICE  # 允许绑定80/443端口
      runAsUser: 0

# 端口配置(绑定节点80/443)
ports:
  web:
    port: 80
    hostPort: 80
  websecure:
    port: 443
    hostPort: 443

2. 使用Helm部署Traefik

将上述配置写入traefik-values.yaml,执行以下命令完成部署:

bash 复制代码
# 添加Traefik Helm仓库
helm repo add traefik https://traefik.github.io/charts
helm repo update

# 部署Traefik(指定Chart版本,使用自定义配置)
helm install traefik traefik/traefik \
  --namespace kube-system \
  --create-namespace \
  --version 39.1.0-ea.2 \
  -f traefik-values.yaml

# 验证Traefik Pod调度结果(应分别运行在ubuntu-111/112)
kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik -o wide

3. HAProxy配置(多节点代理+健康检查)

3.1 完整HAProxy配置文件

修改HAProxy配置,代理两个Traefik节点的80/443端口,并增加TCP层健康检查(验证Traefik服务可用性):

bash 复制代码
#!/bin/bash
set -euo pipefail

# 基础配置
HAPROXY_NODE_IP="192.168.56.102"  # HAProxy所在节点IP
MASTER_NODES=("192.168.56.111" "192.168.56.112" "192.168.56.113")
K8S_API_PORT=6443
HAPROXY_PORT=6443

# Traefik配置(代理ubuntu-111/112的80/443端口)
TRAEFIK_NODES=("192.168.56.111" "192.168.56.112")  # Traefik运行节点
TRAEFIK_HTTP_PORT=80
TRAEFIK_HTTPS_PORT=443

# 安装haproxy
apt update -y && apt install -y haproxy net-tools || true
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak$(date +%Y%m%d%H%M%S) || true

# 生成haproxy.cfg
cat > /etc/haproxy/haproxy.cfg << EOF
global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    maxconn 2000

defaults
    log     global
    mode    tcp
    option  tcplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

# K8s apiserver代理(原有配置)
frontend k8s-api-frontend
    bind ${HAPROXY_NODE_IP}:${HAPROXY_PORT}
    default_backend k8s-api-backend

backend k8s-api-backend
    mode tcp
    balance roundrobin
    option tcp-check
EOF

# 添加master节点到apiserver backend
for master in "${MASTER_NODES[@]}"; do
    cat >> /etc/haproxy/haproxy.cfg << EOF
    server master-${master//./-} ${master}:${K8S_API_PORT} check inter 2000 fall 3 rise 2
EOF
done

# Traefik HTTP代理(多节点+健康检查)
cat >> /etc/haproxy/haproxy.cfg << EOF

# Traefik HTTP代理(hostNetwork模式)
frontend traefik-http-frontend
    bind ${HAPROXY_NODE_IP}:${TRAEFIK_HTTP_PORT}
    default_backend traefik-http-backend

backend traefik-http-backend
    mode tcp
    balance roundrobin
    # TCP健康检查:验证后端80端口是否可连接
    option tcp-check
    tcp-check connect port ${TRAEFIK_HTTP_PORT}
    tcp-check send GET /ping HTTP/1.1\r\nHost: localhost\r\n\r\n
    tcp-check expect string 200 OK
EOF

# 添加两个Traefik节点到HTTP backend(带健康检查)
for node in "${TRAEFIK_NODES[@]}"; do
    cat >> /etc/haproxy/haproxy.cfg << EOF
    server traefik-node-${node//./-}-http ${node}:${TRAEFIK_HTTP_PORT} check inter 2000 fall 3 rise 2 timeout connect 3s
EOF
done

# Traefik HTTPS代理(多节点+健康检查)
cat >> /etc/haproxy/haproxy.cfg << EOF

# Traefik HTTPS代理(hostNetwork模式)
frontend traefik-https-frontend
    bind ${HAPROXY_NODE_IP}:${TRAEFIK_HTTPS_PORT}
    default_backend traefik-https-backend

backend traefik-https-backend
    mode tcp
    balance roundrobin
    # TCP健康检查:验证后端443端口是否可连接
    option tcp-check
    tcp-check connect port ${TRAEFIK_HTTPS_PORT}
EOF

# 添加两个Traefik节点到HTTPS backend(带健康检查)
for node in "${TRAEFIK_NODES[@]}"; do
    cat >> /etc/haproxy/haproxy.cfg << EOF
    server traefik-node-${node//./-}-https ${node}:${TRAEFIK_HTTPS_PORT} check inter 2000 fall 3 rise 2 timeout connect 3s
EOF
done

# 重启haproxy并验证
systemctl daemon-reload
systemctl enable --now haproxy
systemctl restart haproxy

# 验证HAProxy状态
if systemctl is-active --quiet haproxy; then
    echo -e "\033[32mHAProxy部署成功:"
    echo -e "  - K8s API: ${HAPROXY_NODE_IP}:${HAPROXY_PORT}"
    echo -e "  - Traefik HTTP: ${HAPROXY_NODE_IP}:${TRAEFIK_HTTP_PORT} (代理到${TRAEFIK_NODES[*]})"
    echo -e "  - Traefik HTTPS: ${HAPROXY_NODE_IP}:${TRAEFIK_HTTPS_PORT} (代理到${TRAEFIK_NODES[*]})\033[0m"
else
    echo -e "\033[31mHAProxy启动失败\033[0m"
    systemctl status haproxy --no-pager
    exit 1
fi
3.2 健康检查关键配置说明
  • option tcp-check:启用TCP层健康检查,验证后端端口是否存活;
  • tcp-check send GET /ping HTTP/1.1\r\nHost: localhost\r\n\r\n:向Traefik的/ping接口发送请求(Traefik内置健康检查接口);
  • tcp-check expect string 200 OK:期望返回200状态码,确认Traefik服务正常;
  • check inter 2000 fall 3 rise 2:每2秒检查一次,连续3次失败标记为不可用,连续2次成功恢复可用;
  • timeout connect 3s:连接超时时间3秒,避免健康检查阻塞。
3.3 验证HAProxy健康检查
bash 复制代码
# 查看HAProxy后端状态
echo "show stat" | socat /run/haproxy/admin.sock stdio | grep traefik

# 查看HAProxy日志(验证健康检查结果)
tail -f /var/log/haproxy.log | grep traefik

四、hostNetwork vs NodePort:差异与优劣对比

特性 hostNetwork模式 NodePort模式
网络模型 Pod直接使用节点的网络命名空间,监听节点IP和端口。 Service在节点上打开一个端口(NodePort),流量通过kube-proxy转发到Pod。
端口占用 直接占用节点的80/443等标准端口,同一节点上的多个Pod不能监听同一端口。 使用30000-32767范围内的端口,避免与主机服务冲突。
性能 性能最优,无额外的NAT和转发开销。 存在kube-proxy的转发开销,性能略低。
隔离性 差,Pod可以看到节点上的所有网络接口和连接。 好,Pod的网络栈与节点隔离。
高可用 需要通过Pod反亲和性确保每个节点只运行一个Pod,配合HAProxy健康检查实现高可用。 自动负载均衡到所有节点的NodePort,高可用更简单,但依赖kube-proxy。
适用场景 对性能要求极高的Ingress Controller、网络插件等。 通用的服务暴露方式,适合大多数应用。

五、Python HTTP服务部署

1. 服务代码(新增容器信息获取)

python 复制代码
from http.server import BaseHTTPRequestHandler, HTTPServer
import os, socket, json

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.end_headers()
        
        # 获取容器与Pod元数据
        pod_name = os.getenv("POD_NAME", socket.gethostname())
        node_name = os.getenv("NODE_NAME", "unknown-node")
        app_info = {
            "app": "python-http-server",
            "container": os.getenv("CONTAINER_NAME", "python-http-server")
        }
        
        response = f"""
        <h1>✅ Python HTTP Server</h1>
        <p>Pod: {pod_name}</p>
        <p>Node: {node_name}</p>
        <p>App Info: {json.dumps(app_info, indent=2)}</p>
        """
        self.wfile.write(response.encode('utf-8'))

def run(server_class=HTTPServer, handler_class=Handler, port=8080):
    server_address = ('0.0.0.0', port)
    httpd = server_class(server_address, handler_class)
    print(f"🚀 Python HTTP服务器启动: 0.0.0.0:{port}")
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        httpd.server_close()
        print("🛑 服务器已停止")

if __name__ == '__main__':
    run()

2. K8s资源配置

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-http-server
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: python-http-server
  template:
    metadata:
      labels:
        app: python-http-server
    spec:
      containers:
      - name: python-http-server
        image: 192.168.56.102/library/python-http-server:v1
        ports:
        - containerPort: 8080
          name: http
        env:
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: CONTAINER_NAME
          value: "python-http-server"
---
apiVersion: v1
kind: Service
metadata:
  name: python-http-server
  namespace: default
spec:
  selector:
    app: python-http-server
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: python-http-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "traefik"
spec:
  rules:
  - host: python-http.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: python-http-server
            port:
              number: 80

六、整体验证流程

1. 验证Traefik调度

bash 复制代码
kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik -o wide
# 预期结果:两个Traefik Pod分别运行在ubuntu-111、ubuntu-112

2. 验证HAProxy健康检查

bash 复制代码
# 查看Traefik后端状态(STATUS列为UP表示正常)
echo "show stat" | socat /run/haproxy/admin.sock stdio | grep traefik | awk '{print $1,$2,$18}'

3. 验证Python服务访问

bash 复制代码
# 配置本地hosts
echo "192.168.56.102 python-http.example.com" >> /etc/hosts

# 多次访问验证负载均衡(会轮询到两个Traefik节点)
curl http://python-http.example.com
curl http://python-http.example.com

4. 故障模拟验证

bash 复制代码
# 停止ubuntu-111上的Traefik Pod
kubectl delete pod -n kube-system $(kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik -o name | grep ubuntu-111 | cut -d/ -f2)

# 查看HAProxy后端状态(ubuntu-111节点会被标记为DOWN,流量自动切换到ubuntu-112)
echo "show stat" | socat /run/haproxy/admin.sock stdio | grep traefik

七、总结

本次实践完成了Traefik在多节点(ubuntu-111/112)的部署,通过节点标签和亲和性实现精准调度,配合HAProxy的多节点代理和健康检查,保障了入口流量的高可用。对比hostNetwork和NodePort模式,清晰体现了不同网络模式的优劣,也验证了Python HTTP服务通过Traefik Ingress暴露的完整链路,为K8s流量管理的学习打下了坚实基础。

相关推荐
laplace01231 小时前
第二章 字符串和文本 下
服务器·数据库·python·mysql·agent
得一录2 小时前
VS Code创建虚拟环境指南
python
List<String> error_P2 小时前
蓝桥杯高频考点练习:模拟问题“球队比分类”
数据结构·python·算法·模拟·球队比分
nix.gnehc2 小时前
深入浅出 K8s 内外部通信:全场景方案解析与生产实践
云原生·容器·kubernetes
啊阿狸不会拉杆2 小时前
《计算机视觉:模型、学习和推理》第 4 章-拟合概率模型
人工智能·python·学习·算法·机器学习·计算机视觉·拟合概率模型
七夜zippoe2 小时前
模拟与存根实战:unittest.mock深度使用指南
linux·服务器·数据库·python·模拟·高级摸您
踩坑记录2 小时前
leetcode hot100 17. 电话号码的字母组合 medium 递归回溯
python
芒果不茫QAQ2 小时前
Upstash Vector 免费版完整使用指南
python·aigc·embedding·rag·upstash
~央千澈~2 小时前
优雅草正版授权系统 - 优雅草科技开源2月20日正式发布
python·vue·php·授权验证系统