将服务暴露给外部客户端 P136

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

  • 将服务的类型设置成 NodePort
  • 将服务的类型设置为 LoadBalance
  • 创建一个 Ingress 资源

使用 NodePort 类型的服务 P137

通过创建一个 NodePort 服务,可以让 Kubernetes 在其所有节点上保留一个端口(所有节点上都使用相同端口号),并将传入的连接转发给作为服务部分的 pod 。 P137

创建 NodePort 类型的服务 P137

可以使用如下描述文件 kubia-svc-nodeport.yaml 创建一个 NodePort 类型的服务。

# 遵循 v1 版本的 Kubernetes API
apiVersion: v1
# 资源类型为 Service
kind: Service
metadata:
# Service 的名称
name: kubia-nodeport
spec:
# 指定服务类型为 NodePort
type: NodePort
# 该服务可用的端口
ports:
# 第一个可用端口的名字
- name: http
# 可用端口为 80
port: 80
# 服务将连接转发到容器的 8080 端口
targetPort: 8080
# 通过集群节点的 30000 端口可以访问该服务
nodePort: 30000
# 第二个可用端口的名字
- name: https
# 可用端口为 443
port: 443
# 服务将连接转发到容器的 8443 端口
targetPort: 8443
# 通过集群节点的 32767 端口可以访问该服务
nodePort: 32767
# 具有 app=kubia 标签的 pod 都属于该服务
selector:
app: kubia

nodePort 属性不是强制的,如果忽略就会随机选择一个端口。 P137

kubectl get services kubia-nodeport: 查看该服务的基础信息

NAME               TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)                      AGE
kubia-nodeport NodePort 10.111.59.156 <none> 80:30000/TCP,443:32767/TCP 2s

PORT(S) 列显示集群 IP 内部端口 (80, 443) 和节点端口 (30000, 32767) ,可通过 10.111.59.156:80<any-node-ip>:30000 等访问服务。 P138

使用 JSONPath 输出需要的信息:通过指定 kubectl 的 JSONPath ,我们可以只输出需要的信息。例如: kubectl get nodes -o jsonpath='{.items[*].status.addresses[0].address}' 将输出所有节点的 IP 地址。

通过负载均衡器将服务暴露出来 P140

负载均衡器拥有自己独一无二的可公开访问的 IP 地址,并将所有连接重定向到服务。 P140

创建 LoadBalance 服务 P140

可以使用如下描述文件 kubia-svc-loadbalancer.yaml 创建一个 LoadBalancer 类型的服务。

# 遵循 v1 版本的 Kubernetes API
apiVersion: v1
# 资源类型为 Service
kind: Service
metadata:
# Service 的名称
name: kubia-loadbalancer
spec:
type: LoadBalancer
# 该服务可用的端口
ports:
# 第一个可用端口的名字
- name: http
# 可用端口为 80
port: 80
# 服务将连接转发到容器的 8080 端口
targetPort: 8080
# 第二个可用端口的名字
- name: https
# 可用端口为 443
port: 443
# 服务将连接转发到容器的 8443 端口
targetPort: 8443
# 具有 app=kubia 标签的 pod 都属于该服务
selector:
app: kubia

使用 minikube 会发现服务的 EXTERNAL-IP 一直为 <pending> ,我们可以使用 minikube 自带的 minikube tunnel 命令可以完成暴露(02. 开始使用 Kubernetes 和 Docker 介绍过相关处理及踩过的坑)。

LoadBalancer 类型的服务是一个具有额外的基础设施提供的负载均衡器 NodePort 服务。使用 kubectl describe service kubia-loadbalancer 命令可以发现该服务选择了一个节点端口。 P141

了解外部连接的特性 P142

了解并防止不必要的网络跳数:当外部客户端通过节点端口连接到服务时,随机选择的 pod 并不一定在接收连接的同一节点上。可能需要额外的网络跳转才能到达 pod 。可配置 Service.spec.externalTrafficPolicy 的值为 Local 指定仅将外部通信重定向到接收连接的节点上运行的 pod 。

  • 如果接收连接的节点上没有运行对应的 pod ,那么连接将挂起,所以需要确保负载均衡器将连接转发给至少具有一个 pod 的节点
  • 假设有一个两节点三个 pod 的集群(节点 A 运行一个 pod ,节点 B 运行两个 pod),如果负载均衡器在两个节点间均匀分布连接,那么 pod 的负载分布不均衡

