让客户端发现pod并与之通信

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

配置服务上的会话亲和性

服务代理通常将每个连接(指向服务)随机指向选中的后端 pod中的一个,即使连接来自于同一个客户端。
如果希望特定客户端产生的所有请求每次都指向同 一个 pod, 可以设置服务的 sessionAffinity 属性为 ClientIP (而不是 None,None 是默认值)。

apiVersion: v1 kind: Service spec: seccionAffinity: ClientIP

这种方式将会使服务代理将来自同一个 client IP 的所有请求转发至同一个 pod上。
Kubernetes 仅仅支持两种形式的会话亲和性服务: None 和 ClientIP。不支持基于cookie的会话亲和性的选项。Kubernetes 服务不是在 HTTP 层面上工作。服务处理 TCP 和 UDP 包,并不关心其中的载荷内容。因为 cookie 是 HTTP 协议中的一部分,服务并不知道它们。

同一个服务暴露多个端口

spec: ports: - name: http port: 80 targetPort: 8080 - name: https port: 443 targetPort: 8443 selector: app: kubia

注意:在创建一个有多个瑞口的服务的时候,必须给每个瑞口指定名字。标签选择器应用于整个服务,不能对每个端口做单独的配置。如果不同的 pod 有不同的端口映射关系,需要创建两个服务。

使用名字的端口

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

通过名称来指定 pod 中 spec 不同的端口,最大好处就是即使更换端口号,也无须更改服务的 spec 。

通过环境变发现服务

在pod开始运行时候,Kubernetes会初始化一系列的环境变量指向现在存在的服务。 如果你创建的服务早于客户端pod的创建,pod 上的进程可以根据环境变量获得服务的IP地址和端口号。
由于服务的创建晚于pod 的创建,需要删除所有的 pod 使得 ReplicationController创建全新的pod。

通过 FQDN 连接服务

前端pod可以通过打开以下 FQDN 的连接来访问后端数据库服务:
backend-database.default.svc cluster.local
backend-database 对应于服务名称,default 表示服务在其中定义的名称空间,而 svc.cluster.local 是在所有集群本地服务名称中使用的可配置集群域后缀。
注意 客户端仍然必须知道服务的端口号。
无法 ping 通服务 IP 的原因
curl服务是工作的,但是却 ping 不通。这是因为服务的集群 IP是一个虚拟 IP ,并且只有在与服务端口结合时才有意义。
连接集群外部的服务
希望通过 Kubernetes 符务特性暴露外部服的情况,不要让服务将连接重定向到集群中的 pod ,而是让它重定向到外部 IP 和端口。这样做可以让你充分利用服务负载平衡和服务发现。在集群中运行的客户端 pod 可以像连接到内部服务一样连接到外部服务。

介绍服务 endpoint

服务并不是和 pod 直接相连的,相反有一种资源介于两者之间,它就是 Endpoint 资源。Endpoint 资源就是暴露一个服务的 IP 地址和端口的列表,Endpoint 资源和其他Kubernetes 资源一样,所以可以使用 kubectl info 来获取它的基本信息。

[root@master ~]# kubectl get endpoints kubernetes NAME ENDPOINTS AGE kubernetes 192.168.163.140:6443 228d

手动配置服务的 endpoint

如果创建了不包含 pod选择器的服务,Kubemetes 将不会创建 Endpoint 资源(毕竟,缺少选择器,将不会知道服务中包含哪些 pod)。这样就需要创建 Endpoint 资源来指定该服务的 endpoint 列表。

创建没有选择器的服务

apiVersion: v1 kind: Service metadata: name: external-service #服务的名字必须和Endpoint对象的名字相匹配 spec: #服务中没有定义选择器 ports: - port: 80

为没有选择器的服务创建Endpoint资源
Endpoint是一个单独的资源并不是服务的一个属性。由于创建的资源中并不包含选择器,相关的Endpoints 资源并没有自动创建,所以必须手动创建。

