第六章 Kubernetes进阶之Service与外界连通
1.Pod与Service的关系
Pod出现故障以后Deployment会根据策略重启Pod,但是重启Pod会生成新的IP,需要引入Service概念保证访问正常
Service
- 防止Pod失联
- 定义一组Pod访问策略
- 支持ClusterIP,NodePort以及LoadBanlancer三种类型
- Service的底层主要有Iptables和IPVS两种网络模式
2.Service的定义
Pod与Service的关系
- 通过label-selector相关联
- 通过Service实现Pod的负载均衡(TCP/UDP 4层)
示例service.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #版本 apiVersion: v1 #类型是service kind: Service metadata: name: my - service namespace: default spec: #service默认clusterIP clusterIP: 10.10 . 10.123 ports: - name: http #service端口 port: 80 protocol: TCP #后端容器端口 targetPort: 80 #标签选择器关联后端的一组Pod selector: run: nginx |
创建
1 | kubectl apply - f service.yaml |
因为该service标签匹配一个nginx所以如果没有创建nginx的deployment需要创建一个
1 | kubectl run nginx - - replicas = 3 - - image = nginx - - port = 80 |
创建以后可以查看有对应标签的pod
1 2 3 4 5 | # kubectl get pod -l run=nginx NAME READY STATUS RESTARTS AGE nginx - 57867cc648 - b4rct 1 / 1 Running 0 9m53s nginx - 57867cc648 - qgbwl 1 / 1 Running 0 9m53s nginx - 57867cc648 - qmbbw 1 / 1 Running 0 9m53s |
查看
1 2 3 4 | # kubectl get svc NAME TYPE CLUSTER - IP EXTERNAL - IP PORT(S) AGE kubernetes ClusterIP 10.10 . 10.1 <none> 443 / TCP 6d23h my - service ClusterIP 10.10 . 10.123 <none> 80 / TCP 6m25s |
其中name为kubernetes的service是k8s安装以后默认的一个service默认IP的service的第一个IP 10.10.10.1端口是443
默认的svc的作用是负载均衡后端master的IP
service需要动态感知后端ip变化可以通过以下命令查看,每个svc管理后端的一组容器
1 2 3 4 | # kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168 . 1.63 : 6443 , 192.168 . 1.64 : 6443 6d23h my - service 172.17 . 41.2 : 80 , 172.17 . 55.2 : 80 , 172.17 . 55.4 : 80 9m59s |
在集群内部node例如192.168.1.65可以使用ClusterIP访问
1 | curl 10.10 . 10.123 |
PS:这里配置文件指定了clusterIP为10.10.10.123,默认不知道该clusterIP是随机的
1 2 3 4 5 6 7 8 9 10 11 12 13 | apiVersion: v1 kind: Service metadata: labels: run: nginx name: my - service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: run: nginx |
不能直接应用生效
1 2 | # kubectl apply -f service.yaml The Service "my-service" is invalid: spec.clusterIP: Invalid value: "": field is immutable |
需要删除原svc再应用生效
1 2 3 | kubectl delete svc my - service kubectl apply - f service.yaml |
查看生成了随机的clusterIP
1 2 3 4 | # kubectl get svc NAME TYPE CLUSTER - IP EXTERNAL - IP PORT(S) AGE kubernetes ClusterIP 10.10 . 10.1 <none> 443 / TCP 7d5h my - service ClusterIP 10.10 . 10.196 <none> 80 / TCP 29s |
3.service类型
service提供四层负载均衡把请求发送到后端的pod,默认规则是轮训
- ClusterIP:默认,分配一个集群内部可以访问的虚拟IP
- NodePort:在每个node上分配一个端口作为外部访问入口
- LoadBanlancer:工作在特定的Cloud Provider上,例如Google,AWS,OpenStack
ClusterIP
分配一个内部集群IP地址,只能在集群内部访问(同Namespace内的Pod),默认ServiceType。 ClusterIP 模式的 Service 为你提供的,就是一个 Pod 的稳定的 IP 地址,即 VIP。
NodePort
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务,可以在集群外部访问。 访问地址:: node端口范围30000-32067
Client→NodeIP:NodePort→ClusterIP:ServicePort→PodIP:containerPort
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #版本 apiVersion: v1 #类型是service kind: Service metadata: name: my - service namespace: default spec: type : NodePort ports: - name: http #service端口 port: 80 protocol: TCP #后端容器端口 targetPort: 80 #标签选择器关联后端的一组Pod selector: run: nginx |
应用,service定义类型不支持自动更新,需要删除原有的配置再重新应用
1 2 | kubectl delete - f service.yaml kubectl apply - f service.yaml |
查看,类型变成NodePort了并且随机产生一个端口,本次随机端口是46194
1 2 3 4 | # kubectl get svc NAME TYPE CLUSTER - IP EXTERNAL - IP PORT(S) AGE kubernetes ClusterIP 10.10 . 10.1 <none> 443 / TCP 7d3h my - service NodePort 10.10 . 10.238 <none> 80 : 46194 / TCP 104s |
即使是使NodePort类型也会分配一个ClusterIP在集群内部可以访问,NodePort是供集群外部访问使用的
使用NodePort会在多个node上可以访问,企业应用可以加一台负载均衡负载到一个或多个node
LoadBalancer
分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。 除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去
4.Service代理模式
底层流量转发与负载均衡实现
- Iptables
- IPVS
service通过部署在node的应用kube-proxy实现
可以通过kube-proxy配置文件查看模式
1 2 3 4 5 6 7 8 | # cat /opt/kubernetes/cfg/kube-proxy KUBE_PROXY_OPTS = " - - logtostderr = true \ - - v = 4 \ - - hostname - override = 192.168 . 31.65 \ - - cluster - cidr = 10.0 . 0.0 / 24 \ - - proxy - mode = ipvs \ - - masquerade - all = true \ - - kubeconfig = / opt / kubernetes / cfg / kube - proxy.kubeconfig" |
查看Iptables的转发方式
删除其中一台node192.168.1.66的ipvs配置
1 2 3 4 5 | KUBE_PROXY_OPTS = " - - logtostderr = true \ - - v = 4 \ - - hostname - override = 192.168 . 31.66 \ - - cluster - cidr = 10.0 . 0.0 / 24 \ - - kubeconfig = / opt / kubernetes / cfg / kube - proxy.kubeconfig" |
重启kube-proxy组件
1 | systemctl restart kube - proxy |
查看service对应的Iptables规则,过滤的IP为上面service的ip通过IP地址找到对应的规则
1 | iptables - save|grep 10.10 . 10.238 |
查看对应的规则
1 | iptables - save|grep KUBE - SVC - I37Z43XJW6BD4TLV |
继续查看对应规则
1 | iptables - save|grep KUBE - SEP - ETBSYW4QFKX7DP4Z |
Iptables的问题
1,创建很多Iptables(更新,非增量式)
2,Iptables规则是从上至下逐条匹配(规则多了,匹配延时大)
无法大规模应用,救世主IPVS
查看IPVS的工作方式
LVS基于IPVS内核调度模块实现的负载均衡
查看ipvs规则,需要kube-proxy设置ipvs工作模式才能查看到
1 | ipvsadm - ln |
如果没有这个命令安装即可
1 | yum -y install ipvsadm |
会生成虚拟网卡kube-ipvs0,所有的ClusterIP会绑定在该网卡上
默认使用rr轮训负载均衡策略,因为工作在内核态所以速度快
对比
Iptables
- 灵活功能强大(可以在数据包不同阶段对包进行操作)
- 规则遍历匹配和更新,呈线性时延
IPVS
- 工作在内核态,有更好的性能
- 调度算法丰富:rr,wrr,lc,wlc,ip hash
设置调度算法,一般使用默认即可无需配置
Iptables和ipvs示意图
5.DNS
service创建以后在集群内部可以通过cluserIP访问,但是涉及迁移时IP会发生变化,需要部署内部DNS服务
DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析
DNS配置文件官方下载地址https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns
下载以后需要修改以下几处
修改后
修改镜像
修改后
修改资源限制
修改后
修改集群DNS地址
修改后
应用
1 | kubectl apply - f coredns.yaml |
排错:应用以后pod显示pending状态
1 2 | kubectl get pod - n kube - system kubectl describe pod coredns - 65589b968c - s7m28 - n kube - system |
错误信息为
1 | nodes are available: 2 node(s) didn't match node selector |
标签不匹配
查看系统标签
1 2 3 4 | kubectl get node - - show - labels NAME STATUS ROLES AGE VERSION LABELS 192.168 . 1.65 Ready <none> 10d v1. 13.4 beta.kubernetes.io / arch = amd64,beta.kubernetes.io / os = linux,kubernetes.io / hostname = 192.168 . 1.65 192.168 . 1.66 Ready <none> 10d v1. 13.4 beta.kubernetes.io / arch = amd64,beta.kubernetes.io / os = linux,kubernetes.io / hostname = 192.168 . 1.66 |
查看配置文件发现确实不匹配实际beta.kubernetes.io/os=linux 配置文件为beta.kubernetes.io/os=linux
修改或者注释这两行即可
部署DNS以后测试
1 | kubectl run - it - - image = busybox: 1.28 . 4 - - rm - - restart = Never sh |
PS:镜像需要使用1.28.4版本
解析 nslookup加svc名
1 | nslookup kubernetes |
默认的service是在默认的命名空间default下
1 2 3 4 | # kubectl get svc -n default NAME TYPE CLUSTER - IP EXTERNAL - IP PORT(S) AGE kubernetes ClusterIP 10.10 . 10.1 <none> 443 / TCP 9d my - service NodePort 10.10 . 10.196 <none> 80 : 37159 / TCP 2d18h |
创建一个容器使用命名空间为kube-system
1 | kubectl run - it - - image = busybox: 1.28 . 4 - - rm - - restart = Never sh - n kube - system |
因为该容器的命名空间是kube-system所以无法解析默认命名空间default下的service需要在域名后加命名空间名称访问
1 2 3 4 5 6 7 8 9 10 11 | # nslookup kubernetes Server: 10.10 . 10.2 Address 1 : 10.10 . 10.2 coredns.kube - system.svc.cluster.local nslookup: can 't resolve ' kubernetes' / # nslookup kubernetes.default Server: 10.10 . 10.2 Address 1 : 10.10 . 10.2 coredns.kube - system.svc.cluster.local Name: kubernetes.default Address 1 : 10.10 . 10.1 kubernetes.default.svc.cluster.local |
排错:nslookup可以正确解析外网DNS例如www.baidu.com但是无法解析内网DNS
查看core日志
1 | kubectl logs - n kube - system coredns - 7777dd7b8c - 7dv26 |
1 | E0309 03 : 15 : 43.061842 1 reflector.go: 205 ] github.com / coredns / coredns / plugin / kubernetes / controller.go: 318 : Failed to list * v1.Namespace: Get https: / / 10.10 . 10.1 : 443 / api / v1 / namespaces?limit = 500 &resourceVersion = 0 : x509: certificate is valid for 10.0 . 0.1 , 127.0 . 0.1 , 192.168 . 1.60 , 192.168 . 1.61 , 192.168 . 1.62 , 192.168 . 1.63 , 192.168 . 1.64 , 192.168 . 1.65 , 192.168 . 1.66 , not 10.10 . 10.1 |
原因是因为在创建api证书的时候填写hosts信息错误
2025-01-26补充开始
创建一个deployment用于长期测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | apiVersion: apps/v1 kind: Deployment metadata: name: busybox-deployment namespace : default # 或者你指定的其他命名空间 spec: replicas: 1 # 副本数量,这里设置为1 selector: matchLabels: app: busybox template: metadata: labels: app: busybox spec: containers: - name: busybox image: harbor.xiaoxingcloud.com/foundation/busybox:1.28.4 # 使用busybox镜像 command: [ "/bin/sh" , "-c" , "sleep 3600" ] |
2025-01-26补充结束
修改IP地址以后重新创建证书重启api即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
2018-03-06 Python全栈day28(描述符应用)
2018-03-06 Python全栈day28(上下文管理)
2018-03-06 Openstack实现共有云VPC的SDN网络
2018-03-06 Openstack实现共有云多flat网络