Skip to content

k8s学习笔记(4)——Service

一、定义

由于Pod是不可靠的,会被创建或者销毁,而且每次重新创建都会使用不同的IP,因此直接访问Pod是不可靠的。而Service就是在Pod之上,对Pod做了一层抽象,从而对上层服务屏蔽了下面具体的Pod。这样即使下面的Pod发生了改变,上层的服务看到的依然是同一个Service。

Service的模板如下:

yaml
kind: Service
apiVersion: v1
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

其中:

  • selector:定义了选择哪些Pod
  • protocol:支持TCP,UDP和SCTP
  • port:Srevice暴露出来的端口,其它服务通过这个端口来访问该Service
  • targetPort:Pod的端口,默认和port一致

其中targetPort不仅可以是一个数字,还可以是一个字符串,用来指向Pod的端口的名字,这样即使Pod改变了端口,Service也依然不用改变。例如:

yaml
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:latest
      	ports:
      	- name: nginx-port
      	  containerPort: 80
      	  protocol: TCP

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8000
    targetPort: ngxin-port

如果一个Service需要暴露多个端口的话,需要对每个端口指定名字。端口名字只能是小写字母、数字以及连字符,且不能以连字符开始或者结束。例如:

yaml
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 Type

通常来说,我们不仅需要可以在集群内访问Service,也经常会需要将Service暴露到集群外。Service的type字段可以定义Service的类型,从而可以控制Service的访问。Service Type有以下几种:

  • ClusterIP:默认的类型,Service只能在集群内被访问
  • NodePort:对外提供服务,可以通过<NodeIP>:<NodePort>来访问Service
  • LoadBalancer:通过云服务提供商的负载均衡暴露Service
  • ExternalName:结合externalName字段来使用,externalName的值可以为例如foo.bar.example.com这样的格式

下面是使用NodePort的一个例子:

yaml
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:latest

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8000
    targetPort: 80

然后通过kubectl get service可以看到:

NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
nginx-service   NodePort    10.101.53.78   <none>        8000:31483/TCP   2m

然后访问localhost:31483即可,也就是说,Service的8000端口被映射到了节点的31483端口。映射到节点的端口是被随机分配的,且在--service-node-port-range选项所指定的范围内(默认为30000-32767),也可以通过添加nodePort字段来指定某一个端口,例如:

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8000
    nodePort: 31234
    targetPort: 80

这样就可以访问localhost:31234了。