欢迎访问我的博客,你的支持,是我最大的动力!

马哥_K8s进阶实战(4)Service/Ingress

Docker 马从东 345℃ 评论
目录:
[显示]

Service

Service和Pod对象的IP仅在K8s集群内可达,Service的IP也称为Cluster IP,是虚拟IP,能被同集群中Pod访问
Service关联Pod资源借助于标签选择器完成

Service与Pod之间关联关系是松耦合方式,Service可先于Pod创建而不会发生错误

Service并不直接链接至Pod,中间还有一层 Endpoints 资源对象(IP地址和端口组成的列表)
默认,创建Service时,其关联的Endpoints对象会自动创建
一个Service对象就是工作节点上的一些iptables或ipvs规则,由kube-proxy实时维护

资源模型

kube-proxy请请求代理至相应端点的方式有三种:userspace/iptables/ipvs

1、userspace 用户空间

该模型中,请求流量到达内核空间后,由套接字送往用户空间的kube-proxy,再由它送回内核空间,并调度至后端Pod。来回转发,效率不高

2、iptables
为Service创建iptables规则,直接捕获到达ClusterIP和Port的流量,并重定向至当前Service的后端。对每个Endpoints对象,Service资源会为其创建iptables规则并关联至挑选的后端Pod资源
优点,比userspace更加高效和可靠;缺点,不会在后端Pod无响应时自动重定向,而userspace可以

3、ipvs
自1.11版本起为默认设置
请求流量的调度功能由ipvs实现,余下的其他功能仍由iptables完成
ipvs流量转发速度快,规则同步性能好,且支持众多调度算法,如rr/lc/dh/sh/sed/nq等

Service 基础

创建 Service 资源

创建可使用 kubectlexpose 命令或通过资源配置文件完成

# 创建 Service myapp-svc 后,会自动创建名为同名的Endpoints对象
kubectl get endpoints  # 查看Endpoints对象
kubectl get svc

也可不为Service资源指定spec.selector属性值,关联的Pod资源可由用户手动创建Endpoints进行定义
kubectl get endpoints myapp-svc -o yaml --export

向 Service 对象请求服务

Service的默认类型为ClusterIP,仅能接收来自集群中Pod对象的请求

创建临时使用的Pod作为交互式客户端使用
# CirrOS 是Linux的微型发行版,拥有curl等工具 镜像仅10.3MB
kubectl run cirros-$RANDOM --rm -it --image=cirros -- sh
curl http://10.108.91.175:80/
curl http://10.108.91.175:80/hostname.html

Service 会话粘性

Service支持Session affinity机制,能将同一个客户端的请求始终转发至同一个后端Pod对象
会话粘性效果默认在10800s后会重新调度 (3小时)
仅能基于客户端IP进行识别,调度粒度较粗,不推荐使用

spec.sessionAffinity,定义粘性会话的类型,可为 None 和 ClientIP
spec.sessionAffinityConfig,配置会话保持时长,默认10800s 范围 1-86400

kubectl patch services myapp-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'

服务发现

Service Discovery

客户端发现,客户端到服务注册中心获取服务信息,需要内置特定的服务发现程序和发现逻辑
服务端发现,服务消费者将请求发往中央路由器或负载均衡器,由中央路由器或负载均衡查询服务注册中心获得提供者位置信息后,转发给服务提供者

Eureka是较为流行的服务发现系统,以可用性目的优先;Consul也是常用的服务发现系统
k8s中的服务发现则是 CoreDNS (注,也支持使用环境变量进行服务发现)

服务发现方式:环境变量

1、Kubernetes Service环境变量
创建Pod时,kubelet会将所属名称空间内所有活动Service对象以环境变量形式注入  查看 env 或printenv
形如:
{SVCNAME}_SERVICE_HOST   # SVCNAME中 - 会转换为 _
{SVCNAME}_SERVICE_PORT

2、Docker Link形式的环境变量
env|grep MYAPP_SVC | grep -v SERVICE
如上,不包含SERVICE的环境变量

限制:1、不处于同一名称空间;2、后于Pod建立的Service  不能使用环境变量

