K3s + Harbor 端口冲突问题解决方案(Harbor 使用 80 端口)

K3s + Harbor 端口冲突问题解决方案(Harbor 使用 80 端口)

1. 环境概述

  • 操作系统:Linux(CentOS/Rocky 等)
  • K3s 版本:v1.34.5+k3s1(单节点)
  • Harbor 版本:v2.14.1,通过 Docker Compose 部署
  • Harbor 配置:Nginx 容器直接绑定主机 80 端口
  • K3s 网络插件 :默认使用 Traefik 作为 Ingress Controller,Service 类型为 LoadBalancer

2. 问题现象

完成 Harbor 部署后,在浏览器中访问 http://<主机IP>(例如 http://192.168.100.172),返回页面内容为:

复制代码
404 page not found

此页面为 Traefik 的默认 404 页面,而非 Harbor 的登录界面,说明请求被 Traefik 拦截,未能到达 Harbor 容器。

3. 问题分析

3.1 端口占用情况

通过 ss -antl 查看主机端口监听状态:

复制代码
LISTEN    0    4096    0.0.0.0:80     0.0.0.0:*
LISTEN    0    4096    [::]:80        [::]:*

80 端口确实被 Harbor 的 Nginx 容器占用(通过 docker ps 确认)。但为何访问仍会进入 Traefik?

3.2 K3s 默认 Traefik 行为

K3s 安装时会自动部署 Traefik Ingress Controller,并创建一个 LoadBalancer 类型的 Service:

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: kube-system
spec:
  ports:
  - name: web
    port: 80
    targetPort: web
    nodePort: 31415
  - name: websecure
    port: 443
    targetPort: websecure
    nodePort: 32397
  type: LoadBalancer

K3s 自带的 service loadbalancer 组件(svclb-traefik)会监听主机端口,并通过 iptables 规则 将目标为 EXTERNAL-IP:80 的流量 DNAT 到 Traefik Pod 的 nodePort(如 31415)。这些规则优先级高于 Harbor 直接绑定的端口,导致请求被劫持。

3.3 iptables 规则验证

在主机上执行以下命令,可以看到相关 DNAT 规则:

bash 复制代码
iptables -t nat -L PREROUTING -n -v

输出类似:

复制代码
DNAT       tcp  --  0.0.0.0/0   192.168.100.172   tcp dpt:80 to:10.43.160.149:31415

其中 10.43.160.149 是 Traefik Service 的 ClusterIP,31415 是 NodePort。正是这条规则将原本发往主机 80 端口的流量重定向到了 Traefik Pod,从而绕过了 Harbor 的 Nginx 容器。

4. 解决方案

核心思路:移除或修改 Traefik Service 对主机 80 端口的监听,释放该端口给 Harbor 使用。

由于用户明确要求 Harbor 使用 80 端口且不能修改 Harbor 配置,因此只能调整 Traefik 的暴露方式。

4.1 方案一:将 Traefik 的 web 端口改为其他端口(推荐)

修改 traefik Service,将 web 端口的 port80 改为其他未占用端口(例如 81)。这样 K3s 的 svclb 组件将不再监听主机 80 端口,原有的 iptables DNAT 规则会被自动清理。

4.2 方案二:完全删除 Traefik Service 的 web 端口条目

如果不需要通过 Traefik 暴露任何 HTTP 服务,可以删除 web 端口条目,仅保留 websecure(443)端口。但这样会导致所有 HTTP Ingress 无法工作,一般不建议。

5. 操作步骤(以修改端口为例)

5.1 编辑 Traefik Service

bash 复制代码
kubectl edit service -n kube-system traefik

5.2 修改端口配置

找到 ports 部分,将 web 端口的 port 值从 80 改为 81

yaml 复制代码
ports:
- name: web
  nodePort: 31415
  port: 81          # 原为 80,改为 81
  protocol: TCP
  targetPort: web
- name: websecure
  nodePort: 32397
  port: 443
  protocol: TCP
  targetPort: websecure

保存退出后,K3s 会自动更新 Service 和相关的 iptables 规则。

5.3 验证修改结果

bash 复制代码
kubectl get service -n kube-system traefik

