1 Service

Kubernetes Pods 是有生命周期的。他们会被创建,被销毁,但是他们不会无条件"复活"。比如 ReplicaSets 这种 Pod 控制器会动态生成或者销毁 Pods(如在扩容或者缩容时)。当然每个Pod 都会自动被 k8s 分配IP地址,且这些 IP 也是动态分配的,也就是说如果你重新启动 Pod, 这个 Pod 将会得到一个新的 IP 地址。这导致了如下问题:如果这些 Pod (比如后台程序)对其他 Pods (比如前端程序) 提供某些功能,那么这些前端服务怎么才能锁定后端程序呢?(如果IP一直被动态分配)

K8s Service 其实就是为了解决这些问题而设计的。

Service 是定义一组 Pod 访问权限的抽象服务(服务也被称之为 microservice)。这些Pod 组通常是被一个叫  Label Selector 的组件锁定住的。比如:你有一组处理图片的后台程序,这个程序有3 个replica 副本。这3个副本运行相同的内容,前端无论访问哪个副本都可以达到同样的效果。这是如果你给这组后台程序设置了 Service,那么你的前端程序只需要与 Service通信,而不需要关心后台程序 IP 地址有没有变化等问题。在这里 Service 扮演了一个解耦的角色。

一个 Kubernetes-Native 应用,k8s一般会提供一个简单的 Endpoints API 它会追踪 Service 配置的变化。对于 non-native 的应用,k8s 提供了 桥接 Service 的 virtual-IP,它会重定向给后台 Pod。

 

PS: Service 一共有3 种工作方式

  • userspace: kubernetes 1.1 之前
  • iptables: k8s 1.1 and 1.10 之间
  • ipvs: 1.11+ (最新)

Service 类型:

ExternalName, ClusterIP, NodePort 和LoadBalancer

2. 为 Redis 创建 Service

使用如下模板创建:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      role: logstore
  template:
    metadata:
      labels:
        app: redis
        role: logstore
    spec:
      containers:
        - name: redis
          image: redis:4.0-alpine
          ports:
            - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-svc
  namespace: default
spec:
  selector:
    app: redis
    role: logstore
  clusterIP: 10.97.97.97
  type: ClusterIP
  ports:
    - port: 6379
      targetPort: 6379

 说明:

* port -> service ip address port

* targetPort -> Container 的 Port 且带有 Label "app=redis and role=logstore"

* nodePort -> node port 用于对外提供访问

* clusterIP: 会自动生成,通常由 Service 自动分配(在上面的例子中我们自己定义了), 这个IP address 主要由 service proxy 提供

 详见: https://kubernetes.io/docs/concepts/services-networking/service

运行如下命令:

[root@k8smaster service]# kubectl apply -f redis-svc.yaml 
service/redis created


[root@k8smaster service]# kubectl get pods -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE   IP            NODE       LABELS
redis-797f4cc7c4-xmvcm   1/1     Running   0          18d   10.244.1.47   k8snode1   app=redis,pod-template-hash=3539077370,role=logstore


[root@k8smaster service]# kubectl get svc -o wide --show-labels
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE   SELECTOR                  LABELS
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    24d   <none>                    component=apiserver,provider=kubernetes
redis-svc    ClusterIP   10.97.97.97   <none>        6379/TCP   18d   app=redis,role=logstore   <none>


[root@k8smaster service]# kubectl describe svc redis-svc
Name:              redis-svc
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis-svc","namespace":"default"},"spec":{"clusterIP":"10.97.97.9...
Selector:          app=redis,role=logstore
Type:              ClusterIP
IP:                10.97.97.97
Port:              <unset>  6379/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.1.47:6379
Session Affinity:  None
Events:            <none>

 

从命令行输出可以看到 Endpoint 指向 10.244.1.47:6379, ip 符合了随机生成 ip 的范围。

Endpoint 也是一个 k8s 对象,用户也可以自己手动配置, 它起着在 Pod 和 Service 间桥梁的作用。