# 第五章 服务:让客户端发现pod并与之通信 ##

1.什么是服务

简单来说服务就是为一组功能相同的pod提供单一不变的接入点的资源:
1.因为Pod是不稳定的,所以不能固定一个Pod的IP,但是服务是稳定的,服务的IP固定,通过服务来连接Pod也是稳定的
2.服务只是连通了集群内部所有IP访问pod的问题,但是不解决外部访问pod问题

2.创建服务

1.创建一个rc控制器,启动三个pod,暴露容器端口8080

apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    app: kubia
  template:
    metadata:
      labels:
        app: kubia
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080

2.创建一个服务

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia

创建的服务会根据selector标签来选择pod,凡是pod标签和服务标签匹配的都属于同一个服务,上面服务会占用80端口,服务会将链接转发到容器的8080端口

3.检测新服务

[[email protected] ~]# k get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   5d3h
kubia        ClusterIP   10.96.51.176   <none>        80/TCP    5s

4.检测服务是否代理到对应的pod

随机进入一个pod,执行请求命令
[[email protected] ~]# k get pods
NAME                         READY   STATUS      RESTARTS   AGE
batch-job-1576940400-jwkrn   0/1     Completed   0          8m6s
kubia-dzhlj                  1/1     Running     0          5m16s
kubia-mg8d7                  1/1     Running     0          5m16s
kubia-vccvt                  1/1     Running     0          5m16s

[[email protected] ~]# kubectl exec kubia-vccvt -- curl -s http://10.96.51.176
You've hit kubia-dzhlj
[[email protected] ~]# kubectl exec kubia-vccvt -- curl -s http://10.96.51.176
You've hit kubia-dzhlj
[[email protected] ~]# kubectl exec kubia-vccvt -- curl -s http://10.96.51.176
You've hit kubia-mg8d7
[[email protected] ~]# kubectl exec kubia-vccvt -- curl -s http://10.96.51.176
You've hit kubia-vccvt
[[email protected] ~]# curl http://10.96.51.176
You've hit kubia-vccvt

# kubectl exec 功能等同于ssh,另外 --(两个横杠) 的作用代表kubectl exec 命令结束,进入pod内部执行命令

5.以上svc代理的全过程

1.首先svc接收到请求,会随机分配到属于其代理范畴的pod中(负载均衡)
2.pod内的接收到服务代理的请求,返回pod自身的名称
3.curl命令向标准输出打印返回值

6.配置服务上的会话亲和性

如果多次执行相同的命令,每次调用执行应该在不同的pod上,因为svc会将每个链接随机分配到某个pod上,即使请求来自同一个客户端。

如果希望特定的客户端产生的请求指向同一个pod,可以设置服务的sessionAffinity属性为ClientIP(而不是None,默认为None)

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  sessionAffinity: ClientIP
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia

验证:

[[email protected] ~]# k exec kubia-lmhd5 -- curl -s http://10.96.50.191
You've hit kubia-vdksm
[[email protected] ~]# k exec kubia-lmhd5 -- curl -s http://10.96.50.191
You've hit kubia-vdksm
[[email protected] ~]# k exec kubia-lmhd5 -- curl -s http://10.96.50.191
You've hit kubia-vdksm

7.同一个服务暴露多个端口

创建的服务可以暴露多个端口,通过一个集群IP,使用一个服务就可以将多个端口全部暴露出来

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  - name: https
    port: 443
    targetPort: 8443
  selector:
    app: kubia

注意: 标签选择器应用于整个服务,不能对某个pod做单独配置,如果不同的pod需要暴露的端口不同,那么需要创建两个或者多个服务

8.使用命名的端口

为什 么要采用 命名端口的方式?最大 的 好处就是即使更换端口号 也无须更改服务 spec 。 你的 po d 现在对 http 服务用的是 8080 ,但是假设过段时间你决定将端口更换为 80 呢 ?

如果采用命名方式的话,只需要更改pod中的端口就可以了,svc不用做任何改变

kind: Pod
spec:
  containers:
  -name :kubia
    ports:
    -name: http
      containerPort: 8080
    -name: https
      containerPort: 8443
kind: Service
spec:
  - name: http
    port: 80
    targetPort: http
  - name: https
    port: 443
    targetPort: https

3.服务发现

当前端pod需要访问后端pod时是怎么发现后端服务pod呢?

1.第一种方式,根据环境变量

早期K8S通过环境变量来解决,每个Service生成对应的环境变量,并在POD启动时注入这些变量。

