cn-translation-from-2017-08-14-to-2017-09-03 (#5364)
parent
7eb3fa9f2e
commit
fdbe5086a0
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
approvers:
|
||||
- dchen1107
|
||||
- roberthbailey
|
||||
- liggitt
|
||||
|
||||
title: Master 节点通信
|
||||
---
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## 概览
|
||||
|
||||
|
||||
本文对 Master 节点(确切说是 apiserver)和 Kubernetes 集群之间的通信路径进行了分类。目的是为了让用户能够自定义他们的安装,对网络配置进行加固,使得集群能够在不可信的网络上(或者在一个云服务商完全公共的 IP 上)运行。
|
||||
|
||||
|
||||
## Cluster -> Master
|
||||
|
||||
|
||||
所有从集群到 master 的通信路径都终止于 apiserver(其它 master 组件没有被设计为可暴露远程服务)。在一个典型的部署中,apiserver 被配置为在一个安全的 HTTPS 端口(443)上监听远程连接并启用一种或多种形式的客户端[身份认证](/docs/admin/authentication/)机制。一种或多种客户端[身份认证](/docs/admin/authentication/)机制应该被启用,特别是在允许使用 [匿名请求](/docs/admin/authentication/#anonymous-requests) 或 [service account tokens](/docs/admin/authentication/#service-account-tokens) 的时候。
|
||||
|
||||
|
||||
应该使用集群的公共根证书开通节点,如此它们就能够基于有效的客户端凭据安全的连接 apiserver。例如:在一个默认的 GCE 部署中,客户端凭据以客户端证书的形式提供给 kubelet。请查看 [kubelet TLS bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 获取如何自动提供 kubelet 客户端证书。
|
||||
|
||||
|
||||
想要连接到 apiserver 的 Pods 可以使用一个 service account 安全的进行连接。这种情况下,当 Pods 被实例化时 Kubernetes 将自动的把公共根证书和一个有效的不记名令牌注入到 pod 里。`kubernetes` service (所有 namespaces 中)都配置了一个虚拟 IP 地址,用于转发(通过 kube-proxy)请求到 apiserver 的 HTTPS endpoint。
|
||||
|
||||
|
||||
Master 组件通过非安全(没有加密或认证)端口和集群的 apiserver 通信。这个端口通常只在 master 节点的 localhost 接口暴露,这样,所有在相同机器上运行的 master 组件就能和集群的 apiserver 通信。一段时间以后,master 组件将变为使用带身份认证和权限验证的安全端口(查看[#13598](https://github.com/kubernetes/kubernetes/issues/13598))。
|
||||
|
||||
|
||||
这样的结果使得从集群(在节点上运行的 nodes 和 pods)到 master 的缺省连接操作模式默认被保护,能够在不可信或公网中运行。
|
||||
|
||||
|
||||
## Master -> Cluster
|
||||
|
||||
|
||||
从 master(apiserver)到集群有两种主要的通信路径。第一种是从 apiserver 到集群中每个节点上运行的 kubelet 进程。第二种是从 apiserver 通过它的代理功能到任何 node、pod 或者 service。
|
||||
|
||||
|
||||
### apiserver -> kubelet
|
||||
|
||||
|
||||
从 apiserver 到 kubelet 的连接用于获取 pods 日志、连接(通过 kubectl)运行中的 pods,以及使用 kubele 的端口转发功能。这些连接终止于 kubelet 的 HTTPS endpoint。
|
||||
|
||||
|
||||
默认的,apiserver 不会验证 kubelet 的服务证书,这会导致连接遭到中间人攻击,因而在不可信或公共网络上是不安全的。
|
||||
|
||||
|
||||
为了对这个连接进行认证,请使用 `--kubelet-certificate-authority` 标记给 apiserver 提供一个根证书捆绑,用于 kubelet 的服务证书。
|
||||
|
||||
|
||||
如果这样不可能,又要求避免在不可信的或公共的网络上进行连接,请在 apiserver 和 kubelet 之间使用 [SSH 隧道](/docs/concepts/architecture/master-node-communication/#ssh-tunnels)。
|
||||
|
||||
|
||||
最后,应该启用[Kubelet 用户认证和/或权限认证](/docs/admin/kubelet-authentication-authorization/)来保护 kubelet API。
|
||||
|
||||
|
||||
### apiserver -> nodes, pods, and services
|
||||
|
||||
|
||||
从 apiserver 到 node、pod或者service 的连接默认为纯 HTTP 方式,因此既没有认证,也没有加密。他们能够通过给API URL 中的 node、pod 或 service 名称添加前缀 `https:` 来运行在安全的 HTTPS 连接上。但他们即不会认证 HTTPS endpoint 提供的证书,也不会提供客户端证书。这样虽然连接是加密的,但它不会提供任何完整性保证。这些连接**目前还不能安全的**在不可信的或公共的网络上运行。
|
||||
|
||||
|
||||
### SSH 隧道
|
||||
|
||||
|
||||
[Google Container Engine](https://cloud.google.com/container-engine/docs/) 使用 SSH 隧道保护 Master -> Cluster 通信路径。在这种配置下,apiserver 发起一个到集群中每个节点的 SSH 隧道(连接到在 22 端口监听的 ssh 服务)并通过这个隧道传输所有到 kubelet、node、pod 或者 service 的流量。这个隧道保证流量不会在集群运行的私有 GCE 网络之外暴露。
|
|
@ -0,0 +1,234 @@
|
|||
---
|
||||
assignees:
|
||||
- caesarxuchao
|
||||
- dchen1107
|
||||
|
||||
title: Nodes
|
||||
redirect_from:
|
||||
- "/docs/admin/node/"
|
||||
- "/docs/admin/node.html"
|
||||
- "/docs/concepts/nodes/node/"
|
||||
- "/docs/concepts/nodes/node.html"
|
||||
---
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## Node 是什么?
|
||||
|
||||
|
||||
`Node` 是 Kubernetes 的工作节点,以前叫做 `minion`。取决于你的集群,Node 可以是一个虚拟机或者物理机器。每个 node 都有用于运行 [pods](/docs/user-guide/pods) 的必要服务,并由 master 组件管理。Node 上的服务包括 Docker、kubelet 和 kube-proxy。请查阅架构设计文档中 [The Kubernetes Node](https://git.k8s.io/community/contributors/design-proposals/architecture.md#the-kubernetes-node) 一节获取更多细节。
|
||||
|
||||
|
||||
## Node 状态
|
||||
|
||||
|
||||
一个 node 的状态包含以下信息:
|
||||
|
||||
* [地址](#地址)
|
||||
* ~~[阶段](#阶段)~~ **已废弃**
|
||||
* [条件](#条件)
|
||||
* [容量](#容量)
|
||||
* [信息](#信息)
|
||||
|
||||
|
||||
下面对每个章节进行详细描述。
|
||||
|
||||
|
||||
### 地址
|
||||
|
||||
|
||||
这些字段组合的用法取决于你的云服务商或者裸金属配置。
|
||||
|
||||
* HostName:HostName 和 node 内核报告的相同。可以通过 kubelet 的 `--hostname-override` 参数覆盖。
|
||||
* ExternalIP:通常是可以外部路由的 node IP 地址(从集群外可访问)。
|
||||
* InternalIP:通常是仅可在集群内部路由的 node IP 地址。
|
||||
|
||||
|
||||
### 阶段
|
||||
|
||||
|
||||
一废弃:node 阶段已经不再使用。
|
||||
|
||||
|
||||
### 条件
|
||||
|
||||
|
||||
`conditions` 字段描述了所有 `Running` nodes 的状态。
|
||||
|
||||
|
||||
| Node 条件 | 描述 |
|
||||
| ---------------- | ---------------------------------------- |
|
||||
| `OutOfDisk` | `True` 表示 node 的空闲空间不足以用于添加新 pods, 否则为 `False` |
|
||||
| `Ready` | `True` 表示 node 是健康的并已经准备好接受 pods;`False` 表示 node 不健康而且不能接受 pods;`Unknown` 表示 node 控制器在最近 40 秒内没有收到 node 的消息 |
|
||||
| `MemoryPressure` | `True` 表示 node 不存在内存压力 -- 即 node 内存用量低, 否则为 `False` |
|
||||
| `DiskPressure` | `True` 表示 node 不存在磁盘压力 -- 即磁盘用量低, 否则为 `False` |
|
||||
|
||||
|
||||
Node 条件使用一个 JSON 对象表示。例如,下面的响应描述了一个健康的 node。
|
||||
|
||||
```json
|
||||
"conditions": [
|
||||
{
|
||||
"kind": "Ready",
|
||||
"status": "True"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
如果 Ready 条件处于状态 "Unknown" 或者 "False" 的时间超过了 `pod-eviction-timeout`(一个传递给 [kube-controller-manager](/docs/admin/kube-controller-manager/) 的参数),node 上的所有 Pods 都会被 Node 控制器计划删除。默认的删除超时时长为**5分钟**。某些情况下,当 node 不可访问时,apiserver 不能和其上的 kubelet 通信。删除 pods 的决定不能传达给 kubelet,直到它重新建立和 apiserver 的连接为止。与此同时,被计划删除的 pods 可能会继续在分区 node 上运行。
|
||||
|
||||
|
||||
在 1.5 版本之前的 Kubernetes 里,node 控制器会将不能访问的 pods 从 apiserver 中[强制删除](/docs/concepts/workloads/pods/pod/#force-deletion-of-pods)。但在 1.5 或更高的版本里,在node 控制器确认这些 pods 已经在集群里停运行前不会强制删除它们。你可以看到这些处于 "Terminating" 或者 "Unknown" 状态的 pods 可能在无法访问的 node 上运行。为了防止 kubernetes 不能从底层基础设施中推断出一个 node 是否已经永久的离开了集群,集群管理员可能需要手动删除这个 node 对象。从 Kubernetes 删除 node 对象将导致 apiserver 删除 node 上所有运行的 Pod 对象并释放它们的名字。
|
||||
|
||||
|
||||
### 容量
|
||||
|
||||
|
||||
描述 node 上的可用资源:CPU、内存和可以调度到 node 上的 pods 的最大数量。
|
||||
|
||||
|
||||
### 信息
|
||||
|
||||
|
||||
关于 node 的通用信息,例如内核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、Docker 版本 (如果使用了)和 OS 名。这些信息由 Kubelet 从 node 搜集而来。
|
||||
|
||||
|
||||
## 管理
|
||||
|
||||
|
||||
与 [pods](/docs/user-guide/pods) 和 [services](/docs/user-guide/services) 不同,node 并不是在 Kubernetes 内部创建的:它是被外部的云服务商创建,例如 Google Compute Engine 或者你的集群中的物理或者虚拟机。这意味着当 Kubernetes 创建一个 node 时,它其实仅仅创建了一个对象来代表这个 node。创建以后,Kubernetes 将检查这个 node 是否可用。例如,如果你尝试使用如下内容创建一个 node:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Node",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "10.240.79.157",
|
||||
"labels": {
|
||||
"name": "my-first-k8s-node"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Kubernetes 会在内部创一个 node 对象(象征 node),并基于 `metadata.name` 字段(我们假设 `metadata.name` 能够被解析)通过健康检查来验证 node。如果 node 可用,意即所有必要服务都已运行,它就符合了运行一个 pod 的条件;否则它将被所有的集群动作忽略指导变为可用。请注意,Kubernetes 将保存不可用 node 的对象,除非它被客户端显式的删除。Kubernetes 将持续检查 node 是否变的可用。
|
||||
|
||||
|
||||
当前,有3个组件同 Kubernetes node 接口交互:node 控制器、kubelet 和 kubectl。
|
||||
|
||||
|
||||
### Node 控制器
|
||||
|
||||
|
||||
Node 控制器是一个 Kubernetes master 组件,管理 nodes 的方方面面。
|
||||
|
||||
|
||||
Node 控制器在 node 的生命周期中扮演了多个角色。第一个是当 node 注册时为它分配一个 CIDR block(如果打开了 CIDR 分配)。
|
||||
|
||||
|
||||
第二个是使用云服务商提供了可用节点列表保持 node 控制器内部的 nodes 列表更新。如果在云环境下运行,任何时候当一个 node 不健康时 node 控制器将询问云服务 node 的虚拟机是否可用。如果不可用,node 控制器会将这个 node 从它的 nodes 列表删除。
|
||||
|
||||
|
||||
第三个是监控 nodes 的健康情况。Node 控制器负责在 node 不能访问时(也即是 node 控制器因为某些原因没有收到心跳,例如 node 宕机)将它的 NodeStatus 的 NodeReady 状态更新为 ConditionUnknown。后续如果 node 持续不可访问,Node 控制器将删除 node 上的所有 pods(使用优雅终止)。(默认情况下 40s 开始报告 ConditionUnknown,在那之后 5m 开始删除 pods。)Node 控制器每隔 `--node-monitor-period` 秒检查每个 node 的状态。
|
||||
|
||||
|
||||
在 Kubernetes 1.4 中我们更新了 node 控制器逻辑以更好的处理大批量 nodes 访问 master 出问题的情况(例如 master 的网络出了问题)。从 1.4 开始,node 控制器在决定删除 pod 之前会检查集群中所有 nodes 的状态。
|
||||
|
||||
|
||||
大部分情况下, node 控制器把删除频率限制在每秒 `--node-eviction-rate` 个(默认为 0.1)。这表示它在 10 秒钟内不会从超过一个 node 上删除 pods。
|
||||
|
||||
|
||||
当一个 availability zone 中的 node 变为不健康时,它的删除行为将发生改变。Node 控制器会同时检查 zone 中不健康(NodeReady 状态为 ConditionUnknown 或 ConditionFalse)的 nodes 的百分比。如果不健康 nodes 的部分超过 `--unhealthy-zone-threshold` (默认为 0.55),删除速率将会减小:如果集群较小(意即小于等于 `--large-cluster-size-threshold` 个 nodes - 默认为50),删除将会停止,否则删除速率将降为每秒 `--secondary-node-eviction-rate` 个(默认为 0.01)。在单个 availability zone 实施这些策略的原因是当一个 availability zone 可能从 master 分区时其它的仍然保持连接。如果你的集群没有跨越云服务商的多个 availability zones,那就只有一个 availability zone(整个集群)。
|
||||
|
||||
|
||||
在多个 availability zones 分布你的 nodes 的一个关键原因是当整个 zone 故障时,工作负载可以转移到健康的 zones。因此,如果一个 zone 中的所有 nodes 都不健康时,node 控制器会以正常的速率 `--node-eviction-rate` 删除。在所有的 zones 都不健康(也即集群中没有健康 node)的极端情况下,node 控制器将假设 master 的连接出了某些问题,它将停止所有删除动作直到一些连接恢复。
|
||||
|
||||
|
||||
从 Kubernetes 1.6 开始,NodeController 还负责删除运行在拥有 `NoExecute` taints 的 nodes 上的 pods,如果这些 pods 没有 tolerate 这些 taints。此外,作为一个默认禁用的 alpha 特性,NodeController 还负责根据 node 故障(例如 node 不可访问或没有 ready)添加 taints。请查看 [这个文档](/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature)了解关于 `NoExecute` taints 和这个 alpha 特性。
|
||||
|
||||
|
||||
### Nodes 自注册
|
||||
|
||||
|
||||
当 kubelet 标志 `--register-node` 为 true (默认)时,它会尝试向 API 服务注册自己。这是首选模式,被绝大多数发行版选用。
|
||||
|
||||
|
||||
对于自注册模式,kubelet 使用下列参数启动:
|
||||
|
||||
- `--api-servers` - apiservers 地址。
|
||||
- `--kubeconfig` - 用于向 apiserver 验证自己的凭据路径。
|
||||
- `--cloud-provider` - 如何从云服务商读取关于自己的元数据。
|
||||
- `--register-node` - 自动向 API 服务注册。
|
||||
- `--register-with-taints` - 使用 taints 列表(逗号分隔的 `<key>=<value>:<effect>`)注册 node。当 `register-node` 为 false 时无效。
|
||||
- `--node-ip` - node IP 地址。
|
||||
- `--node-labels` - 向集群注册时给 node 添加的 labels。
|
||||
- `--node-status-update-frequency` - 指定 kubelet 向 master 发送状态的频率。
|
||||
|
||||
|
||||
目前,任何 kubelet 都被授权可以创建/修改任意 node 资源,但通常只对自己的进行创建/修改。(未来我们计划只允许一个 kubelet 修改它自己 node 的资源。)
|
||||
|
||||
|
||||
#### 手动 Node 管理
|
||||
|
||||
|
||||
集群管理员可以创建及修改 node 对象。
|
||||
|
||||
|
||||
如果管理员希望手动创建 node 对象,请设置 kubelet 标记 `--register-node=false`。
|
||||
|
||||
|
||||
管理员可以修改 node 资源(忽略 `--register-node` 设置)。修改包括在 node 上设置 labels及标记它为不可调度。
|
||||
|
||||
|
||||
Nodes 上的 labels 可以和 pods 的 node selectors 一起使用来控制调度,例如限制一个 pod 只能在一个符合要求的 nodes 子集上运行。
|
||||
|
||||
|
||||
标记一个 node 为不可调度的将防止新建 pods 调度到那个 node 之上,但不会影响任何已经在它之上的 pods。这是重启 node 等操作之前的一个有用的准备步骤。例如,标记一个 node 为不可调度的,执行以下命令:
|
||||
|
||||
```shell
|
||||
kubectl cordon $NODENAME
|
||||
```
|
||||
|
||||
|
||||
请注意,被 daemonSet 控制器创建的 pods 将忽略 Kubernetes 调度器,且不会遵照 node 上不可调度的属性。这个假设基于守护程序属于节点机器,即使在准备重启而隔离应用的时候。
|
||||
|
||||
|
||||
### Node 容量
|
||||
|
||||
|
||||
Node 的容量(cpu 数量和内存容量)是 node 对象的一部分。通常情况下,在创建 node 对象时,它们会注册自己并报告自己的容量。如果你正在执行[手动 node 管理](#manual-node-administration),那么你需要在添加 node 时手动设置 node 容量。
|
||||
|
||||
|
||||
Kubernetes 调度器保证一个 node 上有足够的资源供其上的所有 pods 使用。它会检查 node 上所有容器要求的总和不会超过 node 的容量。这包括所有 kubelet 启动的容器,但不包含 Docker 启动的容器和不在容器中的进程。
|
||||
|
||||
|
||||
如果希望显式的为非 pod 进程预留资源,你可以创建一个占位 pod。使用如下模板:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: resource-reserver
|
||||
spec:
|
||||
containers:
|
||||
- name: sleep-forever
|
||||
image: gcr.io/google_containers/pause:0.8.0
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
```
|
||||
|
||||
|
||||
设置 `cpu` 和 `memory` 值为你希望预留的资源量。将文件放在清单文件夹中(kubelet 的 `--config=DIR` 标志)。当你希望预留资源时,在每个 kubelet 上都这样执行。
|
||||
|
||||
|
||||
## API 对象
|
||||
|
||||
|
||||
Node 是 Kubernetes REST API 的顶级资源。更多关于 API 对象的细节可以在这里找到: [Node API
|
||||
object](/docs/api-reference/{{page.version}}/#node-v1-core).``
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
|
||||
title: 安装扩展(Addons)
|
||||
---
|
||||
|
||||
|
||||
## 概览
|
||||
|
||||
|
||||
Add-ons 扩展了 Kubernetes 的功能。
|
||||
|
||||
|
||||
本文列举了一些可用的 add-ons 以及到它们各自安装说明的链接。
|
||||
|
||||
|
||||
每个 add-ons 按字母顺序排序 - 顺序不代表任何优先地位。
|
||||
|
||||
|
||||
## 网络和网络策略
|
||||
|
||||
|
||||
* [Calico](http://docs.projectcalico.org/latest/getting-started/kubernetes/installation/hosted/) 是一个安全的 L3 网络和网络策略提供者。
|
||||
* [Canal](https://github.com/tigera/canal/tree/master/k8s-install) 结合 Flannel 和 Calico, 提供网络和网络策略。
|
||||
* [Cilium](https://github.com/cilium/cilium) 是一个 L3 网络和网络策略插件, 能够透明的实施 HTTP/API/L7 策略。 同时支持路由(routing)和叠加/封装( overlay/encapsulation)模式。
|
||||
* [Contiv](http://contiv.github.io) 为多种用例提供可配置网络(使用 BGP 的原生 L3,使用 vxlan 的 overlay,经典 L2 和 Cisco-SDN/ACI)和丰富的策略框架。Contiv 项目完全[开源](http://github.com/contiv)。[安装工具](http://github.com/contiv/install)同时提供基于和不基于 kubeadm 的安装选项。
|
||||
* [Flannel](https://github.com/coreos/flannel/blob/master/Documentation/kube-flannel.yml) 是一个可以用于 Kubernetes 的 overlay 网络提供者。
|
||||
* [Romana](http://romana.io) 是一个 pod 网络的层 3 解决方案,并且支持 [NetworkPolicy API](/docs/concepts/services-networking/network-policies/)。Kubeadm add-on 安装细节可以在[这里](https://github.com/romana/romana/tree/master/containerize)找到。
|
||||
* [Weave Net](https://www.weave.works/docs/net/latest/kube-addon/) 提供了在网络分组两端参与工作的网络和网络策略,并且不需要额外的数据库。
|
||||
* [CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) 使 Kubernetes 无缝连接到一种 CNI 插件,例如:Flannel、Calico、Canal、Romana 或者 Weave。
|
||||
|
||||
|
||||
## 可视化管理
|
||||
|
||||
|
||||
* [Dashboard](https://github.com/kubernetes/dashboard#kubernetes-dashboard) 是一个 Kubernetes 的 web 控制台界面。
|
||||
* [Weave Scope](https://www.weave.works/documentation/scope-latest-installing/#k8s) 是一个图形化工具,用于查看你的 containers、 pods、services等。 请和一个 [Weave Cloud account](https://cloud.weave.works/) 一起使用,或者自己运行 UI。
|
||||
|
||||
|
||||
## 遗留 Add-ons
|
||||
|
||||
|
||||
还有一些其它 add-ons 归档在已废弃的 [cluster/addons](https://git.k8s.io/kubernetes/cluster/addons) 路径中。
|
||||
|
||||
|
||||
维护完善的 add-ons 应该被链接到这里。欢迎提出 PRs!
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
|
||||
title: 集群管理概述
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
集群管理概述面向任何创建和管理 Kubernetes 集群的读者人群。我们假设你对 [用户指南](/docs/user-guide/)中的概念有一些熟悉。
|
||||
{% endcapture %}
|
||||
|
||||
{% capture body %}
|
||||
|
||||
## 规划集群
|
||||
|
||||
|
||||
查阅 [选择正确解决方案](/docs/setup/pick-right-solution/) 中的指导,获取如何规划、建立以及配置 Kubernetes 集群的示例。本文所列的文章称为*发行版*。
|
||||
|
||||
|
||||
在选择一个指南前,有一些因素需要考虑:
|
||||
|
||||
- 你是打算在你的电脑上尝试 Kubernetes,还是要构建一个高可用的多节点集群?请选择最适合你需求的发行版。
|
||||
- **如果你正在设计一个高可用集群**,请了解[在多个 zones 中配置集群](/docs/admin/multi-cluster)。
|
||||
- 你的集群是在**本地**还是**云(IaaS)**上?Kubernetes 不能直接支持混合集群。作为代替,你可以建立多个集群。
|
||||
- **如果你在本地配置 Kubernetes**,需要考虑哪种[网络模型](/docs/admin/networking)最适合。一种自定义网络的选项是 [*OpenVSwitch GRE/VxLAN 网络*](/docs/admin/ovs-networking/),它使用 OpenVSwitch 在跨 Kubernetes 节点的 pods 之间建立起网络。
|
||||
- 你的 Kubernetes 在 **裸金属硬件** 还是 **虚拟机(VMs)**上运行?
|
||||
- 你**只想运行一个集群**,还是打算**活动开发 Kubernetes 项目代码**?如果是后者,请选择一个活动开发的发行版。某些发行版只提供二进制发布版,但提供更多的选择。
|
||||
- 让你自己熟悉运行一个集群所需的[组件](/docs/admin/cluster-components) 。
|
||||
|
||||
|
||||
请注意:不是所有的发行版都被积极维护着。请选择测试过最近版本的 Kubernetes 的发行版。
|
||||
|
||||
|
||||
如果你正在使用和 Salt 有关的指南,请查阅 [使用 Salt 配置 Kubernetes](/docs/admin/salt)。
|
||||
|
||||
|
||||
## 管理集群
|
||||
|
||||
|
||||
[管理集群](/docs/concepts/cluster-administration/cluster-management/)叙述了和集群生命周期相关的几个主题:创建一个新集群、升级集群的 master 和 worker 节点、执行节点维护(例如内核升级)以及升级活动集群的 Kubernetes API 版本。
|
||||
|
||||
|
||||
## 保护集群
|
||||
|
||||
|
||||
* [Kubernetes 容器环境](/docs/concepts/containers/container-environment-variables/) 描述了 Kubernetes 节点上由 Kubelet 管理的容器的环境。
|
||||
|
||||
|
||||
* [控制到 Kubernetes API 的访问](/docs/admin/accessing-the-api) 描述了如何为用户和 service accounts 建立权限许可.
|
||||
|
||||
|
||||
* [用户认证](/docs/admin/authentication) 阐述了 Kubernetes 中的认证功能,包括许多认证选项。
|
||||
|
||||
|
||||
* [授权](/docs/admin/authorization)从认证中分离出来,用于控制如何处理 HTTP 请求。
|
||||
|
||||
|
||||
* [使用 Admission Controllers](/docs/admin/admission-controllers) 阐述了在认证和授权之后拦截到 Kubernetes API 服务的请求的插件。
|
||||
|
||||
|
||||
* [在 Kubernetes Cluster 中使用 Sysctls](/docs/concepts/cluster-administration/sysctl-cluster/) 描述了管理员如何使用 `sysctl` 命令行工具来设置内核参数。
|
||||
|
||||
|
||||
* [审计](/docs/tasks/debug-application-cluster/audit/) 描述了如何与 Kubernetes 的审计日志交互。
|
||||
|
||||
|
||||
### 保护 kubelet
|
||||
|
||||
* [Master 节点通信](/docs/concepts/cluster-administration/master-node-communication/)
|
||||
* [TLS 引导](/docs/admin/kubelet-tls-bootstrapping/)
|
||||
* [Kubelet 认证/授权](/docs/admin/kubelet-authentication-authorization/)
|
||||
|
||||
|
||||
## 可选集群服务
|
||||
|
||||
|
||||
* [DNS 与 SkyDNS 集成](/docs/concepts/services-networking/dns-pod-service/)描述了如何将一个 DNS 名解析到一个Kubernetes service。
|
||||
|
||||
|
||||
* [记录和监控集群活动](/docs/concepts/cluster-administration/logging/) 阐述了Kubernetes 的日志如何工作以及怎样实现。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
|
||||
title: 访问集群上运行的服务
|
||||
redirect_from:
|
||||
- "/docs/user-guide/accessing-the-cluster/"
|
||||
- "/docs/user-guide/accessing-the-cluster.html"
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
本文展示了如何连接 Kubernetes 集群上运行的服务。
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
{% include task-tutorial-prereqs.md %}
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## 访问集群上运行的服务
|
||||
|
||||
|
||||
在 Kubernetes 里, [nodes](/docs/admin/node)、[pods](/docs/user-guide/pods) 和 [services](/docs/user-guide/services) 都有它们自己的 IP。许多情况下,集群上的 node IP、pod IP 和某些 service IP 路由不可达,所以不能从一个集群之外的节点访问它们,例如从你自己的台式机。
|
||||
|
||||
|
||||
### 连接方式
|
||||
|
||||
|
||||
你有多种从集群外连接 nodes、pods 和 services 的选项:
|
||||
|
||||
|
||||
- 通过公共 IP 访问 services。
|
||||
- 使用具有 `NodePort` 或 `LoadBalancer` 类型的 service,可以从外部访问它们。请查阅 [services](/docs/user-guide/services) 和 [kubectl expose](/docs/user-guide/kubectl/v1.6/#expose) 文档。
|
||||
- 取决于你的集群环境,你可以仅把 service 暴露在你的企业网络环境中,也可以将其暴露在因特网上。需要考虑暴露的 service 是否安全,它是否有自己的用户认证?
|
||||
- 将 pods 放置于 services 背后。如果要访问一个副本集合中特定的 pod,例如用于调试目的时,请给 pod 指定一个独特的标签并创建一个新 service 选择这个标签。
|
||||
- 大部分情况下,都不需要应用开发者通过节点 IP 直接访问 nodes。
|
||||
- 通过 Proxy Verb 访问 services、nodes 或者 pods。
|
||||
- 在访问 Apiserver 远程服务之前是否经过认证和授权?如果你的服务暴露到因特网中不够安全,或者需要获取 node IP 之上的端口,又或者处于调试目的时,请使用这个特性。
|
||||
- Proxies 可能给某些应用带来麻烦。
|
||||
- 仅适用于 HTTP/HTTPS。
|
||||
- 在[这里](#manually-constructing-apiserver-proxy-urls)描述
|
||||
- 从集群中的 node 或者 pod 访问。
|
||||
- 运行一个 pod,然后使用 [kubectl exec](/docs/user-guide/kubectl/v1.6/#exec) 连接到它的一个shell。从那个 shell 连接其他的 nodes、pods 和 services。
|
||||
- 某些集群可能允许你 ssh 到集群中的节点。你可能可以从那儿访问集群服务。这是一个非标准的方式,可能在一些集群上能工作,但在另一些上却不能。浏览器和其他工具可能安装或可能不会安装。集群 DNS 可能不会正常工作。
|
||||
|
||||
|
||||
### 发现内置服务
|
||||
|
||||
|
||||
典型情况下,kube-system 会启动集群中的几个服务。使用 `kubectl cluster-info` 命令获取它们的列表:
|
||||
|
||||
```shell
|
||||
$ kubectl cluster-info
|
||||
|
||||
Kubernetes master is running at https://104.197.5.247
|
||||
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
|
||||
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
|
||||
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
|
||||
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
|
||||
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
|
||||
```
|
||||
|
||||
这显示了用于访问每个服务的 proxy-verb URL。例如,这个集群启用了(使用 Elasticsearch)集群层面的日志,如果提供合适的凭据可以通过 `https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/` 访问,或通过一个 kubectl 代理地址访问,如:`http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/`。(请查看 [上文](#accessing-the-cluster-api) 关于如何传递凭据或者使用 kubectl 代理的说明。)
|
||||
|
||||
|
||||
#### 手动构建 apiserver 代理 URLs
|
||||
|
||||
|
||||
如同上面所提到的,你可以使用 `kubectl cluster-info` 命令取得 service 的代理 URL。为了创建包含 service endpoints、suffixes 和 parameters 的代理 URLs,你可以简单的在 service 的代理 URL中 添加:
|
||||
`http://`*`kubernetes_master_address`*`/api/v1/namespaces/`*`namespace_name`*`/services/`*`service_name[:port_name]`*`/proxy`
|
||||
|
||||
|
||||
如果还没有为你的端口指定名称,你可以不用在 URL 中指定 *port_name*。
|
||||
|
||||
|
||||
##### 示例
|
||||
|
||||
|
||||
* 你可以通过 `http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy` 访问 Elasticsearch service endpoint `_search?q=user:kimchy`。
|
||||
* 你可以通过 `https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true` 访问 Elasticsearch 集群健康信息 endpoint `_cluster/health?pretty=true`。
|
||||
|
||||
```json
|
||||
{
|
||||
"cluster_name" : "kubernetes_logging",
|
||||
"status" : "yellow",
|
||||
"timed_out" : false,
|
||||
"number_of_nodes" : 1,
|
||||
"number_of_data_nodes" : 1,
|
||||
"active_primary_shards" : 5,
|
||||
"active_shards" : 5,
|
||||
"relocating_shards" : 0,
|
||||
"initializing_shards" : 0,
|
||||
"unassigned_shards" : 5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 通过 web 浏览器访问集群中运行的服务
|
||||
|
||||
|
||||
你或许能够将 apiserver 代理的 url 放入浏览器的地址栏,然而:
|
||||
|
||||
|
||||
- Web 服务器不总是能够传递令牌,所以你可能需要使用基本(密码)认证。 Apiserver 可以配置为接受基本认证,但你的集群可能并没有这样配置。
|
||||
- 某些 web 应用可能不能工作,特别是那些使用客户端侧 javascript 的应用,它们构造 url 的方式可能不能理解代理路径前缀。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,411 @@
|
|||
---
|
||||
assignees:
|
||||
- derekwaynecarr
|
||||
- janetkuo
|
||||
|
||||
title: 应用资源配额和限额
|
||||
redirect_from:
|
||||
- "/docs/admin/resourcequota/walkthrough/"
|
||||
- "/docs/admin/resourcequota/walkthrough.html"
|
||||
- "/docs/tasks/configure-pod-container/apply-resource-quota-limit/"
|
||||
- "/docs/tasks/configure-pod-container/apply-resource-quota-limit.html"
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
|
||||
本示例展示了在一个 namespace 中控制资源用量的典型设置。
|
||||
|
||||
|
||||
本文展示了以下资源的使用: [Namespace](/docs/admin/namespaces), [ResourceQuota](/docs/concepts/policy/resource-quotas/) 和 [LimitRange](/docs/tasks/configure-pod-container/limit-range/)。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
* {% include task-tutorial-prereqs.md %}
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
## 场景
|
||||
|
||||
|
||||
集群管理员正在操作一个代表用户群体的集群,他希望控制一个特定 namespace 中可以被使用的资源总量,以达到促进对集群的公平共享及控制成本的目的。
|
||||
|
||||
|
||||
集群管理员有以下目标:
|
||||
|
||||
|
||||
* 限制运行中 pods 使用的计算资源数量
|
||||
* 限制 persistent volume claims 数量以控制对存储的访问
|
||||
* 限制 load balancers 数量以控制成本
|
||||
* 防止使用 node ports 以保留稀缺资源
|
||||
* 提供默认计算资源请求以实现更好的调度决策
|
||||
|
||||
|
||||
## 创建 namespace
|
||||
|
||||
|
||||
本示例将在一个自定义的 namespace 中运行,以展示相关概念。
|
||||
|
||||
|
||||
让我们创建一个叫做 quota-example 的新 namespace:
|
||||
|
||||
```shell
|
||||
$ kubectl create namespace quota-example
|
||||
namespace "quota-example" created
|
||||
$ kubectl get namespaces
|
||||
NAME STATUS AGE
|
||||
default Active 2m
|
||||
kube-system Active 2m
|
||||
quota-example Active 39s
|
||||
```
|
||||
|
||||
|
||||
## 应用 object-count 配额到 namespace
|
||||
|
||||
|
||||
集群管理员想要控制下列资源:
|
||||
|
||||
* persistent volume claims
|
||||
* load balancers
|
||||
* node ports
|
||||
|
||||
|
||||
我们来创建一个简单的配额,用于控制这个 namespace 中那些资源类型的对象数量。
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-object-counts.yaml --namespace=quota-example
|
||||
resourcequota "object-counts" created
|
||||
```
|
||||
|
||||
|
||||
配额系统将察觉到有一个配额被创建,并且会计算 namespace 中的资源消耗量作为响应。这应该会很快发生。
|
||||
|
||||
|
||||
让我们显示一下配额来观察这个 namespace 中当前被消耗的资源:
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota object-counts --namespace=quota-example
|
||||
Name: object-counts
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
persistentvolumeclaims 0 2
|
||||
services.loadbalancers 0 2
|
||||
services.nodeports 0 0
|
||||
```
|
||||
|
||||
|
||||
配额系统现在将阻止用户创建比各个资源指定数量更多的资源。
|
||||
|
||||
|
||||
|
||||
## 应用计算资源配额到 namespace
|
||||
|
||||
|
||||
为了限制这个 namespace 可以被使用的计算资源数量,让我们创建一个跟踪计算资源的配额。
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-compute-resources.yaml --namespace=quota-example
|
||||
resourcequota "compute-resources" created
|
||||
```
|
||||
|
||||
|
||||
让我们显示一下配额来观察这个 namespace 中当前被消耗的资源:
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota compute-resources --namespace=quota-example
|
||||
Name: compute-resources
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 0 2
|
||||
limits.memory 0 2Gi
|
||||
pods 0 4
|
||||
requests.cpu 0 1
|
||||
requests.memory 0 1Gi
|
||||
```
|
||||
|
||||
|
||||
配额系统现在会防止 namespace 拥有超过 4 个没有终止的 pods。此外它还将强制 pod 中的每个容器配置一个 `request` 并为 `cpu` 和 `memory` 定义 `limit`。
|
||||
|
||||
|
||||
## 应用默认资源请求和限制
|
||||
|
||||
|
||||
Pod 的作者很少为它们的 pods 指定资源请求和限制。
|
||||
|
||||
|
||||
既然我们对项目应用了配额,我们来看一下当终端用户通过创建一个没有 cpu 和 内存限制的 pod 时会发生什么。这通过在 pod 里创建一个 nginx 容器实现。
|
||||
|
||||
|
||||
作为演示,让我们来创建一个运行 nginx 的 deployment:
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=quota-example
|
||||
deployment "nginx" created
|
||||
```
|
||||
|
||||
|
||||
现在我们来看一下创建的 pods。
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
```
|
||||
|
||||
|
||||
发生了什么?我一个 pods 都没有!让我们 describe 这个 deployment 来看看发生了什么。
|
||||
|
||||
```shell
|
||||
$ kubectl describe deployment nginx --namespace=quota-example
|
||||
Name: nginx
|
||||
Namespace: quota-example
|
||||
CreationTimestamp: Mon, 06 Jun 2016 16:11:37 -0400
|
||||
Labels: run=nginx
|
||||
Selector: run=nginx
|
||||
Replicas: 0 updated | 1 total | 0 available | 1 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: nginx-3137573019 (0/1 replicas created)
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
Deployment 创建了一个对应的 replica set 并尝试按照大小来创建一个 pod。
|
||||
|
||||
|
||||
让我们看看 replica set 的更多细节。
|
||||
|
||||
```shell
|
||||
$ kubectl describe rs nginx-3137573019 --namespace=quota-example
|
||||
Name: nginx-3137573019
|
||||
Namespace: quota-example
|
||||
Image(s): nginx
|
||||
Selector: pod-template-hash=3137573019,run=nginx
|
||||
Labels: pod-template-hash=3137573019
|
||||
run=nginx
|
||||
Replicas: 0 current / 1 desired
|
||||
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
|
||||
No volumes.
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
4m 7s 11 {replicaset-controller } Warning FailedCreate Error creating: pods "nginx-3137573019-" is forbidden: Failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
|
||||
```
|
||||
|
||||
|
||||
Kubernetes API server 拒绝了 replica set 创建一个 pod 的请求,因为我们的 pods 没有为 `cpu` 和 `memory` 指定 `requests` 或 `limits`。
|
||||
|
||||
|
||||
因此,我们来为 pod 指定它可以使用的 `cpu` 和 `memory` 默认数量。
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-limits.yaml --namespace=quota-example
|
||||
limitrange "limits" created
|
||||
$ kubectl describe limits limits --namespace=quota-example
|
||||
Name: limits
|
||||
Namespace: quota-example
|
||||
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
|
||||
---- -------- --- --- --------------- ------------- -----------------------
|
||||
Container memory - - 256Mi 512Mi -
|
||||
Container cpu - - 100m 200m -
|
||||
```
|
||||
|
||||
|
||||
如果 Kubernetes API server 发现一个 namespace 中有一个创建 pod 的请求,并且 pod 中的容器没有设置任何计算资源请求时,作为准入控制的一部分,一个默认的 request 和 limit 将会被应用。
|
||||
|
||||
|
||||
在本例中,创建的每个 pod 都将拥有如下的计算资源限制:
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx \
|
||||
--image=nginx \
|
||||
--replicas=1 \
|
||||
--requests=cpu=100m,memory=256Mi \
|
||||
--limits=cpu=200m,memory=512Mi \
|
||||
--namespace=quota-example
|
||||
```
|
||||
|
||||
|
||||
由于已经为我们的 namespace 申请了默认的计算资源,我们的 replica set 应该能够创建它的 pods 了。
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-3137573019-fvrig 1/1 Running 0 6m
|
||||
```
|
||||
|
||||
|
||||
而且如果打印出我们在这个 namespace 中的配额使用情况:
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota --namespace=quota-example
|
||||
Name: compute-resources
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 200m 2
|
||||
limits.memory 512Mi 2Gi
|
||||
pods 1 4
|
||||
requests.cpu 100m 1
|
||||
requests.memory 256Mi 1Gi
|
||||
|
||||
|
||||
Name: object-counts
|
||||
Namespace: quota-example
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
persistentvolumeclaims 0 2
|
||||
services.loadbalancers 0 2
|
||||
services.nodeports 0 0
|
||||
```
|
||||
|
||||
|
||||
就像你看到的,创建的 pod 消耗了明确的计算资源量,并且正被 Kubernetes 正确的追踪着。
|
||||
|
||||
|
||||
## 高级配额 scopes
|
||||
|
||||
|
||||
让我们想象一下如果你不希望为你的 namespace 指定默认计算资源使用量。
|
||||
|
||||
|
||||
作为替换,你希望用户在它们的 namespace 中运行指定数量的 `BestEffort` pods,以从宽松的计算资源中获得好处。然后要求用户为需要更高质量服务的 pods 配置一个显式的资源请求。
|
||||
|
||||
|
||||
让我们新建一个拥有两个配额的 namespace 来演示这种行为:
|
||||
|
||||
```shell
|
||||
$ kubectl create namespace quota-scopes
|
||||
namespace "quota-scopes" created
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-best-effort.yaml --namespace=quota-scopes
|
||||
resourcequota "best-effort" created
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-not-best-effort.yaml --namespace=quota-scopes
|
||||
resourcequota "not-best-effort" created
|
||||
$ kubectl describe quota --namespace=quota-scopes
|
||||
Name: best-effort
|
||||
Namespace: quota-scopes
|
||||
Scopes: BestEffort
|
||||
* Matches all pods that have best effort quality of service.
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
pods 0 10
|
||||
|
||||
|
||||
Name: not-best-effort
|
||||
Namespace: quota-scopes
|
||||
Scopes: NotBestEffort
|
||||
* Matches all pods that do not have best effort quality of service.
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 0 2
|
||||
limits.memory 0 2Gi
|
||||
pods 0 4
|
||||
requests.cpu 0 1
|
||||
requests.memory 0 1Gi
|
||||
```
|
||||
|
||||
|
||||
在这种场景下,一个没有配置计算资源请求的 pod 将会被 `best-effort` 配额跟踪。
|
||||
|
||||
|
||||
而配置了计算资源请求的则会被 `not-best-effort` 配额追踪。
|
||||
|
||||
|
||||
让我们创建两个 deployments 作为演示:
|
||||
|
||||
```shell
|
||||
$ kubectl run best-effort-nginx --image=nginx --replicas=8 --namespace=quota-scopes
|
||||
deployment "best-effort-nginx" created
|
||||
$ kubectl run not-best-effort-nginx \
|
||||
--image=nginx \
|
||||
--replicas=2 \
|
||||
--requests=cpu=100m,memory=256Mi \
|
||||
--limits=cpu=200m,memory=512Mi \
|
||||
--namespace=quota-scopes
|
||||
deployment "not-best-effort-nginx" created
|
||||
```
|
||||
|
||||
|
||||
虽然没有指定默认的 limits,`best-effort-nginx` deployment 还是会创建 8 个 pods。这是由于它被 `best-effort` 配额追踪,而 `not-best-effort` 配额将忽略它。`not-best-effort` 配额将追踪 `not-best-effort-nginx` deployment,因为它创建的 pods 具有 `Burstable` 服务质量。
|
||||
|
||||
|
||||
让我们列出 namespace 中的 pods:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=quota-scopes
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
best-effort-nginx-3488455095-2qb41 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-3go7n 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-9o2xg 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-eyg40 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-gcs3v 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-rq8p1 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-udhhd 1/1 Running 0 51s
|
||||
best-effort-nginx-3488455095-zmk12 1/1 Running 0 51s
|
||||
not-best-effort-nginx-2204666826-7sl61 1/1 Running 0 23s
|
||||
not-best-effort-nginx-2204666826-ke746 1/1 Running 0 23s
|
||||
```
|
||||
|
||||
|
||||
如你看到的,所有 10 个 pods 都已经被准许创建。
|
||||
|
||||
|
||||
让我们 describe 这个 namespace 当前的配额使用情况:
|
||||
|
||||
```shell
|
||||
$ kubectl describe quota --namespace=quota-scopes
|
||||
Name: best-effort
|
||||
Namespace: quota-scopes
|
||||
Scopes: BestEffort
|
||||
* Matches all pods that have best effort quality of service.
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
pods 8 10
|
||||
|
||||
|
||||
Name: not-best-effort
|
||||
Namespace: quota-scopes
|
||||
Scopes: NotBestEffort
|
||||
* Matches all pods that do not have best effort quality of service.
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 400m 2
|
||||
limits.memory 1Gi 2Gi
|
||||
pods 2 4
|
||||
requests.cpu 200m 1
|
||||
requests.memory 512Mi 1Gi
|
||||
```
|
||||
|
||||
|
||||
如你看到的,`best-effort` 配额追踪了我们在 `best-effort-nginx` deployment 中创建的 8 个 pods 的资源用量,而 `not-best-effort` 配额追踪了我们在 `not-best-effort-nginx` deployment 中创的两个 pods 的用量。
|
||||
|
||||
|
||||
Scopes 提供了一种来对任何配额文档追踪的资源集合进行细分的机制,给操作人员部署和追踪资源消耗带来更大的灵活性。
|
||||
|
||||
|
||||
除 `BestEffort` 和 `NotBestEffort` scopes 之外,还有用于限制长时间运行和有时限 pods 的scopes。`Terminating` scope 将匹配任何 `spec.activeDeadlineSeconds` 不为 `nil` 的 pod。`NotTerminating` scope 将匹配任何 `spec.activeDeadlineSeconds` 为 `nil` 的 pod。这些 scopes 允许你基于 pods 在你集群中 node 上的预期持久程度来为它们指定配额。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture discussion %}
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
消耗节点 cpu 和 memory 资源的动作受到 namespace 配额定义的硬性配额限制的管制。
|
||||
|
||||
|
||||
任意消耗那些资源的动作能够被调整,或者获得一个 namespace 级别的默认值以符合你最终的目标。
|
||||
|
||||
|
||||
可以基于服务质量或者在你集群中节点上的预期持久程度来分配配额。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
|
||||
title: 改变默认 StorageClass
|
||||
---
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
本文展示了如何改变默认的 Storage Class,它用于为没有特殊需求的 PersistentVolumeClaims 配置 volumes。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
{% include task-tutorial-prereqs.md %}
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
|
||||
## 为什么要改变默认 storage class?
|
||||
|
||||
|
||||
取决于安装模式,您的 Kubernetes 集群可能和一个被标记为默认的已有 StorageClass 一起部署。这个默认的 StorageClass 以后将被用于动态的为没有特定 storage class 需求的 PersistentVolumeClaims 配置存储。更多细节请查看 [PersistentVolumeClaim 文档](/docs/user-guide/persistent-volumes/#class-1)。
|
||||
|
||||
|
||||
预先安装的默认 StorageClass 可能不能很好的适应您期望的工作负载;例如,它配置的存储可能太过昂贵。如果是这样的话,您可以改变默认 StorageClass,或者完全禁用它以防止动态配置存储。
|
||||
|
||||
|
||||
简单的删除默认 StorageClass 可能行不通,因为它可能会被您集群中的扩展管理器自动重建。请查阅您的安装文档中关于扩展管理器的细节,以及如何禁用单个扩展。
|
||||
|
||||
|
||||
## 改变默认 StorageClass
|
||||
|
||||
|
||||
1. 列出您集群中的 StorageClasses:
|
||||
|
||||
kubectl get storageclass
|
||||
|
||||
|
||||
输出类似这样:
|
||||
|
||||
NAME TYPE
|
||||
standard (default) kubernetes.io/gce-pd
|
||||
gold kubernetes.io/gce-pd
|
||||
|
||||
|
||||
默认 StorageClass 以 `(default)` 标记。
|
||||
|
||||
|
||||
2. 标记默认 StorageClass 非默认:
|
||||
|
||||
|
||||
默认 StorageClass 的注解 `storageclass.kubernetes.io/is-default-class` 设置为 `true`。注解的其它任意值或者缺省值将被解释为 `false`。
|
||||
|
||||
|
||||
要标记一个 StorageClass 为非默认的,您需要改变它的值为 `false`:
|
||||
|
||||
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
|
||||
|
||||
|
||||
这里的 `<your-class-name>` 是您选择的 StorageClass 的名字。
|
||||
|
||||
|
||||
3. 标记一个 StorageClass 为默认的:
|
||||
|
||||
|
||||
和前面的步骤类似,您需要添加/设置注解 `storageclass.kubernetes.io/is-default-class=true`。
|
||||
|
||||
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
|
||||
|
||||
|
||||
请注意,最多只能有一个 StorageClass 能够被标记为默认。如果它们中有两个或多个被标记为默认,Kubernetes 将忽略这个注解,也就是它将表现为没有默认 StorageClass。
|
||||
|
||||
|
||||
4. 验证您选用的 StorageClass 为默认的:
|
||||
|
||||
kubectl get storageclass
|
||||
|
||||
|
||||
输出类似这样:
|
||||
|
||||
NAME TYPE
|
||||
standard kubernetes.io/gce-pd
|
||||
gold (default) kubernetes.io/gce-pd
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
|
||||
* 了解更多关于 [StorageClasses](/docs/concepts/storage/persistent-volumes/)。
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
title: 更改 PersistentVolume 的回收策略
|
||||
---
|
||||
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
本文展示了如何更改 Kubernetes PersistentVolume 的回收策略。
|
||||
{% endcapture %}
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
{% include task-tutorial-prereqs.md %}
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
|
||||
## 为什么要更改 PersistentVolume 的回收策略
|
||||
|
||||
|
||||
`PersistentVolumes` 可以有多种回收策略,包括 "Retain"、"Recycle" 和 "Delete"。对于动态配置的 `PersistentVolumes` 来说,默认回收策略为 "Delete"。这表示当用户删除对应的 `PeristentVolumeClaim` 时,动态配置的 volume 将被自动删除。如果 volume 包含重要数据时,这种自动行为可能是不合适的。那种情况下,更适合使用 "Retain" 策略。使用 "Retain" 时,如果用户删除 `PersistentVolumeClaim`,对应的 `PersistentVolume` 不会被删除。相反,它将变为 `Released` 状态,表示所有的数据可以被手动恢复。
|
||||
|
||||
|
||||
## 更改 PersistentVolume 的回收策略
|
||||
|
||||
|
||||
1. 列出你集群中的 PersistentVolumes
|
||||
|
||||
kubectl get pv
|
||||
|
||||
输出类似于这样:
|
||||
|
||||
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
|
||||
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 10s
|
||||
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 6s
|
||||
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim3 3s
|
||||
|
||||
|
||||
这个列表同样包含了绑定到每个 volume 的 claims 名称,以便更容易的识别动态配置的 volumes。
|
||||
|
||||
|
||||
2. 选择你的 PersistentVolumes 中的一个并更改它的回收策略:
|
||||
|
||||
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
|
||||
|
||||
这里的 `<your-pv-name>` 是你选择的 PersistentVolume 的名字。
|
||||
|
||||
3. 验证你选择的 PersistentVolume 拥有正确的策略:
|
||||
|
||||
kubectl get pv
|
||||
|
||||
输出类似于这样:
|
||||
|
||||
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
|
||||
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 40s
|
||||
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 36s
|
||||
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Retain Bound default/claim3 33s
|
||||
|
||||
|
||||
在前面的输出中,你可以看到绑定到 claim `default/claim3` 的 volume 拥有的回收策略为 `Retain`。当用户删除 claim `default/claim3` 时,它不会被自动删除。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% capture whatsnext %}
|
||||
|
||||
* 了解更多关于 [PersistentVolumes](/docs/concepts/storage/persistent-volumes/)的信息。
|
||||
* 了解更多关于 [PersistentVolumeClaims](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 的信息。
|
||||
|
||||
|
||||
### 参考
|
||||
|
||||
* [PersistentVolume](/docs/api-reference/{{page.version}}/#persistentvolume-v1-core)
|
||||
* [PersistentVolumeClaim](/docs/api-reference/{{page.version}}/#persistentvolumeclaim-v1-core)
|
||||
|
||||
* 查阅 [PersistentVolumeSpec](/docs/api-reference/{{page.version}}/#persistentvolumeclaim-v1-core) 的 `persistentVolumeReclaimPolicy` 字段。
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -0,0 +1,227 @@
|
|||
---
|
||||
approvers:
|
||||
- lavalamp
|
||||
- thockin
|
||||
title: 集群管理
|
||||
---
|
||||
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
本文描述了和集群生命周期相关的几个主题:创建新集群、更新集群的 master 和 worker 节点、执行节点维护(例如升级内核)以及升级运行中集群的 Kubernetes API 版本。
|
||||
|
||||
|
||||
## 创建和配置集群
|
||||
|
||||
|
||||
要在一组机器上安装 Kubernetes, 请根据您的环境,查阅现有的 [入门指南](/docs/getting-started-guides/)
|
||||
|
||||
|
||||
## 升级集群
|
||||
|
||||
|
||||
集群升级当前是配套提供的,某些发布版本在升级时可能需要特殊处理。推荐管理员在升级他们的集群前,同时查阅 [发行说明](https://git.k8s.io/kubernetes/CHANGELOG.md) 和版本具体升级说明。
|
||||
|
||||
|
||||
* [升级到 1.6](/docs/admin/upgrade-1-6)
|
||||
|
||||
|
||||
### 升级 Google Compute Engine 集群
|
||||
|
||||
|
||||
Google Compute Engine Open Source (GCE-OSS) 通过删除和重建 master 来支持 master 升级。通过维持相同的 Persistent Disk (PD) 以保证在升级过程中保留数据。
|
||||
|
||||
|
||||
GCE 的 Node 升级采用 [管理实例组](https://cloud.google.com/compute/docs/instance-groups/),每个节点将被顺序的删除,然后使用新软件重建。任何运行在那个节点上的 Pod 需要用 Replication Controller 控制,或者在扩容之后手动重建。
|
||||
|
||||
|
||||
开源 Google Compute Engine (GCE) 集群上的升级过程由 `cluster/gce/upgrade.sh` 脚本控制。
|
||||
|
||||
|
||||
运行 `cluster/gce/upgrade.sh -h` 获取使用说明。
|
||||
|
||||
|
||||
例如,只将 master 升级到一个指定的版本 (v1.0.2):
|
||||
|
||||
```shell
|
||||
cluster/gce/upgrade.sh -M v1.0.2
|
||||
```
|
||||
|
||||
|
||||
或者,将整个集群升级到最新的稳定版本:
|
||||
|
||||
```shell
|
||||
cluster/gce/upgrade.sh release/stable
|
||||
```
|
||||
|
||||
|
||||
### 升级 Google Container Engine (GKE) 集群
|
||||
|
||||
|
||||
Google Container Engine 自动升级 master 组件(例如 `kube-apiserver`、`kube-scheduler`)至最新版本。它还负责 master 运行的操作系统和其它组件。
|
||||
|
||||
|
||||
节点升级过程由用户初始化,[GKE 文档](https://cloud.google.com/container-engine/docs/clusters/upgrade) 里有相关描述。
|
||||
|
||||
|
||||
### 在其他平台上升级集群
|
||||
|
||||
|
||||
不同的供应商和工具管理升级的过程各不相同。建议您查阅它们有关升级的主要文档。
|
||||
|
||||
* [kops](https://github.com/kubernetes/kops)
|
||||
* [kubespray](https://github.com/kubernetes-incubator/kubespray)
|
||||
* [CoreOS Tectonic](https://coreos.com/tectonic/docs/latest/admin/upgrade.html)
|
||||
* ...
|
||||
|
||||
|
||||
## 调整集群大小
|
||||
|
||||
|
||||
如果集群资源短缺,您可以轻松的添加更多的机器,如果集群正运行在[节点自注册模式](/docs/admin/node/#self-registration-of-nodes)下的话。如果正在使用的是 GCE 或者 GKE,这将通过调整管理节点的实例组的大小完成。在 [Google Cloud Console page](https://console.developers.google.com) 的 `Compute > Compute Engine > Instance groups > your group > Edit group` 下修改实例数量或使用 gcloud CLI 都可以完成这个任务。
|
||||
|
||||
```shell
|
||||
gcloud compute instance-groups managed resize kubernetes-minion-group --size 42 --zone $ZONE
|
||||
```
|
||||
|
||||
|
||||
实例组将负责在新机器上放置恰当的镜像并启动它们。Kubelet 将向 API server 注册它的节点以使其可以用于调度。如果您对 instance group 进行缩容,系统将会随机选取节点来终止。
|
||||
|
||||
|
||||
在其他环境上,您可能需要手动配置机器并告诉 Kubelet API server 在哪台机器上运行。
|
||||
|
||||
|
||||
### 集群自动伸缩
|
||||
|
||||
|
||||
如果正在使用 GCE 或者 GKE,您可以配置您的集群,使其能够基于 pod 需求自动重新调整大小。
|
||||
|
||||
|
||||
如 [Compute Resource](/docs/concepts/configuration/manage-compute-resources-container/) 所述,用户可以控制预留多少 CPU 和内存来分配给 pod。这个信息被 Kubernetes scheduler 用来寻找一个运行 pod 的地方。如果没有一个节点有足够的空闲容量(或者不能满足其他 pod 的需求),这个 pod 就需要等待某些 pod 结束,或者一个新的节点被添加。
|
||||
|
||||
|
||||
集群 autoscaler 查找不能被调度的 pod 并检查添加一个新节点(和集群中其它节点类似的)是否有帮助。如果是的话,它将调整集群的大小以容纳等待调度的 pod。
|
||||
|
||||
|
||||
如果发现在一段延时时间内(默认10分钟,将来有可能改变)某些节点不再需要,集群 autoscaler 也会缩小集群。
|
||||
|
||||
|
||||
集群 autoscaler 在每一个实例组(GCE)或节点池(GKE)上配置。
|
||||
|
||||
|
||||
如果您使用 GCE,那么您可以在使用 kube-up.sh 脚本创建集群的时候启用它。要想配置集群 autoscaler,您需要设置三个环境变量:
|
||||
|
||||
|
||||
* `KUBE_ENABLE_CLUSTER_AUTOSCALER` - 如果设置为 true 将启用集群 autoscaler。
|
||||
* `KUBE_AUTOSCALER_MIN_NODES` - 集群的最小节点数量。
|
||||
* `KUBE_AUTOSCALER_MAX_NODES` - 集群的最大节点数量。
|
||||
|
||||
|
||||
示例:
|
||||
|
||||
```shell
|
||||
KUBE_ENABLE_CLUSTER_AUTOSCALER=true KUBE_AUTOSCALER_MIN_NODES=3 KUBE_AUTOSCALER_MAX_NODES=10 NUM_NODES=5 ./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
|
||||
在 GKE 上,您可以在创建、更新集群或创建一个特别的节点池(您希望自动伸缩的)时,通过给对应的 `gcloud` 命令传递 `--enable-autoscaling` `--min-nodes` 和 `--max-nodes` 来配置集群 autoscaler。
|
||||
|
||||
|
||||
示例:
|
||||
|
||||
```shell
|
||||
gcloud container clusters create mytestcluster --zone=us-central1-b --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5
|
||||
```
|
||||
|
||||
```shell
|
||||
gcloud container clusters update mytestcluster --enable-autoscaling --min-nodes=1 --max-nodes=15
|
||||
```
|
||||
|
||||
|
||||
**集群 autoscaler 期望节点未被手动修改过(例如通过 kubectl 添加标签),因为那些属性可能不能被传递到相同节点组中的新节点上。**
|
||||
|
||||
|
||||
## 维护节点
|
||||
|
||||
|
||||
如果需要重启节点(例如内核升级、libc 升级、硬件维修等),且停机时间很短时,当 Kubelet 重启后,它将尝试重启调度到节点上的 pod。如果重启花费较长时间(默认时间为 5 分钟,由 controller-manager 的 `--pod-eviction-timeout` 控制),节点控制器将会结束绑定到这个不可用节点上的 pod。如果存在对应的 replica set(或者 replication controller)时,则将在另一个节点上启动 pod 的新副本。所以,如果所有的 pod 都是复制而来,那么在不是所有节点都同时停机的前提下,升级可以在不需要特殊调整情况下完成。
|
||||
|
||||
|
||||
如果您希望更多的控制升级过程,可以使用下面的工作流程:
|
||||
|
||||
|
||||
使用 `kubectl drain` 优雅的结束节点上的所有 pod 并同时标记节点为不可调度:
|
||||
|
||||
```shell
|
||||
kubectl drain $NODENAME
|
||||
```
|
||||
|
||||
|
||||
在您正试图使节点离线时,这将阻止新的 pod 落到它们上面。
|
||||
|
||||
|
||||
对于有 replica set 的 pod 来说,它们将会被新的 pod 替换并且将被调度到一个新的节点。此外,如果 pod 是一个 service 的一部分,则客户端将被自动重定向到新的 pod。
|
||||
|
||||
|
||||
对于没有 replica set 的 pod,您需要手动启动 pod 的新副本,并且如果它不是 service 的一部分,您需要手动将客户端重定向到这个 pod。
|
||||
|
||||
|
||||
在节点上执行维护工作。
|
||||
|
||||
|
||||
重新使节点可调度:
|
||||
|
||||
```shell
|
||||
kubectl uncordon $NODENAME
|
||||
```
|
||||
|
||||
|
||||
如果删除了节点的虚拟机实例并重新创建,那么一个新的可调度节点资源将被自动创建(只在您使用支持节点发现的云服务提供商时;当前只有 Google Compute Engine,不包括在 Google Compute Engine 上使用 kube-register 的 CoreOS)。相关详细信息,请查阅 [节点](/docs/admin/node)。
|
||||
|
||||
|
||||
## 高级主题
|
||||
|
||||
|
||||
### 升级到不同的 API 版本
|
||||
|
||||
|
||||
当新的 API 版本发布时,您可能需要升级集群支持新的 API 版本(例如当 'v2' 发布时从 'v1' 切换到 'v2')。
|
||||
|
||||
|
||||
这不是一个经常性的事件,但需要谨慎的处理。这里有一系列升级到新 API 版本的步骤。
|
||||
|
||||
1. 开启新 API 版本。
|
||||
2. 升级集群存储来使用新版本。
|
||||
3. 升级所有配置文件。识别使用旧 API 版本 endpoint 的用户。
|
||||
4. 运行 `cluster/update-storage-objects.sh` 升级存储中的现有对象为新版本。
|
||||
5. 关闭旧 API 版本。
|
||||
|
||||
|
||||
### 打开或关闭集群的 API 版本
|
||||
|
||||
|
||||
可以在启动 API server 时传递 `--runtime-config=api/<version>` 标志来打开或关闭特定的 API 版本。例如:要关闭 v1 API,请传递 `--runtime-config=api/v1=false`。运行时配置还支持两个特殊键值:api/all 和 api/legacy,分别控制全部和遗留 API。例如要关闭除 v1 外全部 API 版本,请传递 `--runtime-config=api/all=false,api/v1=true`。对于这些标志来说,_legacy_ API 指那些被显式废弃的 API(例如 `v1beta3`)。
|
||||
|
||||
|
||||
### 切换集群存储的 API 版本
|
||||
|
||||
|
||||
存储于磁盘中,用于在集群内部代表 Kubernetes 活跃资源的对象使用特定的 API 版本书写。当支撑的 API 改变时,这些对象可能需要使用更新的 API 重写。重写失败将最终导致资源不再能够被 Kubernetes API server 解析或使用。
|
||||
|
||||
|
||||
`kube-apiserver` 二进制文件的 `KUBE_API_VERSIONS` 环境变量控制了集群支持的 API 版本。列表中的第一个版本被用作集群的存储版本。因此,要设置特定的版本为存储版本,请将其放在 `KUBE_API_VERSIONS` 参数值版本列表的最前面。您需要重启 `kube-apiserver` 二进制以使这个变量的改动生效。
|
||||
|
||||
|
||||
### 切换配置文件为新 API 版本
|
||||
|
||||
|
||||
可以使用 `kubectl convert` 命令对不同 API 版本的配置文件进行转换。
|
||||
|
||||
```shell
|
||||
kubectl convert -f pod.yaml --output-version v1
|
||||
```
|
||||
|
||||
|
||||
更多选项请参考 [kubectl convert](/docs/user-guide/kubectl/v1.6/#convert) 命令用法。
|
Loading…
Reference in New Issue