Kubernetes Service

Service 的作用

参考链接

虽然每个Pod都有自己的IP地址,但即使这些IP地址不能长期保持稳定。这导致了一个问题:如果一些Pod(称为它们的后端)为Kubernetes集群内的其他Pod(我们称之为前端)提供了功能,那么这些前端如何发现并跟踪哪些后端位于该集合中?

通过Service。

Kubernetes的 service是一个抽象概念,它定义了Pod的逻辑集合以及访问它们的策略 - 有时称为微服务。service所针对的Pod集(通常)由标签选择器决定(请参阅下面为什么您可能需要没有选择器的服务)。

举一个例子,考虑一个运行3个副本的应用处理后端。这些副本是可替代的 - 前端不关心他们使用的后端。虽然构成后端集合的实际Pod可能会发生变化,但前端客户端不需要知道该事件,也不需要跟踪后端列表本身。服务抽象使这种解耦成为可能。

对于Kubernetes原生应用程序,Kubernetes提供了一个简单的Endpoints API,只要服务中的Pod集合发生更改,它就会更新。对于非本机应用程序,Kubernetes提供了一个基于虚拟IP的网桥,用于重定向到后端Pod的服务。

定义Service

Serive 可以通过两种方式定义,yaml 文件方式和使用命令行创建的方式。

使用yaml方式

使用yaml文件定义个service:

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

此规范将创建一个名为“my-service”的新服务对象,该服务对象将任何Pod上的TCP端口9376以“app = MyApp”标签作为目标。 该服务还将被分配一个IP地址(有时称为“群集IP”),服务代理使用该地址(见下文)。 服务的选择器将被连续评估,结果将被发送到一个名为“my-service”的端点对象。

请注意,服务可以将传入端口映射到任何目标端口。 默认情况下,targetPort将设置为与端口字段相同的值。 也许更有趣的是,targetPort可以是一个字符串,指的是后端Pod中端口的名称。 分配给该名称的实际端口号可以在每个后端Pod中不同。 这为部署和发展您的服务提供了很大的灵活性。 例如,您可以在不中断客户端的情况下,更改后续版本后端软件中的端口号。
Kubernetes 的 Services 支持TCP和UDP协议,默认支持TCP。

使用命令方式

使用kubectl expose命令也可以创建一个Services:

 kubectl  expose deployment php-apache

创建不带标签选择器的service

我们有时候也可以定义一个不带标签选择器的Service,即无法选择后端的Pod,系统不会自动创建Endpoint,当要正式使用的时候再手动创建一个和该Service同名的Endpoint,用于指向实际的后端访问地址。
这种方式一般有如下的应用场景:

  • 在生产环境中,需要连接一个外部的数据库,但是在测试的阶段,我们会使用自己的测试数据库。
  • 需要将service指向其他namespace的服务或外部集群中。
  • 您正在将工作负载迁移到Kubernetes,而您的一些后端运行在Kubernetes之外。

这样定义一个不含选择器标签的service:

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  ports:
  - protocol: TCP
    port: 80                       # services 的端口
    targetPort: 9376               # endpoint 的端口

在使用的时候还需要手动创建一个同名的Endpoint:

kind: Endpoints
apiVersion: v1
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 1.2.3.4       # 外部服务的IP和端口,这里相当于Pod 的IP,只不过是外部的一个不变的地址
    ports:
      - port: 9376

虚拟IP和服务代理

Kubernetes群集中的每个节点都运行一个kube-proxy。 kube-proxy负责为ExternalName以外的其他类型的服务提供一个虚拟IP。 在Kubernetes v1.0中,服务是“第4层”(TCP / UDP over IP)构造,代理纯粹在用户空间中。 在Kubernetes v1.1中,添加了(测试版)Ingress API以表示“第7层”(HTTP)服务,还添加了iptables代理,并成为自Kubernetes v1.2以来的默认操作模式。 在Kubernetes v1.8.0-beta.0中,添加了ipvs代理。

用户空间代理模式

在此模式下,kube-proxy监视Kubernetes主服务器以添加和删除Service和Endpoints对象。 对于每个服务,它在本地节点上打开一个端口(随机选择)。 与此“代理端口”的任何连接都将代理到Service的后端Pod之一(如端点中所报告)。 根据服务的SessionAffinity决定使用哪个后端Pod。 最后,它安装iptables规则,捕获流量到服务的clusterIP(虚拟)和端口,并将该流量重定向到代理后端Pod的代理端口。 默认情况下,后端的选择是轮询模式。

iptables 代理模式

