service服务介绍

在k8s中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问

为了解决这个问题,k8s提供了service资源,service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问service的入口地址就能访问到后面的pod服务

Service服务也是Kubernetes里的核心资源对象之一,Kubernetes里的每个Service其实就是我们经常提起的微服务架构中的一个微服务,受kube-proxy管理,运行在每个Node上的kube-proxy进程其实就是一个智能的软件负载均衡器,负责把对Service的请求转发到后端的某个Pod实例上,并在内部实现服务的负载均衡与会话保持机制。

可以看到上面的架构图,service服务通过标签选择器定位后端pod,前提是service的selector必须和后端Pod标签对应上才能找到相对应的Pod,而前段frontend通过service就可以访问到后端提供服务的pod了,而service默认IP类型为主要分为:

  • ClusterIP:主要是为集群内部提供访问服务的 (默认类型)
  • NodePort:可以被集群外部所访问,访问方式为    宿主机:端口号
  • LoadBalancer:在NodePort的基础上,借助cloud provider(云提供商)创建一个外部负载均衡器并将请求转发到NodePort
  • ExternalName: 把集群外部的访问引入到集群内部来,在集群内部直接使用,没有任何代理被创建

当Service一旦被创建,Kubernetes就会自动为它分配一个可用的Cluster IP,而且在Service的整个生命周期内,它的Cluster IP不会发生改变,service会通过标签选择器与后端的pod进行连接并被kubo-poxry监控,当后端pod被重建时会通过标签自动加入到对应的service服务中,从而避免失联。

service三种代理模式

  • userspace

这种模式,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

  • iptables

这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。

  • ipvs

在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。该控制循环可确保 IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端 Pod 之一。

IPVS 代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 提供了更多选项来平衡后端 Pod 的流量。这些是:

  • rr:轮替(Round-Robin)
  • lc:最少链接(Least Connection),即打开链接数量最少者优先
  • dh:目标地址哈希(Destination Hashing)
  • sh:源地址哈希(Source Hashing)
  • sed:最短预期延迟(Shortest Expected Delay)
  • nq:从不排队(Never Queue)
说明:

要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。

当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

ipvs模式设置

先下载ipvsadm

然后修改kube-poxy的configmap

[root@master ~]# kubectl edit cm kube-proxy -n kube-system
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
config.conf: |-
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 0.0.0.0
bindAddressHardFail: false
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
qps: 0
clusterCIDR: 10.244.0.0/16
configSyncPeriod: 0s
conntrack:
maxPerCore: null
min: null
tcpCloseWaitTimeout: null
tcpEstablishedTimeout: null
detectLocalMode: ""
enableProfiling: false
healthzBindAddress: ""
hostnameOverride: ""
iptables:
masqueradeAll: false
masqueradeBit: null
minSyncPeriod: 0s
syncPeriod: 0s
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
strictARP: false
syncPeriod: 0s
tcpFinTimeout: 0s
tcpTimeout: 0s
udpTimeout: 0s
kind: KubeProxyConfiguration
metricsBindAddress: ""
mode: "ipvs" #将模式改为ipvs
nodePortAddresses: null
oomScoreAdj: null
portRange: ""
showHiddenMetricsForVersion: ""
udpIdleTimeout: 0s
winkernel:
enableDSR: false
networkName: ""
sourceVip: ""
kubeconfig.conf: |-
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
server: https://192.168.248.129:6443
name: default
contexts:
- context:
cluster: default
namespace: default
user: default
name: default
current-context: default
users:
- name: default
user:
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

删除当前的kube-poxy。

[root@master ~]# kubectl get pod -n kube-system|grep kube-proxy|awk '{system("kubectl delete pod "$1" -n kube-system")}'

ClusterIP(内部集群访问)

下面演示ClusterIP的service

先创建一个yaml文件

 
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: nginx-svc
namespace: default
spec:
ports:
- name: http
port: 3001 # service暴露的端口
protocol: TCP
targetPort: 80 #后端容器的端口
selector: #标签选择器与deployment一致
app: web
type: ClusterIP
--- apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: deployment-nginx
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: nginx:1.21.4
name: nginx
ports:
- name: http
containerPort: 80 #容器端口

