k8s-Service
Service的作用:
- 防止pod失联(服务发现)
service解决podIP动态变化的功能
- 定义一组pod的访问策略(负载均衡)
为什么要有Service?
在kubernetes中,Pod是有生命周期的,如果Pod重启它的IP很有可能会发生变化。如果我们的服务都是将Pod的IP地址写死,Pod挂掉或者重启,和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod,为了解决这个问题,在kubernetes中定义了service资源对象,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,service是一组Pod的逻辑集合,这一组Pod能够被Service访问到,通常是通过Label Selector实现的。
1、pod ip经常变化,service是pod的代理,我们客户端访问,只需要访问service,就会把请求代理到Pod
2、pod ip在k8s集群之外无法访问,所以需要创建service,这个service可以在k8s集群外访问的。
Service概述
service是一个固定接入层,客户端可以通过访问service的ip和端口访问到service关联的后端pod,这个service工作依赖于在kubernetes集群之上部署的一个附件,就是kubernetes的dns服务(不同kubernetes版本的dns默认使用的也是不一样的,1.11之前的版本使用的是kubeDNs,较新的版本使用的是coredns),service的名称解析是依赖于dns附件的,因此在部署完k8s之后需要再部署dns附件,kubernetes要想给客户端提供网络功能,需要依赖第三方的网络插件(flannel,calico等)。每个K8s节点上都有一个组件叫做kube-proxy,kube-proxy这个组件将始终监视着apiserver中有关service资源的变动信息,需要跟master之上的apiserver交互,随时连接到apiserver上获取任何一个与service资源相关的资源变动状态,这种是通过kubernetes中固有的一种请求方法watch(监视)来实现的,一旦有service资源的内容发生变动(如创建,删除),kube-proxy都会将它转化成当前节点之上的能够实现service资源调度,把我们请求调度到后端特定的pod资源之上的规则,这个规则可能是iptables,也可能是ipvs,取决于service的实现方式。
Service工作原理
k8s在创建Service时,会根据标签选择器selector(lable selector)来查找Pod,据此创建与Service同名的endpoint对象,当Pod 地址发生变化时,endpoint也会随之发生变化,service接收前端client请求的时候,就会通过endpoint,找到转发到哪个Pod进行访问的地址。(至于转发到哪个节点的Pod,由负载均衡kube-proxy决定)
[root@master01 ~]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.1.180:6443,192.168.1.181:6443 6d5h
Pod与Service的关系
通过labe-selector相关联
通过Service实现 Pod的负载均衡(TCP/UDP 只支持4层负载均衡)
Service的四种IP地址
- ClusterIP:集群内部使用
默认,分配一个稳定的IP地址,即VIP,只能在集群内部访问
生成Service的yaml文件方法
#控制器名字 [root@master01 ~]# kubectl expose deployment myapp-v1 --port=8080 --target-port=80 --name=web01 -o yaml --dry-run=client
apiVersion: v1 kind: Service metadata: creationTimestamp: null name: web01 spec: ports: - port: 8080 protocol: TCP targetPort: 80 selector: app: myapp version: v1 status: loadBalancer: {}
- NodePort:对外暴露应用
在每个节点上启用一个端口来暴露服务,在集群外部进行访问,也会分配一个稳定内部集群IP地址,
访问地址:<NodeIP>:<NodePort>
Client----->NodeIP:NodePort----->Service Ip:ServicePort----->PodIP:ContainerPort。
[root@master01 ~]# cat nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 2 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 #pod中的容器需要暴露的端口 --- apiVersion: v1 kind: Service metadata: name: web01 namespace: default spec: ports: - port: 80 #svc端口,可以与其他svc端口号相同,因为ip不同 protocol: TCP targetPort: 80 #跟你控制器里定义的端口有关 nodePort: 30008 #宿主机上映射的端口,比如一个Web应用需要被k8s集群之外的其他用户访问,那么需要配置type=NodePort,若配置nodePort=30001,那么其他机器就可以通过浏览器访问scheme://k8s集群中的任何一个节点ip:30001即可访问到该服务,例如http://192.168.1.63:30001。>如果在k8s中部署MySQL数据库,MySQL可能不需要被外界访问,只需被内部服务访问,那么就不需要设置NodePort selector: run: my-nginx type: NodePort
[root@master01 ~]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.1.180:6443,192.168.1.181:6443 6d22h web01 172.16.196.151:80,172.16.196.152:80 27m
- LoadBanlancer:对外暴露应用,适用公有云
与NodePort类似,在每个节点上启用一个端口来爆率服务,除此之外,kubernetes会请求底层云平台上的负载均衡器,将每个Node作为后端添加进去
- ExternalName:
适用于k8s集群内部容器访问外部资源,它没有selector,也没有定义任何的端口和Endpoint。
应用场景:不同命名空间下的容器实现跨命名空间访问
#需求:default名称空间下的client 服务想要访问nginx-ns名称空间下的nginx-svc服务
- 只要有一个ns里的svc专门做代理类型为ExternalName,对应其他ns的全指向域名就可以
//这个svc没有定义标签选择器,就是不是给特定pod使用的,它就是单纯的svc apiVersion: v1 kind: Service metadata: name: client-svc namespace: default spec: type: ExternalName externalName: nginx-svc.nginx-ns.svc.cluster.local ports: - name: http port: 80 targetPort: 80
namespace:nginx-ns的svc
[root@master1 -]# kubectl create ns nginx-ns
[root@master1 exter]# cat server_nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: nginx-ns spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent
[root@master1 exter]# cat nginx_svc.yaml apiVersion: v1 kind: Service metadata: name: nginx-svc namespace: nginx-ns spec: selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80 type: ClusterIP
当查询主机 my-service.prod.svc.cluster.local 时,群集DNS将返回值为my.database.example.com的CNAME记录。
service的FQDN是: <service_name>.<namespace>.svc.cluster.local
my-service.prod. svc.cluster.local SVC名字.ns名字.svc.cluster.local
SVc要是想要在主机通过域名访问pod,需要把svc的ip对应的全地址解析写到/etc/hosts文件中
自定义Endpoint资源
作用:
- 将外部IP地址和服务引入到k8s集群内部,由service作为一个代理来达到能够访问k8s集群外部服务的目的。
k8s最佳实践:映射外部服务案例分享
- 场景1:k8s集群引用外部的mysql数据库
在node1上安装mysql数据库:
- 略
创建mysql的svc
[root@master1 mysql]# cat mysql_service.yaml apiVersion: v1 kind: Service metadata: name: mysql spec: type: ClusterIP ports: - port: 3306
查看Endpoint资源
[root@xianchaomaster1 mysql]# kubectl describe svc mysql Name: mysql Namespace: default Labels: <none> Annotations: <none> Selector: <none> Type: ClusterIP IP Families: <none> IP: 10.107.232.103 IPs: 10.107.232.103 Port: <unset> 3306/TCP TargetPort: 3306/TCP Endpoints: <none> #还没有endpoint Session Affinity: None Events: <none>
创建mysql对应Endpoint资源
[root@master1 mysql]# cat mysql_endpoint.yaml apiVersion: v1 kind: Endpoints metadata: name: mysql ##要是svc中定义的名字一致 subsets: - addresses: - ip: 192.168.1.182 ports: - port: 3306
再次查看mysql的svc
[root@master1 mysql]# kubectl describe svc mysql Name: mysql Namespace: default Labels: <none> Annotations: <none> Selector: <none> Type: ClusterIP IP Families: <none> IP: 10.107.232.103 IPs: 10.107.232.103 Port: <unset> 3306/TCP TargetPort: 3306/TCP Endpoints: 192.168.1.62:3306 #这个就是定义的外部数据库 Session Affinity: None Events: <none>

评论