在此模式下,kube-proxy监视Kubernetes主服务器以添加和删除Service和Endpoints对象。 对于每个服务,它都会安装iptables规则,这些规则将流量捕获到服务的clusterIP(这是虚拟的)和端口,并将该流量重定向到服务的后端集合之一。 对于每个Endpoints对象,它都会安装选择后端Pod的iptables规则。 默认情况下,后端的选择是随机的。

显然,iptables不需要在用户空间和内核空间之间切换,它应该比用户空间代理更快,更可靠。 但是,与用户空间连接器不同,如果iptables连接器最初选择的连接器不响应,iptables连接器不能自动重试另一个连接,因此它依赖于正在工作的准备就绪探测器。

IPVS代理模式

在这种模式下,Kubernetes Services和Endpoints调用netlink接口来相应地创建ipvs规则,并定期与Kubernetes Services和Endpoints同步ipvs规则,以确保ipvs状态与预期一致。 当访问服务时,流量将被重定向到其中一个后端Pod。

与iptables类似,Ipvs基于netfilter钩子函数,但使用散列表作为基础数据结构并在内核空间中工作。 这意味着ipvs可以更快地重定向流量,并且在同步代理规则时具有更好的性能。 此外,ipvs为负载均衡算法提供了更多选项,例如:

  • rr:轮询
  • lc:最少连接
  • dh:目标哈希
  • sh:源哈希
  • sed:预计的最短延迟
  • nq:从不排队

在运行kube-proxy之前,ipvs模式假定在节点上安装了IPVS内核模块。 当kube-proxy以ipvs代理模式启动时,kube-proxy会验证节点上是否安装了IPVS模块,如果未安装,kube-proxy将回退到iptables代理模式。

在任何这些代理模型中,为服务的IP:端口绑定的任何流量都会代理到适当的后端,而客户端不知道任何关于Kubernetes或服务或Pod的信息。 通过将service.spec.sessionAffinity设置为“ClientIP”(缺省值为“None”),可以选择基于Client-IP的会话关联,并且可以通过设置字段service.spec.sessionAffinityConfig.clientIP来设置最大会话粘滞时间。 timeoutSeconds如果您已经将service.spec.sessionAffinity设置为“ClientIP”(默认值为“10800”)

多端口service

有时一个容器也可以映射多个端口服务,在service的定义中也可以相应的设置多端口的对应到多个应用服务器上:

kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - name: http
    protocol: TCP
    port: 80
    targetPort: 9376
  - name: https
    protocol: TCP
    port: 443
    targetPort: 9377

在映射多个端口的时候,需要给每一个端口指定名称。

服务发现机制

在Kubernetes 集群中是如何进行服务发现的呢? Kubernetes为我们提供了两种方式:

  • 环境变量
  • DNS

环境变量

当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。 它同时支持 Docker links兼容 变量(查看 makeLinkVariables)、简单的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 变量,这里 Service 的名称需大写,横线被转换成下划线。

举个例子,一个名称为 "redis-master" 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

使用环境变量需要有顺序的要求 —— Pod 想要访问的任何 Service 必须在 Pod 自身之前被创建,否则这些环境变量就不会被赋值。但是DNS 并没有这个限制。

DNS

一个可选(尽管强烈推荐)集群插件 是 DNS 服务器。 DNS 服务器监视着创建新 Service 的 Kubernetes API,从而为每一个 Service 创建一组 DNS 记录。 如果整个集群的 DNS 一直被启用,那么所有的 Pod 应该能够自动对 Service 进行名称解析。

例如,有一个名称为 "my-service" 的 Service,它在 Kubernetes 集群中名为 "my-ns" 的 Namespace 中,为 "my-service.my-ns" 创建了一条 DNS 记录。 在名称为 "my-ns" 的 Namespace 中的 Pod 应该能够简单地通过名称查询找到 "my-service"。 在另一个 Namespace 中的 Pod 必须限定名称为 "my-service.my-ns"。 这些名称查询的结果是 Cluster IP。

Kubernetes 也支持对端口名称的 DNS SRV(Service)记录。 如果名称为 "my-service.my-ns" 的 Service 有一个名为 "http" 的 TCP 端口,可以对 "_http._tcp.my-service.my-ns" 执行 DNS SRV 查询,得到 "http" 的端口号。

Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName 类型的 Service 的方式。 更多信息可以查看DNS Pod 和 Service。

Headless Service

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。

这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。 应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。

对这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。 DNS是否能够自动配置,依赖于 Service 是否定义了 selector。

带Selectors 的Headless Service