客户端 IP 是不记录的:当通过节点端口接收到连接时,由于对数据包执行了源网络地址转换 (SNAT) ,因此数据包对源 IP 将发生更改。如果配置 Service.spec.externalTrafficPolicy 的值为 Local ,那么将会保留客户端 IP ,因为在接收连接的节点和托管目标 pod 的节点之间没有额外的跳跃(不执行 SNAT )。 P143

通过 Ingress 暴露服务 P143

为什么需要 Ingress P144

每个 LoadBalancer 服务都需要自己的负载均衡器,以及独有的公有 IP 地址,而 Ingress 只需要一个公网 IP 就能为许多服务提供访问。当客户端向 Ingress 发送 HTTP 请求时, Ingress 会根据请求的主机名和路径决定请求转发到的服务。 P144

Ingress 在网络栈 (HTTP) 的应用层操作,并且可以提供一些服务不能实现的功能,例如基于 cookie 的会话亲和性 (session affinity) 等功能。 P144

Ingress 控制器是必不可少的 P144

只有 Ingress 控制器在集群中运行, Ingress 资源才能正常工作。 P144

在 minikube 上启动 Ingress 的扩展功能 P145

minikube addons list: 可以列出所有的插件及其启用状态

minikube addons enable ingress: 启用 ingress 插件

kubectl get pods -n kube-system: 查看 kube-system 命名空间下的 pod ,可以发现 Ingress 控制器 pod

创建 Ingress 资源 P145

可以使用如下描述文件 kubia-ingress.yaml 创建一个 Ingress 资源。

# 遵循 extensions/v1beta1 版本的 Kubernetes API
apiVersion: extensions/v1beta1
# 资源类型为 Ingress
kind: Ingress
metadata:
# Ingress 的名称
name: kubia
spec:
# Ingress 的规则列表
rules:
# 第一条规则匹配的域名为 kubia.example.com
- host: kubia.example.com
# 匹配 http
http:
# 匹配的路径列表
paths:
# 第一条路径为 /
- path: /
# 该路径将被转发到的后端服务
backend:
# 将被转发到 kubia-nodeport 服务
serviceName: kubia-nodeport
# 对应服务的端口为 80
servicePort: 80

minikube 下创建 Ingress 资源时报错了,提示超时。后来找到一种解决方案:使用 kubectl edit ValidatingWebhookConfiguration/ingress-nginx-admission 进行编辑,找到 failurePolicy: Fail 这行,并将 Fail 改为 Ignore ,然后就能成功创建 Ingress 资源了,等一段时间后就可以看见其分配了一个 IP 地址 (192.168.64.70) 。

为了能将指定的域名 kubia.example.com 指向分配的 IP 地址 (192.168.64.70),可以使用 SwitchHosts 这个软件进行快速切换。

此时我们在主机上就可以通过 curl kubia.example.com 访问 kubia-nodeport 服务了。

了解 Ingress 的工作原理 P147

  1. 客户端对 kubia.example.com 执行 DNS 查找,本地操作系统返回了 Ingress 控制器的 IP
  2. 客户端向 Ingress 控制器发送 HTTP 请求,并在 Host 头中指定 kubia.example.com
  3. 控制器从头部确定客户端尝试访问哪个服务,通过与该服务关联的 Endpoint 对象查看 pod IP ,并将客户端的请求转发给其中一个 pod

Ingress 控制器不会将请求转发给服务,只用它来选择一个 pod 。大多数控制器都是这样工作的。 P147

通过相同的 Ingress 暴露多个服务 P147

Ingerssrulespaths 都是数组,所以它们可以包含多个条目,因此一个 Ingress 可以将多个域名和路径映射到多个服务。 P147

配置 Ingress 处理 TLS 传输 P149

Ingress 创建 TLS 认证 P149

当客户端创建到 Ingress 控制器到 TLS 连接时,控制器将终止 TLS 连接。客户端和控制器之间到通信是加密的,而控制器和后端 pod 之间的通信则未加密。运行在 pod 上的应用程序不需要支持 TLS 。 P149

为了让 Ingress 控制器负责处理与 TLS 相关的所有内容,需要将证书和私钥附加到 Ingress 。这两个必须资源存储在称为 Secret 的 Kubernetes 资源中(将在第 7 章中详细介绍 Secret),然后在 Ingress 的描述文件中引用它。 P149

