K8s网络:服务发现与负载均衡
Ingress(七层) -> Service (SVC)(四层) > EndPoint -> kube-proxy -> Lvs/iptables
Ingress负责七层HTTP/HTTPS路由,将不同域名或路径的请求转发至对应Service;Service通过标签选择器关联后端Pod,创建Endpoints记录真实IP;kube-proxy监听Service变化,通过iptables或IPVS规则实现流量转发,确保请求精准到达目标Pod。整个过程实现解耦与动态更新,支撑应用弹性伸缩与高可用。
K8s网络解决的主要问题?
服务发现:如何找到Pod,Pod如何找到其他的Pod;
- Pod内部通信:localhost:port
- 用户查找Pod:Pod的ip:port
- Pod与Pod通信:跨节点,但是不用NAT地址转换
CNI插件实现Pod间通信
- Flannel:使用VXLAN“隧道”技术,适合中小型集群;
- Calico:适合大规模集群;BGP 边界网关协议(Border Gateway Protocol,BGP)是互联网上一个核心的去中心化自治路由协议。BGP不使用传统的内部网关协议(IGP)的指标。
服务发现
通过Service实现:
- 通过“标签”选中Pod,提供固定的入口(类似“VIP”),然后通过负载均衡;
- 给Pod提供DNS服务,Pod通过域名访问Service;
Service -> EndPoint(动态的IP列表) -> Pod
创建Service时,自动创建EndPoints;
- 网络和负载均衡:kube-proxy -> 系统内核(Lvs/iptables)
Service三大功能:
- 服务发现:通过DNS域名(如web-service.default.svc.cluster.local)
ServiceName.NameSpace.svc.cluster.local 替代动态Pod IP
2、负载均衡:把请求平均分给背后的多个Pod,避免单个Pod过载;
3、端口映射:隐藏Pod内部端口(如外部访问80端口,转发到Pod的8080端口)。
Service的四大模式/四种类型:
-
ClusterIP(默认):只允许集群内部访问,外部不可见,用于集群内部Pod间通信,例如:后端调用,数据库连接等;
前提是先拥有一个标签是app: my-app的Pod在运行,因为Service的Selector需要匹配Pod的标签,如果没有这样的标签,需要现添加一个,以下举例说明:
# 给名为my-nginx-66bf7cffd7-2vgl7的Pod添加标签
kubectl label pod my-nginx-66bf7cffd7-2vgl7 app=my-app
vim my-service.yaml
---
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP #可省略,默认就是 ClusterIP
selector:
app: my-app #匹配 Pod 的标签
ports:
- protocol: TCP
port: 80 #Service 的端口,集群内的其他 Pod 通过该端口访问服务。
targetPort: 80 #Pod 的端口,Service 将流量转发到该端口。
---
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
clusterIP: 10.96.0.100 #手动指定 ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 80
# 应用yaml文件
kubectl apply -f my-service.yaml
# 验证svc运行情况并获取 ClusterIP 地址:
kubectl get svc my-clusterip-service
会出现以下:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-clusterip-service ClusterIP 10.110.83.243 <none> 80/TCP 16s
# 然后通过ClusterIP访问
curl 10.110.83.243
vim my-service.yaml
---
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP #可省略,默认就是 ClusterIP
selector:
app: my-app #匹配 Pod 的标签
ports:
- protocol: TCP
port: 80 #Service 的端口,集群内的其他 Pod 通过该端口访问服务。
targetPort: 80 #Pod 的端口,Service 将流量转发到该端口。
---
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
clusterIP: 10.96.0.100 #手动指定 ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 80
# 应用yaml文件
kubectl apply -f my-service.yaml
# 验证svc运行情况并获取 ClusterIP 地址:
kubectl get svc my-clusterip-service
会出现以下:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-clusterip-service ClusterIP 10.110.83.243 <none> 80/TCP 16s
# 然后通过ClusterIP访问
curl 10.110.83.243
-
NodePort:外部通过任意Node的IP进行访问,NodePort的默认范围是30000-32767,但可以手动指定。简单服务、对外测试;
和上面同理,需要有一个标签和你的选择器写的标签一致。
vim 07-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort #指定服务类型为 NodePort
selector: #用于匹配目标 Pod 的标签
app: my-web #匹配 Pod 的标签
ports:
- protocol: TCP
port: 80 #Service 的端口,客户端通过该端口访问服务
targetPort: 80 #Pod 的端口,Service 将流量转发到该端口
nodePort: 30000 #可选,指定节点端口(范围 30000-32767)
# 应用yaml文件
kubectl apply -f 07-nodeport.yaml
# 验证Service
kubectl get svc
# 访问服务:使用节点 IP 和 NodePort 访问服务。(三个节点都可以)
-
LoadBalancer:使用云厂商的负载均衡器,实现对外的服务,适合在生产环境云平台上使用;
# 先给Pod添加标签
kubectl label pod my-nginx-66bf7cffd7-4k5hc aihao=haha
# 下载插件,应用 MetalLB 资源
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
# 配置IP 地址池(示例为192.168.221.10-192.168.221.100)
vim metallb-ip-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: example
namespace: metallb-system
spec:
addresses:
- 192.168.221.10-192.168.221.100
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
kubectl apply -f metallb-ip-pool.yaml
cat 08-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer #指定服务类型为 LoadBalancer
selector:
aihao: haha
ports:
- protocol: TCP
port: 80 #服务暴露的端口(外部访问的端口)
targetPort: 80 #Pod中应用监听的端口
# 应用yaml文件
kubectl apply -f 08-loadbalancer.yaml
# 检查服务状态,# EXTERNAL-IP #表示负载均衡器的外部 IP 地址,外部用户可以通过该地址访问服务。PORT(S) #显示服务端口和映射的节点端口。
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.109.77.71 192.168.221.10 80:32179/TCP 26s
# 一旦 EXTERNAL-IP 可用,外部用户可以通过以下方式访问服务:
http://<EXTERNAL-IP>:80或者用自己节点IP+端口号也能访问
# Pod内部也可以用域名来访问
curl my-nodeport-service.default.svc.cluster.local
-
ExternalName:域名转换,给域名起别名,Service通过DNS解析将请求转发到指定的外部域名。
# 配置一个yaml文件
vim 03-externalname.yaml
apiVersion: v1
kind: Service
metadata:
name: svc1
spec:
type: ExternalName
externalName: httpbin.org #这个可以看到502页面
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
# 应用yaml文件
kubectl apply -f 03-externalname.yaml
# 先查看有什么运行的Pod,然后随便进入一个Pod
kubectl exec -it my-web-664c6fd8c-t77gw -- bash
# 验证网站,可以看到网页内容
curl svcl.default.svc.cluster.local
特殊模式:
- Headless(无IP):Service没有IP,也不做负载均衡,仅返回Pod列表;
vim 09-headless.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: yourapp
name: yourapp
spec:
replicas: 3
selector:
matchLabels:
app: yourapp
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: yourapp
spec:
containers:
- image: 192.168.57.200:8099/library/nginx:1.24
name: nginx
---
apiVersion: v1
kind: Service
metadata:
name: web-service # Headless Service名称,会在svc显示
namespace: default
spec:
clusterIP: None # 关键:设置为None,声明为Headless Service
selector:
app: yourapp # 关联标签为app=myapp的Pod
ports:
- name: http
port: 80 # 服务端口
targetPort: 80 # Pod内应用监听的端口
kubectl apply -f 09-headless.yaml






1万+

被折叠的 条评论
为什么被折叠?