如果在Services定义了一个Selectors, K8S将会为每个Pod创建一个Endpoint,并配置到DNS,访问此Service时,会将Pod对应的所有A记录地址返回。
这对于分布式的集群创建非常有用,可以通过使用这种方式获得集群的列表。

定义:

cat nginx-headless-service.yaml 

kind: Service
apiVersion: v1
metadata:
  name: nginx-service
  labels:
    app: nginx-service
spec:
  selector:
    app: nginx
  clusterIP: None
  ports:
  - protocol: TCP
    port: 80

创建一个nginx 的deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.10.3
        ports:
        - containerPort: 80

查看对应的serivce和pod 信息:

# kubectl  get svc nginx-service
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   None         <none>        80/TCP    27m

# kubectl  get pod -o wide |grep nginx
nginx-deployment-75d56bb955-pw7mm   1/1       Running   0          40m       10.2.61.9   10.0.0.2
nginx-deployment-75d56bb955-qprjw   1/1       Running   0          40m       10.2.39.3   10.0.0.3
nginx-deployment-75d56bb955-xfgbk   1/1       Running   0          40m       10.2.39.2   10.0.0.3

在pod中访问此服务,可以发现DNS上直接绑定了Pod的IP列表,不再绑定Cluster IP:

# kubectl  run  busybox --image=busybox -it sh  --rm

/ # nslookup nginx-service
Server:    10.1.0.100
Address 1: 10.1.0.100 coredns.kube-system.svc.cluster.local

Name:      nginx-service
Address 1: 10.2.39.2 10-2-39-2.nginx-service.default.svc.cluster.local
Address 2: 10.2.39.3 10-2-39-3.nginx-service.default.svc.cluster.local
Address 3: 10.2.61.9 10-2-61-9.nginx-service.default.svc.cluster.local

使用headless service 和 Stateful Sets 部署Cassandra分布式集群实例参考此链接:https://kubernetes.io/docs/tutorials/stateful-application/cassandra/

发布服务-集群外部访问Pod或Service

在kubernetes中,发布服务有有如下几种方式:

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

将容器端口映射到宿主机

通过设置hostPort来设置容器端口到物理机:

apiVersion: v1
kind: Pod
metadata:
  name: redis-php
  labels:
    name: redis-php
spec:
  hostNetwork: true                        # 指定可以通过宿主机访问pod中的服务
  containers:
  - name: frontend
    image: kubeguide/guestbook-php-frontend:localredis
    ports:
    - containerPort: 80
    # 指定宿主机映射端口。在不与hostNetwork: true 同时使用时可以指定任意端口,但是在某些使用CNI插件的情况下可能不会生效。
    # 与hostNetwork使用的时候,只能与容器端口一致,且可以省略,一般只在测试时使用。
      hostPort: 80
  - name: redis
    image: kubeguide/redis-master
    ports:
    - containerPort: 6379
      hostPort: 6379

使用nodePort将Service的端口映射到物理机

如果设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。配置如下参数指定端口范围:

# grep -ir "20000-40000" /usr/lib/systemd/system/

/usr/lib/systemd/system/kube-apiserver.service:  --service-node-port-range=20000-40000 

该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定。

如果需要指定的端口号,可以配置 nodePort 的值,系统将分配这个端口,否则调用 API 将会失败(比如,需要关心端口冲突的可能性)。并且指定的端口要在配置文件指定的端口范围内。
从kubernetes 1.10开始,支持指定IP, 通过如下参数:

--nodeport-addresses=127.0.0.0/8

也可以支持指定多个IP段,用逗号分隔的IP块列表(例如10.0.0.0/8,1.2.3.4/32)用于过滤本节点的地址。例如,如果您使用标志--nodeport-addresses = 127.0.0.0 / 8启动kube-proxy,则kube-proxy将仅为NodePort服务选择环回接口。 --nodeport地址默认为空([]),这意味着选择所有可用的接口并符合当前的NodePort行为。

这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的 IP 地址。

需要注意的是,Service 将能够通过 <NodeIP>:spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而对外可见。

定义示例:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 28888

创建此service后,所有安装有kube-proxy的节点上都会映射28888的端口,供外部访问。

原文地址:http://blog.51cto.com/tryingstuff/2136829

时间: 2024-07-30 19:44:37

Kubernetes Service的相关文章

浅谈 kubernetes service 那些事(上篇)

欢迎访问网易云社区,了解更多网易技术产品运营经验. 一.问题 首先,我们思考这样一个问题: 访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态.那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知? 二.k8s service 什么是service 是发现后端pod服务: 是为一组具有相同功能的容器应用提供一个统一的入口地址: 是将请求进行负载分发到后端的各个容器应用上的控制器. 对service的访问来源 访问service的请求来源有两种:k8s集

