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

k8s之service服务的更多相关文章

  1. 记录一起k8s的service服务名解析灵异事件

    故障现象: 基于alpine 3.7的镜像,构建的spring boot服务及eureka服务器. 在使用deployment和service文件部署到k8s集群之后, 在不同的pod内部,访问ser ...

  2. 【K8S】Service服务详解,看这一篇就够了!!

    k8s用命名空间namespace把资源进行隔离,默认情况下,相同的命名空间里的服务可以相互通讯,反之进行隔离. 1.1 Service Kubernetes中一个应用服务会有一个或多个实例(Pod, ...

  3. Kubernetes K8S之Service服务详解与示例

    K8S之Service概述与代理说明,并详解所有的service服务类型与示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master Cent ...

  4. k8s~k8s里的服务Service

    k8s用命名空间namespace把资源进行隔离,默认情况下,相同的命名空间里的服务可以相互通讯,反之进行隔离. 服务Service 1.1 Service Kubernetes中一个应用服务会有一个 ...

  5. k8s的service简述

    k8s向集群外部暴露端口的3种方式: 1.service->nodePort :仅暴露一个宿主机端口,用于集群外部访问,因为此操作被写入各个节点的iptables或ipvs规则当中,可以用任意一 ...

  6. .Net Core 商城微服务项目系列(十二):使用k8s部署商城服务

    一.简介 本篇我们将会把商城的服务部署到k8s中,同时变化的还有以下两个地方: 1.不再使用Consul做服务的注册和发现,转而使用k8s-dns来实现. 2.不再使用Ocelot作为业务网关,使用T ...

  7. 中国.NET开发者峰会特别活动-基于k8s的微服务和CI/CD动手实践报名

    2019.11.9 的中国.NET开发者峰会将在上海举办,到目前为止,大会的主题基本确定,这两天就会和大家会面,很多社区的同学基于对社区的信任在我们议题没有确定的情况下已经购票超过了300张,而且分享 ...

  8. ASP.NET Core基于K8S的微服务电商案例实践--学习笔记

    摘要 一个完整的电商项目微服务的实践过程,从选型.业务设计.架构设计到开发过程管理.以及上线运维的完整过程总结与剖析. 讲师介绍 产品需求介绍 纯线上商城 线上线下一体化 跨行业 跨商业模式 从0开始 ...

  9. [转帖]k8s 中的服务如何沟通

    k8s 中的服务如何沟通 https://www.jianshu.com/p/9fae09876eb7 本文将介绍 k8s 中的服务如何相互访问,例如后端服务访问数据库,不同类型的服务间的相互访问.并 ...

  10. dial tcp 10.96.0.1:443: getsockopt: no route to host --- kubernetes(k8s)DNS 服务反复重启

    kubernetes(k8s)DNS 服务反复重启解决: k8s.io/dns/pkg/dns/dns.go:150: Failed to list *v1.Service: Get https:// ...

随机推荐

  1. JavaScript:操作符:逗号运算符

    逗号运算符,是极少见的运算符,我们看一下代码理解一下逗号运算符的功能: 先说结论,逗号运算符的优先级非常低,比赋值运算符=还要低: 同时,逗号隔开的几个表达式,都会各自进行计算,但是整体表达式只会返回 ...

  2. 15、MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

    转载自 一.报错信息: Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollback ...

  3. [0x11] 131.直方图中最大的矩形【单调栈】

    题意 link(more:SPOJ1805) 如图,在水平线上有 \(n(n\leqslant10^5)\) 个宽度为 1 ,高度为 \(h(0\leqslant h\leqslant10^9)\) ...

  4. eclipse打不开maven项目中的pom.xml

    1.问题描述 在eclipse中我双击打开maven项目中的pom.xml报错. 2.产生原因 正如报错中描述的那样"Failed to create the part's controls ...

  5. 用Java写一个分布式缓存——缓存淘汰算法

    前言 之前也用过一些缓存中间件,框架,也想着自己是不是也能用Java写一个出来,于是就有了这个想法,打算在写的过程中同步进行总结. 源码:weloe/Java-Distributed-Cache (g ...

  6. ElasticSearch必知必会-进阶篇

    京东物流:康睿 姚再毅 李振 刘斌 王北永 说明:以下全部均基于elasticsearch8.1 版本 一.跨集群检索 - ccr 官网文档地址: https://www.elastic.co/gui ...

  7. Java基础1-1-3—java基础语法(条件控制语句)

    3. 条件控制语句 3.1 流程控制语句-顺序结构 流程控制语句:通过一些语句,来控制程序的[执行流程] 流程控制语句分类: 顺序结构 分支结构(if,switch) 循环结构(for,while,d ...

  8. 命令行部署repmgr管理集群+switchover+切换测试

    本次部署未使用securecmd/kbha工具.无需普通用户到root用户的互信. 建立系统数据库安装用户组及用户,在所有的节点执行 root用户登陆服务器,创建用户组及用户并且设置密码 [root@ ...

  9. 【Rust学习】内存安全探秘:变量的所有权、引用与借用

    作者:京东零售 周凯 一.前言 Rust 语言由 Mozilla 开发,最早发布于 2014 年 9 月,是一种高效.可靠的通用高级语言.其高效不仅限于开发效率,它的执行效率也是令人称赞的,是一种少有 ...

  10. redis06-事务

    1 基本说明 可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞. 2 事务相关的几个命令 2.1 MULTI 标记一个事务块 ...