kubernetes 的Service
Service概念:
Kubernetes中的 Pod是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁pod生命就永远结束,这个pod就不存在了,通过ReplicaSets能够动态地创建和销毁Pod(例如,需要进行扩缩容,或者执行滚动升级),每个Pod都会获取它自己的 IP 地址,这些IP地址并不是一直处于稳定的状态,可能随时改变。 在 Kubernetes 集群中,如果一组Pod(称为 backend)为其它Pod (称为 frontend)提供服务,那么那些 frontend(pod) 通过设置的标签来绑定service,进而对外提供网络服务
关于Service
Kubernetes Service定义了这样一种抽象:逻辑上的一组Pod,一种可以访问它们的策略-通常称为微服务。 这一组Pod能够被Service访问到,通常是通过Label Selector实现的。举个例子,考虑一个图片处理程序 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。 Service 定义的抽象能够解耦这种关联。
例如想要用nginx反向代理tomcat,那么tomcat如果是通过pod部署的,pod的ip可能会随时变化,那么我们就需要在所有这些部署tomcat的pod前面加上一个固定接入层service,我们nginx反向代理只需要写service地址,就会代理到后端的pod,那么pod就算ip怎么变化,通过service都可以找到,对 Kubernetes 集群中的应用,Kubernetes 提供了简单的Endpoints API,只要Service中的一组Pod发生变更,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问Service,再由Service重定向到backend Pod。
简单归纳一下
service是一个固定接入层,客户端可以通过访问service来访问到service关联的后端pod,这个service工作依赖于在kubernetes集群之上部署的一个附件,就是kubernetes的dns服务(不同kubernetes版本的dns默认使用的也是不一样的,1.11之前的版本使用的是kubeDNs,较新的版本使用的是coredns),service的名称解析是依赖于dns附件的,因此在部署完k8s之后需要在部署dns附件,kubernetes要想给客户端提供网络功能,需要依赖第三方的网络插件(flannel,calico等)。
在kubernetes集群中有三类ip地址:node network(节点网络),pod network(pod 网络),这两种网络地址是我们实实在在配置的,其中节点网络地址是配置在节点接口之上,而pod网络地址是配置在pod资源之上的,因此这些地址都是配置在某些设备之上的,这些设备可能是硬件,也可能是软件模拟的,cluster network(集群地址,也成为service network),这个地址是虚拟的地址(virtual ip),没有配置在某个接口上,只是出现在service的规则当中。
每个K8s节点上都有一个工作的组件叫做kube-proxy,kube-proxy这个组件将始终监视着apiserver中有关service资源的变动信息,需要跟master之上的apiserver交互,随时连接到apiserver上获取任何一个与service资源相关的资源变动状态,这种是通过kubernetes中固有的一种请求方法watch(监视)来实现的,一旦有service资源的内容发生变动(如创建,删除),kube-proxy都会将它转化成当前节点之上的能够实现service资源调度,把我们请求调度到后端特定的pod资源之上的规则,这个规则可能是iptables,也可能是ipvs,取决于service的实现方式
service实现方式
第一种:iptables
客户端ip请求时直接请求service的ip,这个请求报文被本地内核空间中的service规则所截取,进而直接调度给相关的pod,这个方式是直接工作在内核空间,由iptables规则直接实现
第二种:ipvs
客户端请求到达内核空间之后直接由ipvs规则来调度到相关的pod资源
1.11之前的版本使用的是iptables
1.11+版本使用的是ipvs,ipvs如果没有被激活就会自动降级为iptables
如果某个服务背后的pod资源发生改变,比如service的标签选择器适用的pod又多了一个,这个pod使用的信息会立即反应在apiserver上,kube-proxy能监听到这个service的变化,将其立即转为service规则(如iptables规则)
编写server yaml 文件
[root@master-1 kongzhiqi]# cat deployment.yaml apiVersion: apps/v1 #api版本 kind: Deployment #资源类型 metadata: #源数据 name: deployment #控制器名字 namespace: deployment # 所在的名称空间 labels: # 标签的设置 dev: deployment-test spec: # 控制器期望状态 minReadySeconds: 4 # 等待就绪时间 revisionHistoryLimit: 5 # 保留的历史版本 replicas: 3 # pod 个数 strategy: # 更新策略 rollingUpdate: # 选择更新方式 maxSurge: 5 # 最大的pod 数量比pod个数多 maxUnavailable: 1 # 最大不可用的pod 数量 selector: # 标签选择器 matchLabels: # 标签选择器设定 dev: deployment-test # 标签的key与值的设定 template: # pod 属性定义 metadata: # 元数据 labels: # 标签设定 dev: deployment-test # 标签的key 与值 spec: # pod 的期望状态 containers: # 容器的属性定义 - name: web # 容器的名字 image: nginx:1.8.1 # 运行的镜像 imagePullPolicy: IfNotPresent # 获取镜像策略 ports: # 端口设置 - name: web # 端口的名字 containerPort: 80 # 容器的端口 livenessProbe: # 存活性探测属性设置 httpGet: # 探测类型 port: web # 探测的端口 path: index.html # 探测的url initialDelaySeconds: 5 # 容器里进程初始化时间等待探测时间 periodSeconds: 5 # 探测周期 timeoutSeconds: 2 #探测超时时间 failureThreshold: 3 # 探测连续失败的最大次数 readinessProbe: # 就绪性探测 httpGet: # 探测的钩子 port: web # 探测的端 口 path: index.html #探测的url initialDelaySeconds: 5 # 容器里进程初始化时间等待探测时间 periodSeconds: 5 # 探测周期 timeoutSeconds: 2 #探测超时时间 failureThreshold: 3 # 探测连续失败的最大次数 vim service.yaml apiVersion: v1 #api版本 kind: Service # 资源类型 metadata: # 元数据 name: deployment-service # service 的名字 namespace: deployment # 名称空间 labels: # 设置标签属性 dev: dev-service spec: #期望状态 selector: # 绑定拥有以下标签的pod dev: deployment-test ports: # 端口设置 - name: dev-chenxi # 名字 nodePort: 30880 # node 暴漏的端口;如果不写默认随机 port: 80 # 集群内部暴漏的端口,必写字段 protocol: TCP # 协议 支持"TCP", "UDP", and "SCTP",默认TCP targetPort: web # 绑定的端口支持名字 type: NodePort # 暴露的类型支持ExternalName、ClusterIP、NodePort 和 LoadBalancer。“ClusterIP”为负载均衡分配集群内部 IP 地址“NodePort”建立在 ClusterIP 之上,并在每个节点上分配一个端口路由到与 clusterIP 相 同的端点。“LoadBalancer”建立在NodePort 并创建一个外部负载均衡器(如果当前支持cloud) 路由到与 clusterIP 相同的端点。 “外部名称”将此服务别名为指定的externalName。 其他几个领域不适用于 ExternalName 服务
运行service
[root@master-1 kongzhiqi]# kubectl apply -f service.yaml service/deployment-service created [root@master-1 kongzhiqi]# kubectl get svc -n deployment NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE deployment-service NodePort 10.10.198.163 <none> 80:30880/TCP 3s [root@master-1 kongzhiqi]# kubectl describe svc -n deployment Name: deployment-service Namespace: deployment Labels: dev=dev-service Annotations: <none> Selector: dev=deployment-test Type: NodePort IP Families: <none> IP: 10.10.198.163 IPs: 10.10.198.163 Port: dev-chenxi 80/TCP TargetPort: web/TCP NodePort: dev-chenxi 30880/TCP Endpoints: 10.244.84.163:80,10.244.84.164:80,10.244.84.165:80 Session Affinity: None External Traffic Policy: Cluster Events: <none>
访问node:30880
noselector 类型的service
[root@master-1 service]# cat noselector-service.yaml apiVersion: v1 kind: Service metadata: name: my-cx-1 spec: ports: - port: 80 protocol: TCP targetPort: 3306 [root@master-1 service]# cat endpoints.yaml apiVersion: v1 kind: Endpoints metadata: name: my-cx-1 # 注意名字与service 一致 subsets: - addresses: - ip: 1.2.3.4 ports: - port: 3306 kubectl apply -f noselector-service.yaml kubectl apply -f endpoints.yaml [root@master-1 service]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.10.29:6443,192.168.10.30:6443,192.168.10.31:6443 2d my-chenxi 172.16.84.131:80,172.16.84.132:80 12s my-cx-1 1.2.3.4:3306 6m32s [root@master-1 service]# kubectl describe svc my-cx-1 Name: my-cx-1 Namespace: default Labels: <none> Annotations: <none> Selector: <none> Type: ClusterIP IP Families: <none> IP: 10.255.154.164 IPs: 10.255.154.164 Port: <unset> 80/TCP TargetPort: 3306/TCP Endpoints: 1.2.3.4:3306 Session Affinity: None Events: <none>
externalname service 格式
[root@master-1 service]# kubectl create namespace cx namespace/cx created [root@master-1 deployment]# cat externalname.yaml apiVersion: v1 kind: Service metadata: name: my-cx-2 namespace: cx spec: type: ExternalName externalName: www.baidu.com #返回的 域名 访问格式 name.namespace.svc.cluster.local
无头service
[root@master-1 service]# cat service_2.yaml apiVersion: v1 kind: Service metadata: name: my-chenxi-2 spec: clusterIP: 'None' ports: - port: 80 protocol: TCP selector: run: my-cx-2 [root@master-1 service]# kubectl get ep NAME ENDPOINTS AGE kubernetes 192.168.10.29:6443,192.168.10.30:6443,192.168.10.31:6443 2d2h my-chenxi 172.16.84.131:80,172.16.84.132:80 79m my-chenxi-2 <none> 9m19s my-cx-1 1.2.3.4:3306 85m