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 环境。

相关推荐
鹿鸣天涯1 天前
Xftp传输文件时,解决“无法显示远程文件夹”方法
运维·服务器·计算机
unDl IONA1 天前
服务器部署,用 nginx 部署后页面刷新 404 问题,宝塔面板修改(修改 nginx.conf 配置文件)
运维·服务器·nginx
Web极客码1 天前
WordPress管理员角色详解及注意事项
运维·服务器·wordpress
geinvse_seg1 天前
中小团队如何低成本搭建项目管理系统?基于 Ubuntu 的 Dootask 私有化部署实战
linux·运维·ubuntu
星辰徐哥1 天前
鸿蒙金融理财全栈项目——上线与运维、用户反馈、持续迭代优化
运维·金融·harmonyos
CSCN新手听安1 天前
【linux】高级IO,以ET模式运行的epoll版本的TCP服务器实现reactor反应堆
linux·运维·服务器·c++·高级io·epoll·reactor反应堆
丶伯爵式1 天前
Ubuntu 24.04 更换国内软件源指南 | 2026年3月26日
linux·运维·ubuntu·国内源·升级
xingyuzhisuan1 天前
租用GPU服务器进行深度学习课程教学的实验环境搭建
运维·人工智能·深度学习·gpu算力
Java后端的Ai之路1 天前
Linux端口进程查找与终止教程
linux·运维·服务器
busy dog~乌鸦~1 天前
【THM-题目答案】:Web Fundamentals-How The Web Works-DNS in Detail: Domain Hierarchy
运维·web安全·网络安全·系统安全