openssl genrsa -out tls.key 2048: 创建私钥

openssl req -new -x509 -key tls.key -out tls.cert -days 365 -subj /CN=kubia.example.com: 创建证书

kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key: 创建 Secret 资源

然后我们就可以改写 kubia-ingress.yaml 得到 kubia-ingress-tls.yaml 描述文件:

...
spec:
# 配置 TLS
tls:
# 第一条配置的域名列表
- hosts:
- kubia.example.com
# 这些域名使用 tls-secret 获得私钥和证书
secretName: tls-secret
...

然后我们就可以使用 curl -k -v https://kubia.example.com 通过 HTTPS 访问服务了。( minikube 下未进行上述操作前也可以访问,不过可以发现是 Ingress 控制器使用了假证书) P150

pod 就绪后发出信号 P150

与存活探测器(04. 副本机制和其他控制器:部署托管的 pod 中介绍过)类似, Kubernetes 还允许为容器定义就绪探测器。就绪探测器会定期调用,并确保特定的 pod 是否接收客户端请求。当容器的就绪探测器返回成功时,表示容器已准备好接收请求。 P151

就绪探测器的类型P151

  • Exec 探测器:在容器内执行任意命令,并检查命令的退出状态码。如果状态码是 0 ,则探测成功,认为容器已经就绪,所有其他状态码都被认为失败
  • HTTP GET 探测器:对容器的 IP 地址(指定的端口和路径)执行 HTTP GET 请求。如果探测器收到响应,并且响应状态码不代表错误(状态码为 2xx 或 3xx ),则认为探测成功,认为容器已经就绪。如果服务器返回错误响应状态码或者没有响应,那么探测就被认为是失败的
  • TCP Socket探测器:尝试与容器指定端口建立 TCP 连接。如果连接成功建立,则探测成功,认为容器已经就绪

了解就绪探测器的操作 P151

启动容器时,可以为 Kubernetes 配置一个等待时间,经过等待时间后才可以执行第一次准备就绪检查。之后,它会周期性地调用探测器,并根据就绪探测器的结果采取行动。如果某个 pod 报告它尚未准备就绪,那么就会从服务中删除该 pod ;如果这个 pod 再次准备就绪,那么就会将给 pod 重新添加到服务中。 P151

就绪探测器和存活探测器的区别 P151

存活探测器通过杀死异常的容器并用新的正常容器替代它们来保持 pod 正常工作,而就绪探测器确保只有准备好处理请求的 pod 才可以接收请求,并不会终止或重新启动容器。 P151

就绪探测器的重要性:确保客户端只与正常的 pod 交互,并且永远不会知道系统存在的问题。 P152

了解就绪探测器的实际作用 P154

务必定义就绪探测器 P155

应该始终定义一个就绪探测器,即使它只是向基准 URL 发送 HTTP 请求一样简单。如果没有将就绪探测器添加到 pod 中,那么它们启动后几乎立即成为服务端点。 P155

不要将停止 pod 的逻辑纳入到就绪探测器中 P155

当一个容器关闭时,运行在其中的应用程序通常会在收到终止信号后立即停止接收连接。但在启动关机程序后,没有必要让就绪探测器返回失败以达到从所有服务中移除 pod 目的,因为在该容器删除后, Kubernetes 就会自动从所有服务中移除该容器。 P155

使用 headless 服务来发现独立的 pod P155

要让客户端连接到所有 pod ,需要找出每个 pod 的 IP 。 Kubernetes 允许客户通过 DNS 查找发现 pod IP 。通常,当执行服务的 DNS 查找时, DNS 服务器会返回单个 IP —— 服务的集群 IP 。但是,如果告诉 Kubernetes ,不需要为服务提供集群 IP (通过在服务 spec 中将 clusterIP 字段设置为 None 来完成此操作),则 DNS 服务器将会返回 pod IP 而不是单个服务 IP 。 P155

DNS 服务器不会返回单个 DNS A 记录,而是会为该服务返回多个 A 记录,每个记录指向当时支持该服务的单个 pod 的 IP 。客户端因此可以做一个简单的 DNS A 记录查询并获取属于该服务的所有 pod 的 IP 。客户端可以使用该信息连接到其中的一个、多个或全部。 P155

