Service

18 篇文章 0 订阅
9 篇文章 0 订阅


一、Service

Pod 的生命是有限的,死亡之后是不会复活的。但是RC 和 Deployment 可以用来动态的创建和销毁 Pod。尽管每个 Pod 都有自己的 IP 地址,但是如果 Pod 重新启动了的话那么他的 IP 很有可能也就变化了,这就会带来一个问题:比如我们有一些后端的 Pod 的集合为集群中的其他前端的 Pod 集合提供 API 服务,如果我们在前端的 Pod 中把所有的这些后端的 Pod 的地址都写死,然后去某种方式去访问其中一个 Pod 的服务,这样看上去是可以工作的,但是如果这个 Pod 挂掉了,然后重新启动起来了,是不是 IP 地址有可能就变了,这个时候前端就极大可能访问不到后端的服务了。

遇到这种的问题怎么解决呢,不一定是 IP 变化的问题,比如我们在部署一个 WEB 服务器的时候,前端一般部署一个Nginx 作为服务的入口,然后Nginx 后面肯定就是挂载的这个服务的大量后端,很早以前我们可能就是去手动更改 Nginx 配置中的 upstream 选项, 来动态改变提供服务的数量,到后面出现了一些服务发现的工具,比如 Consul 、 Zookeeper 还有我们熟悉的 etcd 等工具,有了这些工具过后我们就可以只需要把我们的服务注册到这些服务发现中心去就可以,然后这些工具动态的去更新 Nginx 的配置就可以了,我们完全不用去手工操作。

在这里插入图片描述

当我们的 Pod 被销毁或者新建过后,我们可以把这个 Pod 的地址注册到这个服务发现中心去就可以,但是这样的话我们的前端的 Pod 结合就不能直接去连接后台的 Pod 集合了吧,应该连接到一个能够做服务发现的中间件上面。

Kubernetes为了我们提供了 -Service ,Service是一种抽象的对象,它定义了一组 Pod 的逻辑集合和一个用于访问它们的策略,其实这个概念和微服务非常类似。一个 Service 下面包含的 Pod 集合一般是由 Label Selector 来决定的。

比如上面的例子,假如我们后端运行了3个副本,这些副本都是可以代替的,因为前端并不关心它们使用的是哪个后端服务,尽管由于各种原因后端的 Pod 集合会发送变化,但是前端缺不需要知道这些变化,也不需要自己用一个列表来记录这些后端的服务,Service 的这种抽象就可以帮我们打到这种解耦的目的。

二、三种 IP

  • Node IP :Node节点的 IP 地址
  • Pod IP : Pod 的 IP地址
  • Cluster IP : Service 的 IP 地址

首先, Node IP 是 Kubernetes 集群中节点的物理网卡 IP 地址(一般为内网)所有属于这个网络的服务器之间都可以直接通信,所以 Kubernetes 集群外要想访问 Kubernetes 集群内部的某个节点或者服务,肯定得过 Node IP 进行通信(这个时候一般是通过外网 IP 了)

然后 Pod 是每个 Pod 的 IP 地址,它是 Docker Engine 根据 docker网桥的IP 地址段进行分配的(我们这里使用的是 flannel 这种网络插件保证所有节点的 Pod IP 不会冲突)

最后 cluster IP 是一个虚拟的 IP ,仅仅作用于 Kubernetes Service 这个对象,由 Kubernetes 自己来进行管理和分配地址,当然我们也无法ping 这个地址,他没用一个真正的实体对象来响应,他只能结合 Service Port 来组成一个可以通信的服务。

三、定义 Service

定义 Service 的方式和我们之前定义各种资源的方式类型一样,例如:我们有一组Pod 服务他们对外暴露了 8080 端口 ,同时都被打上了 app=myapp 这样的标签,那么我们可以像以下定义一个 Service 对象:

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
    name: myapp-http

然后通过使用 kubectl create -f myservice.yaml 就可以创建一个名为 myservice 的Service 对象,它会将请求代理到使用 TCP 端口为 8080 ,具有标签 app=myapp 的 Pod 上,这个 Service 会被系统分配一个我们上面所说的 Cluster IP 。该 Service 会持续监听 selector 下面的 pod ,会把这些 pod 信息 更新到一个名为 myservice 的 Endpoints 对象上去,这个对象就类似于我们上面说的 Pod 集合了。

需要注意的是, Service 能够将一个接受端口映射到任意的 targetPort。默认情况下, targetPort 将会被设置为与 Port 字段相同的值。targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称,因指派给端口名称的端口号,在每个 backend Pod 中可能并不相同,所以对于部署和设计 Service ,这种方式会提供更大的灵活性。

另外 Service 能够支持 TCP 和UDP 协议,默认是 TCP 协议。

四、kube-proxy

在 Kubernetes 集群中,每个 Node 会运行一个 kube-proxy 进程,负责为 Service 实现一种 VIP(虚拟IP,就是cluster IP)的代理形式,现在的 Kubernetes 中默认是使用的 iptables 这种模式来代理,这种模式, kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service ,它会添加上 iptables 规则,从而捕获到该 Service 的 cluster IP (虚拟IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的 某一个上面,对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod 。

默认的策略是,随机选择一个 backend ,我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinit 的值设置为 ClientIP (默认为None)。

另外需要了解的是如果是最开始选择的 Pod 没有响应,iptables 代理能够自动的重试另一个 Pod ,所以它需要依赖 readiness probes。

在这里插入图片描述

五、Service 类型

Service 默认是 Cluster IP 类型

我们可以使用的服务类型如下:

  • Cluster IP :通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
  • NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务,NodePort服务会路由到 ClusterIP服务,这个ClusterIP 服务会自动创建。通过请求,可以从集群的外部访问一个 NodePort服务。
  • LoadBalancer:使用云提供商的负载均衡器,可以向外暴力服务,外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
  • ExternalName:通过返回CNAME和它的值,可以将服务映射到 externalName 字段的内容(例如:foo.bar.example.com),没有任何类型代理被创建,这只有 Kubernetes 1.7或者更高的版本 kube-dns才支持。

NodePort 类型

如果设置 type 的值为 NodePort ,Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个Node 将从该端口,(每个Node上的同一端口)代理到Service 。该端口将通过 Service 的 spec.ports[*].NodePort字段被指定,如果不指定的话会自动生成一个端口。

需要注意的是,Service 将能够通过:spec.ports[].NodePort和 spec.clusterIP:spec.ports[].port而对外可见。

我们创建一个 NodePort 的服务来访问我们前面的 Nginx 服务:(保存为service-demo.yaml)

apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  selector:
    app: myapp
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    name: myapp-http

创建该Service :

$ kubectl create -f service-demo.yaml

然后我们可以查看 Service 对象信息:

$ kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        27d
myservice    NodePort    10.104.57.198   <none>        80:32560/TCP   14h

我们可以看到 myservice 的type类型已经变成了 NodePort ,后面的 Ports 部分也多了一个32560的映射端口。

六、ExternalName

ExternalName 是 Service 的特例,它没有 selector ,也没有定义任何的端口和 Endpoints,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供。

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

当查询主机 my-service.prod.svc.cluster.local 时,集群的 DNS 服务将会返回一个值为my.database.eaxmple.com的 CNAME记录。访问这个服务的工作方式与其他的相同,唯一不同的是重定向发生在DNS层,而且不会进行代理或转发,如果后续决定要将数据库迁移到Kubernetes 集群中,可以启动对应的 Pod,增加合适的 Selector 或 Endpoint ,修改 Service 的type,完全不需要修改调用的代码,这样就解耦了。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值