【K8S in Action】服务:让客户端发现pod 并与之通信(2)
一 通过Ingress暴露服务
Ingress (名词) 一一进入或进入的行为;进入的权利;进入的手段或地点;入口。一个重要的原因是每个 LoadBalancer 服务都需要自己的负载均衡器, 以及
独有的公有 IP 地址, 而 Ingress 只需要一个公网 IP 就能为许多服务提供访问。
Ingress 在网络栈 (HTTP) 的应用层操作。
1.1 Ingress 控制器是必不可少的
只有Ingress控制器在集群中运行,Ingress 资源才能正常工作。在 minikube 上启动 Ingress 的扩展功能。
# 确保已启用 Ingress 附加组件
$ minikube addons list
- default-storageclass: enabled
- kube-dns: enabled
- heapster: disabled
- ingress: disabled # 没有启动
- registry-creds: disabled
- addon-manager: enabled
- dashboard: enabled
# 启用 Ingress 附加组件
$ minikube addons enable ingress
ingress was successfully enabled
# 查看控制Pod
$ kubectl get po --all-namespaces
1.2 创建 Ingress 资源
apiVersion: extensions/vlbetal
kind: Ingress
metadata:
name : kubia.example.com
spec :
rules:
- host: kubia.example.com #将域名映射到对应的服务
http :
paths
- path: /
backend:
serviceName: kubia-nodeport # 将请求发送到kubia-nodeport 的80端口
servicePort 80
要通过 http://kubi example.com 访问服务,需要确保域名解析为 ngress 控制器 IP
kubectl get ingresses
NAME HOSTS ADDRESS PORTS AGE
kubia kubia.example.com 192.168.99.100 80 29m
通过配置 DNS 服务器将kubia.example.com解析为 IP地址,或者在 /ect/host文件( Windows 系统为 \windows\system32\drivers\etc\hosts 中添加下面 行内容
192.168.99.100 kubia.example.com
通过 Ingress 访问 pod: curl http: / /kubia.example.com
1.3 通过相同的Ingress 暴露多个服务
- host:kubia.example.com
http:
paths:
- path: /kubia
backend:
serviceName : kubia # kubia.example.com/kubia 转发到kubia服务80端口
servicePort: 80
- path: /foo
backend:
serviceName : bar # kubia.example.com/foo 转发到bar服务80端口
ser cePort: 80
二 pod 就绪后发出信号
还有一件关于 Service 和 Ingress 的事情。pod 可能需要时间来加载配置或数据。不要将请求转发到正在启动的 pod 中, 到完全准备就绪。
像存活探针一样,就绪探针有三种类型:
• Exec 探针,执行进程的地方。容器的状态由进程的退出状态代码确定
•HTTP GET 探针,向容器发送 HTTP GET 请求,通过响应的 HTTP 状态代码
判断容器是否准备好
• TCP socket 探针,它打开 TCP 连接到容器的指定端口。如果连接己建立,
则认为容器己准备就绪
启动容器时,可以为 k8s 配置等待时间,经过等待时间后才可以执行第1次准备就绪检查。之后,它会周期性地调用探针,并根据就绪探针的结果采取行动。如果某个 po 报告它尚未准备就绪,则会从该服务中删除该 pod 。如果再次准备就绪,则重新添加 pod。
apiVersion: vl
kind: ReplicationController
spec:
template:
spec:
containers:
- name: kubia
image: luksa/kubia
readinessProbe: 就绪探针
exec:
- ls
- /var/ready 定期在容器内执行ls/var/ready命令,返回退出码0, 表示成功
- 务必定义就绪探针
- 不要将停止 pod 的逻辑纳入就绪探针中
只要删除该容器, Kubemetes就会从所有服务中移除该容器。
三 使用 headless服务来发现独立的pod
如果客户端需要链接到所有的 pod 呢?如果后端的 pod 都需要连接到所有其他
pod如何处理。
- 一种选择是让客户端调用 Kubemetes API 服务器并通过 API调用获取 pod 及其 IP 地址列表。
但由于应始终努力保持应用程序与 Kubemetes 无关, 因此使用 API 服务器并不理想。 - Kubemetes 允许客户通过 DNS 查找发现 pod IP
当执行服务的 DNS 查找时, DNS 服务器会返回单个 IP一服务的集群 IP。 但是, 如果告诉Kubemetes, 不需要为服务提供集群 IP (通过在服务 spec 中将 clusterIP 字段设置为 None 来完成此操作), 则 DNS 服务器将返回 podIP 而不是单个服务 IP。
3.1 创建headless服务
apiVersion: vl
kind: Service
metadata:
name: kubia-headless
spec:
clusterIP: None 服务成为handless的
ports:
- port: 80
targetPort: 8080
selector:
app: kubia
kubectl create 创建服务之后,可以 通过kubectl get和kubectl describe来查看服务,你会发现它没有集群IP,并且它的后端 包含与pod选择器匹配的就绪 pod。
3.2 通过DNS发现pod
尝试执行DNS查找以查看是否获得了实际的podIP。需要从其中 一个pod中执行查找。
注意: headless 服务仍然提供跨 pod 的负载平衡, 但是通过 DNS 轮询机制不是通过服务代理
kubect1 run dnsutils --image=tutum/dnsutils --generator=run-pod/vl --command -- sleep infinity
kubectl exec dnsutils nslookup kubia-headless 执行 DNS 查找
Name: kubia-headless.default.svc.cluster.local
Address: 10.108.1.4
Name: kubia-headless.default.svc.cluster.local
Address: 10.108.2.5
kubectl exec dnsutils nslookup kubia 返回的IP是服务的集群 IP
Name: kubia.default.svc.cluster.local
Address: 10.111.249.153
–generator=run-pod/vl 选项中, 该选项让 kubec七1直接创建pod, 而不需要通过 ReplicationController 之类的资源来创建。
3.3 发现所有的pod一包括未就绪的pod
不必通过查询KubemetesAPI服务器, 可以使用DNS查找机制来查找那些未准备好的pod。 要告诉Kubemetes无论pod的准备状态如何, 希望将所有pod 添加到服务中 。 必须将以下注解添加到服务中
kind: Service
metadata:
annotations:
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
警告: 注解名称表明了这是一个alpha功能。Service AP I已经支待一个 名为 publishNotReadyAddresses 的新服务规范字段。
4 排除服务故障
服务是Kubemetes的一个重要概念, 也是让许多开发人员感到困扰的根源。 许多开发人员为了弄清楚无法通过服务IP 或FQDN 连接到他们的pod的原因花费了
大量时间。
如果无法通过服务访问pod, 应该根据下面的列表进行排查:
- 确保从集群内连接到服务的集群IP,而不是从外部
- 不要通过ping服务IP 来判断服务是否可 访问(请记住, 服务的集群IP 是虚
拟IP, 是无法ping通的) - 如果已经定义了就绪探针, 请确保 它返回成功;否则该pod不会成为服务的
一部分 - 要确认某个容器是服务的一部分, 请使用kubectl ge七 endpoints来检
查相应的端点对象 - 如果尝 试通 过FQDN或其 中 一 部 分来访问服务(例如, myservice.
mynamespace.svc.cluster.local或 myservice.mynamespace), 但并不起作用, 请查看是否可以使用其集群IP而不是FQDN来访问服务 - 检查是否连接到服务公开的端口,而不是目标端口
- 尝试直接连接到podIP以确认pod正在接收正确端口上的 连接
- 如果甚至无法通过pod的IP 访问应用, 请确保应用不是仅绑定到本地主机