Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。
一个简单的示例
该示例是将Service的80端口映射到具有app: nginx
标签的Pod上。
1 | apiVersion: v1 |
spec.selector
: 通过label选择需要将流量转发哪些Pod。
spec.ports[].port
: 这个Service将会暴露的端口。该端口需要是一个整型。
spec.ports[].targetPort
: 目标Pod的端口号或者端口名称。如果是端口名称,则必须是IANA_SVC_NAME
。如果不指定,则targetPort
的值与port
是一致。
关于Service Spec更多配置,请查看官方API Reference
通过如下执行命令创建一个Service:
1 | kubectl apply -f https://raw.githubusercontent.com/chengqing-su/kubernetes-learning/master/service/nginx-service.yaml |
我们可以得到下面的结果:
Service的类型(Service的访问方式)
上面的截图中,我们可以看见Service是有类型的。可以通过spec.type
指定Service的类型,有ClusterIP
、NodePort
、LoadBalancer
和ExternalName
四种。
Type | 描述 |
---|---|
ClusterIP | 默认的Service类型。使用集群内部的IP公开Service,使用该类型之后,服务只有在集群的内部被访问 |
NodePort | 通过静态端口(NodePort)在每个节点的IP上公开Service。 |
LoadBalancer | 使用云提供商的负载平衡器对外公开Service。 |
ExternalName | 通过返回CNAME记录,将服务映射到externalName字段的内容(例如foo.bar.example.com) |
为什么需要Service?
为了更好地理解Service,我们可以创建一个Deployment,相关的代码如下所示:
1 | apiVersion: apps/v1 |
通过下面的命令创建该Deployment:
1 | kubectl apply -f https://raw.githubusercontent.com/chengqing-su/kubernetes-learning/master/service/nginx-deployment.yaml |
结果如下:
这时候我们可以看到Endpoints
中有了值,这些IP就是Deployment所创建的Pod的IP。
现在需要把Deployment所管理的应用暴露给集群内部的应用A使用,应用A可以使用Pod的IP或者通过Service去访问该应用。
但是应用总是在不停的升级迭代中,而Pod在一开始设计的时候就没有被当作一个会永久存在的对象。Pod总会死的,死了之后也不会被复活。
现在,尝试着更新一下上面的这个Nginx应用。执行下面的命令可以升级nginx到1.17, 不推荐通过该方式去升级生产环境上的任何应用。
1 | kubectl set image deployment nginx-deployment nginx=nginx:1.17 |
结果如下:
Endpoints
发生了改变,Deployment之前所创建的Pod已经被删除,Endpoints
指向的是新的Pod。应用A如果使用了Pod的IP访问该应用,此时它就需要更新它的访问IP。
Service是一种抽象,定义了Pod的逻辑集和访问Pod的策略(有时将该模式称为微服务)。 我们的具体应用都是运行在Pod中,而Pod又是不稳定的,如果直接使用Pod到Pod的通信会有很大的维护成本。 而Service是相对稳定的,能给其他应用提供一个稳定的接口。这也可以帮助我们对Pod进行解耦。
Headless Service
有些时候,我们并不需要Service提供的默认负载均衡功能和一个Service IP,或者其他应用希望知道该Service下面的实例。可以将spec.clusterIP
设置为None
来实现一个Headless Service。