输出应显示:

复制代码
NAME      TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
traefik   LoadBalancer   10.43.160.149   192.168.100.172   81:31415/TCP,443:32397/TCP   127m

此时主机 80 端口已不再被 Traefik 占用,仅 Harbor Nginx 容器监听:

bash 复制代码
ss -antl | grep :80

应只显示 Harbor 的监听。

6. 验证结果

在浏览器中访问 http://192.168.100.172(或你的主机 IP),应看到 Harbor 的登录页面,而非 Traefik 的 404 页面。若仍无法访问,检查 Harbor 容器状态及防火墙规则。

7. 原理说明

7.1 K3s 的 LoadBalancer 实现

K3s 使用内置的 service loadbalancer 组件(由 svclb Pod 实现)为 LoadBalancer 类型的 Service 分配外部 IP。该组件在每个节点上运行一个 Pod,该 Pod 通过 netlinkiptables 在主机上创建规则,将发往 Service 外部 IP 的流量 DNAT 到 Service 的 ClusterIP 或 NodePort。对于 traefik Service,这些规则会拦截所有目的端口为 80 和 443 的流量,并转发到 Traefik Pod。

7.2 端口冲突的根本原因

  • 直接绑定 :Harbor 的 Nginx 容器通过 Docker 的 -p 80:8080 直接绑定主机 80 端口,这是用户空间的端口监听。
  • 内核空间劫持 :iptables 规则位于内核的 PREROUTING 链,优先级高于用户空间进程的监听。当请求到达主机时,内核首先检查 iptables 规则,匹配的流量会被直接 DNAT 到目标地址,用户空间的应用程序(如 Harbor Nginx)根本收不到数据包。

因此,尽管 ss 显示 80 端口被 Harbor 占用,实际上流量在进入应用层之前已被重定向。

7.3 解决方法的核心

通过修改 Traefik Service 的 port 值,使 K3s 的 svclb 不再创建针对主机 80 端口的 iptables 规则。原有的 DNAT 规则会在 Service 更新后被自动删除,从而让流量正常流入 Harbor 容器。

8. 注意事项

  • 修改 Traefik Service 后,所有原本通过 HTTP(80端口)访问的 Ingress 资源将无法通过默认的 80 端口访问。如果需要继续使用 HTTP Ingress,可以考虑:
    • 将 Ingress 的端口改为 81(即访问 http://<IP>:81),但需在 Ingress 规则中指定。
    • 或者使用 HTTPS(443)替代 HTTP。
  • 如果未来需要恢复 Traefik 对 80 端口的监听,只需再次编辑 Service,将 port 改回 80 即可。
  • 确保防火墙(如 firewalld、iptables)没有额外限制 80 端口。Harbor 容器正常监听后,应能正常访问。

9. 总结

通过调整 K3s 中 Traefik Service 的端口映射,成功释放了主机 80 端口给 Harbor 使用,解决了因 iptables 规则优先级导致的端口冲突问题。该方法无需修改 Harbor 配置,保持了 Harbor 使用 80 端口的原意,且操作简单、可回滚,适用于单节点 K3s 环境。

相关推荐
qq_339191142 小时前
uv 设置系统默认版本, linux设置uv
linux·运维·uv
小猿姐2 小时前
当KubeBlocks遇上国产数据库之Kingbase:让信创数据库“飞得更高”
运维·数据库·云原生
似水এ᭄往昔2 小时前
【Linux】--进程概念
linux·运维·服务器
IDIOT___IDIOT2 小时前
Linux 使用 `cp` 命令导致挂载点被覆盖问题记录
linux·运维·服务器
李彦亮老师(本人)3 小时前
Rocky Linux 9.x 安全加固实战指南:从系统初始化到生产级防护
linux·运维·安全·rocky
RisunJan3 小时前
Linux命令-mount(用于挂载Linux系统外的文件)
linux·运维·服务器
国冶机电安装3 小时前
其他弱电系统安装:从方案设计到落地施工的完整指南
大数据·运维·网络
蓝天守卫者联盟13 小时前
玩具喷涂废气治理厂家:行业现状、技术路径与选型指南
大数据·运维·人工智能·python