Kubernetes 系列文章:

  1. 从 RunC 聊起
  2. Kubernetes 介绍与安装
  3. Pod
  4. Service
  5. Replicas

在前面第四篇中,我介绍 Service 的那篇文章(Kubernetes 入门四:Service)里面,我描述了 Service 的主要用途,其中一个用途就是多实例负载均衡,那么,怎么启动多实例呢?很简单,如果根据之前了解过的知识的话,那不是可以简单地通过创建多个 Pod 来实现吗?这是一个很正常的想法,事实上也是推荐这么做的,就是运行多个 Pod。

但是,至于怎么运行多个 Pod 是个有技巧的活,因为如果是你手动启动多个 Pod 的话,那么还需要保持 Pod 的健康和异常恢复等问题,于是乎 Kubernetes 内置提供了解决方案,对于 Pod 的一些操作可以由内置的一些所谓的 Controller 来解决。

ReplicationController

假设如果你要创建一个 3 实例的应用,用来供用户访问,那么你可以尝试一下 ReplicationController,通过它,你可以简单地通过一个 YAML 配置文件就稳定得运行你想要的 Pod 实例个数,例如我这里运行一个简单的应用,它的作用也很简单,就是打印出它自己实例的 ID 标示:

[[email protected]]# cat 01-replication-controller.yaml 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: simple-pod-rc
spec:
  replicas: 3
  template:
    metadata:
      name: simple-pod
      labels:
        app: simple-pod
    spec:
      containers:
        - image: lukelau/rest-docker:0.0.1
          name: timemachine
          args:
            - -server.addr=0.0.0.0:8080

那么这里我们要认识的第三种 Resource 出现了,那就是 ReplicationController,它的作用就是维护 Pod 的数量如资源所定义的那样,例如我这里定义的是 3 个,那么它就会确保我们的 Pod 的数量就是稳定是 3 个。那么我们怎么着也得验证一下是吧,下面我就来操作一波:

[[email protected]]# kubectl apply -f 01-replication-controller.yaml
[[email protected]]# kubectl  get pods
NAME                  READY   STATUS    RESTARTS   AGE
simple-pod-rc-2xsgp   1/1     Running   0          10s
simple-pod-rc-gjxpt   1/1     Running   0          19s
simple-pod-rc-q2g6g   1/1     Running   0          30s
[[email protected]]# kubectl delete pods simple-pod-rc-q2g6g
pod "simple-pod-rc-q2g6g" deleted
[[email protected]]# kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
simple-pod-rc-2xsgp   1/1     Running   0          59s
simple-pod-rc-gjxpt   1/1     Running   0          68s
simple-pod-rc-lx6wh   1/1     Running   0          4s

从这里可以发现,当我们删除掉一个 Pod 之后,很快 ReplicationController 就帮助我们创建出了一个新的 Pod 来维持 Pod 的数量,那么这里问题就来了,ReplicationController 是如何知道我们的 Pod 已经被删除了呢?难道是去查看 K8S 的资源列表看对应的 Pod 在不在?或者状态是不是 Running 的?那如果我们的应用内部卡死了怎么办?岂不是很没有保障。

事实上,RC 之所以会发现我们的 Pod 已经挂掉了是因为有探针的存在,在 Kubernetes 中,kubelet 会通过指定的探针方式去探测容器是否存活,当前最新版本中(1.15),有三种探针方式,分别是:

所以当你的 Pod 的健康探针探测发现 Pod 的不健康的次数超过设定的次数的时候,那么 RC 就会将这个有问题的 Pod 删除(没有 restart 操作),然后再创建出一个新的出来;同样的,并不是只有健康检查不通过才会进行 Pod 操作,从我前面的操作演示中可以发现,其实 RC 还会检测 Pod 的当前数量,如果 Pod 的数量不足 replicas,那么也会创建出新的;如果 Pod 的数量超过 replicas,那么也会被关掉一些,从而符合 replicas 的设置。

ReplicaSet

这里你可能会稍微奇怪一下,为什么文章的标题叫 ReplicaSet 而上来就先说 ReplicationController 呢?原因是其实这两种资源本质上是一致的,根据 Kubernetes 的文档介绍,它们没有太大区别,细微的区别之处在于 ReplicaSet 的 Selector 会比 ReplicationController 要强大一些,例如从这个例子中可以看到:

[[email protected]]# cat 01-replication-controller.yaml 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: simple-pod-rc
spec:
  replicas: 3
  template:
    metadata:
      name: simple-pod
      labels:
        app: simple-pod
    spec:
      containers:
        - image: lukelau/rest-docker:0.0.1
          name: timemachine
          args:
            - -server.addr=0.0.0.0:8080

只有一个简单的 Labels 的选择:app: simple-pod,但是,通过 ReplicaSet 选择就变得多样化起来了,这个对应的 ReplicaSet 是这样的:

[[email protected]]# cat 02-replicaset.yaml 
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: simple-pod-rc
spec:
  selector:
    matchLabels:
      app: simple-pod
  replicas: 3
  template:
    metadata:
      name: simple-pod
      labels:
        app: simple-pod
    spec:
      containers:
        - image: lukelau/rest-docker:0.0.1
          name: timemachine
          args:
            - -server.addr=0.0.0.0:8080

可以发现,这里的 selector 变得稍微有点复杂了,除了可以 matchLabels 之外,还支持 matchExpressions,所以这算是一种改进;通过这两种对比,可能在大多数情况下你都会选择 ReplicationController,但是,接下来要介绍的一个资源 Deployment 已经将内置的 replicas 集从 ReplicationController 转成 ReplicaSet 了,所以很多地方都会推荐你使用 ReplicaSet,不要再使用 ReplicationController 了。