apiVersion: v1 kind: Endpoints metadata: name: external-service #Endpoint的名称必须和服务的名称相匹配 subsets: - addresses: - ip: 11.11.11.11 # 服务将连接重定向到endpoint的IP地址 - ip: 22.22.22.22 ports: - port: 80 # endpoint的目标端口

Endpoint对象需要与服务具有相同的名称,并包含该服务的目标IP地址和端口列表。服务和Endpoint资源都发布到服务器后,这样服务就可以像具有pod选择器那样的服务正常使用。在服务创建后创建的容器将包含服务的环境变量,并且与其IP : port对的所有连接都将在服务端点之间进行负载均衡。

为外部服务创建别名

要创建一个具有别名的外部服务的服务时,要将创建服务资源的一个type字段设置为ExternalName。例如,设想一下在someapi.company.com上有公共可用的API,可以定义一个指向它的服务。

apiVersion: v1 kind: Service metadata: name: external-service spec: type: ExternalName externalName: api.somecompany.com #实际服务的完全限定域名 ports: - port: 80

服务创建 完成后,pod可以通过external-service.default.svc .cluster.local域名(甚至是external-service)连接到外部服务,而不是使用服务的实际FQDN。

将服务暴露给外部客户端

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

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

NodePort 类型的服务

通过创建NodePort服务,可以让Kubernetes在其所有节点上保留一个端口(所有节点上都使用相同的端口号), 并将传入的连接转发给作为服务部分的pod。这与常规服务类似(它们的实际类型是ClusterIP), 但是不仅可以通过服务的内部集群IP访问NodePort 服务,还可以通过任何节点的IP和预留节点端口访问NodePort 服务。

apiVersion: v1 kind: Service metadata: name: kubia-nodeport spec: type: NodePort #为NodePort设置服务类型 ports: - port: 80 #服务集群IP的端口号 targetPort: 8080 #背后pod的目标端口号 nodePort: 30123 #通过集群节点的30123端口可以访问该服务。如果忽略,Kubemetes将选择一个随机端口。 selector: app: kubia


在第一个节点的端口30123收到的连接, 可以被重定向到第一节点个上运行的pod, 也可能是第二个节点上运行的pod。

$ kubectl get svc kubia-nodeport NAME CLUSTER-IPt EXTERNAL-IP PORT(S) AGE kubia-nodeport 10.111.254.223 <nodes> 80:30123/TCP 2m

EXTERNAL-IP列,它显示nodes 表明服务可通过任何集群节点的IP地址访问。
10.11.254.223:80
<1stnode'sIP>:30123
<2ndnode'sIP>:30123
在整个互联网可以通过任何节点上的30123端口访问到pod

注意:当在GKE(Google Kubernetes Engine)中创建服务时,kubectl打印出一个关于必须配置防火墙规则的警告。
gcloud compute firewall-rules create kubia-svc-rule --allow=tcp:30123

通过负载均衡器

在云提供商上运行的Kubernetes集群通常支持从云基础架构自动提供负载平衡器。 所有需要做的就是设置服务的类型为Load Badancer而不是NodePort。 负载均衡器拥有自己独一无二的可公开访问的 IP 地址, 并将所有连接重定向到服务。可以通过负载均衡器的 IP 地址访问服务。
如果Kubemetes在不支持Load Badancer服务的环境中运行, 则不会调配负载平衡器, 但该服务仍将表现得像一个NodePort服 务。 这是因为LoadBadancer服务是NodePort 服务的扩展。

apiVersion: v1 kind: Service metadata: name: kubia-loadbalancer spec: type: LoadBalancer #该服务从Kubernetes集群的基础架构获取负载平衡器 ports: - port: 80 targetPort: 8080 selector: app: kubia

如果没有指定特定的节点端口, Kubemetes将会选择一个端口。

kubectt get svc kubia-loadbalancer NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubia-loadbalancer 10.111.241.153 130.211.53.173 80:32143/TCP lm

