k8s service
定义Service
一个Service在k8s中是一个rest对象,和pod类似,像所有的rest对象一样,Servvice定义可以基于post方式,请求apiserver创建的新的实例,例如,假如有一组pod,他们对外暴露了80端口,同时还被打上了app=Myapp的标签
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: Myapp
ports:
- portocol: TCP
port: 80
targetPort: 9376
上诉配置将要创建一个名称为my-service的service对象,他会将请求代理到使用TCP端口的9376,并且具有标签"app=Myapp"的pod上,这个service将指派一个ip地址(通常称为Cluster IP),他会被服务端代理使用,该service的selector将会持续评估,处理结果将被post到一个名称为my-service的Endpoints对象上
定义一个没有selector的Service
service抽象了该如何访问k8s pod,但也能够抽象其他类型backend,如:
- 希望在生产环境中访问外部的数据库集群
- 希望service指向另一个Namespace中或其他集群中的服务。
- 正在将工作负载转移到k8s集群,和运行在k8s集群之的backend
在任意这些场景中,都能定义没有selector的service:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由于这个service没有selector,就不会创建相关的endpoints对象,可以手动将service映射到指定的endpoints:
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 1.2.3.4
ports:
- port: 9376
注意:endpoint IP地址不能是loopback(127.0.0.0/8).link-local(169.254.0.0/16)或者link-local多播地址(224.0.0.0/24)
访问没有selector的service与有selector的service的原理相同,请求将被路由到用户定义的endpoint,上图示例为1.2.3.4:9376
extemalname service是service的特例,它没有selector也没有定义任何端口和endpoint,他通过返回该外部服务的别名来提供服务。比如当查询主机my-service.prod.svc时,集群的DNS服务将放回一个值为my.database.example.com的CNAME记录:
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
多端口的service
在很多情况下,service可能需要暴露多个端口,对应这种情况k8s支持service定义多个端口,但使用多个端口时,必须提供所有端口的名称,如:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http #名称
protocol: TCP
port: 80
targetPort: 9376
- name: https #名称
protocol: TCP
port: 443
targetPort: 9377
service类型
k8s service type(服务类型)注意包括以下几种:
- ClusterIP:在集群内部使用,默认值,中能在集群中访问
- NodePort:在所有安装kube-proxy的节点上打开一个端口,此端口可以代理值后端pod,可以通过NodePort从集群外部访问集群内的服务,格式为NodePort:NodePort
- loadBalancer:使用云提供商的负载均衡器公开服务,成本较高
- externalName:通过返回定义的CNAME别名,没有设置任何类型的代理,需要1.7或更高版本kube-dns支持
NodePort类型
如果将service的type字段设置为NodePort,则k8s将从--service-node-port-range参数指定的范围(默认30000-32767)中自动分配端口,也可以手动指定NodePort,创建该Service后,集群每一个节点都将暴露一个端口,通过某个宿主机的IP+端口即访问到后端的应用。
定义一个NodePort类型的service:
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kube-system
spec:
type: NodePort
ports:
- port: 443
targetPort: 8443
nodePort: 30000
selector:
k8s-app: kubernetes-dashboard
使用service代理k8s外部服务
使用场景:
- 希望在生产环境中使用某个固定的名称,而非IP访问外部的中间件服务
- 希望service指向一个nsmespace中或集群中的服务
- 将正在工作负载的转移到k8s集群,但是一部分服务仍运行在k8s集群之外的backend
# cat nginx-svc-external.yaml
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
sessionAffinity: None
type: ClusterIP
# cat nginx-ep-external.yaml
apiVersion: v1
kind: Endpoints
metadata:
labels:
app: nginx-svc-external
name: nginx-svc-external
subsets:
- addresses:
- ip: 140.205.94.189
ports:
- name: http
port: 80
protocol: TCP