然后创建service和deployment

[root@master ~]# kubectl apply -f deploymen_nginx_serivce.yaml
service/nginx-svc created
deployment.apps/web created

查看service和pod状态

[root@master ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 40m <none>
nginx-svc ClusterIP 10.103.130.138 <none> 3001/TCP 12m app=web
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-nginx-64fc98d58f-6llbw 1/1 Running 0 10m 10.101.11.32 node2 <none> <none>
deployment-nginx-64fc98d58f-9s6mt 1/1 Running 0 10m 10.101.11.31 node2 <none> <none>
deployment-nginx-64fc98d58f-fkcmf 1/1 Running 0 10m 10.101.149.15 node1 <none> <none>

此时我们发现nginx-svc有了一个CLUSTER-IP:10.103.130.138, 用curl检查一下是否能访问10.103.130.138:3001

[root@master ~]# curl 10.103.130.138:3001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p> <p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p>
</body>
</html>

NodePod(外部访问)

下面创建一个NodePort的service演示,只需要将上面yaml文件中的ClusterIP改为NodePort

apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: nginx-svc
namespace: default
spec:
ports:
- name: http
port: 3001
protocol: TCP
targetPort: 80
selector:
app: web
type: NodePort
--- apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: deployment-nginx
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: nginx:1.21.4
name: nginx
ports:
- name: http
containerPort: 80
~

执行yaml文件后查看pod和svc的信息

[root@master ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 59m <none>
nginx-svc NodePort 10.99.62.52 <none> 3001:31966/TCP 3s app=web
[root@master ~]# kubectl get node -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready control-plane,master 79d v1.21.0 192.168.248.129 <none> CentOS Linux 7 (Core) 3.10.0-1062.el7.x86_64 docker://20.10.14
node1 Ready <none> 79d v1.21.0 192.168.248.128 <none> CentOS Linux 7 (Core) 3.10.0-1062.el7.x86_64 docker://20.10.14
node2 Ready <none> 79d v1.21.0 192.168.248.130 <none> CentOS Linux 7 (Core) 3.10.0-1062.el7.x86_64 docker://20.10.14
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-nginx-64fc98d58f-b5s2t 1/1 Running 0 112s 10.101.11.36 node2 <none> <none>
deployment-nginx-64fc98d58f-gd5fw 1/1 Running 0 112s 10.101.11.35 node2 <none> <none>
deployment-nginx-64fc98d58f-p6tw5 1/1 Running 0 112s 10.101.149.17 node1 <none> <none>

此时发现svc的PORT变成3001:31966/TCP ,其中3001为svc的端口,31966为随机生成的node端口,我们可以通过nodeIP加端口访问

headless service(无头服务)

headless service就是无头service(也就是没有ip的service),这种无头服务对于有状态应用来说很重要,我们可以利用service的labels关联后端pod,我们访问的流量就可以直接到达pod而不再需要service负载均衡至后端pod

定义无头服务如下:

apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: redis
spec:
ports:
- port: 6379
name: redis-port
clusterIP: None
selector:
app: redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: "redis"
replicas: 3 # 默认值是 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis # 必须匹配 .spec.selector.matchLabels
spec:
containers:
- name: redis
image: redis
ports:
- containerPort: 6379
name: redis

查看pod以及service

[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-0 1/1 Running 0 29s 10.101.11.37 node2 <none> <none>
redis-1 1/1 Running 0 23s 10.101.149.18 node1 <none> <none>
redis-2 1/1 Running 0 21s 10.101.11.38 node2 <none> <none>
[root@master ~]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 89m <none>
redis ClusterIP None <none> 6379/TCP 40s app=redis

查看coredns地址

[root@master ~]# kubectl get pod -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-65898446b5-qtcgv 1/1 Running 1 79d 10.101.149.1 node1 <none> <none>
calico-node-7wcsl 1/1 Running 0 79d 192.168.248.128 node1 <none> <none>
calico-node-8sjcz 1/1 Running 0 79d 192.168.248.129 master <none> <none>
calico-node-f84fw 1/1 Running 0 79d 192.168.248.130 node2 <none> <none>
coredns-545d6fc579-w5rj2 1/1 Running 0 79d 10.101.11.1 node2 <none> <none>
coredns-545d6fc579-xr62w 1/1 Running 0 79d 10.101.11.2 node2 <none> <none>
etcd-master 1/1 Running 0 79d 192.168.248.129 master <none> <none>
kube-apiserver-master 1/1 Running 0 79d 192.168.248.129 master <none> <none>
kube-controller-manager-master 1/1 Running 0 79d 192.168.248.129 master <none> <none>
kube-proxy-2qx8x 1/1 Running 0 79d 192.168.248.129 master <none> <none>
kube-proxy-6khnn 1/1 Running 0 79d 192.168.248.128 node1 <none> <none>
kube-proxy-znv97 1/1 Running 0 79d 192.168.248.130 node2 <none> <none>
kube-scheduler-master 1/1 Running 0 79d 192.168.248.129 master <none> <none>

解析service服务

[root@master ~]# dig redis.default.svc.cluster.local @10.101.11.1              

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.9 <<>> nginx.default.svc.cluster.local @10.101.11.1
;; 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: 49448
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx.default.svc.cluster.local. IN A ;; ANSWER SECTION:
nginx.default.svc.cluster.local. 30 IN A 10.101.11.38 # 这个地址对应的是statefulset集群的的redis-2的地址
nginx.default.svc.cluster.local. 30 IN A 10.101.149.18
nginx.default.svc.cluster.local. 30 IN A 10.101.11.37 ;; Query time: 7 msec
;; SERVER: 10.101.11.1#53(10.101.11.1)
;; WHEN: 三 7月 27 23:10:03 CST 2022
;; MSG SIZE rcvd: 201

ExternalName 类型

类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择算符,例如 my-service 或者 cassandra。 你可以使用 spec.externalName 参数指定这些服务。

例如,以下 Service 定义将 prod 名称空间中的 my-service 服务映射到 my.database.example.com

apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

当查找主机 my-service.prod.svc.cluster.local 时,集群 DNS 服务返回 CNAME 记录, 其值为 my.database.example.com。 访问 my-service 的方式与其他服务的方式相同,但主要区别在于重定向发生在 DNS 级别,而不是通过代理或转发。 如果以后你决定将数据库移到集群中,则可以启动其 Pod,添加适当的选择算符或端点以及更改服务的 type

外部 IP

如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。 通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量, 将会被路由到 Service 的 Endpoint 上。 externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。

根据 Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。 在上面的例子中,my-service 可以在 "80.11.12.10:80"(externalIP:port) 上被客户端访问。

apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10

最新文章

  1. C#读取Excel文件
  2. Application、 session、iewstate,以及repeater 的commang用法
  3. 初学structs2,结果类型简单示例
  4. js中object的申明方法
  5. Java核心 --- 注解
  6. javascript注意点(1)
  7. [转载]ubuntu Atheros Communications Device 1083 驱动
  8. easyui常用控件样式收藏
  9. HDOJ(HDU) 2148 Score(比较、)
  10. Android NumberPicker和DatePicker分割线颜色设置
  11. Poj 3771 hdu 3405
  12. SRM 582 Div II Level Three: ColorTheCells, Brute Force 算法
  13. PhoneGap开发环境搭建
  14. 看图说话,P2P 分享率 90% 以上的 P2P-CDN 服务,来了!
  15. 济南清北学堂游记 Day 7.
  16. 大型三甲医院信息管理系统源码 His系统功能齐全 完整可用
  17. explode() 字符串分割函数
  18. github分支规范
  19. 再谈STM32的CAN过滤器-bxCAN的过滤器的4种工作模式以及使用方法总结
  20. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #11cpuset

热门文章

  1. 解决多次重连rabbitMQ失败
  2. c语言学习总结(原创)
  3. Keil 5(C51 与 MDK-ARM)官网下载安装包 [ 图文教程 ]
  4. 读Java8函数式编程笔记04_类库
  5. GitLab CI-CD 学习笔记
  6. 新开一个系列,c++刷题集
  7. 详解Redisson分布式限流的实现原理
  8. mybatis学习日记
  9. Git 多账号 SSH 配置
  10. 2021级《JAVA语言程序设计》上机考试试题10