了解外部连接的特性

了解并防止不必要的网络跳数

通过将服务配置为仅将外部通信重定向到接收连接的节点上运行的pod来阻止此额外跳数。有一个缺点,使用local外部流量策略的服务可能会导致跨pod的负载分布不均衡

spec: externalTrafficPolicy: Local

客户端IP是不记录的
通常, 当集群内的客户端连接到服务时,支持服务的pod可以获取客户端的IP地址 。 但是, 当通过节点端口接收到连接时,由于对数据包执行了源网络地址转换(SNAT), 因此数据包的源IP将发生更改。
后端的pod无法看到实际的客户端IP, 这对于某些需要了解客户端IP的应用程序来说可能是个问题。 例如, 对于Web服务器, 这意味着访问日志无法显示浏览器的IP。
上一节中描述的local外部流量策略会影响客户端IP的保留, 因为在接收连接的节点和托管目标pod的节点之间没有额外的跳跃(不执行SNAT)。

通过Ingress暴露服务

Ingress (名词) 一一进入或进入的行为;进入的权利;进入的手段或地点;入口
使用Ingress的 一个重要的原因是每个 LoadBalancer 服务都需要自己的负载均衡器,以及独有的公有 IP 地址, 而 Ingress 只需要一个公网 IP 就能为许多服务提供访问。当客户端向 Ingress 发送 HTTP 请求时, Ingress 会根据请求的主机名和路径决定请求转发到的服务。

只有Ingress控制器在集群中运行,Ingress 资源才能正常工作。 不同的 Kubernetes 环境使用不同的控制器实现, 但有些并不提供默认控制器。

apiVersion: extensions/v1beta1 kind: Ingress metadata: name: kubia spec: rules: - host: kubia.example.com #Ignress将域名kubia.example.com映射到你的服务 http: paths: - path: / #将所有的请求发送到kubia-nodeport服务的80端口 backend: # serviceName: kubia-nodeport # servicePort: 80 #

定义了一个单规则的 Ingress ,确保 Ingress 控制器收到的所有请求主机 kubia example.com HTTP 请求,将被发送到端口 80 上的 kubia nodeport服务。

Ingress的工作原理

如图显示了客户端如何通过 Ingress 控制器连 pod。客户端首先对 kubia.example.com 执行 DNS查找,DNS 务器(或本地操作系统)返回了 Ingress 控制器的 IP 。客户端然后向 Ingress 控制器发送 HTTP 请求,并在 Host中指kubia.example.com 。控制器从该头部确定客户端尝试访问哪个服务,通与该服务关联的 Endpoint 对象查看 pod IP ,并将客户端的请求转发给其中一个pod。
Ingress 控制器不会将请求转发给该服务,只用它来选择一个 pod大多数(即使不是全部)控制器都是这样工作的。

将不同的服务映射到相同主机的不同 paths

- host: kubia.example.com http: paths: - path: /kubia backend: serviceName: kubia #对kubia.example.com/kubia的请求将会转发至kubia服务 servicePort: 80 # - path: /foo backend: serviceName: bar #对kubia.example.com/foo 的请求将会转发至bar服务 servicePort: 80 #

将不同的服务映射到不同的主机上
使用 Ingress 根据 HTTP 请求中的主机而不是(仅)路径映射到不同的服务

- host: foo.example.com #对foo.example.com/kubia的请求将会转发至foo服务 http: paths: - path: / backend: serviceName: foo servicePort: 80 - host: bar.example.com #对bar.example.com/kubia的请求将会转发至bar服务 http: paths: - path: / backend: serviceName: bar servicePort: 80

配置 Ingress处理TLS 传输 HTTPS
传输层安全性协议(英语:Transport Layer Security,缩写作TLS),及其前身安全套接层(Secure Sockets Layer,缩写作SSL)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。安全传输层协议(TLS)用于在两个通信应用程序之间提供保密性和数据完整性。