当创建一个Pod的时候,kubelet会在该Pod中注入集群内所有Service的相关环境变量。需要注意的是,要想一个Pod中注入某个Service的环境变量,则必须Service要先比该Pod创建。这一点,几乎使得这种方式进行服务发现不可用。
k exec kubia-vdksm env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubia-vdksm
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBIA_SERVICE_HOST=10.96.51.176
KUBIA_PORT_80_TCP_PROTO=tcp
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBIA_PORT_80_TCP_ADDR=10.96.51.176
KUBERNETES_PORT_443_TCP_PORT=443
KUBIA_PORT_80_TCP=tcp://10.96.51.176:80
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBIA_SERVICE_PORT=80
KUBIA_PORT=tcp://10.96.51.176:80
KUBIA_PORT_80_TCP_PORT=80
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=7.9.0
YARN_VERSION=0.22.0
HOME=/root

其中的UBIA_SERVICE_HOST=10.96.51.176和KUBIA_SERVICE_PORT=80就是环境变量中对应的服务IP和服务PORT,只要前端pod获取到这两个信息就可以实现数据库的交互

2.通过DNS发现服务

kubernetes 根据CoreDNS来提供DNS服务,如下coredns运行者dns服务,在集群中的其他pod都被配置成使用它作为dns服务(ubemetes 通过修改每个容器的/ etc/resolv. conf 文件 实现))。也就是说每个pod在resolv.conf中都存在着和coredns相同的DNS规则。运行在pod进程的DNS查询都会被Kubernetes自身的DNS服务器响应,该服务器知道系统中运行的所有服务

kube-system   coredns-9d85f5447-kthw8              1/1     Running   8          6d17h
kube-system   coredns-9d85f5447-pqvcl              1/1     Running   8          6d17h

注意:

pod 是否使用内部的DNS服务器是根据pod中的spec的dnsPlicy属性来决定的

每个服务从内部 DNS 服务器中获得 一 个 DNS 条目, 客户端 的 pod 在知道服务名称的情况下可以通过全限定域名 CFQDN )来访问,而不是诉诸于环境变量。

通过FQDN连接服务:

前端pod可以通过打开以下的FQDN的连接来访问后端数据库服务:
backend database.default svc.cluster. l ocal

backend-database对应服务名称,default表示服务在其中定义的命名空间,而svc.cluster.local是在所有集群本地服务名称中使用的可配置集群域后缀,但是前端仍然必须知道服务的端口号,如果服务使用标准端 口 号(例如,HTTP 的 80 端 口 或 Postgres 的5432端口),这样是没问题的 。 如果并不是标准端口,客户端可以从环境变量中获取端口号 。

如果前端pod和后端pod在同一个namespace下,可以省略svc.cluster.local后缀,甚至命名空间。因此可以使用backend-database来指代服务
如下:
[[email protected] ~]# k get po
NAME          READY   STATUS    RESTARTS   AGE
kubia-b24bc   1/1     Running   0          79m
kubia-nqvst   1/1     Running   0          79m
kubia-svsln   1/1     Running   0          79m
[[email protected] ~]# k exec kubia-b24bc sh
[[email protected] ~]# k exec -it  kubia-b24bc sh
# curl kubia
You've hit kubia-b24bc

3.连接集群外的服务

1.介绍endpoint

Endpoint是一种介于服务和pod之间的资源,因此服务和pod不是直接连接的。

[[email protected] ~]# k get endpoints kubia
NAME    ENDPOINTS                                      AGE
kubia   10.38.0.1:8080,10.38.0.2:8080,10.40.0.3:8080   45h

Endpoint资源就是暴露一个服务的IP地址和端口的列表,svc只有定义了selector之后,才会自动生成Endpoints资源

2.创建没有选择器的服务

要想创建没有选择器的服务,就需要手动创建服务和Endpoints资源

首先创建rc/rs/pod,选择先前的kubia rc

然后创建svc

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
  - port: 80

最后创建ep(注意要和svc有相同的名称,同时address要对应pod()地址)

apiVersion: v1
kind: Endpoints
metadata:
  name: external-service
subsets:
  - addresses:
    - ip: 10.38.0.1
    - ip: 10.38.0.2
    - ip: 10.40.0.3
    ports:
    - port: 8080 

然后验证是否将svc和pod关联到

[[email protected] ~]# k get ep
NAME               ENDPOINTS                                      AGE
external-service   10.38.0.1:8080,10.38.0.2:8080,10.40.0.3:8080   15s
kubernetes         10.0.2.6:6443                                  7d2h

[[email protected] ~]# k exec -it kubia-svsln sh
# curl kubia
curl: (6) Could not resolve host: kubia
# curl external-service
You've hit kubia-nqvst

如果想要把外部的服务迁移到pod中,只需要为服务添加选择器关联到pod,从而对Endpoint进行自动管理

2.为外部服务创建别名

spec:
   type: ExternalName
   externalName: someapi.somecompany.com
   ports:
   - port: 80

