# ReplicationController

ReplicationController顾名思义，可以用来创建Pod的多副本，并且被该Controller接管的Pod，当Node出现故障时，该Pod会随之挂掉，此时ReplicationController会检测到，并且重新调度到新的Node上创建。

ReplicationController的工作时确保**Pod的数量**始终与**其标签选择器匹配**，若不匹配，则其会根据所需，调整Pod的数量。

![ReplicationController对于Pod数量的协调方式](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2F514740dc0ba6ca2ffeb07f22a1f242054e150880.png?generation=1588594610395895\&alt=media)

从上面图可以看出，ReplicationController是根据Pod的标签进行匹配的，会根据标签决定当前被接管的Pod的数量。

{% hint style="info" %}
**Tips：**&#x52;eplicationController的标签选择器，只能够匹配一个或多个包含特定标签的Pod，例如只匹配带有`env=devel`或`env=production`的Pod（这两个标签的键都是`env`），而不能同时匹配`env=devel`和`env=production`的Pod。这也是为什么现在被ReplicaSet取代的原因。
{% endhint %}

## 创建ReplicationController

使用YAML配置文件创建该资源，在该资源文件中，需要关注的主要有以下三个部分：

* `spec.replicas`：Pod实例的副本数；
* `spec.selector`：标签选择器，决定匹配的带有哪些标签的Pod。相同键的多组标签只能匹配其中一组，比如有`env=test`和`env=prod`，只能匹配其中一组；
* `spec.template`：创建新Pod所用的模板；

下面展示一个具体的例子：

```yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: kubia
spec:
  replicas: 3    # 副本数，Pod的个数
  selector:    # 标签选择器，用来决定RC管理的Pod（相同键的多组标签只能匹配其中一组）
    app: kubia
    env: test
  template:    # 创建新Pod的模板（为什么说新的，是因为如果RC是根据标签选择Pod的，如果当前已经有app: kubia的4个Pod，那么这个RC不会创建，反而会删掉1个，因为它的副本数是3）
    metadata:
      labels:
        app: kubia    # pod的标签一定要与RC的选择器一致，否则RC将无休止的创建新的容器
    spec:
      containers:
      - name: kubia
        image: luksa/kubia
        ports:
        - containerPort: 8080
```

通过`kubectl get rc`可以看到创建出来的RC资源的名字为`kubia`，再通过`kubectl get pods`可以看到创建出来的Pods的名字为`kubia-xxxx`（xxxx为自动生成的值）。

## 删除ReplicationController

### 同时删除接管的Pod

直接使用`kubectl delete`不仅仅会删除RC，同时会删除被其接管的Pod。例如删除名为kubia这个RC：

```bash
kubectl delete rc kubia
```

### 不删除接管的Pod

加上`--cascade=false`可以在删除RC的同时，不删除被其接管的Pod。例如删除名为kubia这个RC的同时，不删除被其接管的Pod：

```bash
kubectl delete rc kubia --cascase=false
```

## 将Pod移入或移出ReplicationController的作用域

由于ReplicationController是通过`spec.selector`即标签选择器决定接管的Pod的，因此可以通过更改Pod的`metadata.labels`的方式，将Pod移入或移出ReplicationController的作用域。

修改Pod的标签的方式，可以参考[**标签**](https://yangsijie151104.gitbook.io/k8s-note/pod/4.pod/biao-qian)章节中的**修改Pod标签**一节中的方式。

## 水平缩放

可以通过三种方式更新：

1. 修改RC的YAML配置文件中的`spec.replicas`字段：
   * 通过`kubectl edit`命令在线修改RC的YAML配置文件；
   * 直接修改RC的配置文件，然后通过`kubectl apply -f`使之生效；
2. 通过`kubectl scale`命令修改。例如将kubia这个RC的副本数调整为10：

   ```bash
    kubectl scale rc kubia --replicas=10
   ```

水平缩放是**声明式**的，即告诉Kubernetes目标副本数为x，而不告诉它该如何做，只是指定期望状态。

## 滚动更新

{% hint style="danger" %}
使用ReplicationController配合`rolling-update`对应用程序进行滚动升级的方式已经过时了，请不要使用！！！

请使用[**Deployment**](https://yangsijie151104.gitbook.io/k8s-note/kong-zhi-qi-controllers/controllers/deployment)，配合`rollout`对应用程序进行滚动升级！！！
{% endhint %}

可以使用`kubectl rolling-update`命令，令RC进行滚动升级。例如，需要升级的RC为`kubia-v1`，升级后的RC为`kubia-v2`，将容器镜像替换为`luksa/kubia:v2`：

```bash
kubectl rolling-update kubia-v1 kubia-v2 --image=luksa/kubia:v2
```

{% hint style="info" %}
**Tips:**&#x20;

1. 可以使用`--help`查看可更新的条目；
2. 可以加上`--v 6`，提高日志级别，可以使得所有kubectl发起到API服务器的请求都会被输出；
   {% endhint %}

输出结果为：

```
Command "rolling-update" is deprecated, use "rollout" instead
Created kubia-v2
Scaling up kubia-v2 from 0 to 3, scaling down kubia-v1 from 3 to 0 (keep 3 pods available, don't exceed 4 pods)
Scaling kubia-v2 up to 1
Scaling kubia-v1 down to 2
Scaling kubia-v2 up to 2
Scaling kubia-v1 down to 1
Scaling kubia-v2 up to 3
Scaling kubia-v1 down to 0
Update succeeded. Deleting kubia-v1
replicationcontroller/kubia-v2 rolling updated to "kubia-v2"
```

从输出可以看到滚动更新过程中，正在运行的Pod数量最大为4个，并且创建了一个新的RC`kubia-v2`来接管新的Pod，并且通过交替对`kubia-v1`缩容，对`kubia-v2`扩容的方式达成滚动升级的功能。在更新完成后，会删除旧的RC`kubia-v1`。可以用下图表示：

![ReplicationController更新过程](https://2906552408-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M6Ub8CloS5kJszh6xSR%2Fsync%2F76c98474249d28db412221e2ff009917b38912cc.png?generation=1588594610902545\&alt=media)

从上图中也可以看到，在更新的过程中，`rolling-update`为区分新旧RC和它们接管的Pod，会为新旧Pod添加上**键为deployment的标签**，同时为新旧RC添加相应的标签选择器（这也是为什么这种更新方式会被废弃的原因之一）。由于新旧Pod都有`app=kubia`这个标签，而Service只匹配这个标签，所以在更新的过程中，客户端发起的请求会被无缝切换至新Pod上。

### 废弃原因

使用`kubectl rolling-upgrade`进行更新被废弃的原因有三个：

1. 更新的过程中，会直接修改RC和Pod资源对象：为新旧RC添加新的标签选择器，为新旧Pod添加新的标签；
2. 新旧RC的扩缩容的请求都是由kubectl客户端发起的，而不是Kubernetes的API服务器，因此若中途产生网络中断，会导致更新过程中断；

   使用`--v 6`可以看到kubectl的日志信息，从中可以发现针对下面两个路径的访问请求：

   ```bash
    /api/v1/namespaces/default/replicationcontrollers/kubia-v1/scale
    /api/v1/namespaces/default/replicationcontrollers/kubia-v2/scale
   ```

   即每次针对新旧RC扩缩容的操作，都是由kubectl向API服务器发起的，类似于平时写的脚本实现的自动化扩缩容。
3. 需要创建新的RC来负责接管新的Pods；
