# Kubernetes 1.10 的秘宝

原文：[Kubernetes 1.10: Hidden Gems](https://blog.jetstack.io/blog/hidden-gems-1.10/)

Kubernetes 发布了 1.10 版本。这是各位贡献者和发布团队的的又一次胜利。

在 Jetstack，无论是为客户服务的 K8S 项目、或是为各级别的用户提供 K8S 培训，又或者向 K8S 社区贡献我们开发的代码，都有着同样的目的，就是将 Kubernetes 推向巅峰。我们一直在跟进这一杰出项目，并保持对其开发过程密切关注。

[官方博客（注 1）](http://blog.kubernetes.io/2018/03/kubernetes-1.10-stabilizing-storage-security-networking.html)中介绍了 1.10 版本中的关键特性，按照以往惯例，我们请我们的工程师分享一下他们在新版本中发现的令人激动、期待的新功能。

## 设备插件

> Matt Turner

设备插件系统现在进入了 Beta 阶段。这一能力可以用附加的任意维度来定义节点的容量，不再只限于 CPU 和内存容量。例如一个节点可能会申明其装有三块 GPU 以及一块高性能网卡；Pod 通过标准的`resources`方式来申请 1 块 GPU，因此该 Pod 必须调度到一个具有空闲 GPU 的节点上。这一插件及其 API 会在为 Pod 提供使用之前，会对这些资源进行初始化和广播。

nVidia 已经提供了一个用于管理自家 GPU 的插件。请求两块 GPU 的语句如下：

~~~yaml
resources:
    limits:
      nvidia.com/gpu: 2
~~~

## CoreDNS

> Charlie Egan

1.10 把 KubeDNS 变成了一个可插接组件。这样就能够更方便的使用其他工具来进行服务发现。其中的一个选项就是 CoreDNS，CoreDNS 使用一个原生插件实现了 Kubernetes 服务发现规范。他是一个单进程应用，支持缓存和健康检查（这样就无需在 DNS Pod 中使用 dnsmasq 或者是 healthz 容器了）。CoreDNS 插件在 1.10 中提升到了 Beta 阶段，最终会成为 Kubernetes 的缺省选项。

## 每 Pod 中的 Pid 数量限制

[1.10 中的一个新的 Alpha 特性（注 2）](https://github.com/kubernetes/kubernetes/pull/57973)就是控制每 Pod 中 Pid 总数的能力。Linux 核心提供了[进程数控制器](https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt)，可以附着在 cgroup 上，在超出特定限制时停止所有新建任务。现在这一核心功能暴露给了集群运维，能够有效的避免一些恶意的或者意外造成的 Fork 炸弹对集群产生不良影响。

在 kubelet 的`--feature-gates=`参数中加入`SupportPodPidsLimit=true`，就激活了这一功能。目前只允许运维通过 kubelet 的`--pod-max-pids`参数来给每节点定义一个简单的上限数量。可能这种硬性限制并不适用于所有场景，在一些情况下会需要超过这一限制。未来也许会让这一选项更具弹性；一个可能的扩展方式就是制定一个上限和下限，让用户在 Pod 中使用一个布尔字段来选择限制。

这一功能为工作负载提供了一种新的重要的隔离机制，他的后续发展让人非常期待。

> Louis Taylor

1.10 加入了共享进程命名空间的 Alpha 支持。要试用这一特性，需要在 apiserver 以及 kubelet 中启用`PodShareProcessNamespace`。启用之后就可以在 Pod 中设置`shareProcessNamespace`：

~~~yaml
apiVersion: v1
kind: Pod
metadata:
  name: shared-pid
spec:
  shareProcessNamespace: true
...
~~~

在 Pod 内共享 PID 命名空间有一些后果。最重要的是，在容器内的进程，对同一 Pod 内的其他所有容器是可见的，并且可以跨越容器边界向进程发送信号。这使得 Sidecar 容器更加强大（例如发送一个`SIGHUP`来重新载入配置）。

> Josh Van Leeuwen

1.10 中多出一些 Alpha 特性，其中包含了 [CRD 的子资源（注 4）](https://github.com/kubernetes/kubernetes/pull/55168)，分别是`/status`和`/scale`。和其他资源一样，他们提供了独立的 API 端点来修改内容。不但你的资源现在可以和`HorizontalPodAutoscaler`这样的系统进行交互，而且还给用户和控制器状态数据提供了更好的访问控制能力。例如控制器具备的对资源状态的变更和销毁能力就可以不分配给用户。

为 CRD 加入`/status`和`/scale`，只要加入如下代码：

~~~yaml
subresources:
  status: {}
  scale:
    specReplicasPath: .spec.replicas
    statusReplicasPath: .status.replicas
    labelSelectorPath: .status.labelSelector
~~~

## 外部自定义指标

> Matt Bates

第一个版本的 HPA（v1）只能基于对 CPU 使用率的监控进行。虽然有用，但是 CPU 并不总是应用伸缩的唯一标准。Kubernetes 1.6 中加入的 HPA v2，可以用自定义指标进行伸缩。我们在 [Kubernetes 1.8 的博客（注 5）](https://blog.jetstack.io/blog/resource-and-custom-metrics-hpa-v2/)中介绍了关于资源指标 API、自定义指标 API、以及 HPA v2 的相关内容。

自定义指标能够描述来自受 HPA 关注的 Pod 的指标，包括资源（CPU、内存）或者对象（服务或者 Ingress）。但是这些选项对于集群之外的基础设施层面是不适用的。最近的客户接触中，就收到了根据 Google 云发布/订阅队列长度进行伸缩的需要。

1.10 中，现在有了一个 Alpha 阶段的 HPA v2 API，用于支持外部指标。例如上述的根据发布/订阅队列长度进行伸缩的需求大概可以这样实现：

~~~yaml
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta2
spec:
  scaleTargetRef:
    kind: ReplicationController
    name: Worker
  minReplicas: 2
  maxReplicas: 10
  metrics:
   - type: External
     external:
       metricName: queue_messages_ready
       metricSelector:
         matchLabels:
           queue: worker_tasks
       targetAverageValue: 30
~~~

HPA 需要一个附加的 API Server，注册为`APIService`，并通过查询发布订阅队列，实现自定义指标 API。

## kubectl `get`和`describe`输出的自定义

> James Munnelly

Kubernetes 1.10 的`kubectl get`和`kubectl describe`的输出生成过程有了一个很小很重要的变化。

过去，[Cert-Manager（注 6）](https://github.com/jetstack/cert-manager)或者 [Navigator（注 7）](https://github.com/jetstack/navigator)这样的第三方 Kubernetes 扩展总会显示一些这样的信息：

~~~bash
$ kubectl get certificates
NAME        AGE
prod-tls    4h
~~~

然而现在的版本中，可以通过对扩展的配置来展示更多有用的信息，例如：

~~~bash
$ kubectl get certificates
NAME        STATUS    EXPIRY        ISSUER
prod-tls    Valid     2018-05-03    letsencrypt-prod

$ kubectl get elasticsearchclusters
NAME       HEALTH    LEADERS    DATA    INGEST
logging    Green     3/3        4/4     2/2
~~~

这样给 API 扩展带来一种原生的风格，让用户能够快速的获取有意义的数据。

## 卷调度和本地存储

> Richard Wall

新版本中，我们很高兴地看到[本地存储升级到 Beta 阶段（注 8）](https://github.com/kubernetes/kubernetes/pull/59391)，并且[缺省启用了卷调度（注 8）](https://github.com/kubernetes/kubernetes/pull/59391)。

相关的 API 发生了一些变化：

1. [PV（注 9）](https://kubernetes.io/docs/concepts/storage/volumes/#local)加入了`PersistentVolume.Spec.NodeAffinity`字段，其中应包含本地节点的主机名。
2. [StorageClass（注 10）](https://kubernetes.io/docs/concepts/storage/storage-classes/#local)新增了`StorageClass.volumeBindingMode: WaitForFirstConsumer`选项，要求 Kubernetes 等到 Pod 和 PV 成功完成调度规划之后才进行绑定。

[在 Kubernetes 集群中使用 Navigator 管理 Cassandra 数据库（注 11）](https://github.com/jetstack/navigator/)就使用这一特性。如果为每个可用的 SSD 加入一个 PV，并且如果 PV 设置了必要的节点亲和性，Kubernetes 会综合 PV 的调度决策，来确定把 Pod 分配到具有未使用 SSD 的节点上去。我们会就这个话题另外写一篇博客。

另外我还要推荐阅读 [Provisioning Kubernetes Local Persistent Volumes（注 12）](https://engineering.salesforce.com/provisioning-kubernetes-local-persistent-volumes-61a82d1d06b0)，本文描述了一种利用 DaemonSet 自动发现和准备本地卷的优雅方式，以及[local PV provisioner（注 13）](https://github.com/kubernetes-incubator/external-storage/tree/master/local-volume)。

1. `http://blog.kubernetes.io/2018/03/kubernetes-1.10-stabilizing-storage-security-networking.html`
2. `https://github.com/kubernetes/kubernetes/pull/57973`
3. `https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt`
4. `https://github.com/kubernetes/kubernetes/pull/55168`
5. `https://blog.jetstack.io/blog/resource-and-custom-metrics-hpa-v2/`
6. `https://github.com/jetstack/cert-manager`
7. `https://github.com/jetstack/navigator`
8. `https://github.com/kubernetes/kubernetes/pull/59391`
9. `https://kubernetes.io/docs/concepts/storage/volumes/#local`
10. `https://kubernetes.io/docs/concepts/storage/storage-classes/#local`
11. `https://github.com/jetstack/navigator/`
12. `https://engineering.salesforce.com/provisioning-kubernetes-local-persistent-volumes-61a82d1d06b0`
13. `https://github.com/kubernetes-incubator/external-storage/tree/master/local-volume`