ClusterDNS和服务发现

默认,Pod会自动配置名称解析服务器为ClusterDNS (cat /etc/resolv.conf)
每个Service会由DNS自动生成相关记录

拥有ClusterIP的Service:
1、A记录:<service>.<ns>.svc.<zone>.<ttl> IN A <cluster-ip>
2、SRV记录:_<port>._<proto>.<service>.<ns>.svc.<zone>.<ttl> IN SRV <weight><priority><port-number><service>.<ns>.svc.<zone>
3、PTR记录:<d>.<c>.<b>.<a>.in-addr.arpa.<ttl> IN PRT <service>.<ns>.svc.<zone>

Headless类型的Service:
1、A记录:<service>.<ns>.svc.<zone>.<ttl> IN A <endpoint-ip>
2、SRV记录:_<port>._<ptoto>.<service>.<ns>.svc.<zone>.<ttl> IN SRV <weight><priority><port-number><hostname>.<service>.<ns>.svc.<zone>
3、PTR记录:<d>.<c>.<b>.<a>.in-addr.arpa.<ttl> INPTR <hostname>.<service>.<ns>.svc.<zone>

ExternalName类型的Service:
1、CNAME记录:<service>.<ns>.svc.<zont>.<ttl> IN CNAME <extname>

服务发现方式:DNS

每个Service有两个DNS记录:
{SVCNAME}.{NS}.{CLUSTER_DOMAIN}
{SVCNAME}.{NS}.svc.{CLUSTER_DOMAIN}   eg: myapp-svc.default.svc.cluster.local

--cluster-dns --cluster-domain 定义dns服务器和本地域,默认会将cluster.local 和 主机所在的域 作为dns本地域使用
基于DNS的服务发现不受名称空间和创建时间的限制

服务暴露

服务暴露,也称为发布服务到外部网络中

Service类型

共四种类型:ClusterIP、NodePort、LoadBalancer、ExternalName
ClusterIP,默认,仅集群内可达
NodePort,构建在ClusterIP之上,增加<NodeIP>:<NodePort>进行请求,默认端口范围 30000~32767
LoadBalancer,构建在NodePort之上,使用运营商负载均衡器
ExternalName,将Service映射至由externalName指定的主机名来暴露服务,此主机名需要被DNS解析到CNAME类型的记录
ExternalName用于将外部服务映射到集群内,让集群内Pod资源能够访问,故其没有ClusterIP、NodePort、标签选择器和Endpoints

NodePort类型的Service

通常,nodePort不需要手工指定,会由系统随机分配

ExternalName类型的Service

将外部服务发布到集群中
该类型的Service实现于DNS级别,无须配置ClusterIP

集群内Pod可通过 external-redis-svc 或 external-redis-svc.default.svc.cluster.local 访问相应服务
ClusterDNS会将名称以CNAME格式解析为externalName中的字段

Headless类型的Service

客户端直接访问Pod的IP地址,而不是Service的IP地址,Headless Service对象没有ClusterIP
前端应用拥有自有的服务发现机制时,适用于Headless Service

情形:
1、有标签选择器,会创建Endpoints记录,DNS将服务的A记录直接解析为Pod的IP地址
2、无标签选择器,不会创建Endpoints。对ExternalName类型的服务,创建CNAME记录;对其他类型,为所有与当前Service共享名称的所有Endpoint对象创建一条记录  (即DNS返回多条IP记录,顺序随机,也可起到负载均衡的功效)

Ingress

Service是TCP负载均衡器,传输层调度,不支持健康检查
Ingress是HTTP(S)负载均衡器,应用层调度,支持多种后端健康状态检查

Ingress是一组基于DNS名称或URL路径把请求转发到指定Service资源(或Pod资源)的规则,用于集群内部服务发布
当Ingress绕过Service直接到具体Pod时,可节省由kube-proxy的代理开销
Ingress资源需要通过Ingress Controller实现功能

Ingress由任何具有反向代理功能的程序实现,如Nginx、Envoy、HAProxy、Vulcand、Traefik等,Ingress本身是运行于集群中的Pod资源对象