3.将服务暴露给外部客户端

有几种方式可以通过外部访问服务:

1.将服务类型设置为NodePort:
    此种方式下,每个集群节点都会在自身节点上打开一个特定的端口,并将在该端口的接收的流量重定向到基础服务,该服务仅在内部集群IP和端口上才可以访问,但是也可以通过所有节点的专用端口访问
2.将服务类型设置为LoadBalance,:
    NodePort类型的一种扩展 -- 使得服务可以通过一个专用的负载均衡器来访问,这是由K8s中正在运行的云基础设施提供的。负载均衡器将流量重定向到跨所有节点的节点端口。客户端通过负载均衡器的 IP 连接到服务。
3.创建一个Ingress资源,这是一个    完全不同的机制,通过一个IP地址公开多个服务, 它是运行在HTTP层(网络协议的7层)上,因此提供比工作在4层服务更多的功能

3.1使用NodePort

apiVersion: v1
kind: Service
metadata:
  name: kubia-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30123
  selector:
    app: kubia

其中port为服务集群的Ip端口号,targetPort为背后pod的目标端口,nodePort可指定也可不指定,如果不制定那就会分配随机端口号

验证:

通过NodePort服务的方式,可以通过以下两种方式访问pod服务

①通过服务IP

②通过NodeIp+端口号

[[email protected] ~]# k get nodes -o wide
NAME         STATUS   ROLES    AGE    VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION               CONTAINER-RUNTIME
master.k8s   Ready    master   7d3h   v1.17.0   10.0.2.6      <none>        CentOS Linux 7 (Core)   3.10.0-1062.9.1.el7.x86_64   docker://19.3.5
node1.k8s    Ready    <none>   7d3h   v1.17.0   10.0.2.15     <none>        CentOS Linux 7 (Core)   3.10.0-1062.9.1.el7.x86_64   docker://19.3.5
node2.k8s    Ready    <none>   7d3h   v1.17.0   10.0.2.4      <none>        CentOS Linux 7 (Core)   3.10.0-1062.9.1.el7.x86_64   docker://19.3.5
[[email protected] ~]# curl 10.0.2.6:30123
You've hit kubia-b24bc
[[email protected] ~]# curl 10.0.2.15:30123
You've hit kubia-svsln
[[email protected] ~]# curl 10.0.2.4:30123
You've hit kubia-nqvst
[[email protected] ~]# k exec kubia-nqvst -it sh
# curl kubia
^C
# curl 10.38.0.1
curl: (7) Failed to connect to 10.38.0.1 port 80: Connection refused
# curl 10.0.2.15:30123
You've hit kubia-nqvst
# curl 10.96.123.159
You've hit kubia-svsln

现在如果你的集群IP是公开的,那么在互联网的任意地方,任意IP+30123端口即可访问你的服务,但是如果节点发生故障,但是此时客户端正在请求该节点,那么就会造成宕机,所以需要在请求前加一个负载均衡器,以确保请求的是一个健康的节点,那么就有了Load Badancer,Load Badancer会自动创建负载均衡器

3.2使用LoadBalance

LoadBanlance,负载均衡器有独一无二的可公开访问的IP地址,并将所有连接重定向到服务,可以通过负载均衡器的IP地址访问服务()

如果Kubernetes在不支持Load Bancer服务的环境的环境中运行,则不会调配负载均衡器,但该服务仍将表现得想一个NodePort服务,这是因为LoadBanlance是NodePort的一个扩展

创建LoadBanlance:

和创建NodePort一样,只是type类型为LoadBalancer

3.3防止不必要的网络跳数

正常情况下,外部客户端通过节点端口连接到服务时,会通过Service层做负载均衡,所以最终的处理请求的pod不一定会落在接收请求的节点上,这会带来额外的网络开销,这不符合预期
可以通过将服务配置将接收请求的节点和将提供服务的pod绑定在一起,通过在spec中配置:
spec:
  externalTrafficPolicy: Local
  如果服务定义包含此设置, 并且通过服务的节点端口打开外部连接, 则服务代理将选择本地运行的pod。 如果没有本地pod存在, 则连接将挂起(它不会像不使用注解那样, 将其转发到随机的全局pod)。 因此, 需要确保负载平衡器将连接转发给至少具有 一 个pod的节点

 缺点:
 ①使用local外部流量策略的服务可能会导致跨pod的负载分布不均衡
 ②追踪不到访问者的IP

原文地址:https://www.cnblogs.com/limengchun/p/12089280.html

时间: 2024-11-09 04:00:45

# 第五章 服务:让客户端发现pod并与之通信 ##的相关文章

第五章 服务熔断(hystrix)+ retrofit底层通信(AsyncHttpclient)