创建 headless 服务 P156

可以使用如下描述文件 kubia-svc-headless.yaml 创建一个 headless 的 Service 资源。

# 遵循 v1 版本的 Kubernetes API
apiVersion: v1
# 资源类型为 Service
kind: Service
metadata:
# Service 的名称
name: kubia-headless
spec:
# 该服务的集群 IP 为 None ,使其变为 headless 的
clusterIP: None
# 该服务可用的端口
ports:
# 第一个可用端口的名字
- name: http
# 可用端口为 80
port: 80
# 服务将连接转发到容器的 8080 端口
targetPort: 8080
# 第二个可用端口的名字
- name: https
# 可用端口为 443
port: 443
# 服务将连接转发到容器的 8443 端口
targetPort: 8443
# 具有 app=kubia 标签的 pod 都属于该服务
selector:
app: kubia

通过 DNS 发现 pod P156

kubia 容器镜像不包含 nslookup 二进制文件,所以需要用一个新的容器镜像来执行相应的命令。 P156

kubectl run dnsutils --image=tutum/dnsutils --generator=run-pod/v1 --command -- sleep infinity: 创建一个可以执行 nslookup 命令的 pod

kubectl exec dnsutils nslookup kubia-headless: 在 dnsutils pod 内执行 nslookup kubia-headless 命令,可以发现 DNS 服务器为 kubia-headless.default.svc.cluster.local FQDN 返回了多个 IP ,且它们都是 pod 的 IP ,可以通过 kubectl get pods -o wide 进行确认

kubectl exec dnsutils nslookup kubia: 在 dnsutils pod 内执行 nslookup kubia 命令,可以发现 DNS 服务器为 kubia.default.svc.cluster.local FQDN 返回了一个 IP ,该 IP 是服务的集群 IP

尽管 headless 服务看起来可能与常规服务不同,但是在客户的视角上它们并无不同。对于 headless 服务,由于 DNS 返回了 pod 的 IP ,客户端直接连接到该 pod ,而不是通过服务代理(注意这里是直接访问的 pod ,所以对应的端口要改成 pod 的端口)。 P157

注意: headless 服务仍然提供跨 pod 的负载均衡,但是通过 DNS 轮循机制不是通过服务代理 P157

发现所有的 pod —— 包括未就绪的 pod P157

可以通过在 Service.metadata.annotations 下面增加一条 service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" 告诉 Kubernetes 无论 pod 的准备状态如何,希望将所有 pod 添加到服务中 P158

排除服务故障 P158

如果无法通过服务访问 pod ,应根据下面的列表进行排查: P158

  • 确保从集群内连接到服务的集群 IP
  • 不要通过 ping 服务 IP 来判断服务是否可访问(服务的集群 IP 是虚拟 IP ,是无法 ping 通的)
  • 如果已经定义了就绪探测器,请确保它返回成功;否则该 pod 不会成为服务的一部分
  • 要确认某个容器是服务的一部分,请使用 kubectl get endpoints 来检查相应的端点对象
  • 如果尝试通过 FQDN 或其中一部分来访问服务,但并不起作用,请查看是否可以使用其集群 IP 而不是 FQDN 来访问服务
  • 检查是否连接到服务公开的端口,而不是目标端口
  • 尝试直接连接到 pod IP 以确认 pod 正在接收正确端口上的连接
  • 如果甚至无法通过 pod 的 IP 访问应用,请确保应用不是仅绑定到 localhost (127.0.0.1)

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/kubernetes-in-action