kubectl get ingress
kubectl get ingresses.extensions my-ingress -o yaml --export
kubectl explain ingress.spec
# 访问
curl -H "Host: test.kube.io" http://192.168.1.125

控制器

kubectl get svc nginx-ingress-controller -n ingress-nginx

说明:
metadate.annotations  其中nginx.ingress.kubernetes.io/ssl-passthrough: "true" 用于SSL透传
spec.rules,定义资源转发规则列表;未定义规则或未匹配到规则时,会转发到spec.backend默认后端
spec.rules.host,域名,不支持IP,不支持端口号,若留空表示通配所有主机名
spec.rules.http.paths.backend,后端
spec.rules.http.paths.path,路径,以 / 开始,若不指定,匹配所有
spec.backend,默认后端;定义Ingress时,至少应该定义rules或backend二者之一
spec.tls,TLS配置,默认仅支持通过443端口提供服务,若要配置指定列表成员指向不同主机,需通过SNI TLS扩展
spec.tls.hosts,主机名称列表,指定哪些域名使用https
spec.tls.secretName,引用SSL会话的secret对象名称,用于基于SNI实现多主机路由

Ingress资源类型

1、单Service资源型Ingress
仅需指定 default backend 即可

2、基于URL路径进行流量分发
# 将www.ilinux.io/api请求转发至API Service;对www.ilinux.io/wap请求转发至WAP Service

3、基于主机名称的虚拟主机
即不同的服务映射成不同的域名

4、TLS类型的Ingress资源
基于一个含有私钥和证书的Secret对象,即可配置TLS协议的Ingress资源

部署Ingress控制器 Nginx

Ingress是运行于Pod中的容器应用,通常是Nginx或Envoy等具有代理及负载均衡功能的守护进程,它监视来自于API Server的Ingress状态,并以及规则生成相应应用程序专有格式的配置文件,并通过重载或重启守护进程使配置生效

Ingress控制器接入外部流量的方式

a、以Deployment管理控制器Pod,并通过NodePort等类型的Service发布到外部网络

b、借助DaemonSet,将控制器的Pod以单一实例方式运行于集群所有或部分节点,并配置这类Pod对象以hostPort或hostNetwork方式接入外部网络

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml
这是采用Deployment的方式进行的,因此接入外部流量前还需要手动创建Service资源对象

externalIPs方式的Service可参考:http://pdf.us/2019/01/25/2666.html 中的 安装 ingress-nginx
下面是NodePort方式的Service:

使用Ingress发布tomcat

a、准备名称空间

kubectl get ns testing

b、部署tomcat实例

kubectl get deployments.apps -n testing tomcat-deploy
kubectl get pods -n testing

c、创建Service资源

Ingress资源需通过Service资源识别相应Pod资源,获取Pod的IP和端口,Ingress控制器直接和各Pod通信,不通过Service代理和调度
Service资源的ClusterIP对Ingress来说没有用

kubectl get svc -n testing
kubectl describe svc tomcat-svc -n testing

d、创建Ingress资源

kubectl describe ingresses.extensions -n testing
curl -H "Host: tomcat.ilinux.io" http://192.168.1.125/

e、配置TLS Ingress资源

通常,HTTPS应该由外部负载均衡器予以实现,并在SSL会话卸载后将访问请求转发到Ingress控制器

1、生成自签名证书
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.ilinux.io -days 3650
# TLS Secret中包含的证书必须以tls.crt作为其键名;私钥文件必须以tls.key为键名

2、创建Secret资源
kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key -n testing
kubectl get secrets -n testing tomcat-ingress-secret -o yaml

3、创建Ingress资源

curl -k -H "Host: tomcat.ilinux.io" https://192.168.1.125:443/

注意,若多个Ingress重叠,则只有一个生效;ingress不区分namespace

实际使用中,在集群之外应该存在一个用于调度用户请求至各节点Ingress控制器相关的NodePort的负载均衡器
可基于Nginx、Happroxy、LVS等手动创建,并通过Keepalived实现高可用配置

 

转载请注明:轻风博客 » 马哥_K8s进阶实战(4)Service/Ingress

喜欢 (0)or分享 (0)