K3s

K3s 部署中解决获取真实 IP 的问题:使用 Calico 实现真实IP传递

Posted by Ksd on December 19, 2023

前言

在 Kubernetes 集群中,获取用户真实 IP 地址是一个至关重要的需求。然而,在 K3s 部署中,很多运维人员可能会遇到一些困扰,尤其是在使用 K3s 默认的 CNI Flannel 作为网络插件时,难以准确获取到用户的真实 IP 地址。

本文将分享在解决这一问题的过程中的实践经验,尤其是通过使用 Calico 替代 Flannel 的方式,成功实现了真实 IP 的传递。值得注意的是,虽然 Flannel 也可以实现获取真实 IP 的功能,但我选择使用 Calico 来代替 Flannel,以获得更灵活和可定制的网络方案。

环境准备

在阿里云环境中进行测试,使用机器内网网段为 172.19.112.0/20,推荐使用全新机器以避免潜在问题。

测试环境 (sip.pro.com)

  • 一台 master(10.42.0.0),三台 node(10.42.1.0 10.42.2.0 10.42.3.0)
  • K3s 版本:1.25.12
  • 操作系统:Ubuntu 20.04.6
  • Traefik 版本:2.9.10(通过 Helm 安装)
  • Rancher 版本:2.7.9

问题发现

在部署中发现 x-forwarded-forx-real-ip 无法获取到用户请求的真实 IP 地址。

探寻原因

通过查阅 K3s 的相关讨论,发现使用内置的 Flannel 无法获取到用户真实 IP,最多只能到 LB 的 IP。解决方案可以禁用掉默认的 flannel,通过手动部署的形式修改 flannel 参数,或者是使用 Calico 替代 Flannel

测试和解决方案尝试

为验证真实 IP 是否正确获取,统一使用 SIP 进行测试。测试环境映射到 https://sip.pro.com。

kubectl create deployment source-ip-app --image=corelab/echoserver:1.4

1. 默认配置

验证: 访问 https://sip.pro.com

CLIENT VALUES:
client_address=10.42.0.27
...
x-forwarded-for=10.42.3.0
x-real-ip=10.42.3.0

未更改 CNI,使用默认的 K3s 安装的 Flannel,只能获取到 Pod 的网段地址 10.42.3.0。

2. Traefik Service 配置 externalTrafficPolicy: Local

利用 HelmChartConfig 自定义 Traefik Service:

cat << EOL > /var/lib/rancher/k3s/server/manifests/traefik-config.yaml
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
  name: traefik
  namespace: kube-system
spec:
  valuesContent: |-
    service:
      spec:
        externalTrafficPolicy: Local
EOL

验证: 访问 https://sip.pro.com

CLIENT VALUES:
client_address=10.42.0.27
...
x-forwarded-for=10.42.2.203
x-real-ip=10.42.2.203

可以获取到指定 node 的 Klipper-lb (Service LB)的 pod ip

3. 测试环境,安装方式改变

禁用默认的 Flannel,同时禁用网络策略,安装 Calico。

curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | \
    INSTALL_K3S_VERSION=v1.25.12+k3s1 \
    INSTALL_K3S_MIRROR=cn \
    INSTALL_K3S_EXEC='--flannel-backend=none --disable-network-policy --cluster-cidr=192.168.0.0/16' \
    sh -

安装 Calico(Manifest 版本):

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.4/manifests/calico.yaml

等待节点安装完成即可。

单节点测试 Calico:

这次按照上文中 K3s 讨论 中说的,换成 calico,真实 ip 已经能到达节点 ip 了,不过现在这个实验场景是使用的单个 k3s 节点。没改 traefik svc 的 Local,可以取到节点 ip,改掉之后,也会取到真实公网 ip

#sip.pro.com

CLIENT VALUES:
client_address=192.168.105.200
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://sip.pro.com:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
accept-encoding=gzip, deflate
accept-language=zh-CN,zh;q=0.9,en;q=0.8
cache-control=max-age=0
host=777.xydao.cn
upgrade-insecure-requests=1
user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
x-forwarded-for=172.19.112.37
x-forwarded-host=sip.pro.com
x-forwarded-port=80
x-forwarded-proto=http
x-forwarded-server=traefik-66fd46ccd-n9qzd
x-real-ip=172.19.112.37
BODY:
-no body in request-

多节点测试:

发现已经拿到公网 ip,成功~可以上生产啦!

#sip.pro.com

CLIENT VALUES:
client_address=192.168.105.200
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://sip.pro.com:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
accept-encoding=gzip, deflate
accept-language=zh-CN,zh;q=0.9,en;q=0.8
host=sip.pro.com
upgrade-insecure-requests=1
user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
x-forwarded-for=171.214.1.1
x-forwarded-host=sip.pro.com
x-forwarded-port=80
x-forwarded-proto=http
x-forwarded-server=traefik-66fd46ccd-n9qzd
x-real-ip=171.214.1.1
BODY:
-no body in request-

结论

通过替代 Flannel 为 K3s 选择 Calico,我们成功解决了在生产环境中获取真实 IP 的问题。这个优化不仅确保了 IP 的准确性,还提高了 Kubernetes 集群的可用性。

进一步阅读

若想深入了解本文所涉及的技术和问题,建议阅读以下参考链接:

后记

感谢大家阅读本文,希望能为 K3s 用户在解决真实 IP 获取问题上提供一些有用的经验。欢迎大家分享和讨论,一起探讨 Kubernetes 在实际应用中的优化与实践。