0%

Service

Service是Kubernetes的核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。

一个简单的示例

该示例是将Service的80端口映射到具有app: nginx标签的Pod上。

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80

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

我们可以得到下面的结果:

create-service.png

Service的类型(Service的访问方式)

上面的截图中,我们可以看见Service是有类型的。可以通过spec.type指定Service的类型,有ClusterIPNodePortLoadBalancerExternalName四种。

Type描述
ClusterIP默认的Service类型。使用集群内部的IP公开Service,使用该类型之后,服务只有在集群的内部被访问
NodePort通过静态端口(NodePort)在每个节点的IP上公开Service。
LoadBalancer使用云提供商的负载平衡器对外公开Service。
ExternalName通过返回CNAME记录,将服务映射到externalName字段的内容(例如foo.bar.example.com)

为什么需要Service?

为了更好地理解Service,我们可以创建一个Deployment,相关的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16
ports:
- containerPort: 80

通过下面的命令创建该Deployment:

1
kubectl apply -f https://raw.githubusercontent.com/chengqing-su/kubernetes-learning/master/service/nginx-deployment.yaml

结果如下:

create-deployment.png

这时候我们可以看到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

结果如下:

update-deployment.png

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。