编排之神-Kubernetes中的微服务介绍及演练
7.Kubernetes中的微服务
7.1 什么是微服务
用控制器来完成集群的工作负载,那么应用如何暴漏出去?
需要通过微服务暴漏出去后才能被访问。
- Service是一组提供相同服务的Pod对外开放的接口。
- 借助Service,应用可以实现服务发现和负载均衡。
- service默认只支持4层负载均衡能力,没有7层功能。(可以通过Ingress实现)

7.2 微服务的类型
微服务类型 | 作用描述 |
---|---|
ClusterIP | 默认值,k8s系统给service自动分配的虚拟IP,只能在集群内部访问 |
NodePort | 将Service通过指定的Node上的端口暴露给外部,访问任意一个NodeIP:nodePort都将路由到ClusterIP |
LoadBalancer | 在NodePort的基础上,借助cloud provider创建一个外部的负载均衡器,并将请求转发到 NodeIP:NodePort,此模式只能在云服务器上使用 |
ExternalName | 将服务通过 DNS CNAME 记录方式转发到指定的域名(通过 spec.externlName 设定 |
7.2.1 示例
# 生成控制器文件并建立控制器
[root@k8s-master ~]# kubectl create deployment dhj --image myapp:v1 --replicas 2 --dry-run=client -o yaml > dhj.yml[root@k8s-master ~]# kubectl apply -f dhj.yml
deployment.apps/dhj created# 生成微服务yaml追加到已有yaml中
[root@k8s-master ~]# kubectl expose deployment dhj --port 80 --target-port 80 --dry-run=client -o yaml >> dhj.yml
[root@k8s-master ~]# vim dhj.yml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: dhjname: dhj
spec:replicas: 2selector:matchLabels:app: dhjtemplate:metadata:creationTimestamp: nulllabels:app: dhjspec:containers:- image: myapp:v1name: myapp
--- # 不同资源间用---隔开apiVersion: v1
kind: Service
metadata:labels:app: dhjname: dhj
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: dhj[root@k8s-master ~]# kubectl apply -f dhj.yml
service/dhj created[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj ClusterIP 10.97.95.78 <none> 80/TCP 6s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d17h
7.2.2 微服务默认使用iptables调度
[root@k8s-master ~]# kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
dhj ClusterIP 10.97.95.78 <none> 80/TCP 112s app=dhj # 集群内部ip为78
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d17h <none># 可以在火墙中查看到策略信息
[root@k8s-master ~]# iptables -t nat -nL
KUBE-SVC-RV2MKWNOHWTUCXGM tcp -- 0.0.0.0/0 10.97.95.78 /* default/dhj cluster IP */ tcp dpt:80
7.3 ipvs模式
- Service 是由 kube-proxy 组件,加上 iptables 来共同实现的
- kube-proxy 通过 iptables 处理 Service 的过程,需要在宿主机上设置相当多的 iptables 规则,如果宿主机有大量的Pod,不断刷新iptables规则,会消耗大量的CPU资源
- IPVS模式的service,可以使K8s集群支持更多量级的Pod
7.3.1 ipvs模式配置方式
7.3.1.1 在所有节点中安装ipvsadm
[root@k8s-master & node1 & node2 ~]# yum install ipvsadm -y
7.3.1.2 修改master节点的代理配置
[root@k8s-master ~]# kubectl -n kube-system edit cm kube-proxymetricsBindAddress: ""mode: "ipvs" #设置kube-proxy使用ipvs模式nftables:

7.3.1.3 重启pod
在pod运行时配置文件中采用默认配置,当改变配置文件后已经运行的pod状态不会变化,所以要重启pod
# 强制重启Kubernetes集群中kube-system命名空间下的所有kube-proxy Pod
[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'[root@k8s-master ~]# ipvsadm -Ln
切换ipvs模式后,kube-proxy会在宿主机上添加一个虚拟网卡:kube-ipvs0,并分配所有service IP
[root@k8s-master ~]# ip a | tail 10: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group defaultlink/ether 1e:1c:4c:d4:f0:86 brd ff:ff:ff:ff:ff:ffinet 10.96.0.10/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.97.95.78/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.96.0.1/32 scope global kube-ipvs0valid_lft forever preferred_lft forever
![]()
7.4 微服务类型详解
7.4.1 clusterip
7.4.1.1 特点
clusterip模式只能在集群内访问,并对集群内的pod提供健康检测和自动发现功能.
7.4.1.2 示例
[root@k8s-master ~]# vim myapp.yml
apiVersion: v1
kind: Service
metadata:labels:app: dhjname: dhj
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: dhjtype: ClusterIP[root@k8s-master ~]# kubectl apply -f myapp.yml[root@k8s-master ~]# kubectl -n kube-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 2d18h# service创建后集群DNS提供解析
[root@k8s-master ~]# dig dhj.default.svc.cluster.local @10.96.0.10

7.4.2 ClusterIP中的特殊模式headless
headless(无头服务)
对于无头 Services
并不会分配 Cluster IP,kube-proxy不会处理它们, 而且平台也不会为它们进行负载均衡和路由,集群访问通过dns解析直接指向到业务pod上的IP,所有的调度有dns单独完成
[root@k8s-master ~]# vim dhj.yaml
---
apiVersion: v1
kind: Service
metadata:labels:app: dhjname: dhj
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: dhjtype: ClusterIPclusterIP: None[root@k8s-master ~]# kubectl apply -f dhj.yaml# 测试
[root@k8s-master ~]# kubectl get services dhj
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE[root@k8s-master ~]# dig dhj.default.svc.cluster.local @10.96.0.10
; <<>> DiG 9.16.23-RH <<>> dhj.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57964
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: aedae9a56ee16284 (echoed)
;; QUESTION SECTION:
;dhj.default.svc.cluster.local. IN A;; ANSWER SECTION: # 直接解析到pod上
dhj.default.svc.cluster.local. 30 IN A 10.244.1.49
dhj.default.svc.cluster.local. 30 IN A 10.244.2.51;; Query time: 1 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Wed Aug 13 18:01:26 CST 2025
;; MSG SIZE rcvd: 160
7.4.3 nodeport
通过ipvs暴漏端口从而使外部主机通过master节点的对外ip:来访问pod业务
7.4.3.1 访问过程
7.4.3.2 示例
[root@k8s-master ~]# vim dhj.yaml
apiVersion: v1
kind: Service
metadata:labels:app: dhj-servicename: dhj-service
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: dhjtype: NodePort[root@k8s-master ~]# kubectl apply -f dhj.yaml[root@k8s-master ~]# kubectl get svc dhj
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj NodePort 10.107.181.27 <none> 80:31595/TCP 38s# nodeport默认端口是30000-32767,超出会报错[root@k8s-master ~]# kubectl get svc dhj
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj NodePort 10.107.181.27 <none> 80:31595/TCP 3m45s[root@k8s-master ~]# curl 10.107.181.27:80 # 内部访问
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master ~]# curl 172.25.254.100:31595 # 外部访问
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

[root@k8s-master ~]# vim dhj.yaml
apiVersion: v1
kind: Service
metadata:labels:app: dhj-servicename: dhj-service
spec:ports:- port: 80protocol: TCPtargetPort: 80nodePort: 33333selector:app: dhjtype: NodePort[root@k8s-master ~]# vim myapp.yml
[root@k8s-master ~]# kubectl apply -f myapp.yml
The Service "dhj" is invalid: spec.ports[0].nodePort: Invalid value: 33333: provided port is not in the valid range. The range of valid ports is 30000-32767
如果需要使用这个范围以外的端口就需要特殊设定
[root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
- --service-node-port-range=30000-40000

添加“–service-node-port-range=“ 参数,端口范围可以自定义修改后api-server会自动重启;
等apiserver正常启动后才能操作集群,集群重启自动完成在修改完参数后全程不需要人为干预。
[root@k8s-master ~]# kubectl apply -f myapp.yml
service/dhj configured[root@k8s-master ~]# kubectl get svc dhj
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj NodePort 10.107.181.27 <none> 80:33333/TCP 19m

7.4.4 loadbalancer
云平台会为我们分配vip并实现访问,如果是裸金属主机那么需要metallb来实现ip的分配
[root@k8s-master ~]# vim dhj.yaml
apiVersion: v1
kind: Service
metadata:labels:app: dhj-servicename: dhj-service
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: dhjtype: LoadBalancer[root@k8s2 service]# kubectl apply -f myapp.yml# 默认无法分配外部访问IP
[root@k8s-master ~]# kubectl get svc # pending:表示正在获取(但就是获取不到)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj LoadBalancer 10.104.182.179 <pending> 80:33333/TCP 8s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d20h# 此时curl一下,发现可以访问,但是在实际的生产环境中一般都是直接访问EXTERNAL-IP的,没有人会去记这么一个奇奇怪怪的端口
[root@k8s-master ~]# curl 172.25.254.100:33333
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a># 此时就会需要一个类似于DHCP分发ip的工具--metallb# LoadBalancer模式适用云平台,裸金属环境需要安装metallb提供支持

7.4.5 metalLB
官网:https://metallb.universe.tf/installation/
metalLB功能为LoadBalancer分配vip;
类似于DHCP,对外分发IP
7.4.5.1 部署方式
1.(看情况)设置ipvs模式(此处查看一下文件,新版本默认是开着的,要是开着的,就不用管)
[root@k8s-master ~]# kubectl edit cm -n kube-system kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:strictARP: true # 新添一行[root@k8s-master ~]# kubectl -n kube-system get pods | awk '/kube-proxy/{system("kubectl -n kube-system delete pods "$1)}'2.下载部署文件(建议直接使用资源包里面的东西)
# 如果想下载使用下面这个被注释掉的命令
# [root@k8s2 metallb]# wget https://raw.githubusercontent.com/metallb/metallb/v0.13.10.7/config/manifests/metallb-native.yaml3.修改文件中镜像地址,与harbor仓库路径保持一致(此处要是使用资源包就不用管了)
[root@k8s-master ~]# vim metallb-native.yaml
image: metallb/controller:v0.14.8
image: metallb/speaker:v0.14.84.上传镜像到harbor(此处要是使用资源包就不用管了)
[root@k8s-master mnt]# docker load -i metalLB.tag.gz
Loaded image: quay.io/metallb/controller:v0.14.8
Loaded image: quay.io/metallb/speaker:v0.14.8[root@k8s-master mnt]# docker tag quay.io/metallb/controller:v0.14.8 reg.dhj.org/metallb/controller:v0.14.8
[root@k8s-master mnt]# docker tag quay.io/metallb/speaker:v0.14.8 reg.dhj.org/metallb/speaker:v0.14.8[root@k8s-master mnt]# docker push reg.dhj.org/metallb/controller:v0.14.8
[root@k8s-master mnt]# docker push reg.dhj.org/metallb/speaker:v0.14.85.部署服务
[root@k8s-master mnt]# kubectl apply -f metallb-native.yaml
[root@k8s-master mnt]# kubectl -n metallb-system get pods
NAME READY STATUS RESTARTS AGE
controller-65957f77c8-d2sc5 0/1 Running 0 4s
speaker-22s8m 0/1 Running 0 4s
speaker-gxc27 0/1 Running 0 4s
speaker-jsd7h 0/1 Running 0 4s6.配置分配地址段
[root@k8s-master ~]# vim configmap.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:name: first-pool # 地址池名称namespace: metallb-system
spec:addresses:- 172.25.254.50-172.25.254.99 # 修改为自己本地地址段(看清自己的ip网段)--- # 两个不同的kind中间必须加分割
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:name: examplenamespace: metallb-system
spec:ipAddressPools:- first-pool # 使用地址池 [root@k8s-master mnt]# kubectl apply -f configmap.yml[root@k8s-master mnt]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj LoadBalancer 10.104.182.179 172.25.254.50 80:33333/TCP 44m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d20h# 通过分配地址从集群外访问服务
[root@reg harbor]# curl 172.25.254.50
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a># 也可以在浏览器中进行访问,如下图:




7.4.6 externalname
- 开启services后,不会被分配IP,而是用dns解析CNAME固定域名来解决ip变化问题
- 一般应用于外部业务和pod沟通或外部业务迁移到pod内时
- 在应用向集群迁移过程中,externalname在过度阶段就可以起作用了。
- 集群外的资源迁移到集群时,在迁移的过程中ip可能会变化,但是域名+dns解析能完美解决此问题
7.4.6.1 示例
[root@k8s-master ~]# kubectl create svc externalname dhj-service --external-name www.baidu.com -o yaml > dhj-service.yml
[root@k8s-master ~]# vim dhj-service.yml
apiVersion: v1
kind: Service
metadata:labels:app: dhj-servicename: dhj-service
spec:externalName: www.baidu.comselector:app: dhj-servicetype: ExternalName[root@k8s-master ~]# kubectl apply -f dhj-service.yml[root@k8s-master ~]# kubectl get svc dhj-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dhj-service ExternalName <none> www.baidu.com <none> 12s# 测试
[root@k8s-master ~]# kubectl run ceshi --image busyboxplus -it
/ # ping dhj-service.default.svc.cluster.local
PING dhj-service.default.svc.cluster.local (183.2.172.17): 56 data bytes
64 bytes from 183.2.172.17: seq=0 ttl=127 time=64.464 ms
