---
vssueId: 107
description: Kubernetes升级1.16.x。本文描述了如何从 kubernetes v1.15.x（或1.16.x）升级到 Kubernetes v1.16.y，前提是，您的 Kubernetes 集群是使用 kubeadm 安装的。
meta:
  - name: keywords
    content: Kubernetes升级,K8S升级,升级Kuberentes1.16.x,Kubernetes升级到1.16
---

# Kubernetes高危漏洞及解决办法（CVE-2019-11253）
<!-- # K8S从1.15.x(1.16.x)升级到 1.16.x -->

<AdSenseTitle/>

参考文档： kubernetes 官网文档 [kubeadm upgrade](https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-upgrade/)

**【漏洞详情】**

2019年10月17日，Kubernetes发布漏洞公告 [[ANNOUNCE] CVE-2019-11253: denial of service vulnerability from malicious YAML or JSON payloads](https://discuss.kubernetes.io/t/announce-cve-2019-11253-denial-of-service-vulnerability-from-malicious-yaml-or-json-payloads/8349)。具备一定权限的攻击者通过发送恶意的 YAML 或 JSON 格式的攻击包可导致 kube-apiserver CPU 或内存资源耗尽，无法正常提供服务，1.14.0 之前的版本由于默认RBAC策略允许匿名用户提交请求，所以之前的版本均在影响范围。

【风险等级】

<font color="red" weight="500">高风险</font>

【影响版本】
* Kubernetes v1.0.0-1.12.x
* Kubernetes v1.13.0-1.13.11（v1.13.12版本已修复）
* Kubernetes v1.14.0-1.14.7（v1.14.8版本已修复）
* Kubernetes v1.15.0-1.15.4（v1.15.5版本已修复）
* Kubernetes v1.16.0-1.16.1（v1.16.2版本已修复）

【安全版本】
* Kubernetes v1.13.12
* Kubernetes v1.14.8
* Kubernetes v1.15.5
* Kubernetes v1.16.2

【修复建议】

请升级到对应的【安全版本】。本文提供了如何升级到 1.16.2 的方法。另可参考 [K8S从1.15.x升级到 1.15.5](./1.15.x-1.15.4.html)

本文描述了如何从 kubernetes v1.15.x（或1.16.x）升级到 Kubernetes v1.16.y，前提是，您的 Kubernetes 集群是使用 kubeadm 安装的。

升级的高阶过程如下所示：

1. 升级主 master 节点
2. 升级从 master 节点
3. 升级 worker 节点

## 预备工作

* 请确保您的 Kubernetes 集群是通过 kubeadm 安装的，且版本号不低于 1.15.0
* swap 已禁用（如果您参考 www.kuboard.cn 上的文档安装，swap已禁用）
* 集群使用静态Pod（apiserver、etcd）或者使用外部 etcd（如果您参考 www.kuboard.cn 上的文档安装，则您的集群符合此条件）
* 确保您备份了重要的信息，例如应用程序的数据库，部署配置信息等。`kubeadm upgrade` 在升级过程中并不涉及到部署在 Kubernetes 上应用程序，而是只升级 Kubernetes 的内部组件，尽管如此，备份始终是推荐的

::: tip
* 升级后，所有的容器都会重启，因为升级改变了容器定义的 hash 值
* 只能从一个小版本升级到下一个小版本，或者在小版本内部升级补丁版本，不能跳过小版本升级。例如，您可以从 1.15.0 升级到 1.15.4，也可以从 1.15.0 升级到 1.16.1，但是您不能从 1.14.9 升级到 1.16.0
:::

## 确定当前版本

在 CentOS 上执行：
``` sh
yum list --showduplicates kubeadm --disableexcludes=kubernetes
# 在列表中找到最新的 1.16 版本号
# 该版本号格式为 1.16.x-0，其中 x 是最新的补丁
```

## 升级 master 节点

### 升级第一个 master 节点

假设所有命令都以 root 身份执行

* 在第一个 master 节点上执行如下命令，升级 kubeadm
  ``` sh
  # 将 1.16.x-0 中的 x 替换为最新的补丁版本
  yum install -y kubeadm-1.16.x-0 --disableexcludes=kubernetes
  ```
  执行命令 `kubeadm version`，以验证升级结果

  ::: danger 替换 1.16.x 中的 x
  本文中，所有碰到 1.16.x 的地方，都要将其中的 x 替换为您前面查询到的最新补丁号
  :::

* 在第一个 master 节点上执行命令 `kubeadm upgrade plan`，输出结果如下所示：

  ``` {9,24,25,26,27,28,29}
  [upgrade/config] Making sure the configuration is correct:
  [upgrade/config] Reading configuration from the cluster...
  [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
  [preflight] Running pre-flight checks.
  [upgrade] Making sure the cluster is healthy:
  [upgrade] Fetching available versions to upgrade to
  [upgrade/versions] Cluster version: v1.15.4
  [upgrade/versions] kubeadm version: v1.16.0
  W1002 21:49:38.572516   14315 version.go:101] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable.txt": Get https://dl.k8s.io/release/stable.txt: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
  W1002 21:49:38.572555   14315 version.go:102] falling back to the local client version: v1.16.0
  [upgrade/versions] Latest stable version: v1.16.0
  W1002 21:49:48.655494   14315 version.go:101] could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable-1.15.txt": Get https://dl.k8s.io/release/stable-1.15.txt: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
  W1002 21:49:48.655532   14315 version.go:102] falling back to the local client version: v1.16.0
  [upgrade/versions] Latest version in the v1.15 series: v1.16.0

  Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
  COMPONENT   CURRENT       AVAILABLE
  Kubelet     1 x v1.15.3   v1.16.0
              3 x v1.15.4   v1.16.0

  Upgrade to the latest version in the v1.15 series:

  COMPONENT            CURRENT   AVAILABLE
  API Server           v1.15.4   v1.16.0
  Controller Manager   v1.15.4   v1.16.0
  Scheduler            v1.15.4   v1.16.0
  Kube Proxy           v1.15.4   v1.16.0
  CoreDNS              1.3.1     1.6.2
  Etcd                 3.3.10    3.3.15-0

  You can now apply the upgrade by executing the following command:

          kubeadm upgrade apply v1.16.0

  _____________________________________________________________________
  ```

  ::: tip
  * 请忽略错误 `could not fetch a Kubernetes version from the internet: unable to get URL "https://dl.k8s.io/release/stable.txt"`，在不能获得最新 kubernetes 版本列表的情况下，将使用 kubeadm 的版本作为升级的目标版本（在前面的步骤中，已经从 yum 仓库找到了最新 kubeadm 的版本）
  :::

* 执行如下命令以升级：

  ``` sh
  # 替换 x 为最新补丁的版本号
  kubeadm upgrade apply v1.16.x
  ```
  ::: tip
  * `kubeadm upgrade` 同时会自动更新节点上的证书。如果不想更新证书，请使用参数 `--certificate-renewal=false`
  :::

  输出信息如下所示：
  ``` {11}
  [upgrade/config] Making sure the configuration is correct:
  [upgrade/config] Reading configuration from the cluster...
  [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
  [preflight] Running pre-flight checks.
  [upgrade] Making sure the cluster is healthy:
  [upgrade/version] You have chosen to change the cluster version to "v1.16.0"
  [upgrade/versions] Cluster version: v1.15.4
  [upgrade/versions] kubeadm version: v1.16.0
  [upgrade/confirm] Are you sure you want to proceed with the upgrade? [y/N]: y
  [upgrade/prepull] Will prepull images for components [kube-apiserver kube-controller-manager kube-scheduler etcd]
  ...省略部分内容以节省篇幅...
  [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
  [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
  [addons] Applied essential addon: CoreDNS
  [addons] Applied essential addon: kube-proxy

  [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.16.0". Enjoy!

  [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
  ```

<!-- * 手动升级CNI插件 -->

### 升级其他 master 节点

* 在其他 master 节点上执行命令

  ``` sh
  kubeadm upgrade node
  ```
  ::: tip
  * 不需要执行 `kubeadm upgrade plan`
  * 第一个 master 节点上执行的是 `kubeadm upgrade apply v1.16.x`，此时执行的是 `kubeadm upgrade node`
  :::

### 升级 kubelet 和 kubectl

* 在所有的 master 节点上执行如下命令以升级 kubelet 和 kubectl

  ``` sh
  # 替换 x 为最新补丁的版本号
  yum install -y kubelet-1.16.x-0 kubectl-1.16.x-0 --disableexcludes=kubernetes
  ```

* 执行如下命令，以重启 kubelet

  ``` sh
  systemctl daemon-reload
  systemctl restart kubelet
  ```

## 升级 worker 节点

建议逐个升级 worker 节点，或者同一时间点只升级少量的 worker 节点，以避免集群出现资源紧缺的状况。

### 升级 kubeadm

* 在所有的 worker 节点上执行如下命令，升级 kubeadm
  ``` sh
  # 将 1.16.x-0 中的 x 替换为最新的补丁版本
  yum install -y kubeadm-1.16.x-0 --disableexcludes=kubernetes
  ```

### 排空（drain）节点

* 执行以下命令，将节点标记为 `不可调度的` 并驱逐节点上所有的 Pod，

  ``` sh
  # 在可以执行 kubectl 命令的位置执行（通常是第一个 master节点）
  # $NODE 代表一个变量，实际执行时，请用您的节点名替换
  kubectl drain $NODE --ignore-daemonsets
  ```

  输出结果如下所示：

  ```
  node/ip-172-31-85-18 cordoned
  WARNING: ignoring DaemonSet-managed Pods: kube-system/kube-proxy-dj7d7, kube-system/weave-net-z65qx
  node/ip-172-31-85-18 drained
  ```

### 升级 kubelet 的配置

* 执行命令
  ``` sh
  kubeadm upgrade node
  ```

### 升级 kubelet 和 kubectl

* 在所有的 worker 节点执行命令

  ``` sh
  # 替换 x 为最新补丁的版本号
  yum install -y kubelet-1.16.x-0 kubectl-1.16.x-0 --disableexcludes=kubernetes
  ```

* 执行如下命令，以重启 kubelet

  ``` sh
  systemctl daemon-reload
  systemctl restart kubelet
  ```

### 恢复（uncordon）节点

* 执行如下命令，使节点重新接受调度并投入使用：

  ``` sh
  kubectl uncordon $NODE
  ```

## 检查集群的状态

在所有节点的 kubelet 本升级以后，执行如下命令以验证所有节点都可用：

``` sh
kubectl get nodes -o wide
```

`STATUS` 字段应该为 `Ready`，版本号也应该显示目标版本号。

## 从错误状态中恢复

如果 `kubeadm upgrade` 执行过程中出现错误且未曾回滚，例如执行过程中意外关机，您可以再次执行 `kubeadm upgrade`。该命令是 [幂等](glossary/idempotent.html) 的，并将最终保证您能够达到最终期望的升级结果。

从失败状态中恢复时，请执行 `kubeadm upgrade --force` 命令，注意要使用集群的当前版本号。

## 工作过程

在第一个 master 节点上，`kubeadm upgrade apply` 执行了如下操作：
* 检查集群是否处于可升级的状态：
  * API Server 可以调用
  * 所有的节点处于 `Ready` 装填
  * master 节点处于 `healthy` 状态
* 检验是否可以从当前版本升级到目标版本
* 确保 master 节点所需要的镜像可以被抓取到节点上
* 升级 master 节点的组件，（如果碰到问题，则回滚）
* 应用新的 `kube-dns` 和 `kube-proxy` 的 manifests 文件，并确保需要的 RBAC 规则被创建
* 如果证书在 180 天内将要过期，则为 API Server 创建新的证书文件，并备份旧的文件

在其他 master 节点上，`kubeadm upgrade node` 执行了如下操作：
* 从集群中抓取 kubeadm 的配置信息 `ClusterConfiguration`
* 备份 kube-apiserver 的证书
* 升级 master 节点上静态组件的 manifest 信息
* 升级 master 节点上 kubelet 的配置信息

在所有的 worker 节点上，`kubeadm upgrade node` 执行了如下操作：
* 从集群中抓取 kubeadm 的配置信息 `ClusterConfiguration`
* 升级 worker 节点上 kubelet 的配置信息