Docker Kubernetes Service 网络服务代理模式详解

Docker Kubernetes  Service 网络服务代理模式详解 Service service是实现kubernetes网络通信的一个服务 主要功能:负载均衡.网络规则分布到具体pod 注:kubernetes deployment服务分配服务器负载均衡VIP只能NODE节点单独访问,这里需要外网用户可以放问到容器内,这里就需要用到service. 网络代理模式 kube-proxy v1.0中只支持userspace模式,在v1.1中,添加了iptables代理,在v1.2开始ip

kubernetes service 和 ingress

一 总述 1 service 作用 POD 中运行的容器存在动态.弹性的变化(容器的重启IP地址会变化),因此便产生了service,其资源为此类POD对象提供一个固定.统一的访问接口及负载均衡能力,并借助DNS系统的服务发现功能,解决客户端发现容器难得问题 service 和POD 对象的IP地址在集群内部可达,但集群外部用户无法接入服务,解决的思路有:1 在POD上做端口暴露(hostPort)2 在工作节点上公用网络名称空间(hostNetwork)3 使用service 的NodePor

ASP.NET Core在Azure Kubernetes Service中的部署和管理

目录 ASP.NET Core在Azure Kubernetes Service中的部署和管理 目标 准备工作 注册 Azure 账户 AKS文档 进入Azure门户(控制台) 安装 Azure Cli 安装 Docker 进入正题 资源组 创建资源组 删除资源组 容器注册表 Azure Container Register (ACR) 创建 ACR 登录 ACR 服务主体 service principle 创建服务主体 给服务主体配置 ACR 的pull权限 K8s服务集群 Azure Ku

浅谈 kubernetes service 那些事

说明 关于 k8s 服务这一块知识,我之前的博文中有些实例应用和说明.下面分享几位大佬的文章,加固对 service 这块有更深的理解- 分享 浅谈 kubernetes service 那些事 本文详细介绍了 k8s service 实现原理和新特性,值得深度拜读和理解- K8s Deployment YAML 名词解释 本文对 Deployment yaml 名词进行了详细解释,值得参考学习- 使用 k8s 部署你的第一个应用: Pod,Deployment 与 Service 通过简单的

CoreDNS for kubernetes Service Discovery

一.CoreDNS简介 Kubernetes包括用于服务发现的DNS服务器Kube-DNS. 该DNS服务器利用SkyDNS的库来为Kubernetes pod和服务提供DNS请求.SkyDNS2的作者,Miek Gieben,创建了一个新的DNS服务器,CoreDNS,它采用更模块化,可扩展的框架构建. Infoblox已经与Miek合作,将此DNS服务器作为Kube-DNS的替代品. CoreDNS利用作为Web服务器Caddy的一部分而开发的服务器框架.该框架具有非常灵活,可扩展的模型,用

[k8s集群系列-10]Kubernetes Service暴露方式及Traefik使用

访问部署在kubernetes集群中服务,有两种类型: 集群内部实现访问 集群外部实现访问 但是不管是集群内部还是外部访问都是要经过kube-proxy的 集群内部实现访问 ClusterIP Clusterip是集群内部的私有ip,在集群内部访问服务非常方便,也是kuberentes集群默认的方式,直接通过service的Clusterip访问,也可以直接通过ServiceName访问.集群外部则是无法访问的. 示例 **创建nginx服务,提供web服务z nginx-ds.yaml api

(七)Kubernetes Service

官网链接 https://kubernetes.io/zh/docs/concepts/services-networking/service/service是将一组运行Pods上的应用程序公开为网络服务的抽象方法为什么要有servicepod具有不停销毁.创建的特征,每个Pod又有自己分配的IP,Pod的创建.销毁意味着IP不停的变更,前端如何跟踪IP地址变得非常困难,service就是来解决这个问题的.它可以实现监控Pod的变化,并对外提供一个固定的访问入口(负载均衡的入口):Endpoin

Kubernetes集群中Service的滚动更新

Kubernetes集群中Service的滚动更新 二月 9, 2017 0 条评论 在移动互联网时代,消费者的消费行为已经"全天候化",为此,商家的业务系统也要保持7×24小时不间断地提供服务以满足消费者的需求.很难想像如今还会有以"中断业务"为前提的服务系统更新升级.如果微信官方发布公告说:每周六晚23:00~次日凌晨2:00进行例行系统升级,不能提供服务,作为用户的你会怎么想.怎么做呢?因此,各个平台在最初设计时就要考虑到服务的更新升级问题,部署在Kubern