Kubernetes 实战 —— 05. 服务:让客户端发现 pod 并与之通信(下)的更多相关文章

  1. Service:让客户端发现pod并与之通信

    5.1.Service介绍 5.1.1.Serice简介 5.1.1.1什么是Service service是k8s中的一个重要概念,主要是提供负载均衡和服务自动发现. Service 是由 kube ...

  2. Kubernetes之无头服务(headless)

    己经看到如何使用服务来提供稳定的ip地址,从而允许客户端连接到支持服务的每个pod (或其他端点).到服务的每个连接都被转发到一个随机选择的pod上.但是如果客户端需要链接到所有的pod呢?如果后端的 ...

  3. AgileConfig 1.6.0 发布 - 支持服务注册与发现

    大家好,好久没有输出博文了,一是因为比较忙,另外一个原因是最近主要的精力是在给 AgileConfig 添加一个新的功能:服务注册与发现. 先说说为什么会添加这个功能.我自己的项目是用 Consul ...

  4. 从零开始入门 | Kubernetes 中的服务发现与负载均衡

    作者 | 阿里巴巴技术专家  溪恒 一.需求来源 为什么需要服务发现 在 K8s 集群里面会通过 pod 去部署应用,与传统的应用部署不同,传统应用部署在给定的机器上面去部署,我们知道怎么去调用别的机 ...

  5. Kubernetes 中的服务发现与负载均衡

    原文:https://www.infoq.cn/article/rEzx9X598W60svbli9aK (本文转载自阿里巴巴云原生微信公众号(ID:Alicloudnative)) 一.需求来源 为 ...

  6. Kubernetes 实战 —— 03. pod: 运行于 Kubernetes 中的容器

    介绍 pod P53 pod 是 Kubernetes 中最为重要的核心概念,而其他对象仅仅用于 pod 管理. pod 暴露或被 pod 使用. pod 是一组并置的容器,代表了 Kubernete ...

  7. 小D课堂 - 新版本微服务springcloud+Docker教程_3-06 服务注册和发现之Eureka Client搭建商品服务实战

    笔记 6.服务注册和发现之Eureka Client搭建商品服务实战     简介:搭建用商品服务,并将服务注册到注册中心 1.创建一个SpirngBoot应用,增加服务注册和发现依赖     2.模 ...

  8. Kubernetes实战 - 从零开始搭建微服务 1 - 使用kind构建一个单层架构Node/Express网络应用程序

    使用kind构建一个单层架构Node/Express网络应用程序 Kubernetes实战-从零开始搭建微服务 1 前言 准备写一个Kubernetes实战系列教程,毕竟cnblogs作为国内最早的技 ...

  9. Kubernetes实战 - 从零开始搭建微服务 - 1.5 提高可用性-发布多节点的Node/Express网络应用程序

    1.5 提高可用性-发布多节点的Node/Express网络应用程序 Kubernetes实战 - 从零开始搭建微服务 前言 在上一篇文章中,已经学习了如何简单地开发一个单层网络应用.[Kuberne ...

随机推荐

  1. React 权限管理

    React 权限管理 react in depth JWT token access_token & refresh_token access token & refresh toke ...

  2. 在浏览器上播放m3u8视频

    在edge上有效 <video width="600" controls> <source src="https://www.gentaji.com/2 ...

  3. windows 隐藏desktop.ini文件

    原文 在文件夹选项>查看 勾选"隐藏受保护的操作系统文件(推荐)"选项

  4. Techme Inc热心公益事业 积极开展公益活动

    从2015年起,Techme inc(公司编号:20151524696)便通过优质的产品和服务,帮助顾客实现营养与健康的目标.与此同时,Techme inc(公司编号:20151524696)多年来始 ...

  5. Linux文件/proc/net/tcp分析

    本文转载自Linux文件/proc/net/tcp分析 导语 /proc/net/tcp文件提供了tcp的连接信息,是由net/ipv4/tcp_ipv4.c中的tcp4_seq_show()实现信息 ...

  6. hutool的DateUtil工具类

    1.0.DateUitl(日期时间) 0)坐标 <dependency> <groupId>cn.hutool</groupId> <artifactId&g ...

  7. docker仓库之分布式harbor (一)

    1.harbor介绍 harbor是一个用于存储和分发docker镜像的企业级Registry服务器,由VMware开源.其通过添加一些企业必须的功能特性,例如安全,标识和管理,扩展了开源docker ...

  8. Java基础语法:运算符

    Java 运算符(operator)根据功能分类: 算术运算符:+,-,*,/,%,++,-- 赋值运算符:= 关系运算符:>,<,>=,<=,==,!=,instanceof ...

  9. Lua C++交互 应用实例步骤(UserData使用)

    一.配置Lua C++交互环境 1.下载Lua 包环境 地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本. 2.新建C++ 控制台应用程序 3 ...

  10. 如果要是把标记为2的那一行Lable1.Text改为其他的Lable显示执行代码

    转: 如果要是把标记为2的那一行Lable1.Text改为其他的Lable显示执行代码 如图,程序很简单,文件路径也没问题,为什么会报错,百思不得其解?[url]https://book.douban ...