当客户端创建到Ingress 控制器的 TLS 连接时,控制器将终止 TLS 连接。客户端和控制器之间的通信是加密的,而控制器和后端 pod 之间的通信则不是 。运行在pod 上的应用程序不需要支持 TLS。 例如,如果 pod 运行 web 务器,则它 只能接收HTTP 通信,并让 Ingress 控制器负责处理与 TLS相关的所有内容。要使控制器能够这样做,需要将证书和私钥附加到 Ingress 。这两个必需资源存储在称为 Secret的Kubernetes 资源中,然后在 Ingress manifest 中引用它。

#首先,需要创建私钥和证书: openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=kubia.example.com #创建 Secret kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key kubectl get secret NAME TYPE DATA AGE default-token-sbcr5 kubernetes.io/service-account-token 3 40d tls-secret kubernetes.io/tls 2 2m45s

通过 CertificateSigningRequest 资源签署证书

cat kubia-ingress-tls.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: kubia spec: tls: #在这个属性下包含了所有的TLS的配置 - hosts: - kubia.example.com #将接收来自kubia.example.com的主机TLS连接 secretName: tls-secret #从tls-secret中获得之前创立的私钥和证书 rules: - host: kubia.example.com http: paths: - path: / backend: serviceName: kubia-nodeport servicePort: 80 curl -k -v https://kubia.example.com/kubia

pod 就绪后发出信号

介绍就绪探针
就绪探测器会定期调用,并确定特定的 pod是否接收客户端请求。当容器的准备就绪探测返回成功时,表示容器己准备好接收请求。
这个准备就绪的概念显然是每个容器特有的东西。 Kubernetes 只能检查在容器中运行的应用程序是否响应一个简单的 GET/请求,或者它可以响应特定的 URL路径(该 URL 导致应用程序执行一系列检查以确定它是否准备就绪)。考虑到应用程序的具体情况,这种确切的准备就绪的判定是应用程序开发人员的责任。

就绪探针有三种类型:
• Exec 探针,执行进程的地方。容器的状态由进程的退出状态代码确定。
• HTTP GET 探针,向容器发送 HTTP GET 请求,通过响应的 HTTP 状态代码判断容器是否准备好。
• TCP socket 探针,它打开 TCP 连接到容器的指定端口。如果连接己建立,则认为容器己准备就绪。

了解就绪探针的操作
启动容器时,可以为 kubernetes 配置一个等待时间,经过等待时间后才可以执行第一次准备就绪检查 。之后,它会周期性地调用探针,并根据就绪探针的结果采取行动。如果某个 pod 报告它尚未准备就绪,则会从该服务中删除该 pod 。如果再次准备就绪,则重新添加 pod。
与存活探针不同,如果容器未通过准备检查 ,则不会被终止或重新启动 。这是存活探针与就绪探针之间的重要区别 。存活探针通过杀死异常的容器并用新的正常容器替代它们来保持 pod 正常工作,而就绪探针确保只有准备好处理请求的 pod才可以接收它们(请求)。 这在容器启动时最为必要,当然在容器运行一段时间后也是有用的。

向pod添加就绪探针

apiVersion: v1 kind: ReplicationController ... spec: ... template: ... spec: containers: - name: kubia image: luksa/kubia readinessProbe: # pod中的每个容器都会有一个就绪探针 exec: # command: - ls - /var/ready ...

就绪探针将定期在容器内执行 ls /var/ready 命令。如果文件存在, 则ls命令返回退出码 0, 否则返回非零的退出码。如果文件存在,则就绪探针将成功,否则,它会失败。

kubectl describe podID Readiness: exec [ls /var/ready] delay=Os timeout=ls period=lOs #success=l #failure=3 # 准备就绪探针会定期检查 默认情况下每10 秒检查一次。 # kubectl get endpoint kubia loadbalancer

