设为首页 收藏本站
查看: 716|回复: 0

[经验分享] Kubernetes Service-Trying

[复制链接]

尚未签到

发表于 2018-9-15 12:00:20 | 显示全部楼层 |阅读模式
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                 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 服务会自动创建。通过请求 :,可以从集群的外部访问一个 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 将能够通过 :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的端口,供外部访问。



  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-583453-1-1.html 上篇帖子: Kubernetes网络 下篇帖子: Kubernetes+Etcd-v1.7.0 + CA 分布式集群部署
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表