Kubernetes 中 Pod 是随时可以消亡的(节点故障、容器内应用程序错误等原因)。如果使用 Deployment 运行您的应用程序,Deployment 将会在 Pod 消亡后再创建一个新的 Pod 以维持所需要的副本数。每一个 Pod 有自己的 IP 地址,然而,对于 Deployment 而言,对应 Pod 集合是动态变化的。
这个现象导致了如下问题:
如果某些 Pod(假设是 'backends')为另外一些 Pod(假设是 'frontends')提供接口,在 'backends' 中的 Pod 集合不断变化(IP 地址也跟着变化)的情况下,'frontends' 中的 Pod 如何才能知道应该将请求发送到哪个 IP 地址?Service 存在的意义,就是为了解决这个问题。

定义Service

定义Service的方式和我们前面定义的各种资源对象的方式类型,例如,假定我们有一组Pod服务,它们对外暴露了 8080 端口,同时都被打上了app=myapp这样的标签,那么我们就可以像下面这样来定义一个Service对象:

apiVersion: v1 
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 8080
name: myapp-http

创建一个名为myservice的Service对象,它会将请求代理到使用 TCP 端口为 8080,具有标签app=myapp的Pod上,这个Service会被系统分配一个Cluster IP,该Service还会持续的监听selector下面的Pod,会把这些Pod信息更新到一个名为myservice的Endpoints对象上去。

Service类型

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的ServiceType。
  • NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。
  • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

NodePort类型

如果设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。

apiVersion: v1 
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 80
name: myapp-http

查看Service信息

kubectl get svc

myservice的 TYPE 类型已经变成了NodePort,后面的PORT(S)部分也多了一个 32212 的映射端口

ExternalName

ExternalName 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

kind: Service 
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

当查询主机 my-service.prod.svc.cluster.local 时,集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME 记录。 访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。