一.集群容错 技术选型:hystrix.(就是上图中熔断器) 熔断的作用: 第一个作用: 假设有两台服务器server1(假设可以处理的请求阈值是1W请求)和server2,在server1上注册了三个服务service1.service2.service3,在server2上注册了一个服务service4,假设service4服务响应缓慢,service1调用service4时,一直在等待响应,那么在高并发下,很快的server1处很快就会达到请求阈值(server1很快就会耗尽处理线程)之后

第五章 服务容错保护:Spring Cloud Hystrix

在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能会导致服务崩溃.为了解决这一系列的问题,断路器等一系列服务保护机制出现了. 断路器本身是一种开关保护机制,用于在电路上保护线路过载,当线路中有电器发生短路时,断路器能够及时切断故障电路,防止发生过载.发热甚至起火等严重后果. 在分布式架构中,断路器模式的作用也是类似的. 针对上述问题,Spring

第五章 服务容错保护: Spring Cloud Hystrix

在微服务架构中, 存在着那么多的服务单元, 若一个单元出现故障, 就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加不稳定.为了解决这样的问题, 产生了断路器等一系列的服务保护机制 Spring Cloud Hystrix实现了断路器. 线程隔离等一系列服务保护功能.它也是基于Netflix的开源框架Hystrix实现的, 该框架的目标在于通过控制那些访问远程系统. 服务和第三方库的节点, 从而对延迟和故障提供更强大的容错能力.Hystrix具备服务降级. 服

《Introduction to Tornado》中文翻译计划——第五章:异步Web服务

http://www.pythoner.com/294.html 本文为<Introduction to Tornado>中文翻译,将在https://github.com/alioth310/itt2zh上面持续更新,本文内容可能不是最新状态,请在GitHub上获得最新版本. 本文也可在http://demo.pythoner.com/itt2zh上进行格式化的预览. 第五章:异步Web服务 到目前为止,我们已经看到了许多使Tornado成为一个Web应用强有力框架的功能.它的简单性.易用性

白话SpringCloud | 第二章:服务注册与发现(Eureka)-上

前言 从本章节开始,正式进入SpringCloud的基础教程.从第一章<什么是SpringCloud>中我们可以知道,一个微服务框架覆盖的东西是很多的,而如何去管理这些服务或者说API接口,就显得异常重要了.所以本章节,主要介绍下SpringCloud中使用Eureka实现服务的注册与发现. 服务治理 Eureka实践 Eureka简单介绍 创建Eureka服务端 创建Eureka客户端 Eureka自我保护模式 参考资料 总结 最后 老生常谈 服务治理 服务治理是微服务架构中最为核心和基础的

【译文连载】 理解Istio服务网格(第五章 混沌测试)

全书目录 第一章 概述 第二章 安装 第三章 流控 第四章 服务弹性 本文目录 第5章 混沌测试................................................................................................. 1 5.1 HTTP错误............................................................................................

【第五章】API服务网关(Zuul) 上

微服务场景下,每一个微服务对外暴露了一组细粒度的服务.客户端的请求可能会涉及到一串的服务调用,如果将这些微服务都暴露给客户端,那么客户端需要多次请求不同的微服务才能完成一次业务处理,增加客户端的代码复杂度.另外,对于微服务我们可能还需要服务调用进行统一的认证和校验等等.微服务架构虽然可以将我们的开发单元拆分的更细,降低了开发难度,但是如果不能够有效的处理上面提到的问题,可能会造成微服务架构实施的失败. Zuul参考GOF设计模式中的Facade模式,将细粒度的服务组合起来提供一个粗粒度的服务,所

UNIX 网络编程第五章读后有感

刚看完 UNIX 第五章内容,我想按照自己的方式将自己获得的知识梳理一遍,以便日后查看!先贴上一段简单的 TCP 服务器端代码: 1 #include <sys/socket.h> 2 #include <netinet/in.h> 3 #include <stdio.h> 4 #include <error.h> 5 #include <unistd.h> 6 #include <string.h> 7 #include <s

【.NET Core项目实战-统一认证平台】第十五章 网关篇-使用二级缓存提升性能

原文:[.NET Core项目实战-统一认证平台]第十五章 网关篇-使用二级缓存提升性能 [.NET Core项目实战-统一认证平台]开篇及目录索引 一.背景 首先说声抱歉,可能是因为假期综合症(其实就是因为懒哈)的原因,已经很长时间没更新博客了,现在也调整的差不多了,准备还是以每周1-2篇的进度来更新博客,并完成本项目所有功能. 言归正传,本重构项目是在我根据实际需求重构,由于还未完全写完,所以也没进行压测,在2月份时,张善友老师给我留言说经过压测发现我重构的Ocelot网关功能性能较差,其中