深入了解Kubernetes Service
Service是Kubernetes最核心的概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求进行负载分发到后端的各个容器应用上。
Service的四种类型
- Clusterip: 默认类型,自动分配一个仅cluster内部可以访问的虚拟ip
- NodePort: 在clusterip基础上为service在每台机器上绑定一个端口,这样就可以通过Nodeip:port方式来访问该服务
- Loadbalance: 在NodePort基础上,接触cloud provider创建一个外部负载均衡器,并将请求转发到nodeip:port
- externalName: 把集群外部的服务引入到集群内部,在集群内中直接使用,没有任何类型的代理被创建
yaml格式的pod配置文件内容及属性说明
apiVersion: v1 // 必选,版本: v1
kind: Service // 必选,Service
metadata: // 必选,元数据
name: string // 必选,Service名称
namespace: string // 命令空间,不指定时系统系统默认的空间"default"
labels: // 自定义属性标签列表
- name: string // 自定义注释属性列表
spec: // 详细描述
selector: [] // label Selector配置,选择具有指定label标签的Pod作为管理范围
type: string // Service的类型,默认为ClusterIP,可选NodePort和Loadbalancer。
clusterIP: string // 虚拟服务IP地址,类型为ClusterIP时,如不指定,则系统自动分配
sessionaffinity: string // 是否支持session,默认为空,可选ClusterIP,表示同一个客户端的访问请求转发到同一个口段Pod
ports: // Service需要暴露的端口列表
- name: string // 端口名称
protocol: string // 端口协议,支持tcp和udp,默认tcp
port: int // 服务监听的端口号
targetPort: int // 需要转发到后端Pod的顿口号
nodePort: int // 当type为NodePort时,指定映射到物理机的端口号介于[30000-32767]间
status: // 当type为loadbalancer时,设置尾部负载均衡的地址,用于公有云环境
loadBalancer: // 外部负载均衡器
ingress: // 外部负载均衡器
ip: string // 外部负载均衡器的Ip
hostname: string // 外部负载均衡器的主机名
Service的基本用法
一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最方便的方式就是通过TCP/IP及监听IP和端口号的方式来实现。直接通过Pod的IP地址和端口号访问应用,但是Pod的IP地址是不可靠的,当Pod所在的Node发生故障,Kubernetes会了重新调度到另一台Node上,这样Pod的IP将发生变化。重要的是,容器本身是分布式的部署方式,通过多个实例共同提供服务,需要在这些实例的前端设置一个负载均衡器来实现请求的分发,Kubernetes中的Service就师用来解决该问题的核心组件。
Kubernetes提供一种快速的方法,即通过kubectl expose命令来创建Service
如:
#kubectl expose rc webapp
查看新创建的Service,可以看到系统为它分配了一个虚拟的IP地址(Cluster IP),而Service所需的端口号则从Pod中的containerPort复制而来.
#kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
webapp 169.169.235.79 <none> 8080/TCP 3s
我们可以通过该Service的IP地址和端口号来访问
#curl 169.169.235.79:8080
对Service地址169.169.235.79:8080的访问会自动负载到后端的两个Pod中的一个。 除了使用命令创建Service,也可以通过配置文件定义Service,在通过kubectl create -f命令来进行创建。
apiVersion: v1
kind: service
metadata:
name: webapp
spec:
ports:
- port: 8081 // Service所需的虚拟端口号
targetPort: 8080 // 后端Pod的端口号
selector:
app: webapp // 后端拥有label: app=webapp的Pod
目前,Kubernetes提供两种负载分发策略:RoundRobin和SessionAffinity。默认情况下采用RoundRobin模式进行路由选择。
- RoundRobin:轮询模式,即轮询将请求转发到后端各个Pod
- SessionAffinity:基于客户端Ip地址进行会话保持,即第一次将某个客户端发情的请求转发到后端某个Pod上,之后相同的客户端发起的请求都将被转发到后端相同的Pod上。
默认情况下,Kubernetes采用RoundRbin模式进行路由选择,某些应用场景下开发人员系统自己控制负载均衡策略,Kubernetes通过Headless Service的概念来实现这种功能,即不给Service设置ClusterIP,仅通过Label Selector将后端的Pod列表返回给调用的客户端.
如:
apiVsersion: v1
kind: Service
metadata:
name: nginx
label:
name: nginx
spec:
ports:
- ports: 80
clusterIP: None
selector:
app: nginx
该Service没有虚拟的clusterip地址,对其进行访问将获得具有label "app=nginx"的全部Pod别表,然后客户端程序需要实现自己的负载均衡分发策略。
集群外部访问Pod或Service
由于Pod和Service都是Kubernetes集群范围内的虚拟概念,所以集群外的客户端无法通过Pod的IP或者service的虚拟ip和端口号访问。为了让外部用户可以访问这些服务,可以将Pod和Service的端口映射到宿主机,使客户端通过物理机访问容器应用.
方式将容器应用的端口号映射到物理机
- 通过设置容器级别的hostport,将容器应用的端口号映射到物理机
apiVersion: v1
kind: Pod
metadata:
name: webapp
labels:
name: webapp
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
hostPort:8081
通过kubectl create创建该pod后即可通过物理机的IP和8081端口访问Pod内的容器服务
#curl 10.0.0.23:8081
- 通过设置Pod级别的hostNetwork=true,该Pod中所有容器的端口号都将被直接映射到物理机,需要注意的是,在容器的ports定义部分如不指定hostport,则默认hostport等于containerport。
使用nodePort类型将Service的端口号映射到物理机
- 过设置nodePort映射到物理机,同时这是Service的类型为nodePort
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30033
selector:
name: webapp
通过物理机的IP地址和nodePort30033端口访问服务
#curl 10.0.0.22:30033
同样对该Service的访问也将被负载分发到后端的多个Pod上
- 通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。该用法仅用于在公有云服务商的平台上设置Service的场景