在实际应用中, 应用程序是否可以(并且希望)接收客户端请求, 决定了就绪探测应该返回成功或失败。应该通过删除 pod或更改 pod 标签 而不是手动更改探针来从服务中手动移除pod。
    提示: 如果想要从某个服务中手动添加或删除 pod, 请将 enabled=true 作为标签添加到 pod, 以及服务的标签选择器中。 当想要从服务中移除 pod 时,删除标签。

务必定义就绪探针
有两个关于就绪探针的要点, 需要强调。
第一:如果没有将就绪探针添加到 pod 中, 它们几乎会立即成为服务端点。如果应用程序需要很长时间才能开始监听传入连接, 则在服务启动但尚未准备好接收传入连接时, 客户端请求将被转发到该 pod。 因此, 客户端会看到 “连接被拒绝 ” 类型的错误。
    提示 : 应该始终定义一 个就绪探针, 即使它只是向基准 URL 发送 HTTP 请求一样简单。
第二:不要将停止 pod 的逻辑纳入就绪探针中。当一个容器关闭时, 运行在其中的应用程序通常会在收到终止信号后立即停止接收连接。因此, 可能认为只要启动关机程序 ,就需要让就绪探针返回失败, 以确保从所有服务中删除该 pod。 但这不是必需的,因为只要删除该容器, Kubernetes 就会从所有服务中移除该容器。

使用 headless服务来发现独立的pod
Kubemetes 允许客户通过 DNS 查找发现 pod IP。 通常,当执行服务的 DNS 查找时, DNS 服务器会返回单个 IP ——— 服务的集群 IP。 但是,如果告诉Kubemetes, 不需要为服务提供集群 IP (通过在服务 spec 中将 clusterIP 字段设置为 None 来完成此操作), 则 DNS 服务器将返回 podIP 而不是单个服务 IP。
DNS 服务器不会返回单个 DNS A 记录,而是会为该服务返回多 个 A 记录, 每个记录指向当时支持该服务的单个 pod的 IP。客户端因此可以做一个简单的 DNS A 记录查找并获取属于该服务一部分的所有 pod的 IP。 客户端可以使用该信息连接到其中的一个、 多个或全部。

## kubia-svc-headless.yaml apiVersion: v1 kind: Service metadata: name: kubia-headless spec: clusterIP: None # 这使得服务成为headless ports: - port: 80 targetPort: 8080 selector: app: kubia

使用Docker Hub上提供的tutum/dnsutils 容器镜像, 它包含nslookup和dig二进制文件 。在集群中运行的一个pod中执行DNS查询

kubectl run dnsutils --image=tutum/dnsutils --generator=run-pod/v1 --command -- sleep infinity kubectl exec dnsutils nslookup kubia-headless Name: kubia-headless.default.svc.clus七er.local Address: 10.108.1.4 Name: kubia-headless.default.svc.clus七er.local Address: 10.108.2.5

DNS 服务器为 kubia-headless.default.svc.cluster.local  FQDN 返回两个不同的 IP。 这些是报告准备就绪的两个 pod 的 IP。可以通过使用kubectl get pods -o wide 列出 pod 来确认此问题, 该清单显示了 pod 的 IP。

这与常规(非 headless 服务)服务返回的 DNS 不同, 比如 kubia 服务, 返回的 IP是服务的集群 IP

kubectl exec dnsutils nslookup kubia Name: kubia.default.svc.cluster.local Address: 10.111.249.153 注意  headless 服务仍然提供跨 pod 的负载平衡, 但是通过 DNS 轮询机制不是通过服务代理。

发现所有的pod   包括未就绪的pod
告诉Kubemetes无论pod的准备状态如何, 希望将所有pod 添加到服务中 。

kind: Service metadata: annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"

__EOF__

本文作者何时&明月
本文链接https://www.cnblogs.com/kiyalone/p/15957156.html
关于博主:当你发现自己的才华支撑不起野心时,就请安静下来学习吧!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   何时&明月  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示