一、问题背景与核心场景
在Kubernetes(以下简称K8s)集群里跑服务,最头疼的就是让外部用户能顺利访问到内部服务。Kong作为一款常用的API网关,很多人会把它做成Ingress Controller(以下简称KIC)来统一管理流量,但部署过程中经常卡在网络连通、负载均衡配置这些环节。我之前帮客户排查过三次同类型问题,总结下来核心场景集中在:中小团队刚从虚拟机转容器化,想用KIC统一代理所有微服务,但部署后要么外部访问不通,要么流量只到部分节点,要么配置了负载均衡却没生效。 这类问题的根源往往不是Kong本身的功能bug,而是对K8s网络模型、Service类型、负载均衡注解这些基础概念的理解偏差,再加上不同云厂商的负载均衡实现有差异,很容易踩坑。
1.1 先明确核心概念(生活化解释)
先把两个最容易混淆的概念说清楚,不然后面的排查都是白搭: 第一个是K8s的Service类型,它就像你小区的快递站,不同类型对应不同的取件方式:有的快递站只对小区内部开放(ClusterIP),有的可以让小区外的人直接上门取件(NodePort),还有的是专门安排一个专属快递员送上门(LoadBalancer)。 第二个是负载均衡器注解,它就像你给快递站提的个性化要求:比如要优先给某几栋楼送件、要走专用的快递通道、要检查快递有没有损坏。不同的云厂商(比如阿里云、AWS、腾讯云)对这些要求的写法不一样,不能通用。
二、第一步:Service类型选择的坑与排查
很多人部署KIC的时候,随便选个Service类型就往下走,结果后面出问题根本找不到原因。这一步是基础,必须先把Service类型选对,才能谈后面的配置。
2.1 三种Service类型的适用场景与优缺点
我把三种常用类型的适用场景、优缺点列出来,方便大家对应自己的情况选:
- ClusterIP:只在K8s集群内部能访问,相当于小区内部快递站。优点是配置简单、安全,缺点是外部用户根本连不上,完全不适合给KIC用,除非你有额外的反向代理层,比如Nginx再做一层转发,这种场景很少见。
- NodePort:每个K8s节点都会开一个固定端口,外部用户可以通过任意节点的这个端口访问服务,相当于小区每个单元楼门口都放一个快递柜,外面的人可以去任意一个单元楼取件。优点是配置简单,不需要依赖云厂商的负载均衡,适合测试环境或者没有云厂商LB的场景;缺点是如果节点宕机,这个节点的端口就用不了,而且端口范围有限制(默认是30000-32767),容易和其他服务冲突。
- LoadBalancer:K8s会自动调用云厂商的API创建一个负载均衡器,所有外部流量先到这个LB,再由LB转发到KIC的Pod,相当于专门安排一个专属快递员,不管你家在哪个单元楼,快递员都会把件送到你手里。优点是自动实现高可用,不用管节点宕机的问题,端口可以自定义,适合生产环境;缺点是依赖云厂商的支持,不同厂商的配置不一样,而且会产生额外的费用。
2.2 常见错误示例与排查方法
我遇到过最常见的错误是:部署KIC的时候选了ClusterIP,然后以为外部能访问,结果连不上。还有的选了NodePort,但节点的防火墙没开对应的端口,导致访问超时。 这里给大家一个完整的示例,先创建一个测试用的KIC部署,技术栈统一使用Kubernetes + Kong Ingress Controller(v3.4版本):
# 示例技术栈:Kubernetes 1.27 + Kong Ingress Controller v3.4
# 先创建Namespace,避免和其他服务冲突
apiVersion: v1
kind: Namespace
metadata:
name: kong # 专门用来放KIC的命名空间
---
# 部署KIC的Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: kong-ingress-controller
namespace: kong
labels:
app: kong
spec:
replicas: 2 # 两个副本,实现高可用
selector:
matchLabels:
app: kong
template:
metadata:
labels:
app: kong
spec:
containers:
- name: kong
image: kong/kong:3.4
ports:
- containerPort: 8000 # Kong的HTTP代理端口
name: http
- containerPort: 8443 # Kong的HTTPS代理端口
name: https
env:
- name: KONG_PROXY_LISTEN
value: 0.0.0.0:8000, 0.0.0.0:8443 ssl # 监听所有地址的代理端口
- name: KONG_ADMIN_LISTEN
value: 0.0.0.0:8001 # 管理端口,集群内部用
部署完Pod后,创建Service的时候如果选了ClusterIP,就会出现外部访问不通的问题:
# 错误示例:选了ClusterIP,外部无法访问
apiVersion: v1
kind: Service
metadata:
name: kong-service
namespace: kong
spec:
type: ClusterIP # 错误类型,只内部可访问
ports:
- port: 80
targetPort: 8000
name: http
selector:
app: kong
排查方法很简单,用kubectl命令查看Service的类型和端口:
# 查看kong命名空间下的Service
kubectl -n kong get service
如果输出的TYPE列是ClusterIP,那就是选了错误的类型,需要改成NodePort或者LoadBalancer。
三、第二步:NodePort类型的配置坑与排查
如果是测试环境或者没有云厂商LB的场景,选NodePort是比较合适的,但NodePort有很多容易踩的坑。
3.1 端口范围限制与防火墙配置
K8s默认的NodePort端口范围是30000-32767,这个范围是可以改的,但大部分人不会改,所以创建Service的时候要指定这个范围内的端口,不然会报错。另外,每个K8s节点的防火墙都要开放对应的NodePort端口,不然外部访问会超时。 给大家一个正确的NodePort类型Service示例:
# 示例技术栈:Kubernetes 1.27 + Kong Ingress Controller v3.4
apiVersion: v1
kind: Service
metadata:
name: kong-service
namespace: kong
spec:
type: NodePort # 正确的测试环境类型
ports:
- port: 80 # Service的端口,集群内部用
targetPort: 8000 # 对应Pod的HTTP端口
nodePort: 30080 # 外部访问的端口,必须在30000-32767之间
name: http
- port: 443
targetPort: 8443
nodePort: 30443
name: https
selector:
app: kong
部署完这个Service后,要检查每个节点的防火墙是否开放了30080和30443端口,以CentOS系统为例,检查命令是:
# 查看防火墙开放的端口
firewall-cmd --list-ports
如果没有这两个端口,就要手动开放:
# 开放30080端口
firewall-cmd --add-port=30080/tcp --permanent
# 开放30443端口
firewall-cmd --add-port=30443/tcp --permanent
# 重启防火墙生效
firewall-cmd --reload
3.2 节点宕机的高可用问题
NodePort类型的Service有个天然的缺陷:如果某个节点宕机了,外部用户访问这个节点的NodePort就会失败。比如你的K8s集群有三个节点,IP分别是192.168.1.10、192.168.1.11、192.168.1.12,你给用户的访问地址是192.168.1.10:30080,如果这个节点宕机了,用户就访问不了了。 解决这个问题的方法是在NodePort前面再加一层反向代理,比如用Nginx做负载均衡,把三个节点的IP都加进去,这样就算一个节点宕机了,流量还能转发到其他节点。给大家一个Nginx的配置示例:
# Nginx配置,做NodePort的负载均衡
upstream kong_nodes {
server 192.168.1.10:30080; # 节点1的NodePort
server 192.168.1.11:30080; # 节点2的NodePort
server 192.168.1.12:30080; # 节点3的NodePort
}
server {
listen 80;
server_name api.example.com; # 你的域名
location / {
proxy_pass http://kong_nodes; # 转发到Kong的NodePort
proxy_set_header Host $host; # 保留原请求的Host头,Kong需要这个头来匹配路由
}
}
四、第三步:LoadBalancer类型的注解坑与排查
生产环境一般都会选LoadBalancer类型的Service,因为它自动实现高可用,不用手动维护反向代理,但不同云厂商的负载均衡注解不一样,这是最容易踩坑的地方。
4.1 不同云厂商的注解差异
注解(Annotation)是K8s里给资源加额外配置的一种方式,不同云厂商的负载均衡需要不同的注解来配置,比如阿里云的注解是service.beta.kubernetes.io/alibaba-cloud-loadbalancer-type,腾讯云的是service.beta.kubernetes.io/qcloud-loadbalancer-internal-subnetid,AWS的是service.beta.kubernetes.io/aws-load-balancer-type,这些注解不能通用,用错了就会导致负载均衡配置不生效。
给大家两个常用云厂商的正确示例,第一个是阿里云的LoadBalancer Service配置:
# 示例技术栈:Kubernetes 1.27 + Kong Ingress Controller v3.4 + 阿里云ACK集群
apiVersion: v1
kind: Service
metadata:
name: kong-service
namespace: kong
annotations:
# 阿里云注解:指定负载均衡类型为公网
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-type: "internet"
# 阿里云注解:指定负载均衡的规格,按带宽计费
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-internet-charge-type: "paybybandwidth"
# 阿里云注解:指定带宽峰值为10Mbps
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-bandwidth: "10"
# 阿里云注解:指定负载均衡的后端协议为HTTP
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-protocol-port: "80:HTTP,443:HTTPS"
spec:
type: LoadBalancer # 生产环境用LoadBalancer类型
ports:
- port: 80
targetPort: 8000
name: http
- port: 443
targetPort: 8443
name: https
selector:
app: kong
第二个是腾讯云的LoadBalancer Service配置:
# 示例技术栈:Kubernetes 1.27 + Kong Ingress Controller v3.4 + 腾讯云TKE集群
apiVersion: v1
kind: Service
metadata:
name: kong-service
namespace: kong
annotations:
# 腾讯云注解:指定负载均衡类型为公网
service.beta.kubernetes.io/qcloud-loadbalancer-internet-type: "BGP"
# 腾讯云注解:指定负载均衡的带宽峰值为10Mbps
service.beta.kubernetes.io/qcloud-loadbalancer-bandwidth: "10"
# 腾讯云注解:指定负载均衡的后端协议为HTTP
service.beta.kubernetes.io/qcloud-loadbalancer-protocol: "HTTP"
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8000
name: http
- port: 443
targetPort: 8443
name: https
selector:
app: kong
4.2 常见注解错误与排查方法
最常见的注解错误是用错了前缀,比如把阿里云的注解用到腾讯云的集群上,或者注解的参数值写错了,比如把internet写成intranet,导致创建的是内网负载均衡,外部访问不通。
排查方法是用kubectl命令查看Service的事件,看有没有创建负载均衡失败的错误:
# 查看kong命名空间下kong-service的事件
kubectl -n kong describe service kong-service
如果输出的Events部分有错误信息,比如“failed to create load balancer: invalid annotation”,那就是注解用错了,需要根据云厂商的文档修改注解。 另外,还要检查负载均衡的后端是否正确挂载了K8s节点,比如阿里云的负载均衡后端组里有没有所有的K8s节点,腾讯云的负载均衡后端实例里有没有对应的节点。
五、核心排查流程总结与注意事项
经过上面的分析,我给大家总结了一套完整的排查流程,不管遇到什么问题,按这个流程走都能快速定位:
- 先确认KIC的Pod是否正常运行:用
kubectl -n kong get pod命令查看Pod的状态,如果是Running,说明Pod正常;如果是Pending或者CrashLoopBackOff,先解决Pod的问题。 - 再确认Service的类型是否正确:测试环境用NodePort,生产环境用LoadBalancer,不要用ClusterIP。
- 检查Service的端口是否正确:NodePort的端口要在30000-32767之间,LoadBalancer的端口要和Pod的端口对应。
- 检查节点的防火墙是否开放了对应的端口:NodePort要开放节点的端口,LoadBalancer要开放节点的安全组端口。
- 检查LoadBalancer的注解是否正确:根据云厂商的文档修改注解,不要混用不同厂商的注解。
- 最后检查路由配置:创建Ingress资源,配置正确的Host和路径,用
kubectl -n kong get ingress命令查看Ingress的状态。
5.1 注意事项
- 不同版本的KIC注解可能会有变化,比如v3版本的KIC和v2版本的注解不一样,要根据自己的KIC版本看官方文档。
- 云厂商的负载均衡有配额限制,比如一个账号最多能创建多少个公网负载均衡,要提前确认,避免创建失败。
- 不要把负载均衡的端口范围设置得太宽,比如把所有端口都开放,会带来安全风险。
- 生产环境要给KIC配置高可用,比如部署多个副本,避免单个副本宕机导致服务不可用。
六、文章总结
部署KIC的网络问题,核心是对K8s网络模型的理解和对云厂商负载均衡配置的掌握,大部分问题都不是Kong本身的问题,而是基础配置的错误。从Service类型的选择,到NodePort的端口和防火墙配置,再到LoadBalancer的注解配置,每一步都有容易踩的坑,只要按流程排查,就能快速解决问题。 中小团队在部署的时候,建议先在测试环境用NodePort熟悉配置,等熟悉了之后再转到生产环境用LoadBalancer,这样能减少踩坑的概率。另外,要多参考官方文档,尤其是云厂商的文档,不同厂商的配置差异很大,不能照搬其他厂商的配置。
Comments