一、Service 概述
Service 是 Kubernetes 最核心概念,通过创建 Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。
目前一致的service有两个要求:标签匹配,就绪,如果不满足这两个,则无法匹配。
二、service 类型
2.1、ClusterIp
默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP。
2.2、NodePort(节点端口)
在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 <NodeIP>: NodePort
来访问该服务。
2.3、LoadBalancer
在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 <NodeIP>: NodePort
。
2.4、ExternalName(DNS别名)
把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创 建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持。
DNS别名解析流程:
我们要创建一个 ExternalName 的 service(domain),当创建完 domain 以后,我们就会得到一个域名,tomcat 只要去访问到这个域名,这个域名就会经过 coredns 解析,解析到一个结果上,这个结果可能是一个域名,也可能是一个 IP,这个域名或 IP 可能指向这个 db。
当外部的 db 的 IP 发生变化时,只要修改 domain 的别名地址就好了,例如 db 数据库原来是 bbs.aaa.com,现在是 db.aaa.com,那么只需要将 domain 的别名地址写成 db.aaa.com 即可。
三、Service 的定义
yaml 格式的 Service 定义文件。
apiVersion: v1
kind: Service
metadata:
name: string
namespace: string
labels:
name: string
annotations:
name: string
spec:
selector: {} # 选择器,用于关联 Pod
type: string # 可选值:ClusterIP, NodePort, LoadBalancer, ExternalName
clusterIP: string
sessionAffinity: string # 可选值:None, ClientIP
ports:
- name: string
protocol: string # 可选值:TCP, UDP, SCTP
port: int # Service 端口
targetPort: int # Pod 端口
nodePort: int # 节点端口(当 type: NodePort 时使用)
status:
loadBalancer:
ingress:
- ip: string
hostname: string
四、使用
4.1、ClusterIP 创建
ClusterIP.yaml
apiVersion: v1
kind: Service #service类型
metadata:
name: myapp #当前service的名是myapp
namespace: default #放到default名称空间下
spec: #期望
type: ClusterIP #ClusterIP的类型
selector: #标签选择器,匹配下面两个标签
app: myapp
release: stabel
ports: #端口,
- name: http #端口名称为http
port: 80 #端口是80,集群访问的VIP的端口。
targetPort: 80 #后端目标80,真实服务器的端口
#IPVS是基于NAT工作模式运行的
创建
#基于yaml文件创建ClusterIP类型的svc
kubectl apply -f ClusterIP.yaml
#查看已经创建的svc
kubectl get svc
4.2、NodePort 创建
NodePort.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: default #放在default名称空间下
spec: #期望
type: NodePort #当前的工作模式是NodePort方式
selector:
app: myapp
release: stabel
ports:
- name: http #定义的别名为http
port: 80 #集群的端口80
targetPort: 80 #后端的端口80
创建
kubectl apply -f 6.nodeport.yaml
#这里映射的端口,必须大于三万以上。默认就可以,不用修改,防止冲突
#在外部访问物理机的31225端口即可映射到容器内部的80端口,达到访问容器的内目的
kubectl get svc
4.3、LoadBalancer 创建
与 nodeport 的区别在于,loadbalancer 会自动在外部创建一个调度器将当前的 nodeport 端口进行流量访问,实现高可用,但是必须得借助云平台创建 LB 来向节点导流。
loadBalancer 和 nodePort 其实是同一种方式。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用 cloud provider 去创建 LB 来向节点导流。
loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-loadbalancer #服务的名称,这里是 myapp-loadbalancer。
spec:
selector:
app: myapp # 匹配带有相应标签的 Pods。在这个例子中,它匹配所有标签为 app: myapp 的 Pods。
type: LoadBalancer #为 LoadBalancer,表明我们想要的服务类型是负载均衡器。
ports: #服务的端口配置;
- protocol: TCP
port: 80 #服务内部端口,外部请求会到这个端口;
targetPort: 8080 #Pods 上的端口,服务会将流量从内部端口转发到此端口;
# 如果云提供商支持,也可以指定一个负载均衡器的外部端口,例如:
# nodePort: 30000 #(可选)如果指定,这是节点上用来接收外部流量的端口
创建
kubectl apply -f loadbalancer.yaml
kubectl get svc myapp-loadbalancer
4.4、ExternalName 创建
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容( 例如:hub.aaa.com )。ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
kind: Service
apiVersion: v1
metadata: #元数据
name: my-service #当前service名为my-service
namespace: default #放在default名称空间下
spec:
type: ExternalName #当前的类型为ExternalName类型
externalName: hub.aaa.com # ExternalName的值为hub.hongfu.com
my-service.defalut.svc.cluster.local 这是在集群内可以访问到的域名,如果将他的值找dns解析,解析的应该是hub.aaa.com。
例如:
我有一个 pod,我去访问一个 web 服务,web 服务就是 hub.hongfu.com,就可以靠这个 svc 指向这个 hub.aaa.com,如果有一天我想指向 harbor,那只要 dit 将这个值指向 haobor,他就指过来了,对于 pod 来说,不需要做任何改变。
当查询主机 my-service.defalut.svc.cluster.local ( SVC_NAME.NAMESPACE.svc.cluster.local )时,集群的 DNS 服务将返回一个值 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。
五、Service 示例
一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最简便 的方式就是通过 TCP/IP 机制及监听 IP 和端口号来实现。创建一个基本功能的 Service。
apiVersion: v1
kind: ReplicationController
metadata:
name: mywebapp
spec:
replicas: 2
template:
metadata:
name: mywebapp
labels:
app: mywebapp
spec:
containers:
- name: mywebapp
image: tomcat
ports:
- containerPort: 8080
我们可以通过 kubectl get pods -l app=mywebapp -o yaml | grep podIP
来获取 Pod 的 IP 地址和端口号来访问 Tomcat 服务,但是直接通过 Pod 的 IP 地址和端口访问应用 服务是不可靠的,因为当 Pod 所在的 Node 发生故障时, Pod 将被 kubernetes 重新调度到另一台 Node,Pod 的地址会发生改变。我们可以通过配置文件来定义 Service,再通过 kubectl create
来创建,这样可以通过 Service 地址来访问后端的 Pod.
apiVersion: v1
kind: Service
metadata:
name: mywebAppService
spec:
ports:
- port: 8081
targetPort: 8080
selector:
app: mywebapp
六、多端口 Service
有时一个容器应用也可能需要提供多个端口的服务,那么在 Service 的定义中也可以相应地设置为将多个端口对应到多个应用服务。
apiVersion: v1
kind: Service
metadata:
name: mywebAppService
spec:
ports:
- port: 8080
targetPort: 8080
name: web
- port: 8005
targetPort: 8005
name: management
selector:
app: mywebapp
七、外部服务 Service
在某些特殊环境中,应用系统需要将一个外部数据库作为后端服务进行连接,或将另一个集群或 Namespace 中的服务作为服务的后端,这时可以通过创建一个无 Label Selector 的 Service 来实现。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Endpoints
metadata:
name: my-service # 必须与 Service 名称相同
subsets:
- addresses:
- ip: 10.254.74.3
ports:
- port: 8080
评论