You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

单节点Ubuntu部署的K3s无法访问监听回环地址的主机服务:原因分析与最佳实践

K3s内部服务无法连接主机上监听127.0.0.1的外部服务,改为0.0.0.0则正常,原因是什么?最佳实践是什么?

问题描述

我在单台Ubuntu机器上部署了K3s,同时这台机器还直接安装了Redis、MySQL等K8s集群外部的服务。出于安全考虑,这些服务默认监听回环地址127.0.0.1,但K3s内部的Pod服务无法连接到这些数据库。当我把服务的监听地址改成0.0.0.0后,问题就解决了。

我目前尝试用Endpoints将主机服务映射到K8s中,配置如下:

apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  ports:
  - port: 6379
---
apiVersion: v1
kind: Endpoints
metadata:
  name: redis
subsets:
- addresses:
  - ip: xxxxx (host's ip)
  ports:
  - port: 6379

想请教两个问题:

  1. 为什么监听127.0.0.1时K3s内部服务无法连接?
  2. 这种场景下的最佳实践是什么?

回答

一、为什么监听127.0.0.1时K3s内部服务无法连接?

核心原因是Linux网络命名空间的隔离性

  • 主机和K3s的每个Pod都拥有独立的网络命名空间,各自的127.0.0.1是完全独立的回环接口。当你通过Endpoints配置让Pod访问主机IP时,Pod的请求是从自身的网络命名空间发出,目标是主机的物理/虚拟网卡IP。但你的服务只监听127.0.0.1,意味着它只会响应来自主机自身网络命名空间的请求,Pod的跨命名空间请求自然会被拒绝。
  • 当你把监听地址改为0.0.0.0,服务会绑定主机上所有可用的网络接口(包括主机对外的网卡、K3s创建的虚拟集群网卡),此时Pod发起的请求就能被服务接收,连接也就正常了。

二、这种场景下的最佳实践

直接用0.0.0.0会让服务暴露给主机所在的整个网络,存在安全隐患。推荐以下几种更安全的方案,按安全性和适用性排序:

1. 使用Unix套接字+hostPath挂载(最安全)

如果你的服务支持Unix套接字(Redis、MySQL、PostgreSQL等主流服务都支持),这是最优解——完全不需要开放网络端口,仅通过文件系统权限控制访问。

操作步骤:

  • 修改服务配置,启用套接字监听:
    以Redis为例,修改redis.conf
    # 注释掉bind 127.0.0.1
    # bind 127.0.0.1
    unixsocket /var/run/redis/redis.sock
    unixsocketperm 777  # 权限可根据Pod的运行用户调整,比如770配合用户组
    
  • 重启Redis服务,确保/var/run/redis/redis.sock生成
  • 在需要连接服务的Pod中,通过hostPath挂载套接字所在目录,直接通过套接字访问:
    apiVersion: v1
    kind: Pod
    metadata:
      name: redis-client-pod
    spec:
      containers:
      - name: redis-client
        image: redis:latest
        command: ["redis-cli", "-s", "/host-sockets/redis.sock"]
        volumeMounts:
        - name: redis-socket
          mountPath: /host-sockets
      volumes:
      - name: redis-socket
        hostPath:
          path: /var/run/redis
          type: Directory
    

2. 让服务监听K3s集群的虚拟网卡IP

K3s单节点部署时,会创建一个虚拟网卡(通常是cni0flannel.1),这个网卡的IP是集群内部的网关地址(比如10.42.0.1)。让服务监听这个IP,只有K3s集群内的Pod能访问,外部网络无法触及。

操作步骤:

  • ip addr查看主机上的K3s虚拟网卡IP:
    ip addr show cni0
    
  • 修改服务配置的监听地址为这个IP,比如Redis的bind 10.42.0.1
  • 重启服务后,你的Endpoints配置可以直接用这个IP,Pod就能正常连接了

3. 给需要访问的Pod启用hostNetwork模式

如果你的Pod不需要严格的网络隔离,可以开启hostNetwork: true,让Pod直接使用主机的网络命名空间。此时Pod内的127.0.0.1就是主机的回环地址,能直接连接监听127.0.0.1的服务。

注意:这种模式下Pod会占用主机的端口,要避免端口冲突;同时Pod的网络和主机完全共享,隔离性差,仅适合小型测试或对隔离要求低的场景。

示例Pod配置:

apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
spec:
  hostNetwork: true
  containers:
  - name: my-app
    image: your-app-image:latest
    ports:
    - containerPort: 8080

4. 监听主机私有IP+防火墙限制

如果主机有局域网私有IP,你可以让服务监听这个IP,同时用防火墙规则只允许K3s集群的Pod CIDR段访问该端口。

操作步骤:

  • 修改服务监听地址为主机私有IP(比如192.168.1.100
  • ufw添加防火墙规则(假设K3s Pod CIDR是10.42.0.0/16):
    # 允许集群内Pod访问服务端口
    ufw allow from 10.42.0.0/16 to 192.168.1.100 port 6379
    # 拒绝其他所有来源的访问
    ufw deny 6379
    
  • 保持Endpoints配置中的主机私有IP即可

内容的提问来源于stack exchange,提问作者Chenhe

火山引擎 最新活动