Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
@@ -0,0 +1,153 @@
|
||||
---
|
||||
title: "生产级别的容器编排系统"
|
||||
abstract: "自动化的容器部署、扩展和管理"
|
||||
cid: "home"
|
||||
---
|
||||
|
||||
<section id="oceanNodes">
|
||||
<main>
|
||||
<div class="image-wrapper"><img src="/images/flower.png"></div>
|
||||
<div class="content">
|
||||
|
||||
<h3><a href="/docs/concepts/overview/what-is-kubernetes/">Kubernetes</a> 是用于自动部署,扩展和管理容器化应用程序的开源系统。</h3>
|
||||
<p>它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现,Kubernetes 构建在 <a href="http://queue.acm.org/detail.cfm?id=2898444"> Google 15 年生产环境经验</a>基础之上,并结合来自社区的最佳创意和实践。</p>
|
||||
</div>
|
||||
</main>
|
||||
<main>
|
||||
<div class="image-wrapper"><img src="/images/scalable.png"></div>
|
||||
<div class="content">
|
||||
|
||||
<h4>星际尺度</h4>
|
||||
<p>根据同样的原则设计,允许 Google 每周运行数十亿个容器,Kubernetes 可以在不增加您的 ops 团队的情况下进行弹性扩展。</p>
|
||||
</div>
|
||||
</main>
|
||||
<main>
|
||||
<div class="image-wrapper"><img src="/images/blocks.png"></div>
|
||||
<div class="content">
|
||||
|
||||
<h4>永不过时</h4>
|
||||
<p>无论您应用运行在本地还是运行于全球任何地域,Kubernetes 的灵活性都可以随着您的需求复杂度不断增加,还可以持续、轻松地对外提供服务。</p>
|
||||
</div>
|
||||
</main>
|
||||
<main>
|
||||
<div class="image-wrapper"><img src="/images/suitcase.png"></div>
|
||||
<div class="content">
|
||||
|
||||
<h4>随处运行</h4>
|
||||
<p>Kubernetes 是开源的,可以让您自由地部署在企业内部,私有云、混合云或公有云基础架构,使您轻松将应用迁移至任何位置。</p>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
<section id="video">
|
||||
<div class="light-text">
|
||||
|
||||
<h2>Kubernetes: 最后… 它是真正的云平台</h2>
|
||||
<p>Box 的联合创始人和服务架构师 Sam Ghods 发表了热情洋溢的演讲,随着使用 Kubernetes,我们首次有一个通用接口,可以建立真正的部署工具。</p>
|
||||
<button id="desktopShowVideoButton" onclick="kub.showVideo()">观看视频</button>
|
||||
</div>
|
||||
<button id="mobileShowVideoButton" onclick="kub.showVideo()"></button>
|
||||
</section>
|
||||
<section id="features">
|
||||
<main>
|
||||
|
||||
<h3 class="center">Kubernetes 特性</h3>
|
||||
<div class="feature-box">
|
||||
<div>
|
||||
|
||||
<h4><a href="/docs/concepts/configuration/manage-compute-resources-container/">自动包装</a></h4>
|
||||
<p>根据资源需求和其他约束自动放置容器,同时不会牺牲可用性,混合关键和最大努力的工作负载,以提高资源利用率并节省更多资源。</p>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<h4><a href="/docs/concepts/workloads/controllers/replicationcontroller/#what-is-a-replicationcontroller">自我修复</a></h4>
|
||||
<p>重新启动失败的容器,在节点不可用时,替换和重新编排节点上的容器,终止不对用户定义的健康检查做出响应的容器,并且不会在客户端准备投放之前将其通告给客户端。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-box">
|
||||
<div>
|
||||
|
||||
<h4><a href="/docs/tasks/run-application/horizontal-pod-autoscale/">横向缩放</a></h4>
|
||||
<p>使用简单的命令或 UI,或者根据 CPU 的使用情况自动调整应用程序副本数。</p>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
<h4><a href="/docs/concepts/services-networking/service/">服务发现和负载均衡</a></h4>
|
||||
<p>不需要修改您的应用程序来使用不熟悉的服务发现机制,Kubernetes 为容器提供了自己的 IP 地址和一组容器的单个 DNS 名称,并可以在它们之间进行负载均衡。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-box">
|
||||
<div>
|
||||
|
||||
<h4><a href="/docs/concepts/workloads/controllers/deployment/#what-is-a-deployment">自动部署和回滚</a></h4>
|
||||
<p>Kubernetes 逐渐部署对应用程序或其配置的更改,同时监视应用程序运行状况,以确保它不会同时终止所有实例。 如果出现问题,Kubernetes会为您恢复更改,利用日益增长的部署解决方案的生态系统。</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4><a href="/docs/concepts/configuration/secret/">密钥</a> 和 <a href="/docs/tasks/configure-pod-container/configure-pod-configmap/">配置</a> 管理</h4>
|
||||
<p>部署和更新密钥和应用程序配置,不会重新编译您的镜像,不会在堆栈配置中暴露密钥(secrets)。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="feature-box">
|
||||
<div>
|
||||
<h4><a href="/docs/concepts/storage/persistent-volumes/">存储编排</a></h4>
|
||||
<p>自动安装您所选择的存储系统,无论是本地存储,如公有云提供商 <a href="https://cloud.google.com/storage/">GCP</a> 或 <a href="https://aws.amazon.com/products/storage/">AWS</a>, 还是网络存储系统 NFS, iSCSI,
|
||||
Gluster, Ceph, Cinder, 或 Flocker。</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4><a href="/docs/concepts/workloads/controllers/jobs-run-to-completion/">批处理</a></h4>
|
||||
<p>除了服务之外,Kubernetes还可以管理您的批处理和 CI 工作负载,如果需要,替换出现故障的容器。</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</section>
|
||||
<section id="talkToUs">
|
||||
<main>
|
||||
|
||||
<h3>实例探究</h3>
|
||||
<div id="caseStudiesWrapper">
|
||||
<div>
|
||||
<p>使用Kubernetes来重塑世界上最大的教育公司</p>
|
||||
<a href="/case-studies/pearson/">阅读更多</a>
|
||||
</div>
|
||||
<div>
|
||||
<p>Kubernetes at Box: 微服务的最大优势</p>
|
||||
<a href="https://blog.box.com/blog/kubernetes-box-microservices-maximum-velocity/">阅读更多</a>
|
||||
</div>
|
||||
<div>
|
||||
<p>在 eBay 内部转移到 OpenStack 上的 Kubernetes 和容器</p>
|
||||
<a href="https://www.nextplatform.com/2015/11/12/inside-ebays-shift-to-kubernetes-and-containers-atop-openstack/">阅读更多</a>
|
||||
</div>
|
||||
<div>
|
||||
<p>将本地的集群迁移至 Kubernetes</p>
|
||||
<a href="https://www.youtube.com/watch?v=6XGUTu3WhBw">观看视频</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 style="text-align: center"><a href="/case-studies/" style="color: #3371E3; font-weight: 400">探究所有的案例</a></h5>
|
||||
</main>
|
||||
</section>
|
||||
<div id="videoPlayer">
|
||||
<iframe data-url="https://www.youtube.com/embed/of45hYbkIZs?autoplay=1" frameborder="0" allowfullscreen></iframe>
|
||||
<button id="closeButton"></button>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: Home
|
||||
weight: 5
|
||||
---
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
approvers:
|
||||
- bgrant0607
|
||||
- erictune
|
||||
- lavalamp
|
||||
title: Kubernetes API访问控制
|
||||
---
|
||||
|
||||
用户通过 `kubectl`、客户端库或者通过发送REST请求[访问API](/docs/user-guide/accessing-the-cluster)。 用户(自然人)和[Kubernetes服务账户](/docs/tasks/configure-pod-container/configure-service-account/) 都可以被授权进行API访问。
|
||||
请求到达API服务器后会经过几个阶段,具体说明如图:
|
||||
|
||||

|
||||
|
||||
## 传输层安全
|
||||
|
||||
在典型的Kubernetes集群中,API通过443端口提供服务。
|
||||
API服务器会提供一份证书。 该证书一般是自签名的, 所以用户机器上的 `$USER/.kube/config` 目录通常
|
||||
包含该API服务器证书的根证书,用来代替系统默认根证书。 当用户使用 `kube-up.sh` 创建集群时,该证书通常会被自动写入用户的`$USER/.kube/config`。 如果集群中存在多个用户,则创建者需要与其他用户共享证书。
|
||||
|
||||
## 认证
|
||||
|
||||
一旦 TLS 连接建立,HTTP请求就进入到了认证的步骤。即图中的步骤 **1** 。
|
||||
集群创建脚本或集群管理员会为API服务器配置一个或多个认证模块。
|
||||
更具体的认证相关的描述详见 [这里](/docs/admin/authentication/)。
|
||||
|
||||
认证步骤的输入是整个HTTP请求,但这里通常只是检查请求头和/或客户端证书。
|
||||
|
||||
认证模块支持客户端证书,密码和Plain Tokens,
|
||||
Bootstrap Tokens,以及JWT Tokens (用于服务账户)。
|
||||
|
||||
(管理员)可以同时设置多种认证模块,在设置了多个认证模块的情况下,每个模块会依次尝试认证,
|
||||
直到其中一个认证成功。
|
||||
|
||||
在 GCE 平台中,客户端证书,密码和Plain Tokens,Bootstrap Tokens,以及JWT Tokens同时被启用。
|
||||
|
||||
如果请求认证失败,则请求被拒绝,返回401状态码。
|
||||
如果认证成功,则被认证为具体的 `username`,该用户名可供随后的步骤中使用。一些认证模块还提供了用户的组成员关系,另一些则没有。
|
||||
|
||||
尽管Kubernetes使用 "用户名" 来进行访问控制和请求记录,但它实际上并没有 `user` 对象,也不存储用户名称或其他相关信息。
|
||||
|
||||
## 授权
|
||||
|
||||
当请求被认证为来自某个特定的用户后,该请求需要被授权。 即图中的步骤 **2** 。
|
||||
|
||||
请求须包含请求者的用户名,请求动作,以及该动作影响的对象。 如果存在相应策略,声明该用户具有进行相应操作的权限,则该请求会被授权。
|
||||
|
||||
例如,如果Bob有如下策略,那么他只能够读取`projectCaribou`命名空间下的pod资源:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
|
||||
"kind": "Policy",
|
||||
"spec": {
|
||||
"user": "bob",
|
||||
"namespace": "projectCaribou",
|
||||
"resource": "pods",
|
||||
"readonly": true
|
||||
}
|
||||
}
|
||||
```
|
||||
如果Bob发起以下请求,那么请求能够通过授权,因为Bob被允许访问 `projectCaribou` 命名空间下的对象:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"resourceAttributes": {
|
||||
"namespace": "projectCaribou",
|
||||
"verb": "get",
|
||||
"group": "unicorn.example.org",
|
||||
"resource": "pods"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
如果Bob对 `projectCaribou` 命名空间下的对象发起一个写(`create` 或者 `update`)请求,那么它的授权会被拒绝。 如果Bob请求读取(`get`) 其他命名空间,例如 `projectFish`下的对象,其授权也会被拒绝。
|
||||
|
||||
Kubernetes的授权要求使用通用的REST属性与现有的组织或云服务提供商的访问控制系统进行交互。 采用REST格式是必要的,因为除Kubernetes外,这些访问控制系统还可能与其他的API进行交互。
|
||||
|
||||
Kubernetes 支持多种授权模块,例如ABAC模式,RBAC模式和 Webhook模式。 管理员创建集群时,会配置API服务器应用的授权模块。 如果多种授权模式同时被启用,Kubernetes将检查所有模块,如果其中一种通过授权,则请求授权通过。 如果所有的模块全部拒绝,则请求被拒绝(HTTP状态码403)。
|
||||
|
||||
要了解更多的Kubernetes授权相关信息,包括使用授权模块创建策略的具体说明等,可参考[授权概述](/docs/admin/authorization)。
|
||||
|
||||
|
||||
## 准入控制
|
||||
|
||||
准入控制模块是能够修改或拒绝请求的软件模块。
|
||||
作为授权模块的补充,准入控制模块会访问被创建或更新的对象的内容。
|
||||
它们作用于对象的创建,删除,更新和连接 (proxy)阶段,但不包括对象的读取。
|
||||
|
||||
可以同时配置多个准入控制器,它们会按顺序依次被调用。
|
||||
|
||||
即图中的步骤 **3** 。
|
||||
|
||||
与认证和授权模块不同的是,如果任一个准入控制器拒绝请求,那么整个请求会立即被拒绝。
|
||||
|
||||
除了拒绝请求外,准入控制器还可以为对象设置复杂的默认值。
|
||||
|
||||
可用的准入控制模块描述 [如下](/docs/admin/admission-controllers/)。
|
||||
|
||||
一旦请求通过所有准入控制器,将使用对应API对象的验证流程对其进行验证,然后写入对象存储 (如步骤 **4**)。
|
||||
|
||||
|
||||
## API的端口和IP
|
||||
|
||||
上述讨论适用于发送请求到API服务器的安全端口(典型情况)。
|
||||
实际上API服务器可以通过两个端口提供服务:
|
||||
|
||||
默认情况下,API服务器在2个端口上提供HTTP服务:
|
||||
|
||||
1. `Localhost Port`:
|
||||
|
||||
- 用于测试和启动,以及管理节点的其他组件
|
||||
(scheduler, controller-manager)与API的交互
|
||||
- 没有TLS
|
||||
- 默认值为8080,可以通过 `--insecure-port` 标记来修改。
|
||||
- 默认的IP地址为localhost, 可以通过 `--insecure-bind-address`标记来修改。
|
||||
- 请求会 **绕过** 认证和鉴权模块。
|
||||
- 请求会被准入控制模块处理。
|
||||
- 其访问需要主机访问的权限。
|
||||
|
||||
2. `Secure Port`:
|
||||
|
||||
- 尽可能使用该端口访问
|
||||
- 应用 TLS。 可以通过 `--tls-cert-file` 设置证书, 通过 `--tls-private-key-file` 设置私钥。
|
||||
- 默认值为6443,可以通过 `--secure-port` 标记来修改。
|
||||
- 默认IP是首个非本地的网络接口地址,可以通过 `--bind-address` 标记来修改。
|
||||
- 请求会经过认证和鉴权模块处理。
|
||||
- 请求会被准入控制模块处理。
|
||||
- 要求认证和授权模块正常运行。
|
||||
|
||||
通过 `kube-up.sh`创建集群时, 对 Google Compute Engine (GCE)
|
||||
和一些其他的云供应商来说, API通过443端口提供服务。 对
|
||||
GCE而言,项目上配置了防火墙规则,允许外部的HTTPS请求访问API,其他(厂商的)集群设置方法各不相同。
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: 概述
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
学习有关 Kubernetes 授权的更多信息,包括有关使用支持的授权模块创建策略的详细信息。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
在 Kubernetes 里,您必须经过身份验证(登录),才能授权您的请求(授予访问权限).。有关认证的信息,请参阅[访问控制概述](/docs/admin/access-the-api/)。
|
||||
|
||||
Kubernetes 提供通用的 REST API 请求。这意味着 Kubernetes 授权可以与现有的组织或云提供商的访问控制系统一起使用,该系统可以处理除 Kubernetes API 之外的其他 API。
|
||||
|
||||
## 确定请求是允许还是被拒绝
|
||||
Kubernetes 使用 API 服务器授权 API 请求。它根据所有策略评估所有请求属性,并允许或拒绝请求。某些策略必须允许 API 请求的所有部分继续进行,这意味着默认情况下是拒绝权限。
|
||||
|
||||
(虽然 Kubernetes 使用 API 服务器,访问控制和依赖特定类型对象的特定领域策略由 Admission 控制器处理。)
|
||||
|
||||
当配置多个授权模块时,按顺序检查每个模块,如果有任何模块授权请求,则可以继续执行该请求。如果所有模块拒绝请求,则拒绝该请求(HTTP状态代码403)。
|
||||
|
||||
## 查看您的请求属性
|
||||
|
||||
Kubernetes 仅查看以下API请求属性:
|
||||
|
||||
* **user** - 验证期间提供的 `user` 字符串
|
||||
* **group** - 认证用户所属的组名列表
|
||||
* **“extra"** - 由认证层提供的任意字符串键到字符串值的映射
|
||||
* **API** - 指示请求是否用于API资源
|
||||
* **Request path** - 诸如`/api`或`/healthz`的其他非资源端点的路径(请参阅[kubectl](#kubectl)).
|
||||
* **API request verb** - API 动词 `get`,`list`,`create`,`update`,`patch`,`watch`,`proxy`,`redirect`,`delete`和`deletecollection`用于资源请求。要确定资源 API 端点的请求动词,请参阅**确定下面的请求动词**.
|
||||
* **HTTP request verb** - HTTP动词`get`,`post`,`put`和`delete`用于非资源请求
|
||||
* **Resource** - 正在访问的资源的ID或名称(仅适用于资源请求)
|
||||
--* 对于使用`get`, `update`, `patch`, 和 `delete`动词的资源请求,您必须提供资源名称。
|
||||
* **Subresource** - 正在访问的子资源(仅用于资源请求)
|
||||
* **Namespace** - 正在被访问的对象的命名空间(仅针对命名空间的资源请求)
|
||||
* **API group** - 正在访问的API组(仅用于资源请求). 一个空字符串指定[核心 API 组](/docs/api/).
|
||||
|
||||
## 确定请求动词
|
||||
|
||||
要确定资源 API 端点的请求动词,请查看所使用的HTTP动词以及请求是否对单个资源或资源集合进行操作:
|
||||
|
||||
HTTP动词| 请求动词
|
||||
---------- | ---------------
|
||||
POST | 创建
|
||||
GET,HEAD | 获取(个人资源),列表(集合)
|
||||
PUT | 更新
|
||||
PATCH | 补丁
|
||||
DELETE| 删除(个人资源),删除(收藏)
|
||||
|
||||
Kubernetes 有时会使用专门的动词检查授权以获得额外的权限。例如:
|
||||
|
||||
* [PodSecurityPolicy](/docs/concepts/policy/pod-security-policy/)在`extensions` API组中的`podsecuritypolicies`资源上检查`use`动词的授权。
|
||||
* [RBAC](/docs/admin/authorization/rbac/#privilege-escalation-prevention-and-bootstrapping) 在`rbac.authorization.k8s.io` API组中的`roles`和`clusterroles`资源上检查`bind`动词的授权。
|
||||
* [认证](/docs/admin/authentication/) 在核心API组中的`users`,`groups`和`serviceaccounts`上的`impersonate`动词的授权以及`authentication.k8s.io` API组中的`userextras`进行层次检查。
|
||||
|
||||
## 授权模块
|
||||
* **ABAC模式** - 基于属性的访问控制(ABAC)定义了访问控制范例,通过使用将属性组合在一起的策略来授予用户访问权限。策略可以使用任何类型的属性(用户属性,资源属性,对象,环境属性等)。要了解有关使用ABAC模式的更多信息,请参阅[ABAC模式](/docs/admin/authorization/abac/)
|
||||
* **RBAC模式** - 基于角色的访问控制(RBAC)是一种根据企业内个人用户的角色来调整对计算机或网络资源的访问的方法。在这种情况下,访问是单个用户执行特定任务(例如查看,创建或修改文件)的能力。要了解有关使用RBAC模式的更多信息,请参阅[RBAC模式](/docs/admin/authorization/rbac/)
|
||||
*当指定 "RBAC"(基于角色的访问控制)使用 "rbac.authorization.k8s.io" API组来驱动授权决定时,允许管理员通过Kubernetes API动态配置权限策略.
|
||||
.. *截至1.6 RBAC模式是测试版.
|
||||
.. *要启用RBAC,请使用 `--authorization-mode=RBAC` 启动 apiserver.
|
||||
* **Webhook模式** - WebHook 是HTTP回调:发生事件时发生的HTTP POST; 通过HTTP POST简单的事件通知. 实施 WebHooks 的 Web 应用程序将在某些事情发生时向URL发送消息. 要了解有关使用Webhook模式的更多信息,请参阅[Webhook模式](/docs/admin/authorization/webhook/)
|
||||
* **自定义模块** - 您可以创建使用Kubernetes的自定义模块. 要了解更多信息,请参阅下面的**自定义模块**。
|
||||
|
||||
### 自定义模块
|
||||
可以相当容易地开发其他实现,APIserver 调用 Authorizer 接口:
|
||||
|
||||
```go
|
||||
type Authorizer interface {
|
||||
Authorize(a Attributes) error
|
||||
}
|
||||
```
|
||||
|
||||
以确定是否允许每个API操作.
|
||||
|
||||
授权插件是实现此接口的模块.授权插件代码位于 `pkg/auth/authorizer/$MODULENAME` 中。
|
||||
|
||||
授权模块可以完全实现,也可以拨出远程授权服务。 授权模块可以实现自己的缓存,以减少具有相同或相似参数的重复授权调用的成本。 开发人员应该考虑缓存和撤销权限之间的交互。
|
||||
|
||||
#### 检查API访问
|
||||
|
||||
Kubernetes 将 `subjectaccessreviews.v1.authorization.k8s.io` 资源公开为允许外部访问API授权者决策的普通资源。 无论您选择使用哪个授权器,您都可以使用`SubjectAccessReview`发出一个`POST`,就像webhook授权器的`apis/authorization.k8s.io/v1/subjectaccessreviews` 端点一样,并回复一个响应。 例如:
|
||||
|
||||
|
||||
```bash
|
||||
kubectl create --v=8 -f - << __EOF__
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"resourceAttributes": {
|
||||
"namespace": "kittensandponies",
|
||||
"verb": "get",
|
||||
"group": "unicorn.example.org",
|
||||
"resource": "pods"
|
||||
},
|
||||
"user": "jane",
|
||||
"group": [
|
||||
"group1",
|
||||
"group2"
|
||||
],
|
||||
"extra": {
|
||||
"scopes": [
|
||||
"openid",
|
||||
"profile"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
__EOF__
|
||||
|
||||
--- snip lots of output ---
|
||||
|
||||
I0913 08:12:31.362873 27425 request.go:908] Response Body: {"kind":"SubjectAccessReview","apiVersion":"authorization.k8s.io/v1","metadata":{"creationTimestamp":null},"spec":{"resourceAttributes":{"namespace":"kittensandponies","verb":"GET","group":"unicorn.example.org","resource":"pods"},"user":"jane","group":["group1","group2"],"extra":{"scopes":["openid","profile"]}},"status":{"allowed":true}}
|
||||
subjectaccessreview "" created
|
||||
```
|
||||
|
||||
这对于调试访问问题非常有用,因为您可以使用此资源来确定授权者授予哪些访问权限。
|
||||
|
||||
## 为您的授权模块使用标志
|
||||
|
||||
您的策略中必须包含一个标志,以指出您的策略包含哪个授权模块:
|
||||
|
||||
可以使用以下标志:
|
||||
- `--authorization-mode=ABAC` 基于属性的访问控制(ABAC)模式允许您使用本地文件配置策略。
|
||||
- `--authorization-mode=RBAC` 基于角色的访问控制(RBAC)模式允许您使用Kubernetes API创建和存储策略.
|
||||
- `--authorization-mode=Webhook` WebHook是一种HTTP回调模式,允许您使用远程REST管理授权。
|
||||
- `--authorization-mode=AlwaysDeny` 此标志阻止所有请求. 仅使用此标志进行测试。
|
||||
- `--authorization-mode=AlwaysAllow` 此标志允许所有请求. 只有在您不需要API请求授权的情况下才能使用此标志。
|
||||
|
||||
您可以选择多个授权模块. 如果其中一种模式为 `AlwaysAllow`,则覆盖其他模式,并允许所有API请求。
|
||||
|
||||
## 版本控制
|
||||
|
||||
对于版本 1.2,配置了 kube-up.sh 创建的集群,以便任何请求都不需要授权。
|
||||
|
||||
从版本 1.3 开始,配置由 kube-up.sh 创建的集群,使得 ABAC 授权模块处于启用状态。但是,其输入文件最初设置为允许所有用户执行所有操作,集群管理员需要编辑该文件,或者配置不同的授权器来限制用户可以执行的操作。
|
||||
|
||||
{{% /capture %}}
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 要学习有关身份验证的更多信息,请参阅**身份验证**[控制访问 Kubernetes API](docs/admin/access-the-api/)。
|
||||
* 要了解有关入学管理的更多信息,请参阅[使用 Admission 控制器](docs/admin/admission-controllers/)。
|
||||
*
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: ABAC 模式
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
基于属性的访问控制(Attribute-based access control - ABAC)定义了访问控制范例,其中通过使用将属性组合在一起的策略来向用户授予访问权限。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 策略文件格式
|
||||
|
||||
基于 `ABAC` 模式,可以这样指定策略文件 `--authorization-policy-file=SOME_FILENAME`。
|
||||
|
||||
此文件是 JSON 格式[每行都是一个JSON对象](http://jsonlines.org/),不应存在封闭的列表或映射,每行只有一个映射。
|
||||
|
||||
每一行都是一个 "策略对象",策略对象是具有以下映射的属性:
|
||||
|
||||
- 版本控制属性:
|
||||
- `apiVersion`,字符串类型: 有效值为"abac.authorization.kubernetes.io/v1beta1",允许版本控制和转换策略格式。
|
||||
- `kind`,字符串类型: 有效值为 "Policy",允许版本控制和转换策略格式。
|
||||
- `spec` 配置为具有以下映射的属性:
|
||||
- 匹配属性:
|
||||
- `user`,字符串类型; 来自 `--token-auth-file` 的用户字符串,如果你指定`user`,它必须与验证用户的用户名匹配。
|
||||
- `group`,字符串类型; 如果指定`group`,它必须与经过身份验证的用户的一个组匹配,`system:authenticated`匹配所有经过身份验证的请求。`system:unauthenticated`匹配所有未经过身份验证的请求。
|
||||
- 资源匹配属性:
|
||||
- `apiGroup`,字符串类型; 一个 API 组。
|
||||
- 例: `extensions`
|
||||
- 通配符: `*`匹配所有 API 组。
|
||||
- `namespace`,字符串类型; 一个命名空间。
|
||||
- 例如: `kube-system`
|
||||
- 通配符: `*` 匹配所有资源请求。
|
||||
- `resource`,字符串类型; 资源类型。
|
||||
- 例:`pods`
|
||||
- 通配符: `*`匹配所有资源请求。
|
||||
- 非资源匹配属性:
|
||||
- `nonResourcePath`,字符串类型; 非资源请求路径。
|
||||
- 例如:`/version`或`/apis`
|
||||
- 通配符:
|
||||
- `*` 匹配所有非资源请求。
|
||||
- `/foo/*` 匹配`/foo/`的所有子路径。
|
||||
- `readonly`,键入 boolean,如果为 true,则表示该策略仅适用于 get,list 和 watch 操作。
|
||||
|
||||
**注意:** 未设置的属性与类型设置为零值的属性相同(例如空字符串,0、false),然而未知的应该可读性优先。
|
||||
|
||||
在将来,策略可能以 JSON 格式表示,并通过 REST 界面进行管理。
|
||||
|
||||
## 授权算法
|
||||
|
||||
请求具有与策略对象的属性对应的属性。
|
||||
|
||||
当接收到请求时,确定属性。 未知属性设置为其类型的零值(例如: 空字符串,0,false)。
|
||||
|
||||
设置为`“*"`的属性将匹配相应属性的任何值。
|
||||
|
||||
检查属性的元组,以匹配策略文件中的每个策略。 如果至少有一行匹配请求属性,则请求被授权(但可能会在稍后验证失败)。
|
||||
|
||||
要允许任何经过身份验证的用户执行某些操作,请将策略组属性设置为 `"system:authenticated“`。
|
||||
|
||||
要允许任何未经身份验证的用户执行某些操作,请将策略组属性设置为`"system:authentication“`。
|
||||
|
||||
要允许用户执行任何操作,请使用 apiGroup,命名空间,
|
||||
资源和 nonResourcePath 属性设置为 `“*"`的策略.
|
||||
|
||||
要允许用户执行任何操作,请使用设置为`“*”` 的 apiGroup,namespace,resource 和 nonResourcePath 属性编写策略。
|
||||
|
||||
## Kubectl
|
||||
|
||||
Kubectl 使用 api-server 的 `/api` 和 `/apis` 端点进行协商客户端/服务器版本。 通过创建/更新来验证发送到API的对象操作,kubectl 查询某些 swagger 资源。 对于API版本"v1", 那就是`/swaggerapi/api/v1` & `/swaggerapi/ experimental/v1`。
|
||||
|
||||
当使用 ABAC 授权时,这些特殊资源必须明确通过策略中的 `nonResourcePath` 属性暴露出来(参见下面的[例子](#examples)):
|
||||
|
||||
* `/api`,`/api/*`,`/apis`和`/apis/*` 用于 API 版本协商.
|
||||
* `/version` 通过 `kubectl version` 检索服务器版本.
|
||||
* `/swaggerapi/*` 用于创建/更新操作.
|
||||
|
||||
要检查涉及到特定kubectl操作的HTTP调用,您可以调整详细程度:
|
||||
|
||||
kubectl --v=8 version
|
||||
|
||||
## 例子
|
||||
|
||||
1. Alice 可以对所有资源做任何事情:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}}
|
||||
```
|
||||
2. Kubelet 可以读取任何pod:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}}
|
||||
```
|
||||
3. Kubelet 可以读写事件:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}}
|
||||
```
|
||||
4. Bob 可以在命名空间“projectCaribou"中读取 pod:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
|
||||
```
|
||||
5. 任何人都可以对所有非资源路径进行只读请求:
|
||||
|
||||
```json
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:authenticated", "readonly": true, "nonResourcePath": "*"}}
|
||||
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:unauthenticated", "readonly": true, "nonResourcePath": "*"}}
|
||||
```
|
||||
|
||||
[完整文件示例](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/auth/authorizer/abac/example_policy_file.jsonl)
|
||||
|
||||
## 服务帐户的快速说明
|
||||
|
||||
服务帐户自动生成用户。 用户名是根据命名约定生成的:
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:<serviceaccountname>
|
||||
```
|
||||
创建新的命名空间也会导致创建一个新的服务帐户:
|
||||
|
||||
```shell
|
||||
system:serviceaccount:<namespace>:default
|
||||
```
|
||||
|
||||
例如,如果要将 API 的 kube-system 完整权限中的默认服务帐户授予,则可以将此行添加到策略文件中:
|
||||
|
||||
```json
|
||||
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"system:serviceaccount:kube-system:default","namespace":"*","resource":"*","apiGroup":"*"}}
|
||||
```
|
||||
|
||||
需要重新启动 apiserver 以获取新的策略行.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Webhook Mode
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
WebHook 是一种 HTTP 回调:某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知。一个基于 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL 。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
具体来说,当在判断用户权限时,`Webhook` 模式会使 Kubernetes 查询外部的 REST 服务。
|
||||
|
||||
## 配置文件格式
|
||||
|
||||
`Webhook` 模式需要一个 HTTP 配置文件,通过 `--authorization-webhook-config-file=SOME_FILENAME` 的参数声明。
|
||||
|
||||
配置文件的格式使用 [kubeconfig](/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/)。
|
||||
在文件中,"users" 代表着 API 服务器的 webhook,而 "cluster" 代表着远程服务。
|
||||
|
||||
使用 HTTPS 客户端认证的配置例子:
|
||||
|
||||
```yaml
|
||||
# clusters 代表远程服务。
|
||||
clusters:
|
||||
- name: name-of-remote-authz-service
|
||||
cluster:
|
||||
certificate-authority: /path/to/ca.pem # 对远程服务进行身份认证的CA。
|
||||
server: https://authz.example.com/authorize # 远程服务的查询 URL. 必须使用 'https'。
|
||||
|
||||
# users 代表 API 服务器的 webhook 配置.
|
||||
users:
|
||||
- name: name-of-api-server
|
||||
user:
|
||||
client-certificate: /path/to/cert.pem # webhook plugin 使用的 cert。
|
||||
client-key: /path/to/key.pem # cert 所对应的 key。
|
||||
|
||||
# kubeconfig 文件必须有 context 。 需要提供一个给 API 服务器。
|
||||
current-context: webhook
|
||||
contexts:
|
||||
- context:
|
||||
cluster: name-of-remote-authz-service
|
||||
user: name-of-api-server
|
||||
name: webhook
|
||||
```
|
||||
|
||||
|
||||
## 请求载荷
|
||||
|
||||
在做认证决策时,API 服务器会 POST 一个 JSON 序列化的 api.authorization.v1beta1.SubjectAccessReview 对象来描述这个动作。这个对象包含了描述用户请求的字段,同时也包含了需要被访问资源或者请求特征的具体信息。
|
||||
|
||||
需要注意的是 webhook API 对象与其他 Kubernetes API 对象一样都同样都服从 [版本兼容规则](/docs/api/) 。
|
||||
实施人员应该了解 beta 对象的更宽松的兼容性承诺,同时确认请求的 "apiVersion" 字段以确保能被正确地反序列化。
|
||||
此外,API 服务器还必须启用 `authorization.k8s.io/v1beta1` API 扩展组(`--runtime-config=authorization.k8s.io/v1beta1=true`)。
|
||||
|
||||
|
||||
一个请求内容的例子:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"resourceAttributes": {
|
||||
"namespace": "kittensandponies",
|
||||
"verb": "get",
|
||||
"group": "unicorn.example.org",
|
||||
"resource": "pods"
|
||||
},
|
||||
"user": "jane",
|
||||
"group": [
|
||||
"group1",
|
||||
"group2"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
远程服务被预期能填写请求和反馈的 SubjectAccessReviewStatus 字段,无论是允许访问还是拒绝访问。
|
||||
反馈内容的 "spec" 字段是被忽略的,也是可以被省略的。当请求是被允许的时候,返回的响应如下例所示:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"status": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
如拒绝,远程服务器会返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"status": {
|
||||
"allowed": false,
|
||||
"reason": "user does not have read access to the namespace"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
对于非资源的路径访问是这么发送的:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiVersion": "authorization.k8s.io/v1beta1",
|
||||
"kind": "SubjectAccessReview",
|
||||
"spec": {
|
||||
"nonResourceAttributes": {
|
||||
"path": "/debug",
|
||||
"verb": "get"
|
||||
},
|
||||
"user": "jane",
|
||||
"group": [
|
||||
"group1",
|
||||
"group2"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
非资源类的路径包括:`/api`, `/apis`, `/metrics`, `/resetMetrics`,
|
||||
`/logs`, `/debug`, `/healthz`, `/swagger-ui/`, `/swaggerapi/`, `/ui`, and
|
||||
`/version`。 客户端需要访问 `/api`, `/api/*`, `/apis`, `/apis/*`, 和 `/version` 以便
|
||||
能发现服务器上有什么资源和版本。对于其他非资源类的路径访问在没有 REST API 访问限制的情况下拒绝。
|
||||
|
||||
|
||||
更多信息可以参考 uthorization.v1beta1 API 对象和
|
||||
[webhook.go](https://git.k8s.io/kubernetes/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
approvers:
|
||||
- jbeda
|
||||
title: 使用启动引导令牌(Bootstrap Tokens)认证
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## 概述
|
||||
|
||||
启动引导令牌是一种简单的持有者令牌(Bearer Token),这种令牌是在新建集群或者在现有集群中添加新节点时使用的。
|
||||
它被设计成能够支持 [`kubeadm`](/docs/admin/kubeadm/),但是也可以被用在其他的案例中以便用户在
|
||||
不使用 `kubeadm` 的情况下启动集群。它也被设计成可以通过 RBAC 策略,结合 [Kubelet TLS
|
||||
Bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 系统进行工作。
|
||||
|
||||
启动引导令牌被定义成一个特定类型的 secrets(`bootstrap.kubernetes.io/token`),并存在于
|
||||
`kube-system` 命名空间中。然后这些 secrets 会被 API 服务器上的启动引导的认证器读取。
|
||||
控制器管理器中的控制器TokenCleaner能够删除过期的令牌。在节点发现的过程中Kubernetes会使用特殊的ConfigMap对象。
|
||||
控制器管理器中的BootstrapSigner控制器也会使用启动引导令牌为这类对象生成签名信息。
|
||||
|
||||
目前,启动引导令牌处于 **alpha** 阶段,但是预期也不会有大的突破性变化。
|
||||
|
||||
## 令牌格式
|
||||
|
||||
启动引导令牌使用 `abcdef.0123456789abcdef` 的形式。
|
||||
更加规范地说,它们必须符合正则表达式 `[a-z0-9]{6}\.[a-z0-9]{16}`。
|
||||
|
||||
令牌的第一部分是 "Token ID" ,它是公共信息。用于引用某个令牌,并确保不会泄露认证所使用的秘密信息。
|
||||
第二部分是 "令牌秘密(Token Secret)",它应该被共享给收信的第三方。
|
||||
|
||||
## 启用启动引导令牌
|
||||
|
||||
所有与启动引导令牌相关的特性在 Kubernetes v1.6 版本中默认都是禁用的。
|
||||
|
||||
你可以在 API 服务器上通过 `--experimental-bootstrap-token-auth` 参数启用启动引导令牌。
|
||||
你可以设置控制管理器的 `--controllers` 参数来启用启动引导令牌相关的控制器,例如 `--controllers=*,tokencleaner,bootstrapsigner` 。
|
||||
在使用 `kubeadm` 时,这是自动完成的。
|
||||
|
||||
HTTPS 调用中的令牌是这样使用的:
|
||||
|
||||
```http
|
||||
Authorization: Bearer 07401b.f395accd246ae52d
|
||||
```
|
||||
|
||||
## 启动引导令牌的密文格式
|
||||
|
||||
每个合法的令牌背后对应着 `kube-system` 命名空间中的某个 Secret 对象。
|
||||
你可以从 [这里](https://git.k8s.io/community/contributors/design-proposals/bootstrap-discovery.md) 找到完整设计文档。
|
||||
|
||||
这是 secret 看起来的样子。注意,`base64(string)` 表示应该通过 base64 对值进行编码。
|
||||
这里使用的是未解码的版本以便于阅读。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: bootstrap-token-07401b
|
||||
namespace: kube-system
|
||||
type: bootstrap.kubernetes.io/token
|
||||
data:
|
||||
description: base64(The default bootstrap token generated by 'kubeadm init'.)
|
||||
token-id: base64(07401b)
|
||||
token-secret: base64(f395accd246ae52d)
|
||||
expiration: base64(2017-03-10T03:22:11Z)
|
||||
usage-bootstrap-authentication: base64(true)
|
||||
usage-bootstrap-signing: base64(true)
|
||||
```
|
||||
|
||||
secret 的类型必须是 `bootstrap.kubernetes.io/token` ,而且名字必须是 `bootstrap-token-<token id>`。
|
||||
`description` 是人类可读的描述,而不应该是机器可读的信息。令牌 ID 和 Secret 是包含在数据字典中的。
|
||||
|
||||
`usage-bootstrap-*` 成员表示这个 secret 的用途。启用时,值必须设置为 `true`。
|
||||
|
||||
`usage-bootstrap-authentication` 表示令牌可以用于 API 服务器的认证。认证器会以
|
||||
`system:bootstrap:<Token ID>` 认证。它被包含在 `system:bootstrappers` 组中。
|
||||
命名和组是故意受限制的,以防止用户在启动引导后再使用这些令牌。
|
||||
|
||||
`usage-bootstrap-signing` 表示令牌应该被用于 `cluster-info` ConfigMap 的签名,就像下面描述的那样。
|
||||
|
||||
`expiration` 数据成员显示了令牌在失效后到现在的时间。这是遵循 RFC3339 进行编码的 UTC 时间。
|
||||
TokenCleaner 控制器会删除过期的令牌。
|
||||
|
||||
## 使用 `kubeadm` 管理令牌
|
||||
|
||||
你可以使用 `kubeadm` 工具管理正在运行集群的令牌。它会从 `kubeadm` 创建的集群(`/etc/kubernetes/admin.conf`)
|
||||
自动抓取默认管理员密码。你可以通过参数 `--kubeconfig` 对下面命令指定一个另外的 kubeconfig 文件抓取密码。
|
||||
|
||||
* `kubeadm token list` 列举了令牌,同时显示了它们的过期时间和用途。
|
||||
* `kubeadm token create` 创建一个新令牌。
|
||||
* `--description` 设置新令牌的描述。
|
||||
* `--ttl duration` 设置令牌从 "现在" 起到过期时间的差值。
|
||||
默认是 0 ,也就是不过期。
|
||||
* `--usages` 设置令牌被使用的方式。默认是 `signing,authentication`。用途在上面已经描述。
|
||||
* `kubeadm token delete <token id>|<token id>.<token secret>` 删除令牌。
|
||||
令牌可以只用 ID 来确认,也可以用整个令牌的值。如果只用 ID 的情况下,密文不匹配的令牌也会被删除。
|
||||
|
||||
### ConfigMap签名
|
||||
|
||||
除了认证之外,令牌可以用于签名 ConfigMap。这在集群启动过程的早期,在客户端信任 API 服务器之前被使用。
|
||||
被签名的 ConfigMap 可以通过共享令牌被认证。
|
||||
|
||||
被签名的 ConfigMap 是 `cluster-info`,存在于 `kube-public` 命名空间中。
|
||||
典型的工作流中,客户端在未经认证和忽略 TLS 报错的状态下读取这个 ConfigMap。
|
||||
通过 ConfigMap 中嵌入的签名校验 ConfigMap 的载荷。
|
||||
|
||||
ConfigMap 会是这个样子的:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cluster-info
|
||||
namespace: kube-public
|
||||
data:
|
||||
jws-kubeconfig-07401b: eyJhbGciOiJIUzI1NiIsImtpZCI6IjA3NDAxYiJ9..tYEfbo6zDNo40MQE07aZcQX2m3EB2rO3NuXtxVMYm9U
|
||||
kubeconfig: |
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data: <really long certificate data>
|
||||
server: https://10.138.0.2:6443
|
||||
name: ""
|
||||
contexts: []
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users: []
|
||||
```
|
||||
|
||||
ConfigMap 的 `kubeconfig` 成员是一个填好了集群信息的配置文件。
|
||||
这里主要交换的信息是 `certificate-authority-data`。在将来可能会有扩展。
|
||||
|
||||
签名是一个 JWS 签名,使用了 "detached" 模式。为了检验签名,用户应该按照 JWS 规则
|
||||
(base64 编码而忽略结尾的 `=`)对 `kubeconfig` 的载荷进行编码。完成编码的载荷会被通过插入 JWS 并存在于两个点的中间
|
||||
,用于形成一个完整的 JWS。可以使用令牌的完整信息(比如 `07401b.f395accd246ae52d`)作为共享密钥,
|
||||
通过 `HS256` 方式 (HMAC-SHA256) 对 JWS 进行校验。 用户 _必须_ 确保使用了 HS256。
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
title: 创建大规模集群
|
||||
---
|
||||
|
||||
## 支持规格
|
||||
|
||||
在 {{< param "version" >}},Kubernetes支持最多5000节点规模的集群。 更具体地说,我们支持满足以下 *所有* 标准的配置:
|
||||
|
||||
* 不超过5000节点
|
||||
* 总共不超过15000个pod
|
||||
* 总共不超过300000个容器
|
||||
* 每个节点不超过100个pod
|
||||
|
||||
<br>
|
||||
|
||||
* TOC
|
||||
{{< toc >}}
|
||||
|
||||
## 创建
|
||||
|
||||
集群是一组运行Kubernetes代理组件的节点(物理或虚拟机),它们被 "master" (集群管理平面)所管理。
|
||||
|
||||
一般来说,集群的节点数量通过平台相关的 `config-default.sh` 文件中的 `NUM_NODES` 值来控制,(例如,详见 [GCE's `config-default.sh`](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/gce/config-default.sh))。
|
||||
|
||||
对很多云提供商来说,单纯地修改`NUM_NODES` 为一个非常大的值,可能会导致集群的创建脚本失败。 例如,在GCE中部署时,会因配额不足,导致集群启动失败。
|
||||
|
||||
当建立一个大型的Kubernetes集群,以下几个问题必须考虑。
|
||||
|
||||
### 配额问题
|
||||
|
||||
为了避免出现配额问题,当创建包含大量节点的集群时,考虑:
|
||||
|
||||
* 提高相关配额,如CPU,IP等。
|
||||
* 如,在 [GCE](https://cloud.google.com/compute/docs/resource-quotas)中,你可能需要提高以下资源的配额:
|
||||
* CPU
|
||||
* 虚机实例
|
||||
* 磁盘
|
||||
* 使用的IP地址
|
||||
* 防火墙规则
|
||||
* 转发规则
|
||||
* 路由
|
||||
* 对象池
|
||||
* 设置创建脚本,使其以较小的规模分批次拉起新的节点,并在其间设置一定的等待时间,因为一些云供应商可能对虚机的创建速率进行了限制。
|
||||
|
||||
### Etcd存储
|
||||
|
||||
为了提升大规模集群的性能,我们将事件对象存储到独立的etcd实例中。
|
||||
|
||||
创建集群时,当前的salt脚本:
|
||||
|
||||
* 启动并配置额外的etcd实例
|
||||
* 配置api-server,将该etcd实例用于事件对象的存储
|
||||
|
||||
### 管理节点和组件的规格
|
||||
|
||||
在 GCE/Google Kubernetes Engine 或 AWS平台中, `kube-up` 会根据集群的节点规模合理地设置管理节点的规格。 在其他云平台上,用户需要手动配置。 作为参考,GCE使用的规格为:
|
||||
|
||||
* 1-5 节点: n1-standard-1
|
||||
* 6-10 节点: n1-standard-2
|
||||
* 11-100 节点: n1-standard-4
|
||||
* 101-250 节点: n1-standard-8
|
||||
* 251-500 节点: n1-standard-16
|
||||
* 500节点以上: n1-standard-32
|
||||
|
||||
AWS使用的规格为:
|
||||
|
||||
* 1-5 节点: m3.medium
|
||||
* 6-10 节点: m3.large
|
||||
* 11-100 节点: m3.xlarge
|
||||
* 101-250 节点: m3.2xlarge
|
||||
* 251-500 节点: c4.4xlarge
|
||||
* 500节点以上: c4.8xlarge
|
||||
|
||||
注意,管理节点的规格只会在集群创建时进行设置,后续集群规模发生变化 (如 手动增删节点或集群自动扩缩容)后不会再调整。
|
||||
|
||||
### 插件的资源占用
|
||||
|
||||
为防止 [集群插件](https://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons) 耗尽节点资源引起内存泄漏或其他资源问题, Kubernetes 设置了插件容器资源的上限,来限制其对CPU和内存资源的占用 (参考 PR [#10653](http://pr.k8s.io/10653/files) 和 [#10778](http://pr.k8s.io/10778/files))。
|
||||
|
||||
例如:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: fluentd-cloud-logging
|
||||
image: k8s.gcr.io/fluentd-gcp:1.16
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
```
|
||||
|
||||
除 Heapster 外,这些限制是静态的,基于4个节点规模的集群上运行的插件所采集的数据 (详见 [#10335](http://issue.k8s.io/10335#issuecomment-117861225))。 而实际大规模集群中插件所消耗的资源要多得多 (详见 [#5880](http://issue.k8s.io/5880#issuecomment-113984085))。 所以如果部署大规模集群时不对这些值进行调整,插件可能会因为资源占用达到上限而不断被杀死。
|
||||
|
||||
为了避免集群插件的资源问题,创建多节点的集群时,考虑以下几点:
|
||||
|
||||
* 当扩大集群规模时,如果涉及,相应扩大以下插件的内存和CPU限制 (通过一个实例处理整个集群,因此其内存和CPU使用量往往与集群的大小/负载成比例增长):
|
||||
* [InfluxDB 和 Grafana](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/cluster-monitoring/influxdb/influxdb-grafana-controller.yaml)
|
||||
* [kubedns, dnsmasq, 和 sidecar](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/kubedns-controller.yaml.in)
|
||||
* [Kibana](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/kibana-controller.yaml)
|
||||
* 当扩大集群规模时,如果涉及,相应扩大以下插件副本数 (每个组件有多个副本,因此增加副本将有助于处理增加的负载,但是,由于每个副本的负载也略有增加,也应考虑提高CPU /内存上限):
|
||||
* [elasticsearch](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/es-controller.yaml)
|
||||
* 当扩大集群规模时,如果涉及,略微扩大以下插件的内存和CPU限制 (每个节点一个副本, 但是CPU/内存使用随集群的大小/负载增长变化不明显):
|
||||
* [FluentD with ElasticSearch Plugin](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-elasticsearch/fluentd-es-ds.yaml)
|
||||
* [FluentD with GCP Plugin](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml)
|
||||
|
||||
Heapster的资源限制是基于集群的初始规模动态设置的 (参考 [#16185](http://issue.k8s.io/16185)
|
||||
和 [#22940](http://issue.k8s.io/22940))。 当发现Heapster资源耗尽,应考虑调整计算Heapster内存请求的公式 (参考上述PR)。
|
||||
|
||||
关于如何检测插件是否达到资源上限 参考 [计算资源的故障排除章节](/docs/concepts/configuration/manage-compute-resources-container/#troubleshooting)。
|
||||
|
||||
[将来](http://issue.k8s.io/13048),我们期望基于集群规模来设置集群插件的资源限制,并且在集群规模增长或缩小时能够动态调整。
|
||||
欢迎提出PR来实现这些特性。
|
||||
|
||||
### 启动时允许部分失败
|
||||
|
||||
因为种种原因 (详见 [#18969](https://github.com/kubernetes/kubernetes/issues/18969)),在 `NUM_NODES` 值很大的情况下执行
|
||||
`kube-up.sh`, 可能因为其中一小部分节点没有正常启动而失败。
|
||||
这时我们有两种选择:重启集群 (`kube-down.sh` 然后再 `kube-up.sh`),或者在执行 `kube-up.sh`之前,
|
||||
将环境变量 `ALLOWED_NOTREADY_NODES` 设置为合适的值。 这将允许 `kube-up.sh` 以少于 `NUM_NODES` 的节点数量启动集群。 依据失败的具体原因,另外的节点可能在后面加入集群,或者集群节点数量将保持在 `NUM_NODES - ALLOWED_NOTREADY_NODES`。
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: prometheus-node-exporter
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: prometheus-node-exporter
|
||||
labels:
|
||||
daemon: prom-node-exp
|
||||
spec:
|
||||
containers:
|
||||
- name: c
|
||||
image: prom/prometheus
|
||||
ports:
|
||||
- containerPort: 9090
|
||||
hostPort: 9090
|
||||
name: serverport
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
title: 构建高可用集群
|
||||
---
|
||||
|
||||
|
||||
## 简介
|
||||
|
||||
|
||||
本文描述了如何构建一个高可用(high-availability, HA)的Kubernetes集群。这是一个非常高级的主题。
|
||||
|
||||
对于仅希望使用Kubernetes进行试验的用户,推荐使用更简单的配置工具进行搭建,例如:
|
||||
[Minikube](/docs/getting-started-guides/minikube/),或者尝试使用[Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) 来运行Kubernetes。
|
||||
|
||||
此外,当前在我们的端到端(e2e)测试环境中,没有对Kubernetes高可用的支持进行连续测试。我们将会增加这个连续测试项,但当前对单节点master的安装测试得更加严格。
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## 概览
|
||||
|
||||
|
||||
搭建一个正真可靠,高度可用的分布式系统需要若干步骤。这类似于穿上内衣,裤子,皮带,背带,另一套内衣和另一套裤子。我们会详细介绍每一个步骤,但先在这里给出一个总结来帮助指导用户。
|
||||
|
||||
|
||||
相关步骤如下:
|
||||
|
||||
* [创建可靠的组成节点,共同形成我们的高可用主节点实现。](#可靠的节点)
|
||||
* [使用etcd集群,搭建一个冗余的,可靠的存储层。](#建立一个冗余的,可靠的存储层)
|
||||
* [启动具有备份和负载均衡能力的Kubernetes API 服务](#复制的API服务)
|
||||
* [搭建运行master选举的Kubernetes scheduler和controller-manager守护程序](#进行master选举的组件)
|
||||
|
||||
系统完成时看起来应该像这样:
|
||||
|
||||

|
||||
|
||||
|
||||
## 初始配置
|
||||
|
||||
|
||||
本文假设你正在搭建一个3节点的主节点集群,每个节点上都运行者某种Linux系统。
|
||||
|
||||
指南中的示例使用Debian发行版,但它们应该可以被轻松移植到其他发行版上。
|
||||
|
||||
同样的,不管在公有云还是私有云亦或是裸机上,这个配置都应该可以运行。
|
||||
|
||||
|
||||
从一个现成的单主节点集群开始是实现一个高可用Kubernetes集群的最简单的方法。这篇指导 [https://get.k8s.io](https://get.k8s.io) 描述了在多种平台上方便的安装一个单主节点集群的方法。
|
||||
|
||||
## 可靠的节点
|
||||
|
||||
|
||||
我们在每个主节点上都将运行数个实现Kubernetes API的进程。使他们可靠的第一步是保证在发生故障时,每一个进程都可以自动重启。为了实现这个目标,我们需要安装一个进程监视器。我们选择了在每个工作者节点上都会运行的`kubelet`进程。这会带来便利性,因为我们使用了容器来分发我们的二进制文件,所以我们能够为每一个守护程序建立资源限制并省查它们的资源消耗。当然,我们也需要一些手段来监控kubelete本身(在此监测监控者本身是一个有趣的话题)。对于Debian系统我们选择了monit,但也有许多可替代的工具。例如在基于systemd的系统上(如RHEL, CentOS),你可以运行 'systemctl enable kubelet'。
|
||||
|
||||
|
||||
如果你是从标准的Kubernetes安装扩展而来,那么`kubelet`二进制文件应该已经存在于你的系统中。你可以运行`which kubelet`来判断是否确实安装了这个二进制文件。如果没有安装的话,你应该手动安装 [kubelet binary](https://storage.googleapis.com/kubernetes-release/release/v0.19.3/bin/linux/amd64/kubelet),
|
||||
[kubelet init file](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/saltbase/salt/kubelet/initd) 和 [default-kubelet](/docs/admin/high-availability/default-kubelet)脚本。
|
||||
|
||||
如果使用monit,你还需要安装monit守护程序(`apt-get install monit`)以及[monit-kubelet](/docs/admin/high-availability/monit-kubelet) 和
|
||||
[monit-docker](/docs/admin/high-availability/monit-docker) 配置。
|
||||
|
||||
在使用systemd的系统上,你可以执行 `systemctl enable kubelet` 和 `systemctl enable docker`。
|
||||
|
||||
|
||||
## 建立一个冗余的,可靠的存储层
|
||||
|
||||
|
||||
高可用方案的中心基础是一个冗余的,可靠的存储层。高可用的头条规则是保护数据。不管发生了什么,不管什么着了火,只要还有数据,你就可以重建。如果丢掉了数据,你就完了。
|
||||
|
||||
|
||||
集群化的etcd已经把你存储的数据复制到了你集群中的所有主节点实例上。这意味着如果要想丢失数据,三个节点的物理(或虚拟)硬盘需要全部同时故障。这种情况发生的概率是比较低的,所以对于许多人来说,运行一个复制的etcd集群可能已经足够的可靠了。你可以将集群数量从3个增大到5个来增加集群的可靠性。如果那样还不够,你可以添加[更多的可靠性到你的存储层](#更加可靠的存储)。
|
||||
|
||||
|
||||
### 集群化etcd
|
||||
|
||||
|
||||
集群化etcd的完整细节超出了本文范围,你可以在[etcd clustering page](https://github.com/coreos/etcd/blob/master/Documentation/op-guide/clustering.md)找到许多详细内容。这个例子仅走查一个简单的集群建立过程,使用etcd内置的发现功能来构建我们的集群。
|
||||
|
||||
|
||||
首先,调用etcd发现服务来创建一个新令牌:
|
||||
|
||||
```shell
|
||||
curl https://discovery.etcd.io/new?size=3
|
||||
```
|
||||
|
||||
|
||||
在每个节点上,拷贝 [etcd.yaml](/docs/admin/high-availability/etcd.yaml) 文件到`/etc/kubernetes/manifests/etcd.yaml`。
|
||||
|
||||
|
||||
每个节点上的kubelet会动态的监控这个文件夹的内容,并且会按照`etcd.yaml`里对pod的定义创建一个`etcd`服务的实例。
|
||||
|
||||
|
||||
请注意,你应该使用上文中获取的令牌URL替换全部三个节点上`etcd.yaml`中的`${DISCOVERY_TOKEN}`项。同时还应该将每个节点上的 `${NODE_NAME}`替换为一个不同的名字(例如:`node-1`),并将 `${NODE_IP}`替换为正确的IP地址。
|
||||
|
||||
|
||||
#### 验证你的集群
|
||||
|
||||
|
||||
如果已经将这个文件拷贝到所有三个节点,你应该已经搭建起了一个集群化的etcd。你可以在主节点上进行验证:
|
||||
```shell
|
||||
kubectl exec < pod_name > etcdctl member list
|
||||
```
|
||||
|
||||
和
|
||||
|
||||
```shell
|
||||
kubectl exec < pod_name > etcdctl cluster-health
|
||||
```
|
||||
|
||||
|
||||
你也可以在一个节点上运行 `etcdctl set foo bar`,在另一个节点上运行`etcdctl get foo`来验证集群是否工作正常。
|
||||
|
||||
|
||||
### 更加可靠的存储
|
||||
|
||||
|
||||
当然,如果你对增加数据的可靠性感兴趣,这里还有一些更深入的选项可以使etcd把它的数据存放在比常规硬盘更可靠的地方(裤带和背带,ftw!)。
|
||||
|
||||
|
||||
如果你使用云服务,那么你的提供商通常会为你提供这个特性,例如Google Cloud Platform上的 [Persistent Disk](https://cloud.google.com/compute/docs/disks/persistent-disks) 。它们是可以挂载到你的虚拟机中的块设备持久化存储。其他的云服务提供商提供了类似的解决方案。
|
||||
|
||||
|
||||
如果运行于物理机之上,你仍然可以使用iSCSI或者NFS接口通过网络来连接冗余存储。
|
||||
此外,你还可以运行一个集群文件系统,比如Gluster或者Ceph。最后,你还可以在你的每个物理机器上运行RAID矩阵。
|
||||
|
||||
|
||||
不管你选择如何实现,如果已经选择了使用其中的一个选项,那么你应该保证你的存储被挂载到了每一台机器上。如果你的存储在集群中的三个主节点之间共享,那么你应该在存储上为每一个节点创建一个不同的文件夹。对于所有的这些指导,我们都假设这个存储被挂载到你机器上的`/var/etcd/data`路径。
|
||||
|
||||
|
||||
## 复制的API服务
|
||||
|
||||
|
||||
在正确搭建复制的etcd之后,我们还需要使用kubelet安装apiserver。
|
||||
|
||||
|
||||
|
||||
|
||||
首先,你需要创建初始的日志文件,这样Docker才会挂载一个文件而不是一个文件夹:
|
||||
```shell
|
||||
touch /var/log/kube-apiserver.log
|
||||
```
|
||||
|
||||
接下来,你需要在每个节点上创建一个`/srv/kubernetes/`文件夹。这个文件夹包含:
|
||||
|
||||
* basic_auth.csv - 基本认证的用户名和密码
|
||||
* ca.crt - CA证书
|
||||
* known_tokens.csv - 实体(例如kubelet)用来和apiserver通信的令牌
|
||||
* kubecfg.crt - 客户端证书,公钥
|
||||
* kubecfg.key - 客户端证书,私钥
|
||||
* server.cert - 服务端证书,公钥
|
||||
* server.key - 服务端证书,私钥
|
||||
|
||||
|
||||
创建这个文件夹最简单的方法可以是从一个工作正常的集群的主节点拷贝,或者你也可以手动生成它们。
|
||||
|
||||
|
||||
### 启动API服务
|
||||
|
||||
|
||||
一旦这些文件已经存在了,拷贝 [kube-apiserver.yaml](/docs/admin/high-availability/kube-apiserver.yaml) 到每个主节点的 `/etc/kubernetes/manifests/`文件夹。
|
||||
|
||||
|
||||
kubelet会监控这个文件夹,并且会按照文件里对pod的定义创建一个`kube-apiserver`容器。
|
||||
|
||||
|
||||
### 负载均衡
|
||||
|
||||
|
||||
现在,你应该有3个全部正常工作的apiserver了。如果搭建了网络负载均衡器,你应该能够通过那个负载均衡器访问你的集群,并且看到负载在apiserver实例间分发。设置负载均衡器依赖于你的平台的实际情况,例如对于Google Cloud Platform的指导可以在[这里](https://cloud.google.com/compute/docs/load-balancing/)找到。
|
||||
|
||||
|
||||
请注意,如果使用了身份认证,你可能需要重新生成你的证书,除每个节点的IP地址外额外包含负载均衡器的IP地址。
|
||||
|
||||
|
||||
对于部署在集群中的pods, `kubernetes`服务/dns名称应该自动的为主节点提供了负载均衡的endpoint。
|
||||
|
||||
|
||||
对于使用API的外部用户(如命令行运行的`kubectl`,持续集成管道或其他客户端)你会希望将他们配置成为访问外部负载均衡器的地址。
|
||||
|
||||
|
||||
## 进行Master选举的组件
|
||||
|
||||
|
||||
到目前为止,我们已经搭建了状态存储,也搭建好了API服务,但我们还没有运行任何真正改变集群状态的服务,比如controller manager和scheduler。为了可靠的实现这个目标,我们希望在同一时间只有一个参与者在修改集群状态。但是我们希望复制这些参与者的实例以防某个机器宕机。要做到这一点,我们打算在API中使用一个lease-lock来执行master选举。我们会对每一个scheduler和controller-manager使用`--leader-elect`标志,从而在API中使用一个租约来保证同一时间只有一个scheduler和controller-manager的实例正在运行。
|
||||
|
||||
|
||||
scheduler和controller-manager可以配置为只和位于它们相同节点(即127.0.0.1)上的API服务通信,也可以配置为使用API服务的负载均衡器的IP地址。不管它们如何配置,当使用`--leader-elect` 时scheduler和controller-manager都将完成上文提到的leader选举过程。
|
||||
|
||||
|
||||
为了防止访问API服务失败,选举出的leader不能通过更新租约来选举一个新的leader。当scheduler和controller-manager通过127.0.0.1访问API服务,而相同节点上的API服务不可用时,这一点相当重要。
|
||||
|
||||
|
||||
### 安装配置文件
|
||||
|
||||
|
||||
首先,在每个节点上创建空白日志文件,这样Docker就会挂载这些文件而不是创建一个新文件夹:
|
||||
|
||||
```shell
|
||||
touch /var/log/kube-scheduler.log
|
||||
touch /var/log/kube-controller-manager.log
|
||||
```
|
||||
|
||||
|
||||
接下来,在每个节点上配置scheduler和controller manager pods的描述文件。拷贝 [kube-scheduler.yaml](/docs/admin/high-availability/kube-scheduler.yaml) 和 [kube-controller-manager.yaml](/docs/admin/high-availability/kube-controller-manager.yaml) 到`/etc/kubernetes/manifests/` 文件夹。
|
||||
|
||||
|
||||
## 结尾
|
||||
|
||||
|
||||
此时,你已经完成了master组件的配置(耶!),但你还需要添加工作者节点(噗!)。
|
||||
|
||||
|
||||
如果你有一个现成的集群,你只需要在每个节点上简单的重新配置你的kubeletes连接到负载均衡的endpoint并重启它们。
|
||||
|
||||
|
||||
如果你搭建的是一个全新的集群,你将需要在每个工作节点上安装kubelet和kube-proxy,并设置 `--apiserver`指向复制的endpoint。
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
title: kube-apiserver
|
||||
notitle: true
|
||||
---
|
||||
## kube-apiserver
|
||||
|
||||
|
||||
|
||||
### 概要
|
||||
|
||||
|
||||
Kubernetes API server 为 api 对象验证并配置数据,包括 pods、 services、 replicationcontrollers和其它 api 对象。API Server 提供 REST 操作和到集群共享状态的前端,所有其他组件通过它进行交互。
|
||||
|
||||
```
|
||||
kube-apiserver
|
||||
```
|
||||
|
||||
### 选项
|
||||
```
|
||||
|
||||
--admission-control stringSlice 控制资源进入集群的准入控制插件的顺序列表。逗号分隔的NamespaceLifecycle列表。(默认值[AlwaysAdmit])
|
||||
|
||||
--admission-control-config-file string 包含准入控制配置的文件。
|
||||
|
||||
--advertise-address ip 向集群成员通知apiserver消息的IP地址。这个地址必须能够被集群中其他成员访问。如果IP地址为空,将会使用--bind-address,如果未指定--bind-address,将会使用主机的默认接口地址。
|
||||
|
||||
--allow-privileged 如果为true, 将允许特权容器.
|
||||
|
||||
--anonymous-auth 启用到API server的安全端口的匿名请求。未被其他认证方法拒绝的请求被当做匿名请求。匿名请求的用户名为system:anonymous,用户组名为system:unauthenticated。(默认值true)
|
||||
|
||||
--apiserver-count int 集群中运行的apiserver数量,必须为正数。(默认值1)
|
||||
|
||||
--audit-log-maxage int 基于文件名中的时间戳,旧审计日志文件的最长保留天数。
|
||||
|
||||
--audit-log-maxbackup int 旧审计日志文件的最大保留个数.
|
||||
|
||||
--audit-log-maxsize int 审计日志被轮转前的最大兆字节数。
|
||||
|
||||
--audit-log-path string 如果设置该值,所有到apiserver的请求都将会被记录到这个文件。'-'表示记录到标准输出。
|
||||
|
||||
--audit-policy-file string 定义审计策略配置的文件的路径。需要打开'AdvancedAuditing'特性开关。AdvancedAuditing需要一个配置来启用审计功能。
|
||||
|
||||
--audit-webhook-config-file string 一个具有kubeconfig格式文件的路径,该文件定义了审计的webhook配置。需要打开'AdvancedAuditing'特性开关。
|
||||
|
||||
--audit-webhook-mode string 发送审计事件的策略。 Blocking模式表示正在发送事件时应该阻塞服务器的响应。 Batch模式使webhook异步缓存和发送事件。 Known模式为batch,blocking。 (默认值"batch")
|
||||
|
||||
--authentication-token-webhook-cache-ttl duration 从webhook令牌认证者获取的响应的缓存时长。(默认值2m0s)
|
||||
|
||||
--authentication-token-webhook-config-file string 包含webhook配置的文件,用于令牌认证,具有kubeconfig格式。API server将查询远程服务来决定对bearer令牌的认证。
|
||||
|
||||
--authorization-mode string 在安全端口上进行权限验证的插件的顺序列表。以逗号分隔的列表,包括:AlwaysAllow,AlwaysDeny,ABAC,Webhook,RBAC,Node.(默认值"AlwaysAllow")
|
||||
|
||||
--authorization-policy-file string 包含权限验证策略的csv文件,和--authorization-mode=ABAC一起使用,作用在安全端口上。
|
||||
|
||||
--authorization-webhook-cache-authorized-ttl duration 从webhook授权者获得的'authorized'响应的缓存时长。(默认值5m0s)
|
||||
|
||||
--authorization-webhook-cache-unauthorized-ttl duration 从webhook授权者获得的'unauthorized'响应的缓存时长。(默认值30s)
|
||||
|
||||
--authorization-webhook-config-file string 包含webhook配置的kubeconfig格式文件,和--authorization-mode=Webhook一起使用。API server将查询远程服务来决定对API server安全端口的访问。
|
||||
|
||||
--azure-container-registry-config string 包含Azure容器注册表配置信息的文件的路径。
|
||||
|
||||
--basic-auth-file string 如果设置该值,这个文件将会被用于准许通过http基本认证到API server安全端口的请求。
|
||||
|
||||
--bind-address ip 监听--seure-port的IP地址。被关联的接口必须能够被集群其它节点和CLI/web客户端访问。如果为空,则将使用所有接口(0.0.0.0)。(默认值0.0.0.0)
|
||||
|
||||
--cert-dir string 存放TLS证书的目录。如果提供了--tls-cert-file和--tls-private-key-file选项,该标志将被忽略。(默认值 "/var/run/kubernetes")
|
||||
|
||||
--client-ca-file string 如果设置此标志,对于任何请求,如果存包含client-ca-file中的authorities签名的客户端证书,将会使用客户端证书中的CommonName对应的身份进行认证。
|
||||
|
||||
--cloud-config string 云服务提供商配置文件路径。空字符串表示无配置文件.
|
||||
|
||||
--cloud-provider string 云服务提供商,空字符串表示无提供商。
|
||||
|
||||
--contention-profiling 如果已经启用profiling,则启用锁竞争profiling。
|
||||
|
||||
--cors-allowed-origins stringSlice CORS的域列表,以逗号分隔。合法的域可以是一个匹配子域名的正则表达式。如果这个列表为空则不会启用CORS.
|
||||
|
||||
--delete-collection-workers int 用于DeleteCollection调用的工作者数量。这被用于加速namespace的清理。(默认值1)
|
||||
|
||||
--deserialization-cache-size int 在内存中缓存的反序列化json对象的数量。
|
||||
|
||||
--enable-aggregator-routing 打开到endpoints IP的aggregator路由请求,替换cluster IP。
|
||||
|
||||
--enable-garbage-collector 启用通用垃圾回收器. 必须与kube-controller-manager对应的标志保持同步。 (默认值true)
|
||||
|
||||
--enable-logs-handler 如果为true,则为apiserver日志功能安装一个/logs处理器。(默认值true)
|
||||
|
||||
--enable-swagger-ui 在apiserver的/swagger-ui路径启用swagger ui。
|
||||
|
||||
--etcd-cafile string 用于保护etcd通信的SSL CA文件。
|
||||
|
||||
--etcd-certfile string 用于保护etcd通信的的SSL证书文件。
|
||||
|
||||
--etcd-keyfile string 用于保护etcd通信的SSL密钥文件.
|
||||
|
||||
--etcd-prefix string 附加到所有etcd中资源路径的前缀。 (默认值"/registry")
|
||||
|
||||
--etcd-quorum-read 如果为true, 启用quorum读。
|
||||
|
||||
--etcd-servers stringSlice 连接的etcd服务器列表,形式为(scheme://ip:port),使用逗号分隔。
|
||||
|
||||
--etcd-servers-overrides stringSlice 针对单个资源的etcd服务器覆盖配置, 以逗号分隔。 单个配置覆盖格式为: group/resource#servers, 其中servers形式为http://ip:port, 以分号分隔。
|
||||
|
||||
--event-ttl duration 事件驻留时间。(默认值1h0m0s)
|
||||
|
||||
--experimental-bootstrap-token-auth 启用此选项以允许'kube-system'命名空间中的'bootstrap.kubernetes.io/token'类型密钥可以被用于TLS的启动认证。
|
||||
|
||||
--experimental-encryption-provider-config string 包含加密提供程序的配置的文件,该加密提供程序被用于在etcd中保存密钥。
|
||||
|
||||
--experimental-keystone-ca-file string 如果设置该值,将会使用experimental-keystone-ca-file中的一个authority对Keystone服务的证书进行验证,否则将会使用主机的根CA进行验证。
|
||||
|
||||
--experimental-keystone-url string 如果设置了该值,将启用keystone认证插件。
|
||||
|
||||
--external-hostname string 为此master生成外部URL时使用的主机名(例如Swagger API文档)。
|
||||
|
||||
--feature-gates mapStringBool 一个描述alpha/experimental特性开关的键值对列表。 选项包括:
|
||||
Accelerators=true|false (ALPHA - default=false)
|
||||
AdvancedAuditing=true|false (ALPHA - default=false)
|
||||
AffinityInAnnotations=true|false (ALPHA - default=false)
|
||||
AllAlpha=true|false (ALPHA - default=false)
|
||||
AllowExtTrafficLocalEndpoints=true|false (default=true)
|
||||
AppArmor=true|false (BETA - default=true)
|
||||
DynamicKubeletConfig=true|false (ALPHA - default=false)
|
||||
DynamicVolumeProvisioning=true|false (ALPHA - default=true)
|
||||
ExperimentalCriticalPodAnnotation=true|false (ALPHA - default=false)
|
||||
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - default=false)
|
||||
LocalStorageCapacityIsolation=true|false (ALPHA - default=false)
|
||||
PersistentLocalVolumes=true|false (ALPHA - default=false)
|
||||
RotateKubeletClientCertificate=true|false (ALPHA - default=false)
|
||||
RotateKubeletServerCertificate=true|false (ALPHA - default=false)
|
||||
StreamingProxyRedirects=true|false (BETA - default=true)
|
||||
TaintBasedEvictions=true|false (ALPHA - default=false)
|
||||
|
||||
--google-json-key string 用于认证的Google Cloud Platform服务账号的JSON密钥。
|
||||
|
||||
--insecure-allow-any-token username/group1,group2 如果设置该值, 你的服务将处于非安全状态。任何令牌都将会被允许,并将从令牌中把用户信息解析成为username/group1,group2。
|
||||
|
||||
--insecure-bind-address ip 用于监听--insecure-port的IP地址 (设置成0.0.0.0表示监听所有接口)。(默认值127.0.0.1)
|
||||
|
||||
--insecure-port int 用于监听不安全和为认证访问的端口。这个配置假设你已经设置了防火墙规则,使得这个端口不能从集群外访问。对集群的公共地址的443端口的访问将被代理到这个端口。默认设置中使用nginx实现。(默认值8080)
|
||||
|
||||
--kubelet-certificate-authority string 证书authority的文件路径。
|
||||
|
||||
--kubelet-client-certificate string 用于TLS的客户端证书文件路径。
|
||||
|
||||
--kubelet-client-key string 用于TLS的客户端证书密钥文件路径.
|
||||
|
||||
--kubelet-https 为kubelet启用https。 (默认值true)
|
||||
|
||||
--kubelet-preferred-address-types stringSlice 用于kubelet连接的首选NodeAddressTypes列表。 (默认值[Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP])
|
||||
|
||||
--kubelet-read-only-port uint 已废弃: kubelet端口. (默认值10255)
|
||||
|
||||
--kubelet-timeout duration kubelet操作超时时间。(默认值
|
||||
5s)
|
||||
|
||||
--kubernetes-service-node-port int 如果不为0,Kubernetes master服务(用于创建/管理apiserver)将会使用NodePort类型,并将这个值作为端口号。如果为0,Kubernetes master服务将会使用ClusterIP类型。
|
||||
|
||||
--master-service-namespace string 已废弃: 注入到pod中的kubernetes master服务的命名空间。(默认值"default")
|
||||
|
||||
--max-connection-bytes-per-sec int 如果不为0,每个用户连接将会被限速为该值(bytes/sec)。当前只应用于长时间运行的请求。
|
||||
|
||||
--max-mutating-requests-inflight int 在给定时间内进行中可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0值表示没有限制。(默认值200)
|
||||
|
||||
--max-requests-inflight int 在给定时间内进行中不可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0值表示没有限制。(默认值400)
|
||||
|
||||
--min-request-timeout int 一个可选字段,表示一个handler在一个请求超时前,必须保持它处于打开状态的最小秒数。当前只对监听请求handler有效,它基于这个值选择一个随机数作为连接超时值,以达到分散负载的目的(默认值1800)。
|
||||
|
||||
--oidc-ca-file string 如果设置该值,将会使用oidc-ca-file中的任意一个authority对OpenID服务的证书进行验证,否则将会使用主机的根CA对其进行验证。
|
||||
|
||||
--oidc-client-id string 使用OpenID连接的客户端的ID,如果设置了oidc-issuer-url,则必须设置这个值。
|
||||
|
||||
--oidc-groups-claim string 如果提供该值,这个自定义OpenID连接名将指定给特定的用户组。该声明值需要是一个字符串或字符串数组。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。
|
||||
|
||||
--oidc-issuer-url string OpenID颁发者URL,只接受HTTPS方案。如果设置该值,它将被用于验证OIDC JSON Web Token(JWT)。
|
||||
|
||||
--oidc-username-claim string 用作用户名的OpenID声明值。注意,不保证除默认 ('sub')外的其他声明值的唯一性和不变性。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。
|
||||
|
||||
--profiling 在web接口host:port/debug/pprof/上启用profiling。(默认值true)
|
||||
|
||||
--proxy-client-cert-file string 当必须调用外部程序时,用于证明aggregator或者kube-apiserver的身份的客户端证书。包括代理到用户api-server的请求和调用webhook准入控制插件的请求。它期望这个证书包含一个来自于CA中的--requestheader-client-ca-file标记的签名。该CA在kube-system命名空间的'extension-apiserver-authentication' configmap中发布。从Kube-aggregator收到调用的组件应该使用该CA进行他们部分的双向TLS验证。
|
||||
|
||||
--proxy-client-key-file string 当必须调用外部程序时,用于证明aggregator或者kube-apiserver的身份的客户端证书密钥。包括代理到用户api-server的请求和调用webhook准入控制插件的请求。
|
||||
|
||||
--repair-malformed-updates 如果为true,服务将会尽力修复更新请求以通过验证,例如:将更新请求UID的当前值设置为空。在我们修复了所有发送错误格式请求的客户端后,可以关闭这个标志。
|
||||
|
||||
--requestheader-allowed-names stringSlice 使用--requestheader-username-headers指定的,允许在头部提供用户名的客户端证书通用名称列表。如果为空,任何通过--requestheader-client-ca-file中authorities验证的客户端证书都是被允许的。
|
||||
|
||||
--requestheader-client-ca-file string 在信任请求头中以--requestheader-username-headers指示的用户名之前,用于验证接入请求中客户端证书的根证书捆绑。
|
||||
|
||||
--requestheader-extra-headers-prefix stringSlice 用于检查的请求头的前缀列表。建议使用X-Remote-Extra-。
|
||||
|
||||
--requestheader-group-headers stringSlice 用于检查群组的请求头列表。建议使用X-Remote-Group.
|
||||
|
||||
--requestheader-username-headers stringSlice 用于检查用户名的请求头列表。建议使用X-Remote-User。
|
||||
|
||||
--runtime-config mapStringString 传递给apiserver用于描述运行时配置的键值对集合。 apis/<groupVersion>键可以被用来打开/关闭特定的api版本。apis/<groupVersion>/<resource>键被用来打开/关闭特定的资源. api/all和api/legacy键分别用于控制所有的和遗留的api版本.
|
||||
|
||||
--secure-port int 用于监听具有认证授权功能的HTTPS协议的端口。如果为0,则不会监听HTTPS协议。 (默认值6443)
|
||||
|
||||
--service-account-key-file stringArray 包含PEM加密的x509 RSA或ECDSA私钥或公钥的文件,用于验证ServiceAccount令牌。如果设置该值,--tls-private-key-file将会被使用。指定的文件可以包含多个密钥,并且这个标志可以和不同的文件一起多次使用。
|
||||
|
||||
--service-cluster-ip-range ipNet CIDR表示的IP范围,服务的cluster ip将从中分配。 一定不要和分配给nodes和pods的IP范围产生重叠。
|
||||
|
||||
--ssh-keyfile string 如果不为空,在使用安全的SSH代理访问节点时,将这个文件作为用户密钥文件。
|
||||
|
||||
--storage-backend string 持久化存储后端。 选项为: 'etcd3' (默认), 'etcd2'.
|
||||
|
||||
--storage-media-type string 在存储中保存对象的媒体类型。某些资源或者存储后端可能仅支持特定的媒体类型,并且忽略该配置项。(默认值 "application/vnd.kubernetes.protobuf")
|
||||
|
||||
--storage-versions string 按组划分资源存储的版本。 以"group1/version1,group2/version2,..."的格式指定。当对象从一组移动到另一组时, 你可以指定"group1=group2/v1beta1,group3/v1beta1,..."的格式。你只需要传入你希望从结果中改变的组的列表。默认为从KUBE_API_VERSIONS环境变量集成而来,所有注册组的首选版本列表。 (默认值"admission.k8s.io/v1alpha1,admissionregistration.k8s.io/v1alpha1,apps/v1beta1,authentication.k8s.io/v1,authorization.k8s.io/v1,autoscaling/v1,batch/v1,certificates.k8s.io/v1beta1,componentconfig/v1alpha1,extensions/v1beta1,federation/v1beta1,imagepolicy.k8s.io/v1alpha1,networking.k8s.io/v1,policy/v1beta1,rbac.authorization.k8s.io/v1beta1,settings.k8s.io/v1alpha1,storage.k8s.io/v1,v1")
|
||||
|
||||
--target-ram-mb int apiserver内存限制,单位为MB(用于配置缓存大小等)。
|
||||
|
||||
--tls-ca-file string 如果设置该值,这个证书authority将会被用于从Admission Controllers过来的安全访问。它必须是一个PEM加密的合法CA捆绑包。此外, 该证书authority可以被添加到以--tls-cert-file提供的证书文件中.
|
||||
|
||||
--tls-cert-file string 包含用于HTTPS的默认x509证书的文件。(如果有CA证书,则附加于server证书之后)。如果启用了HTTPS服务,并且没有提供--tls-cert-file和--tls-private-key-file,则将为公共地址生成一个自签名的证书和密钥并保存于/var/run/kubernetes目录。
|
||||
|
||||
--tls-private-key-file string 包含匹配--tls-cert-file的x509证书私钥的文件。
|
||||
|
||||
--tls-sni-cert-key namedCertKey 一对x509证书和私钥的文件路径, 可以使用符合正式域名的域形式作为后缀。 如果没有提供域形式后缀, 则将提取证书名。 非通配符版本优先于通配符版本, 显示的域形式优先于证书中提取的名字。 对于多个密钥/证书对, 请多次使用--tls-sni-cert-key。例如: "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com". (默认值[])
|
||||
|
||||
--token-auth-file string 如果设置该值,这个文件将被用于通过令牌认证来保护API服务的安全端口。
|
||||
|
||||
--version version[=true] 打印版本信息并退出。
|
||||
|
||||
--watch-cache 启用apiserver的监视缓存。(默认值true)
|
||||
|
||||
--watch-cache-sizes stringSlice 每种资源(pods, nodes等)的监视缓存大小列表,以逗号分隔。每个缓存配置的形式为:resource#size,size是一个数字。在watch-cache启用时生效。
|
||||
```
|
||||
|
||||
###### Auto generated by spf13/cobra on 11-Jul-2017
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
approvers:
|
||||
- liggitt
|
||||
title: Kubelet authentication/authorization
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
A kubelet's HTTPS endpoint exposes APIs which give access to data of varying sensitivity,
|
||||
and allow you to perform operations with varying levels of power on the node and within containers.
|
||||
|
||||
This document describes how to authenticate and authorize access to the kubelet's HTTPS endpoint.
|
||||
|
||||
## Kubelet authentication
|
||||
|
||||
By default, requests to the kubelet's HTTPS endpoint that are not rejected by other configured
|
||||
authentication methods are treated as anonymous requests, and given a username of `system:anonymous`
|
||||
and a group of `system:unauthenticated`.
|
||||
|
||||
To disable anonymous access and send `401 Unauthorized` responses to unauthenticated requests:
|
||||
|
||||
* start the kubelet with the `--anonymous-auth=false` flag
|
||||
|
||||
To enable X509 client certificate authentication to the kubelet's HTTPS endpoint:
|
||||
|
||||
* start the kubelet with the `--client-ca-file` flag, providing a CA bundle to verify client certificates with
|
||||
* start the apiserver with `--kubelet-client-certificate` and `--kubelet-client-key` flags
|
||||
* see the [apiserver authentication documentation](/docs/admin/authentication/#x509-client-certs) for more details
|
||||
|
||||
To enable API bearer tokens (including service account tokens) to be used to authenticate to the kubelet's HTTPS endpoint:
|
||||
|
||||
* ensure the `authentication.k8s.io/v1beta1` API group is enabled in the API server
|
||||
* start the kubelet with the `--authentication-token-webhook` and the `--kubeconfig` flags
|
||||
* the kubelet calls the `TokenReview` API on the configured API server to determine user information from bearer tokens
|
||||
|
||||
## Kubelet authorization
|
||||
|
||||
Any request that is successfully authenticated (including an anonymous request) is then authorized. The default authorization mode is `AlwaysAllow`, which allows all requests.
|
||||
|
||||
There are many possible reasons to subdivide access to the kubelet API:
|
||||
|
||||
* anonymous auth is enabled, but anonymous users' ability to call the kubelet API should be limited
|
||||
* bearer token auth is enabled, but arbitrary API users' (like service accounts) ability to call the kubelet API should be limited
|
||||
* client certificate auth is enabled, but only some of the client certificates signed by the configured CA should be allowed to use the kubelet API
|
||||
|
||||
To subdivide access to the kubelet API, delegate authorization to the API server:
|
||||
|
||||
* ensure the `authorization.k8s.io/v1beta1` API group is enabled in the API server
|
||||
* start the kubelet with the `--authorization-mode=Webhook` and the `--kubeconfig` flags
|
||||
* the kubelet calls the `SubjectAccessReview` API on the configured API server to determine whether each request is authorized
|
||||
|
||||
The kubelet authorizes API requests using the same [request attributes](/docs/admin/authorization/#request-attributes) approach as the apiserver.
|
||||
|
||||
The verb is determined from the incoming request's HTTP verb:
|
||||
|
||||
HTTP verb | request verb
|
||||
----------|---------------
|
||||
POST | create
|
||||
GET, HEAD | get
|
||||
PUT | update
|
||||
PATCH | patch
|
||||
DELETE | delete
|
||||
|
||||
The resource and subresource is determined from the incoming request's path:
|
||||
|
||||
Kubelet API | resource | subresource
|
||||
-------------|----------|------------
|
||||
/stats/\* | nodes | stats
|
||||
/metrics/\* | nodes | metrics
|
||||
/logs/\* | nodes | log
|
||||
/spec/\* | nodes | spec
|
||||
*all others* | nodes | proxy
|
||||
|
||||
The namespace and API group attributes are always an empty string, and
|
||||
the resource name is always the name of the kubelet's `Node` API object.
|
||||
|
||||
When running in this mode, ensure the user identified by the `--kubelet-client-certificate` and `--kubelet-client-key`
|
||||
flags passed to the apiserver is authorized for the following attributes:
|
||||
|
||||
* verb=\*, resource=nodes, subresource=proxy
|
||||
* verb=\*, resource=nodes, subresource=stats
|
||||
* verb=\*, resource=nodes, subresource=log
|
||||
* verb=\*, resource=nodes, subresource=spec
|
||||
* verb=\*, resource=nodes, subresource=metrics
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
approvers:
|
||||
- ericchiang
|
||||
- mikedanese
|
||||
- jcbsmpsn
|
||||
title: TLS bootstrapping
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how to set up TLS client certificate bootstrapping for kubelets.
|
||||
Kubernetes 1.4 introduced an API for requesting certificates from a cluster-level Certificate Authority (CA). The original intent of this API is to enable provisioning of TLS client certificates for kubelets. The proposal can be found [here](https://github.com/kubernetes/kubernetes/pull/20439)
|
||||
and progress on the feature is being tracked as [feature #43](https://github.com/kubernetes/features/issues/43).
|
||||
|
||||
## kube-apiserver configuration
|
||||
|
||||
The API server should be configured with an [authenticator](/docs/admin/authentication/) that can authenticate tokens as a user in the `system:bootstrappers` group.
|
||||
|
||||
This group will later be used in the controller-manager configuration to scope approvals in the default approval
|
||||
controller. As this feature matures, you should ensure tokens are bound to a Role-Based Access Control (RBAC) policy which limits requests
|
||||
(using the bootstrap token) strictly to client requests related to certificate provisioning. With RBAC in place, scoping the tokens to a group allows for great flexibility (e.g. you could disable a particular bootstrap group's access when you are done provisioning the nodes).
|
||||
|
||||
While any authentication strategy can be used for the kubelet's initial bootstrap credentials, the following two authenticators are recommended for ease of provisioning.
|
||||
|
||||
1. [Bootstrap Tokens](/docs/admin/bootstrap-tokens/) - __alpha__
|
||||
2. [Token authentication file](###token-authentication-file)
|
||||
|
||||
Using bootstrap tokens is currently __alpha__ and will simplify the management of bootstrap token management especially in a HA scenario.
|
||||
|
||||
### Token authentication file
|
||||
Tokens are arbitrary but should represent at least 128 bits of entropy derived from a secure random number
|
||||
generator (such as /dev/urandom on most modern systems). There are multiple ways you can generate a token. For example:
|
||||
|
||||
`head -c 16 /dev/urandom | od -An -t x | tr -d ' '`
|
||||
|
||||
will generate tokens that look like `02b50b05283e98dd0fd71db496ef01e8`
|
||||
|
||||
The token file should look like the following example, where the first three values can be anything and the quoted group
|
||||
name should be as depicted:
|
||||
|
||||
```
|
||||
02b50b05283e98dd0fd71db496ef01e8,kubelet-bootstrap,10001,"system:bootstrappers"
|
||||
```
|
||||
|
||||
Add the `--token-auth-file=FILENAME` flag to the kube-apiserver command (in your systemd unit file perhaps) to enable the token file.
|
||||
See docs [here](/docs/admin/authentication/#static-token-file) for further details.
|
||||
|
||||
### Client certificate CA bundle
|
||||
|
||||
Add the `--client-ca-file=FILENAME` flag to the kube-apiserver command to enable client certificate authentication,
|
||||
referencing a certificate authority bundle containing the signing certificate (e.g. `--client-ca-file=/var/lib/kubernetes/ca.pem`).
|
||||
|
||||
## kube-controller-manager configuration
|
||||
The API for requesting certificates adds a certificate-issuing control loop to the Kubernetes Controller Manager. This takes the form of a
|
||||
[cfssl](https://blog.cloudflare.com/introducing-cfssl/) local signer using assets on disk. Currently, all certificates issued have one year validity and a default set of key usages.
|
||||
|
||||
### Signing assets
|
||||
You must provide a Certificate Authority in order to provide the cryptographic materials necessary to issue certificates.
|
||||
This CA should be trusted by kube-apiserver for authentication with the `--client-ca-file=FILENAME` flag. The management
|
||||
of the CA is beyond the scope of this document but it is recommended that you generate a dedicated CA for Kubernetes.
|
||||
Both certificate and key are assumed to be PEM-encoded.
|
||||
|
||||
The kube-controller-manager flags are:
|
||||
|
||||
```
|
||||
--cluster-signing-cert-file="/etc/path/to/kubernetes/ca/ca.crt" --cluster-signing-key-file="/etc/path/to/kubernetes/ca/ca.key"
|
||||
```
|
||||
|
||||
### Approval controller
|
||||
|
||||
In 1.7 the experimental "group auto approver" controller is dropped in favor of the new `csrapproving` controller
|
||||
that ships as part of [kube-controller-manager](/docs/admin/kube-controller-manager/) and is enabled by default.
|
||||
The controller uses the [`SubjectAccessReview` API](/docs/admin/authorization/#checking-api-access) to determine
|
||||
if a given user is authorized to request a CSR, then approves based on the authorization outcome. To prevent
|
||||
conflicts with other approvers, the builtin approver doesn't explicitly deny CSRs, only ignoring unauthorized requests.
|
||||
|
||||
The controller categorizes CSRs into three subresources:
|
||||
|
||||
1. `nodeclient` - a request by a user for a client certificate with `O=system:nodes` and `CN=system:node:(node name)`.
|
||||
2. `selfnodeclient` - a node renewing a client certificate with the same `O` and `CN`.
|
||||
3. `selfnodeserver` - a node renewing a serving certificate. (ALPHA, requires feature gate)
|
||||
|
||||
The checks to determine if a CSR is a `selfnodeserver` request is currently tied to the kubelet's credential rotation
|
||||
implementation, an __alpha__ feature. As such, the definition of `selfnodeserver` will likely change in a future and
|
||||
requires the `RotateKubeletServerCertificate` feature gate on the controller manager. The feature progress can be
|
||||
tracked at [kubernetes/features#267](https://github.com/kubernetes/features/issues/267).
|
||||
|
||||
```
|
||||
--feature-gates=RotateKubeletServerCertificate=true
|
||||
```
|
||||
|
||||
The following RBAC `ClusterRoles` represent the `nodeclient`, `selfnodeclient`, and `selfnodeserver` capabilities. Similar roles
|
||||
may be automatically created in future releases.
|
||||
|
||||
```yml
|
||||
# A ClusterRole which instructs the CSR approver to approve a user requesting
|
||||
# node client credentials.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-client-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/nodeclient"]
|
||||
verbs: ["create"]
|
||||
---
|
||||
# A ClusterRole which instructs the CSR approver to approve a node renewing its
|
||||
# own client credentials.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-client-renewal-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/selfnodeclient"]
|
||||
verbs: ["create"]
|
||||
---
|
||||
# A ClusterRole which instructs the CSR approver to approve a node requesting a
|
||||
# serving cert matching its client cert.
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: approve-node-server-renewal-csr
|
||||
rules:
|
||||
- apiGroups: ["certificates.k8s.io"]
|
||||
resources: ["certificatesigningrequests/selfnodeserver"]
|
||||
verbs: ["create"]
|
||||
```
|
||||
|
||||
These powers can be granted to credentials, such as bootstrapping tokens. For example, to replicate the behavior
|
||||
provided by the removed auto-approval flag, of approving all CSRs by a single group:
|
||||
|
||||
```
|
||||
# REMOVED: This flag no longer works as of 1.7.
|
||||
--insecure-experimental-approve-all-kubelet-csrs-for-group="system:bootstrappers"
|
||||
```
|
||||
|
||||
An admin would create a `ClusterRoleBinding` targeting that group.
|
||||
|
||||
```yml
|
||||
# Approve all CSRs for the group "system:bootstrappers"
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: auto-approve-csrs-for-group
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:bootstrappers
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: approve-node-client-csr
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
To let a node renew its own credentials, an admin can construct a `ClusterRoleBinding` targeting
|
||||
that node's credentials:
|
||||
|
||||
```yml
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: node1-client-cert-renewal
|
||||
subjects:
|
||||
- kind: User
|
||||
name: system:node:node-1 # Let "node-1" renew its client certificate.
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: approve-node-client-renewal-csr
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
Deleting the binding will prevent the node from renewing its client credentials, effectively
|
||||
removing it from the cluster once its certificate expires.
|
||||
|
||||
## kubelet configuration
|
||||
To request a client certificate from kube-apiserver, the kubelet first needs a path to a kubeconfig file that contains the
|
||||
bootstrap authentication token. You can use `kubectl config set-cluster`, `set-credentials`, and `set-context` to build this kubeconfig. Provide the name `kubelet-bootstrap` to `kubectl config set-credentials` and include `--token=<token-value>` as follows:
|
||||
|
||||
```
|
||||
kubectl config set-credentials kubelet-bootstrap --token=${BOOTSTRAP_TOKEN} --kubeconfig=bootstrap.kubeconfig
|
||||
```
|
||||
|
||||
When starting the kubelet, if the file specified by `--kubeconfig` does not exist, the bootstrap kubeconfig is used to request a client certificate from the API server. On approval of the certificate request and receipt back by the kubelet, a kubeconfig file referencing the generated key and obtained certificate is written to the path specified by `--kubeconfig`. The certificate and key file will be placed in the directory specified by `--cert-dir`.
|
||||
|
||||
**Note:** The following flags are required to enable this bootstrapping when starting the kubelet:
|
||||
|
||||
```
|
||||
--bootstrap-kubeconfig="/path/to/bootstrap/kubeconfig"
|
||||
```
|
||||
|
||||
Additionally, in 1.7 the kubelet implements __alpha__ features for enabling rotation of both its client and/or serving certs.
|
||||
These can be enabled through the respective `RotateKubeletClientCertificate` and `RotateKubeletServerCertificate` feature
|
||||
flags on the kubelet, but may change in backward incompatible ways in future releases.
|
||||
|
||||
```
|
||||
--feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true
|
||||
```
|
||||
|
||||
`RotateKubeletClientCertificate` causes the kubelet to rotate its client certificates by creating new CSRs as its existing
|
||||
credentials expire. `RotateKubeletServerCertificate` causes the kubelet to both request a serving certificate after
|
||||
bootstrapping its client credentials and rotate the certificate. The serving cert currently does not request DNS or IP
|
||||
SANs.
|
||||
|
||||
## kubectl approval
|
||||
The signing controller does not immediately sign all certificate requests. Instead, it waits until they have been flagged with an
|
||||
"Approved" status by an appropriately-privileged user. This is intended to eventually be an automated process handled by an external
|
||||
approval controller, but for the alpha version of the API it can be done manually by a cluster administrator using kubectl.
|
||||
An administrator can list CSRs with `kubectl get csr` and describe one in detail with `kubectl describe csr <name>`. Before the 1.6 release there were
|
||||
[no direct approve/deny commands](https://github.com/kubernetes/kubernetes/issues/30163) so an approver had to update
|
||||
the Status field directly ([rough how-to](https://github.com/gtank/csrctl)). Later versions of Kubernetes offer `kubectl certificate approve <name>` and `kubectl certificate deny <name>` commands.
|
||||
@@ -0,0 +1,291 @@
|
||||
---
|
||||
approvers:
|
||||
- jlowdermilk
|
||||
- justinsb
|
||||
- quinton-hoole
|
||||
title: 多区域运行
|
||||
---
|
||||
|
||||
## 介绍
|
||||
|
||||
Kubernetes 从v1.2开始支持将集群运行在多个故障域中。
|
||||
(GCE 中称其为 "区(Zones)", AWS 中称其为 "可用区(Availability Zones)",这里我们也称其为 "区")。
|
||||
它是广泛意义上的集群联邦特性的轻量级版本 (之前被称为 ["Ubernetes"](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/multicluster/federation.md))。
|
||||
完整的集群联邦能够将多个分别运行在不同区或云供应商(或本地数据中心)的集群集中管理。
|
||||
然而,很多用户只是希望通过将单一云供应商上的Kubernetes集群运行在多个区域,来提高集群的可用性,
|
||||
这就是1.2版本中提供的对多区域的支持。
|
||||
(之前被称为 "Ubernetes Lite")。
|
||||
|
||||
多区域的支持是有明确限制的: Kubernetes集群能够运行在多个区,但必须在同一个地域内 (云供应商也须一致)。
|
||||
目前只有GCE和AWS自动支持 (尽管在其他云甚至裸机上,也很容易通过为节点和卷添加合适的标签来实现类似的支持)。
|
||||
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## 功能
|
||||
|
||||
节点启动时,Kubelet自动为其添加区信息的标签。
|
||||
|
||||
在单一区域的集群中,Kubernetes 会自动将副本管理器或服务的pod分布到各节点上 (以减轻单实例故障的影响)。
|
||||
在多区域的集群中,这种分布的行为扩展到了区域级别
|
||||
(以减少区域故障对整体的影响)。 (通过 `SelectorSpreadPriority` 来实现)。
|
||||
这种分发是尽力而为(best-effort)的,所以如果集群在各个区之间是异构的
|
||||
(比如,各区间的节点数量不同、节点类型不同、pod的资源需求不同等)可能导致pod无法完全均匀地分布。
|
||||
如果需要的话,用户可以使用同质的区(节点数量和节点类型相同)来减少区域之间分配不均匀的可能。
|
||||
|
||||
当卷被创建时, `PersistentVolumeLabel`准入控制器会自动为其添加区域的标签。
|
||||
调度器 (通过 `VolumeZonePredicate` 断言) 会确申领该卷的pod被调度到该卷对应的区域,
|
||||
因为卷是不支持跨区挂载的。
|
||||
|
||||
## 限制
|
||||
|
||||
对多区的支持有一些重要的限制:
|
||||
|
||||
* 我们假设不同的区域间在网络上离得很近,所以我们不做任何的区域感知路由。 特别是,通过服务的网络访问可能跨区域 (即使该服务后端pod的其中一些运行在与客户端相同的区域中),这可能导致额外的延迟和损耗。
|
||||
|
||||
* 卷的区域亲和性只对 `PersistentVolume`有效。 例如,如果你在pod的spec中直接指定一个EBS的卷,则不会生效。
|
||||
|
||||
* 集群不支持跨云平台或地域 (这些功能需要完整的集群联邦特性支持)。
|
||||
|
||||
* 尽管节点位于多区域,目前默认情况下 kube-up 创建的管理节点是单实例的。 所以尽管服务是高可用的,并且能够容忍跨区域的性能损耗,管理平面还是单区域的。 需要高可用的管理平面的用户可以按照 [高可用](/docs/admin/high-availability) 指导来操作。
|
||||
|
||||
* 目前StatefulSet的卷动态创建时的跨区域分配,与pod的亲和性/反亲和性不兼容。
|
||||
|
||||
* StatefulSet的名称包含破折号 ("-")时,可能影响到卷在区域间的均匀分布。
|
||||
|
||||
* 为deployment或pod指定多个PVC时,要求其StorageClass处于同一区域内,否则,相应的PV卷需要在一个区域中静态配置。 另一种方式是使用StatefulSet,这可以确保同一副本所挂载的卷位于同一区内。
|
||||
|
||||
|
||||
## 演练
|
||||
|
||||
接下来我们将介绍如何同时在 GCE 和 AWS 上创建和使用多区域的集群。 为此,你需要创建一个完整的集群
|
||||
(指定 `MULTIZONE=true`),然后再次执行 `kube-up`(指定 `KUBE_USE_EXISTING_MASTER=true`)来添加其他区域的节点。
|
||||
|
||||
### 创建集群
|
||||
|
||||
按正常方式创建集群,但是传入 MULTIZONE 来通知集群对多区域进行管理。 在 us-central1-a 区域创建节点。
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-a NUM_NODES=3 bash
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2a NUM_NODES=3 bash
|
||||
```
|
||||
|
||||
该步骤按正常方式创建了集群,仍然运行在单个区域中。
|
||||
但 `MULTIZONE=true` 已经开启了多区域的能力。
|
||||
|
||||
### 标记节点
|
||||
|
||||
查看节点,你可以发现节点上打了区域信息的标签。
|
||||
节点位于 `us-central1-a` (GCE) 或者 `us-west-2a` (AWS)。 标签 `failure-domain.beta.kubernetes.io/region` 用于区分地域,
|
||||
标签 `failure-domain.beta.kubernetes.io/zone` 用于区分区域。
|
||||
|
||||
```shell
|
||||
> kubectl get nodes --show-labels
|
||||
|
||||
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-master Ready,SchedulingDisabled 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-master
|
||||
kubernetes-minion-87j9 Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-87j9
|
||||
kubernetes-minion-9vlv Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-a12q Ready 6m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-a12q
|
||||
```
|
||||
|
||||
### 添加其它区中的节点
|
||||
|
||||
接下来我们复用已有的管理节点,添加运行于其它区域 (us-central1-b或us-west-2b)中的节点。
|
||||
再次执行 kube-up, 通过指定 `KUBE_USE_EXISTING_MASTER=true`,
|
||||
kube-up 不会创建新的管理节点,而是会复用之前创建的。
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-b NUM_NODES=3 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
在 AWS 中我们还需要为新增的子网指定网络CIDR,还有管理节点的内部IP地址。
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2b NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.1.0/24 MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
|
||||
再次查看节点,3个新增的节点已经启动,并被标记为us-central1-b:
|
||||
|
||||
```shell
|
||||
> kubectl get nodes --show-labels
|
||||
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-master Ready,SchedulingDisabled 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-master
|
||||
kubernetes-minion-281d Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-281d
|
||||
kubernetes-minion-87j9 Ready 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-87j9
|
||||
kubernetes-minion-9vlv Ready 16m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-a12q Ready 17m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-a12q
|
||||
kubernetes-minion-pp2f Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-pp2f
|
||||
kubernetes-minion-wf8i Ready 2m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-wf8i
|
||||
```
|
||||
|
||||
### 卷的亲和性
|
||||
|
||||
使用动态创建卷的功能创建一个卷 (只有PV持久卷才支持区域亲和性):
|
||||
|
||||
```json
|
||||
kubectl create -f - <<EOF
|
||||
{
|
||||
"kind": "PersistentVolumeClaim",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "claim1",
|
||||
"annotations": {
|
||||
"volume.alpha.kubernetes.io/storage-class": "foo"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"accessModes": [
|
||||
"ReadWriteOnce"
|
||||
],
|
||||
"resources": {
|
||||
"requests": {
|
||||
"storage": "5Gi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**注意:** Kubernetes 1.3以上的版本中可以将PVC分发到多个已配置的区域中,在1.2版本中, 动态卷只能创建在管理节点所在的区域内(即这里的 us-central1-a / us-west-2a);相关issue
|
||||
([#23330](https://github.com/kubernetes/kubernetes/issues/23330))
|
||||
在1.3后续的版本中已解决。
|
||||
|
||||
现在我们验证一下 Kubernetes 自动为创建的PV打上了所在地域和区域的标签。
|
||||
|
||||
```shell
|
||||
> kubectl get pv --show-labels
|
||||
NAME CAPACITY ACCESSMODES STATUS CLAIM REASON AGE LABELS
|
||||
pv-gce-mj4gm 5Gi RWO Bound default/claim1 46s failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a
|
||||
```
|
||||
|
||||
现在我们将创建使用这些PVC的pod。
|
||||
因为 GCE 的PD存储 / AWS 的EBS 卷 不支持跨区域挂载,
|
||||
这意味着相应的pod只能创建在卷所在的区域中。
|
||||
|
||||
```yaml
|
||||
kubectl create -f - <<EOF
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: myfrontend
|
||||
image: nginx
|
||||
volumeMounts:
|
||||
- mountPath: "/var/www/html"
|
||||
name: mypd
|
||||
volumes:
|
||||
- name: mypd
|
||||
persistentVolumeClaim:
|
||||
claimName: claim1
|
||||
EOF
|
||||
```
|
||||
|
||||
注意pod被自动创建在了卷所在的区域中,因为云供应商通常不支持卷的跨区域挂载(attach)。
|
||||
|
||||
```shell
|
||||
> kubectl describe pod mypod | grep Node
|
||||
Node: kubernetes-minion-9vlv/10.240.0.5
|
||||
> kubectl get node kubernetes-minion-9vlv --show-labels
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-minion-9vlv Ready 22m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
```
|
||||
|
||||
### Pod的跨区域分布
|
||||
|
||||
副本管理器或服务的pod被自动创建在了不同的区域。 首先,在第三个区域内启动节点:
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-f NUM_NODES=3 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2c NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.2.0/24 MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh
|
||||
```
|
||||
|
||||
验证你现在在3个区域内拥有节点:
|
||||
|
||||
```shell
|
||||
kubectl get nodes --show-labels
|
||||
```
|
||||
|
||||
创建 guestbook-go 示例应用, 它包含一个副本数为3的RC,运行一个简单的网络应用:
|
||||
|
||||
```shell
|
||||
find kubernetes/examples/guestbook-go/ -name '*.json' | xargs -I {} kubectl create -f {}
|
||||
```
|
||||
|
||||
Pod应该分布在全部3个区域上:
|
||||
|
||||
```shell
|
||||
> kubectl describe pod -l app=guestbook | grep Node
|
||||
Node: kubernetes-minion-9vlv/10.240.0.5
|
||||
Node: kubernetes-minion-281d/10.240.0.8
|
||||
Node: kubernetes-minion-olsh/10.240.0.11
|
||||
|
||||
> kubectl get node kubernetes-minion-9vlv kubernetes-minion-281d kubernetes-minion-olsh --show-labels
|
||||
NAME STATUS AGE VERSION LABELS
|
||||
kubernetes-minion-9vlv Ready 34m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kubernetes.io/hostname=kubernetes-minion-9vlv
|
||||
kubernetes-minion-281d Ready 20m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kubernetes.io/hostname=kubernetes-minion-281d
|
||||
kubernetes-minion-olsh Ready 3m v1.6.0+fff5156 beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-f,kubernetes.io/hostname=kubernetes-minion-olsh
|
||||
```
|
||||
|
||||
|
||||
负载平衡器覆盖集群中的所有区域; guestbook-go 示例包含一个
|
||||
负载均衡服务的例子:
|
||||
|
||||
```shell
|
||||
> kubectl describe service guestbook | grep LoadBalancer.Ingress
|
||||
LoadBalancer Ingress: 130.211.126.21
|
||||
|
||||
> ip=130.211.126.21
|
||||
|
||||
> curl -s http://${ip}:3000/env | grep HOSTNAME
|
||||
"HOSTNAME": "guestbook-44sep",
|
||||
|
||||
> (for i in `seq 20`; do curl -s http://${ip}:3000/env | grep HOSTNAME; done) | sort | uniq
|
||||
"HOSTNAME": "guestbook-44sep",
|
||||
"HOSTNAME": "guestbook-hum5n",
|
||||
"HOSTNAME": "guestbook-ppm40",
|
||||
```
|
||||
|
||||
负载平衡器正确指向了所有的pod,即使它们位于不同的区域内。
|
||||
|
||||
### 停止集群
|
||||
|
||||
使用完成后,进行清理:
|
||||
|
||||
GCE:
|
||||
|
||||
```shell
|
||||
KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true KUBE_GCE_ZONE=us-central1-f kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true KUBE_GCE_ZONE=us-central1-b kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-a kubernetes/cluster/kube-down.sh
|
||||
```
|
||||
|
||||
AWS:
|
||||
|
||||
```shell
|
||||
KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2c kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2b kubernetes/cluster/kube-down.sh
|
||||
KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2a kubernetes/cluster/kube-down.sh
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
approvers:
|
||||
- Random-Liu
|
||||
title: 节点设置校验
|
||||
---
|
||||
|
||||
* TOC
|
||||
{{< toc >}}
|
||||
|
||||
## 节点合规性测试
|
||||
|
||||
*节点合规性测试* 是一个容器化的测试框架,提供了针对节点的系统验证和功能测试。 该测试主要检测节点是否满足 Kubernetes 的最低要求,通过检测的节点有资格加入 Kubernetes 集群。
|
||||
|
||||
## 限制
|
||||
|
||||
在 Kubernetes 1.5版本中,节点合规性测试存在以下限制:
|
||||
|
||||
* 节点合规性测试只支持 Docker 作为容器运行时环境。
|
||||
|
||||
## 节点的前提条件
|
||||
|
||||
为运行节点合规性测试,节点必须满足与标准的 Kubernetes 节点同样的前提条件。最基本地, 节点应安装以下组件:
|
||||
|
||||
* 容器运行时 (Docker)
|
||||
* Kubelet
|
||||
|
||||
## 运行节点合规性测试
|
||||
|
||||
执行以下步骤来运行节点合规性测试:
|
||||
|
||||
1. 因为测试框架会启动一个本地的 master 来测试 Kubelet,
|
||||
所以将 Kubelet 指向本机 `--api-servers="http://localhost:8080"。 还有一些其他 Kubelet 参数可能需要注意:
|
||||
* `--pod-cidr`: 如果使用 `kubenet`, 需要为 Kubelet 任意指定一个 CIDR, 例如 `--pod-cidr=10.180.0.0/24`。
|
||||
* `--cloud-provider`: 如果使用 `--cloud-provider=gce`,需要移除这个参数来运行测试。
|
||||
|
||||
2. 执行以下命令来运行节点合规性测试:
|
||||
|
||||
```shell
|
||||
# $CONFIG_DIR 是 Kubelet 的 manifest 文件路径。
|
||||
# $LOG_DIR 是测试结果输出的路径。
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
## 针对其他硬件体系结构运行节点合规性测试
|
||||
|
||||
Kubernetes 也为其他硬件体系结构的系统提供了节点合规性测试的 Docker 镜像:
|
||||
|
||||
Arch | Image |
|
||||
--------|:-----------------:|
|
||||
amd64 | node-test-amd64 |
|
||||
arm | node-test-arm |
|
||||
arm64 | node-test-arm64 |
|
||||
|
||||
## 运行选定的测试
|
||||
|
||||
为运行指定的测试,用正则表达式来描述将要运行的测试,并重载 `FOCUS` 环境变量。
|
||||
|
||||
```shell
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
-e FOCUS=MirrorPod \ # 只运行MirrorPod测试
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
为跳过指定的测试,用正则表达式来描述将要跳过的测试,并重载 `SKIP` 环境变量。
|
||||
|
||||
```shell
|
||||
sudo docker run -it --rm --privileged --net=host \
|
||||
-v /:/rootfs:ro -v $CONFIG_DIR:$CONFIG_DIR -v $LOG_DIR:/var/result \
|
||||
-e SKIP=MirrorPod \ # 运行除MirrorPod外的所有测试
|
||||
k8s.gcr.io/node-test:0.2
|
||||
```
|
||||
|
||||
节点合规性测试是[节点端到端测试](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/devel/e2e-node-tests.md)的一个容器化的版本。
|
||||
默认情况下, 它会运行所有的合规性测试用例。
|
||||
|
||||
理论上,只要合理地配置容器和挂载所需的卷,就可以运行任何的节点端到端测试用例。 但是这里 **强烈建议只运行合规性测试**,因为运行非合规性测试需要很多复杂的配置。
|
||||
|
||||
## 注意事项
|
||||
|
||||
* 测试会在节点上遗留一些Docker镜像, 包括节点合规性测试本身的镜像,和功能测试相关的镜像。
|
||||
* 测试会在节点上遗留一些死的容器。这些容器是在功能测试的过程中创建的。
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
approvers:
|
||||
- thockin
|
||||
title: Kubernetes OpenVSwitch GRE/VxLAN 网络
|
||||
---
|
||||
|
||||
本文档介绍了如何使用OpenVSwitch,在跨nodes的pods之间设置网络。
|
||||
隧道类型可以是GRE或者是VxLAN。如需在网络内执行大规模隔离时,最好使用VxLAN。
|
||||
|
||||

|
||||
|
||||
Kubernetes中Vagrant的设置如下:
|
||||
|
||||
docker网桥被brctl生成的Linux网桥(kbr0)所代替,kbr0是具有256个地址空间的子网。总的来说,node会得到10.244.x.0/24的子网,docker上配置使用的网桥会代替默认docker0的网桥。
|
||||
|
||||
另外,OVS网桥创建(obr0),并将其作为端口添加到kbr0的网桥中。所有OVS网桥通过GRE隧道连接所有的nodes。因此,每个node都有一个到其他nodes的出站GRE隧道。这个隧道没有必要是一个完整的网状物,但是越像网状结构越好。在网桥上开启STP(生成树)模式以防止环路的发生。
|
||||
|
||||
路由规则允许任何10.244.0.0/16通过与隧道相连的OVS网桥到达目标。
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
approvers:
|
||||
- bprashanth
|
||||
- davidopp
|
||||
- lavalamp
|
||||
- liggitt
|
||||
title: 管理Service Accounts
|
||||
---
|
||||
|
||||
*这是一篇针对service accounts(服务账户)的集群管理员指南。 它呈现了 [User Guide to Service Accounts](/docs/user-guide/service-accounts)中的信息。*
|
||||
|
||||
*对授权和用户账户的支持已在规划中,当前并不完备,为了更好地描述service accounts,有时这些不完善的特性也会被提及。*
|
||||
|
||||
## 用户账户与服务账户
|
||||
|
||||
Kubernetes 区分用户账户和服务账户的概念主要基于以下原因:
|
||||
|
||||
- 用户账户是针对人而言的。 服务账户是针对运行在pod中的进程而言的。
|
||||
- 用户账户是全局性的。 其名称在集群各namespace中都是全局唯一的,未来的用户资源不会做namespace隔离,
|
||||
服务账户是namespace隔离的。
|
||||
- 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 (即权限最小化原则)。
|
||||
- 对人员和服务账户审计所考虑的因素可能不同。
|
||||
- 针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创建,并且有namespace级别的名称,这种配置是很轻量的。
|
||||
|
||||
## 服务账户的自动化
|
||||
|
||||
三个独立组件协作完成服务账户相关的自动化:
|
||||
|
||||
- 服务账户准入控制器(Service account admission controller)
|
||||
- Token控制器(Token controller)
|
||||
- 服务账户控制器(Service account controller)
|
||||
|
||||
### 服务账户准入控制器
|
||||
|
||||
对pod的改动通过一个被称为[Admission Controller](/docs/admin/admission-controllers)的插件来实现。它是apiserver的一部分。
|
||||
当pod被创建或更新时,它会同步地修改pod。 当该插件处于激活状态(在大多数发行版中都是默认的),当pod被创建或更新时它会进行以下动作:
|
||||
|
||||
1. 如果该pod没有 `ServiceAccount` 设置,将其 `ServiceAccount` 设为 `default`。
|
||||
2. 保证pod所关联的 `ServiceAccount` 存在,否则拒绝该pod。
|
||||
4. 如果pod不包含 `ImagePullSecrets`设置,那么 将 `ServiceAccount`中的`ImagePullSecrets` 信息添加到pod中。
|
||||
5. 将一个包含用于API访问的token的 `volume` 添加到pod中。
|
||||
6. 将挂载于 `/var/run/secrets/kubernetes.io/serviceaccount` 的 `volumeSource`添加到pod下的每个容器中。
|
||||
|
||||
### Token管理器
|
||||
|
||||
Token管理器是controller-manager的一部分。 以异步的形式工作:
|
||||
|
||||
- 检测服务账户的创建,并且创建相应的Secret以支持API访问。
|
||||
- 检测服务账户的删除,并且删除所有相应的服务账户Token Secret。
|
||||
- 检测Secret的增加,保证相应的服务账户存在,如有需要,为Secret增加token。
|
||||
- 检测Secret的删除,如有需要,从相应的服务账户中移除引用。
|
||||
|
||||
你需要通过 `--service-account-private-key-file` 参数项传入一个服务账户私钥文件至Token管理器。 私钥用于为生成的服务账户token签名。
|
||||
同样地,你需要通过 `--service-account-key-file` 参数将对应的公钥传入kube-apiserver。 公钥用于认证过程中的token校验。
|
||||
|
||||
#### 创建额外的 API tokens
|
||||
|
||||
控制器中有专门的循环来保证每个服务账户中都存在API token对应的Secret。 当需要为服务账户创建额外的API token时,创建一个类型为 `ServiceAccountToken` 的Secret,并在annotation中引用服务账户,控制器会生成token并更新:
|
||||
|
||||
secret.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Secret",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "mysecretname",
|
||||
"annotations": {
|
||||
"kubernetes.io/service-account.name": "myserviceaccount"
|
||||
}
|
||||
},
|
||||
"type": "kubernetes.io/service-account-token"
|
||||
}
|
||||
```
|
||||
|
||||
```shell
|
||||
kubectl create -f ./secret.json
|
||||
kubectl describe secret mysecretname
|
||||
```
|
||||
|
||||
#### 删除/失效 服务账户token
|
||||
|
||||
```shell
|
||||
kubectl delete secret mysecretname
|
||||
```
|
||||
|
||||
### 服务账户管理器
|
||||
|
||||
服务账户管理器管理各命名空间下的服务账户,并且保证每个活跃的命名空间下存在一个名为 "default" 的服务账户
|
||||
@@ -0,0 +1,248 @@
|
||||
title: 云控制器管理器的基本概念
|
||||
|
||||
## 云控制器管理器
|
||||
|
||||
云控制器管理器(CCM)这个概念创建的初衷是为了让特定的云服务供应商代码和Kubernetes核心相互独立演化。云控制器管理器与其他主要组件如Kubernetes控制器管理器,API服务器和调度程序同时运行。云控制器管理器也可以作为Kubernetes的插件启动,这种情况下,CCM运行在Kubernetes系统之上。
|
||||
|
||||
云控制器管理器基于插件机制设计,允许新的云服务供应商通过插件轻松地与Kubernetes集成。目前已经有在Kubernetes上加入新的云服务供应商计划,并为云服务供应商提供从原先的旧模式迁移到新CCM模式的方案。
|
||||
|
||||
本文讨论了云控制器管理器背后的概念,并提供了相关功能的详细信息。
|
||||
|
||||
下面这张图描述了没有云控制器管理器的Kubernetes集群架构:
|
||||
|
||||

|
||||
|
||||
## 设计
|
||||
|
||||
在上图中,Kubernetes和云服务供应商通过几个不同的组件进行了集成,分别是:
|
||||
|
||||
* Kubelet
|
||||
* Kubernetes 控制管理器
|
||||
* Kubernetes API服务器
|
||||
|
||||
而CCM整合了前三个组件中的所有依赖于云的逻辑,用来创建与云的单点集成。新架构如下图所示:
|
||||
|
||||

|
||||
|
||||
## CCM的组件
|
||||
|
||||
CCM突破了Kubernetes控制器管理器(KCM)的一些功能,并将其作为一个独立的进程运行。具体而言,它打破了KCM中与云相关的控制器。KCM具有以下依赖于云的控制器引擎:
|
||||
|
||||
* 节点控制器
|
||||
* 卷控制器
|
||||
* 路由控制器
|
||||
* 服务控制器
|
||||
|
||||
在1.8版本中,当前运行中的CCM从上面的列表中运行以下控制器:
|
||||
|
||||
* 节点控制器
|
||||
* 路由控制器
|
||||
* 服务控制器
|
||||
|
||||
另外,它运行另一个名为 PersistentVolumeLabels Controller 的控制器。这个控制器负责对在GCP和AWS云里创建的PersistentVolumes的域(Zone)和区(Region)标签进行设置。
|
||||
|
||||
**注意**:卷控制器被特意设计为CCM之外的一部分。由于其中涉及到的复杂性和对现有供应商特定卷的逻辑抽象,因此决定了卷控制器不会被移动到CCM之中。
|
||||
|
||||
原本计划使用CCM来支持卷的目的是为了引入FlexVolume卷来支持可插拔卷。然而,官方正在计划使用更具备竞争力的CSI来取代FlexVolume卷。
|
||||
|
||||
考虑到这些正在进行中的变化,我们决定暂时停止当前工作直至CSI准备就绪。
|
||||
|
||||
云服务供应商工作组(wg-cloud-provider)正在开展相关工作,以实现通过CCM支持PersistentVolume的功能。详细信息请参见[kubernetes/kubernetes#52371](https://github.com/kubernetes/kubernetes/pull/52371)。
|
||||
|
||||
## CCM功能
|
||||
|
||||
CCM从Kubernetes组件中继承了与云服务供应商相关的功能。本节基于被CCM继承其功能的组件展开描述。
|
||||
|
||||
### 1. Kubernetes 控制器管理器
|
||||
|
||||
CCM的大部分功能都来自KCM。 如上一节所述,CCM运行以下控制引擎:
|
||||
|
||||
* 节点控制器
|
||||
* 路由控制器
|
||||
* 服务控制器
|
||||
* PersistentVolumeLabels控制器
|
||||
|
||||
#### 节点控制器
|
||||
|
||||
节点控制器负责通过从云服务供应商获得有关在集群中运行的节点的信息来初始化节点。节点控制器执行以下功能:
|
||||
|
||||
1.使用云特定域(Zone)/区(Region)标签初始化节点。
|
||||
|
||||
1.使用特定于云的实例详细信息初始化节点,例如类型和大小。
|
||||
|
||||
1.获取节点的网络地址和主机名。
|
||||
|
||||
1.如果节点无响应,检查该节点是否已从云中删除。如果该节点已从云中删除,则删除Kubernetes节点对象。
|
||||
|
||||
#### 路由控制器
|
||||
|
||||
路由控制器负责为云配置正确的路由,以便Kubernetes集群中不同节点上的容器可以相互通信。路由控制器仅适用于Google Compute Engine平台。
|
||||
|
||||
#### 服务控制器
|
||||
|
||||
服务控制器负责监听服务的创建、更新和删除事件。根据Kubernetes中各个服务的当前状态,它将配置云负载平衡器(如ELB或Google LB)以反映Kubernetes中的服务状态。此外,它还确保云负载均衡器的服务后端保持最新。
|
||||
|
||||
#### PersistentVolumeLabels 控制器
|
||||
|
||||
PersistentVolumeLabels控制器在AWS的EBS卷、GCE的PD卷创建时申请标签,这使得用户不再需要手动设置这些卷标签。
|
||||
|
||||
这些标签对于pod的调度工作是非常重要的,因为这些卷只能在它们所在的域(Zone)/区(Region)内工作,因此所有使用这些卷的pod都必须要在同一个域/区中才能保证进行调度正常进行。
|
||||
|
||||
PersistentVolumeLabels控制器是专门为CCM创建的; 也就是说,在CCM创建之前它是不存在的。这样做是为了将Kubernetes API服务器(它是一个许可控制器)中的PV标签逻辑移动到CCM。 它不在KCM上运行。
|
||||
|
||||
### 2. Kubelet
|
||||
|
||||
Node控制器包含kubelet中依赖于云的功能。在系统引入CCM组件之前,是由kubelet采用包含云特定信息的方式对节点进行初始化,如IP地址、区(Region)/域(Zone)标签和实例类型信息;引入CCM之后,这部分的初始化操作就从kubelet转移到了CCM中。
|
||||
|
||||
在引入CCM后的新的模型中,kubelet采用不包含云特定信息的方式初始化一个节点。但是,它会为新创建的节点添加一个污点,使得该节点不可被立即调度,直到CCM使用包含云的特定信息初始化节点后,才会删除该污点,使得该节点可被调度。
|
||||
|
||||
### 3. Kubernetes API服务器
|
||||
|
||||
PersistentVolumeLabels控制器将Kubernetes API服务器的依赖于云的功能移至CCM,如前面部分所述。
|
||||
|
||||
## 插件机制
|
||||
|
||||
云控制器管理器使用Go接口与外部对接从而实现功能扩展。具体来说,它使用了[这里](https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/cloud.go)定义的CloudProvider接口。
|
||||
|
||||
上面强调的四个共享控制器的实现,以及一些辅助设施(scaffolding)和共享的云服务供应商接口,将被保留在Kubernetes核心当中。但云服务供应商特有的实现将会建立在核心之外,并实现核心中定义的接口。
|
||||
|
||||
有关开发插件的更多信息,请参阅
|
||||
[开发云控制器管理器](/docs/tasks/administrators-cluster/developing-cloud-controller-manager/)。
|
||||
|
||||
## 授权
|
||||
|
||||
本节分解了CCM对各种API对象的访问,以执行其操作。
|
||||
|
||||
### 节点控制器
|
||||
|
||||
节点控制器仅适用于节点对象。它需要完全访问权限来获取、列出、创建、更新、修补、监视和删除节点对象。
|
||||
|
||||
v1/Node:
|
||||
- Get
|
||||
- List
|
||||
- Create
|
||||
- Update
|
||||
- Patch
|
||||
- Watch
|
||||
|
||||
### 路由控制器
|
||||
|
||||
路由控制器监听节点对象的创建并配置合适的路由。它需要对节点对象的访问权限。
|
||||
|
||||
v1/Node:
|
||||
- Get
|
||||
|
||||
### 服务控制器
|
||||
|
||||
服务控制器侦听服务对象创建、更新和删除事件,然后对这些服务的端点进行恰当的配置。
|
||||
|
||||
要访问服务,它需要罗列和监控权限。要更新服务,它需要修补和更新权限。
|
||||
|
||||
要为服务设置端点,需要访问创建、列表、获取、监视和更新。
|
||||
|
||||
v1/Service:
|
||||
- List
|
||||
- Get
|
||||
- Watch
|
||||
- Patch
|
||||
- Update
|
||||
|
||||
### PersistentVolumeLabels 控制器
|
||||
|
||||
PersistentVolumeLabels控制器监听PersistentVolume(PV)创建事件并更新它们。该控制器需要访问列表、查看、获取和更新PV的权限。
|
||||
|
||||
v1/PersistentVolume:
|
||||
- Get
|
||||
- List
|
||||
- Watch
|
||||
- Update
|
||||
|
||||
### 其它
|
||||
|
||||
CCM核心的实现需要创建事件的权限,为了确保安全操作,需要创建ServiceAccounts的权限。
|
||||
|
||||
v1/Event:
|
||||
- Create
|
||||
- Patch
|
||||
- Update
|
||||
|
||||
v1/ServiceAccount:
|
||||
- Create
|
||||
|
||||
针对CCM的RBAC ClusterRole如下所示:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: cloud-controller-manager
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- nodes/status
|
||||
verbs:
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
verbs:
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- serviceaccounts
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- persistentvolumes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- endpoints
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
```
|
||||
|
||||
## 供应商实施
|
||||
|
||||
以下云服务供应商为自己的云部署了CCM。
|
||||
|
||||
* [Digital Ocean]()
|
||||
* [Oracle]()
|
||||
* [Azure]()
|
||||
* [GCE]()
|
||||
* [AWS]()
|
||||
|
||||
## 群集管理
|
||||
|
||||
[这里](/docs/tasks/administer-cluster/running-cloud-controller/#cloud-controller-manager)提供了配置和运行CCM的完整说明。
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
approvers:
|
||||
- dchen1107
|
||||
- roberthbailey
|
||||
- liggitt
|
||||
|
||||
title: Master 节点通信
|
||||
---
|
||||
|
||||
{{< 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 Kubernetes Engine](https://cloud.google.com/kubernetes-engine/docs/) 使用 SSH 隧道保护 Master -> Cluster 通信路径。在这种配置下,apiserver 发起一个到集群中每个节点的 SSH 隧道(连接到在 22 端口监听的 ssh 服务)并通过这个隧道传输所有到 kubelet、node、pod 或者 service 的流量。这个隧道保证流量不会在集群运行的私有 GCE 网络之外暴露。
|
||||
@@ -0,0 +1,233 @@
|
||||
---
|
||||
approvers:
|
||||
- caesarxuchao
|
||||
- dchen1107
|
||||
|
||||
title: Nodes
|
||||
redirect_from:
|
||||
- "/docs/admin/node/"
|
||||
- "/docs/admin/node.html"
|
||||
- "/docs/concepts/nodes/node/"
|
||||
- "/docs/concepts/nodes/node.html"
|
||||
---
|
||||
|
||||
{{< 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/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: k8s.gcr.io/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/{{< param "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,247 @@
|
||||
---
|
||||
cn-approvers:
|
||||
- lichuqiang
|
||||
title: 证书
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## 创建证书
|
||||
|
||||
当使用客户端证书进行认证时,用户可以使用现有部署脚本,或者通过 `easyrsa`、`openssl` 或
|
||||
`cfssl` 手动生成证书。
|
||||
|
||||
### 使用现有部署脚本
|
||||
|
||||
**现有部署脚本** 位于
|
||||
`cluster/saltbase/salt/generate-cert/make-ca-cert.sh`。
|
||||
|
||||
执行该脚本时需传入两个参数。 第一个参数为 API 服务器的 IP 地址,第二个参数为对象的候补名称列表,
|
||||
形如 `IP:<ip地址> 或 DNS:<dns名称>`。
|
||||
|
||||
脚本生成三个文件: `ca.crt`、`server.crt` 和 `server.key`。
|
||||
|
||||
最后,将以下参数加入到 API 服务器的启动参数中:
|
||||
|
||||
```
|
||||
--client-ca-file=/srv/kubernetes/ca.crt
|
||||
--tls-cert-file=/srv/kubernetes/server.crt
|
||||
--tls-private-key-file=/srv/kubernetes/server.key
|
||||
```
|
||||
|
||||
### easyrsa
|
||||
|
||||
使用 **easyrsa** 能够手动地为集群生成证书。
|
||||
|
||||
1. 下载、解压并初始化 easyrsa3 的补丁版本。
|
||||
|
||||
curl -L -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
|
||||
tar xzf easy-rsa.tar.gz
|
||||
cd easy-rsa-master/easyrsa3
|
||||
./easyrsa init-pki
|
||||
1. 生成 CA(通过 `--batch` 参数设置自动模式。 通过 `--req-cn` 设置默认使用的 CN)
|
||||
|
||||
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
|
||||
1. 生成服务器证书和密钥。
|
||||
参数 `--subject-alt-name` 设置了访问 API 服务器时可能使用的 IP 和 DNS 名称。 `MASTER_CLUSTER_IP`
|
||||
通常为 `--service-cluster-ip-range` 参数中指定的服务 CIDR 的 首个 IP 地址,`--service-cluster-ip-range`同时用于
|
||||
API 服务器和控制器管理器组件。 `--days` 参数用于设置证书的有效期限。
|
||||
下面的示例还假设用户使用 `cluster.local` 作为默认的 DNS 域名。
|
||||
|
||||
./easyrsa --subject-alt-name="IP:${MASTER_IP}"\
|
||||
"IP:${MASTER_CLUSTER_IP},"\
|
||||
"DNS:kubernetes,"\
|
||||
"DNS:kubernetes.default,"\
|
||||
"DNS:kubernetes.default.svc,"\
|
||||
"DNS:kubernetes.default.svc.cluster,"\
|
||||
"DNS:kubernetes.default.svc.cluster.local" \
|
||||
--days=10000 \
|
||||
build-server-full server nopass
|
||||
1. 拷贝 `pki/ca.crt`、 `pki/issued/server.crt` 和 `pki/private/server.key` 至您的目录。
|
||||
1. 填充并在 API 服务器的启动参数中添加以下参数:
|
||||
|
||||
--client-ca-file=/yourdirectory/ca.crt
|
||||
--tls-cert-file=/yourdirectory/server.crt
|
||||
--tls-private-key-file=/yourdirectory/server.key
|
||||
|
||||
### openssl
|
||||
|
||||
使用 **openssl** 能够手动地为集群生成证书。
|
||||
|
||||
1. 生成密钥位数为 2048 的 ca.key:
|
||||
|
||||
openssl genrsa -out ca.key 2048
|
||||
1. 依据 ca.key 生成 ca.crt (使用 -days 参数来设置证书有效时间):
|
||||
|
||||
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
|
||||
1. 生成密钥位数为 2048 的 server.key:
|
||||
|
||||
openssl genrsa -out server.key 2048
|
||||
1. 创建用于生成证书签名请求(CSR)的配置文件。
|
||||
确保在将其保存至文件(如`csr.conf`)之前将尖括号标记的值(如`<MASTER_IP>`)
|
||||
替换为你想使用的真实值。 注意:`MASTER_CLUSTER_IP` 是前面小节中描述的 API 服务器的服务集群 IP
|
||||
(service cluster IP)。 下面的示例也假设用户使用 `cluster.local` 作为默认的 DNS 域名。
|
||||
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C = <country>
|
||||
ST = <state>
|
||||
L = <city>
|
||||
O = <organization>
|
||||
OU = <organization unit>
|
||||
CN = <MASTER_IP>
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
DNS.1 = kubernetes
|
||||
DNS.2 = kubernetes.default
|
||||
DNS.3 = kubernetes.default.svc
|
||||
DNS.4 = kubernetes.default.svc.cluster
|
||||
DNS.5 = kubernetes.default.svc.cluster.local
|
||||
IP.1 = <MASTER_IP>
|
||||
IP.2 = <MASTER_CLUSTER_IP>
|
||||
|
||||
[ v3_ext ]
|
||||
authorityKeyIdentifier=keyid,issuer:always
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage=keyEncipherment,dataEncipherment
|
||||
extendedKeyUsage=serverAuth,clientAuth
|
||||
subjectAltName=@alt_names
|
||||
1. 基于配置文件生成证书签名请求:
|
||||
|
||||
openssl req -new -key server.key -out server.csr -config csr.conf
|
||||
1. 使用 ca.key、ca.crt 和 server.csr 生成服务器证书:
|
||||
|
||||
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
|
||||
-CAcreateserial -out server.crt -days 10000 \
|
||||
-extensions v3_ext -extfile csr.conf
|
||||
1. 查看证书:
|
||||
|
||||
openssl x509 -noout -text -in ./server.crt
|
||||
|
||||
最后,添加同样的参数到 API 服务器的启动参数中。
|
||||
|
||||
### cfssl
|
||||
|
||||
**cfssl** 是另一种用来生成证书的工具。
|
||||
|
||||
1. 按如下所示的方式下载、解压并准备命令行工具。
|
||||
注意:你可能需要基于硬件架构和你所使用的 cfssl 版本对示例命令进行修改。
|
||||
|
||||
curl -LO https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o cfssl
|
||||
chmod +x cfssl
|
||||
curl -LO https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o cfssljson
|
||||
chmod +x cfssljson
|
||||
curl -LO https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o cfssl-certinfo
|
||||
chmod +x cfssl-certinfo
|
||||
1. 创建目录来存放物料,并初始化 cfssl:
|
||||
|
||||
mkdir cert
|
||||
cd cert
|
||||
../cfssl print-defaults config > config.json
|
||||
../cfssl print-defaults csr > csr.json
|
||||
1. 创建用来生成 CA 文件的 JSON 配置文件,例如 `ca-config.json`:
|
||||
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "8760h"
|
||||
},
|
||||
"profiles": {
|
||||
"kubernetes": {
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"server auth",
|
||||
"client auth",
|
||||
],
|
||||
"expiry": "8760h"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1. 创建用来生成 CA 证书签名请求(CSR)的 JSON 配置文件,例如 `ca-csr.json`。
|
||||
确保将尖括号标记的值替换为你想使用的真实值。
|
||||
|
||||
{
|
||||
"CN": "kubernetes",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names":[{
|
||||
"C": "<country>",
|
||||
"ST": "<state>",
|
||||
"L": "<city>",
|
||||
"O": "<organization>",
|
||||
"OU": "<organization unit>",
|
||||
}]
|
||||
}
|
||||
1. 生成 CA 密钥(`ca-key.pem`)和证书(`ca.pem`):
|
||||
|
||||
../cfssl gencert -initca ca-csr.json | ../cfssljson -bare ca
|
||||
1. 按如下所示的方式创建用来为 API 服务器生成密钥和证书的 JSON 配置文件。
|
||||
确保将尖括号标记的值替换为你想使用的真实值。 `MASTER_CLUSTER_IP` 是前面小节中描述的
|
||||
API 服务器的服务集群 IP。 下面的示例也假设用户使用 `cluster.local` 作为默认的 DNS 域名。
|
||||
|
||||
{
|
||||
"CN": "kubernetes",
|
||||
"hosts": [
|
||||
"127.0.0.1",
|
||||
"<MASTER_IP>",
|
||||
"<MASTER_CLUSTER_IP>",
|
||||
"kubernetes",
|
||||
"kubernetes.default",
|
||||
"kubernetes.default.svc",
|
||||
"kubernetes.default.svc.cluster",
|
||||
"kubernetes.default.svc.cluster.local"
|
||||
],
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names": [{
|
||||
"C": "<country>",
|
||||
"ST": "<state>",
|
||||
"L": "<city>",
|
||||
"O": "<organization>",
|
||||
"OU": "<organization unit>"
|
||||
}]
|
||||
}
|
||||
1. 为 API 服务器生成密钥和证书,生成的秘钥和证书分别默认保存在文件 `server-key.pem`
|
||||
和 `server.pem` 中:
|
||||
|
||||
../cfssl gencert -ca=ca.pem -ca-key=ca-key.pem \
|
||||
--config=ca-config.json -profile=kubernetes \
|
||||
server-csr.json | ../cfssljson -bare server
|
||||
|
||||
|
||||
## 分发自签名 CA 证书
|
||||
|
||||
客户端节点可能拒绝承认自签名 CA 证书有效。
|
||||
对于非生产环境的部署,或运行在企业防火墙后的部署,用户可以向所有客户端分发自签名 CA 证书,
|
||||
并刷新本地的有效证书列表。
|
||||
|
||||
在每个客户端上执行以下操作:
|
||||
|
||||
```bash
|
||||
$ sudo cp ca.crt /usr/local/share/ca-certificates/kubernetes.crt
|
||||
$ sudo update-ca-certificates
|
||||
Updating certificates in /etc/ssl/certs...
|
||||
1 added, 0 removed; done.
|
||||
Running hooks in /etc/ca-certificates/update.d....
|
||||
done.
|
||||
```
|
||||
|
||||
## 证书 API
|
||||
|
||||
您可以按照[这里](/docs/tasks/tls/managing-tls-in-a-cluster)记录的方式,
|
||||
使用 `certificates.k8s.io` API 来准备 x509 证书,用于认证。
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
title: 云供应商
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
本文介绍了如何管理运行在特定云供应商上的 Kubernetes 集群。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
# AWS
|
||||
本节介绍在 Amazon Web Services 上运行 Kubernetes 时可以使用的所有配置。
|
||||
|
||||
## 负载均衡器
|
||||
用户可以通过配置注解(annotations)来设置 [外部负载均衡器](/docs/tasks/access-application-cluster/create-external-load-balancer/),以在 AWS 中使用特定功能,如下所示:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: example
|
||||
namespace: kube-system
|
||||
labels:
|
||||
run: example
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:xx-xxxx-x:xxxxxxxxx:xxxxxxx/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx #replace this value
|
||||
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 5556
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: example
|
||||
```
|
||||
可以使用 _注解_ 将不同的设置应用于 AWS 中的负载平衡器服务。 下面描述了 AWS ELB 所支持的注解:
|
||||
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval`:用于指定访问日志的间隔。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-access-log-enabled`:用于在服务中启用或禁用日志访问。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name`:用于指定访问日志的 S3 桶名称。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix`:用于指定访问日志的 S3 桶前缀。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags`:用于在服务中指定一个逗号分隔的键值对列表,它将作为附加标签被记录在 ELB 中。 例如: `"Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"`。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-backend-protocol`:用于在服务中指定监听器后端(pod)所使用的协议。 如果指定 `http` (默认) 或 `https`, 将创建一个终止连接和解析头的 HTTPS 监听器。 如果设置为 `ssl` 或 `tcp`, 将会使用 “原生的” SSL 监听器。 如果设置为 `http` 且不使用 `aws-load-balancer-ssl-cert`,将使用 HTTP 监听器。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-ssl-cert`:用于在服务中请求安全监听器,其值为合法的证书 ARN(Amazon Resource Name)。 更多内容,请参考 [ELB 监听器配置](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html)。 证书 ARN 是 IAM(身份和访问管理) 或 CM(证书管理)类型的 ARN,例如 `arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012`。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled`:用于在服务中启用或禁用连接耗尽(connection draining)。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout`:用于在服务中指定连接耗尽超时时间。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout`:用于在服务中指定空闲连接超时时间。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled`:用于在服务中启用或禁用跨区域负载平衡。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-extra-security-groups`:用于在服务中指定要添加到创建的 ELB 中的其他安全组。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-internal`:用于在服务中表明需要内部 ELB。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-proxy-protocol`:用于在 ELB 上启用代理协议。 当前仅接受 `*` 值,也就是在所有 ELB 后端启用代理协议。 将来可能进行调整,只允许特定的后端设置代理协议。
|
||||
* `service.beta.kubernetes.io/aws-load-balancer-ssl-ports`:用于在服务中指定一个逗号分隔的端口列表,这些端口会使用 SSL/HTTPS 监听器。 默认为 `*`(全部)
|
||||
|
||||
AWS 相关的注解信息取自 [aws.go](https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/providers/aws/aws.go) 文件的注释。
|
||||
|
||||
# OpenStack
|
||||
本节介绍了使用 OpenStack 运行 Kubernetes 时所有可用的配置。
|
||||
|
||||
## cloud.conf
|
||||
Kubernetes 知道如何通过文件 cloud.conf 与 OpenStack 进行交互。 该文件会为 Kubernetes 提供证书和 OpenStack 认证端点的区位信息。
|
||||
用户可以通过在其中指定以下信息来创建 cloud.conf 文件。
|
||||
|
||||
### 最小配置
|
||||
这是一个最小配置的例子,它涉及最常用的值:
|
||||
|
||||
```yaml
|
||||
[Global]
|
||||
username=user
|
||||
password=pass
|
||||
auth-url=https://<keystone_ip>/identity/v3
|
||||
tenant-id=c869168a828847f39f7f06edd7305637
|
||||
domain-id=2a73b8f597c04551a0fdc8e95544be8a
|
||||
|
||||
[LoadBalancer]
|
||||
subnet-id=6937f8fa-858d-4bc9-a3a5-18d2c957166a
|
||||
```
|
||||
|
||||
#### 全局配置
|
||||
* `username`:指 keystone 中设置的一个合法用户的用户名。
|
||||
* `password`:指 keystone 中设置的一个合法用户的密码。
|
||||
* `auth-url`:用于认证的 keystone API 的 URL 。 在 OpenStack 控制面板上,可以在 “访问和安全(Access and Security)> api 访问(API Access)> 凭证(Credentials)” 路径下找到它。
|
||||
* `tenant-id`:用于指定要创建资源的项目 ID。
|
||||
* `domain-id`:用于指定用户所属的域(domain)ID。
|
||||
|
||||
#### 负载均衡器
|
||||
* `subnet-id`:用于指定要创建的负载均衡器所在的子网 ID。 可以在 “Network > Networks” 路径下找到它。 点击相应的网络获取其子网。
|
||||
|
||||
### 可选配置
|
||||
|
||||
#### 块存储
|
||||
|
||||
Kubernetes 利用 OpenStack 服务目录对它知道如何使用的服务进行定位,包括 Cinder 块存储服务。 然而,云供应商的配置中包含一个附加选项,可以影响块存储 API 的使用方式:
|
||||
|
||||
* `bs-version`:指所使用的块存储 API 版本。 其合法值为
|
||||
`v1`、 `v2`、 `v3` 和 `auto`。 `auto` 为默认值,将使用底层 Openstack 所支持的块存储 API 的最新版本。
|
||||
|
||||
如果在 OpenStack 上部署 Kubernetes <= 1.8 的版本,同时使用路径而不是端口来区分端点(endpoints),那么可能需要显式设置 `bs-version` 参数。 基于路径的端点形如 `http://foo.bar/volume` ,而基于端口的的端点形如
|
||||
`http://foo.bar:xxx`。
|
||||
|
||||
在使用基于路径的端点,并且 Kubernetes 使用较旧的自动检索逻辑的环境中,尝试卷卸载(detachment)会返回 `BS API version autodetection failed.` 错误。 为了解决这个问题,可以通过添加以下内容到云供应商配置中,来强制使用 Cinder API V2 版本。
|
||||
|
||||
```yaml
|
||||
[BlockStorage]
|
||||
bs-version=v2
|
||||
```
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
|
||||
title: 集群管理概述
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
集群管理概述面向任何创建和管理 Kubernetes 集群的读者人群。我们假设你对 [用户指南](/docs/user-guide/)中的概念有一些熟悉。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% 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 的日志如何工作以及怎样实现。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
approvers:
|
||||
title: 设备插件
|
||||
description: 使用 Kubernetes 设备插件框架来为 GPUs、 NICs、 FPGAs、 InfiniBand 和其他类似的需要供应商特别设置的资源开发插件。
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{< feature-state state="alpha" >}}
|
||||
|
||||
{{% capture overview %}}
|
||||
从1.8版本开始,Kubernetes 提供了一套
|
||||
[设备插件框架](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/device-plugin.md),
|
||||
使得供应商能够在不改动 Kubernetes 核心代码的情况下,向 kubelet 发布它们的资源。
|
||||
供应商可以实现一个手动或以 DaemonSet 形式部署的插件,而不是编写自定义的 Kubernetes 代码。
|
||||
插件的目标设备包括 GPUs、 高性能 NICs、 FPGAs、 InfiniBand
|
||||
和其他类似的可能需要供应商特定的初始化和设置的计算资源。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 设备插件注册
|
||||
|
||||
设备插件功能通过 `DevicePlugins` 功能入口控制, 该功能默认是禁用的。
|
||||
当设备插件功能被启用时,kubelet 会对外提供一个 `Registration` gRPC 服务:
|
||||
|
||||
```gRPC
|
||||
service Registration {
|
||||
rpc Register(RegisterRequest) returns (Empty) {}
|
||||
}
|
||||
```
|
||||
设备插件通过该 gRPC 服务将自身注册到 kubelet 。
|
||||
注册过程中,设备插件需要发送:
|
||||
|
||||
* 它的 Unix 套接字名称。
|
||||
* 所基于的设备插件 API 版本。
|
||||
* 希望发布的 `ResourceName` 。 这里的 `ResourceName` 需要符合
|
||||
[扩展资源命名方案](https://github.com/kubernetes/kubernetes/pull/48922),
|
||||
形如 `vendor-domain/resource` 。
|
||||
例如,Nvidia GPU 资源被发布为 `nvidia.com/gpu` 。
|
||||
|
||||
注册成功后,设备插件将其管理的设备列表发送至 kubelet ,然后 kubelet 负责将这些资源作为 kubelet 节点状态更新的一部分,通知 apiserver 。
|
||||
例如, 设备插件注册 `vendor-domain/foo` 到 kubelet ,
|
||||
并上报了节点上的两个健康的设备后,节点状态将更新, 发布2个 `vendor-domain/foo` 。
|
||||
|
||||
然后,开发者可以在 [容器](/docs/api-reference/{{< param "version" >}}/#container-v1-core)
|
||||
规格中通过使用与
|
||||
[不透明整数型资源](/docs/tasks/configure-pod-container/opaque-integer-resource/)
|
||||
中同样的流程来请求使用设备。
|
||||
在1.8版本中, 扩展资源仅支持整型的资源,且容器规格中声明的 `limit` 与 `request` 必须相等。
|
||||
|
||||
## 设备插件实现
|
||||
|
||||
设备插件的工作流程一般包括以下步骤:
|
||||
|
||||
* 初始化。 在这个阶段,设备插件执行供应商特定的初始化和设置,以确保设备处于就绪状态。
|
||||
|
||||
* 插件通过主机路径 `/var/lib/kubelet/device-plugins/` 下的一个 Unix 套接字启动 gRPC 服务,该服务实现了以下接口:
|
||||
|
||||
```gRPC
|
||||
service DevicePlugin {
|
||||
// ListAndWatch returns a stream of List of Devices
|
||||
// Whenever a Device state change or a Device disappears, ListAndWatch
|
||||
// returns the new list
|
||||
rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}
|
||||
|
||||
// Allocate is called during container creation so that the Device
|
||||
// Plugin can run device specific operations and instruct Kubelet
|
||||
// of the steps to make the Device available in the container
|
||||
rpc Allocate(AllocateRequest) returns (AllocateResponse) {}
|
||||
}
|
||||
```
|
||||
|
||||
* 插件通过主机路径 `/var/lib/kubelet/device-plugins/kubelet.sock` 下的 Unix 套接字将自身注册到 kubelet 。
|
||||
|
||||
* 注册成功之后,设备插件以服务模式运行,其间持续监测设备健康状态,并在任何设备状态变化时上报到 kubelet 。
|
||||
插件也负责服务 `Allocate` gRPC 请求。 在 `Allocate` 过程中,插件可能会做设备特定的准备动作; 如 GPU 清理 或 QRNG 初始化。
|
||||
如操作成功,设备插件会返回一个 `AllocateResponse` ,它包含了用于访问分配的设备的容器运行时配置信息。 kubelet 将该信息传递到容器运行时。
|
||||
|
||||
我们期望设备插件能够监测到 kubelet 重启,并将自身重新注册到新的 kubelet 实例中。 在1.8版本中,新的 kubelet 实例启动时,会清理当前 `/var/lib/kubelet/device-plugins` 路径下已存在的 Unix 套接字。 通过这一事件,设备插件能够监测到其 Unix 套接字被删除,并重新对自身进行注册。
|
||||
|
||||
## 设备插件部署
|
||||
|
||||
设备插件可以手动部署,也可以作为 DaemonSet 进行部署。 以 DaemonSet 形式部署的好处是设备插件故障时,
|
||||
Kubernetes能够重新启动 Pods 。 否则就需要额外的设备插件故障恢复机制。
|
||||
目录 `/var/lib/kubelet/device-plugins` 需要访问特权,
|
||||
所以设备插件必须在特权的安全上下文环境下运行。
|
||||
如果设备插件以 DaemonSet 形式运行, `/var/lib/kubelet/device-plugins`
|
||||
目录必须在插件的 [PodSpec](/docs/api-reference/{{< param "version" >}}/#podspec-v1-core) 中以 [Volume](/docs/api-reference/{{< param "version" >}}/#volume-v1-core) 的形式挂载。
|
||||
|
||||
## 示例
|
||||
|
||||
设备插件实现的示例,参考
|
||||
[基于 COS 操作系统的 nvidia GPU 设备插件](https://github.com/GoogleCloudPlatform/container-engine-accelerators/tree/master/cmd/nvidia_gpu)。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: 联邦
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
本页面阐明了为何以及如何使用联邦创建Kubernetes集群。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
## 为何使用联邦
|
||||
|
||||
联邦可以使多个集群的管理简单化。它提供了两个主要构件模块:
|
||||
|
||||
* 跨集群同步资源:联邦能够让资源在多个集群中同步。例如,你可以确保在多个集群中存在同样的部署。
|
||||
* 跨集群发现:联邦能够在所有集群的后端自动配置DNS服务和负载均衡。例如,通过多个集群的后端,你可以确保全局的VIP或DNS记录可用。
|
||||
|
||||
联邦技术的其他应用场景:
|
||||
|
||||
* 高可用性:通过跨集群分摊负载,自动配置DNS服务和负载均衡,联邦将集群失败所带来的影响降到最低。
|
||||
* 避免供应商锁定:跨集群使迁移应用程序变得更容易,联邦服务避免了供应商锁定。
|
||||
|
||||
|
||||
只有在多个集群的场景下联邦服务才是有帮助的。这里列出了一些你会使用多个集群的原因:
|
||||
|
||||
* 降低延迟:在多个区域含有集群,可使用离用户最近的集群来服务用户,从而最大限度降低延迟。
|
||||
* 故障隔离:对于故障隔离,也许有多个小的集群比有一个大的集群要更好一些(例如:一个云供应商的不同可用域里有多个集群)。详细信息请参阅[多集群指南](/docs/admin/multi-cluster)。
|
||||
* 可伸缩性:对于单个kubernetes集群是有伸缩性限制的(但对于大多数用户来说并非如此。更多细节参考[Kubernetes扩展和性能目标](https://git.k8s.io/community/sig-scalability/goals.md))。
|
||||
* [混合云](#混合云的能力):可以有多个集群,它们分别拥有不同的云供应商或者本地数据中心。
|
||||
|
||||
### 注意事项
|
||||
|
||||
虽然联邦有很多吸引人的场景,但这里还是有一些需要关注的事项:
|
||||
|
||||
* 增加网络的带宽和损耗:联邦控制面会监控所有的集群,来确保集群的当前状态与预期一致。那么当这些集群运行在一个或者多个云提供者的不同区域中,则会带来重大的网络损耗。
|
||||
* 降低集群的隔离:当联邦控制面中存在一个故障时,会影响所有的集群。把联邦控制面的逻辑降到最小可以缓解这个问题。 无论何时,它都是kubernetes集群里控制面的代表。设计和实现也使其变得更安全,避免多集群运行中断。
|
||||
* 完整性:联邦项目相对较新,还不是很成熟。不是所有资源都可用,且很多资源才刚刚开始。[Issue 38893](https://github.com/kubernetes/kubernetes/issues/38893) 列举了一些团队正忙于解决的系统已知问题。
|
||||
|
||||
### 混合云的能力
|
||||
|
||||
Kubernetes集群里的联邦包括运行在不同云供应商上的集群(例如,谷歌云、亚马逊),和本地部署的集群(例如,OpenStack)。只需在适当的云供应商和/或位置创建所需的所有集群,并将每个集群的API endpoint和凭据注册到您的联邦API服务中(详情参考[联邦管理指南](/docs/admin/federation/))。
|
||||
|
||||
在此之后,您的[API资源](#api资源)就可以跨越不同的集群和云供应商。
|
||||
|
||||
## 建立联邦
|
||||
|
||||
若要能联合多个集群,首先需要建立一个联邦控制面。参照[安装指南](/docs/tutorials/federation/set-up-cluster-federation-kubefed/) 建立联邦控制面。
|
||||
|
||||
## API资源
|
||||
|
||||
控制面建立完成后,就可以开始创建联邦API资源了。
|
||||
以下指南详细介绍了一些资源:
|
||||
|
||||
* [Cluster](/docs/tasks/administer-federation/cluster/)
|
||||
* [ConfigMap](/docs/tasks/administer-federation/configmap/)
|
||||
* [DaemonSets](/docs/tasks/administer-federation/daemonset/)
|
||||
* [Deployment](/docs/tasks/administer-federation/deployment/)
|
||||
* [Events](/docs/tasks/administer-federation/events/)
|
||||
* [Ingress](/docs/tasks/administer-federation/ingress/)
|
||||
* [Namespaces](/docs/tasks/administer-federation/namespaces/)
|
||||
* [ReplicaSets](/docs/tasks/administer-federation/replicaset/)
|
||||
* [Secrets](/docs/tasks/administer-federation/secret/)
|
||||
* [Services](/docs/concepts/cluster-administration/federation-service-discovery/)
|
||||
|
||||
[API参考文档](/docs/reference/federation/)列举了联邦API服务支持的所有资源。
|
||||
|
||||
## 级联删除
|
||||
|
||||
Kubernetes1.6版本支持联邦资源级联删除。使用级联删除,即当删除联邦控制面的一个资源时,也删除了所有底层集群中的相应资源。
|
||||
|
||||
当使用REST API时,级联删除功能不是默认开启的。若使用REST API从联邦控制面删除一个资源时,要开启级联删除功能,即需配置选项 `DeleteOptions.orphanDependents=false`。使用`kubectl delete`使级联删除功能默认开启。使用`kubectl delete --cascade=false`禁用级联删除功能。
|
||||
|
||||
注意:Kubernetes1.5版本开始支持联邦资源子集的级联删除。
|
||||
|
||||
## 单个集群的范围
|
||||
|
||||
对于IaaS供应商如谷歌计算引擎或亚马逊网络服务,一个虚拟机存在于一个[域](https://cloud.google.com/compute/docs/zones)或[可用域](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)中。
|
||||
我们建议一个Kubernetes集群里的所有虚机应该在相同的可用域里,因为:
|
||||
|
||||
- 与单一的全局Kubernetes集群对比,该方式有较少的单点故障。
|
||||
- 与跨可用域的集群对比,该方式更容易推断单区域集群的可用性属性。
|
||||
- 当Kubernetes开发者设计一个系统(例如,对延迟、带宽或相关故障进行假设),他们也会假设所有的机器都在一个单一的数据中心,或者以其他方式紧密相连。
|
||||
|
||||
每个可用区域里包含多个集群当然是可以的,但是总的来说我们认为集群数越少越好。
|
||||
偏爱较少集群数的原因是:
|
||||
|
||||
- 在某些情况下,在一个集群里有更多的节点,可以改进Pods的装箱问题(更少的资源碎片)。
|
||||
- 减少操作开销(尽管随着OPS工具和流程的成熟而降低了这块的优势)。
|
||||
- 为每个集群的固定资源花费降低开销,例如,使用apiserver的虚拟机(但是在全体集群开销中,中小型集群的开销占比要小的多)。
|
||||
|
||||
多集群的原因包括:
|
||||
|
||||
- 严格的安全性策略要求隔离一类工作与另一类工作(但是,请参见下面的集群分割)。
|
||||
- 测试集群或其他集群软件直至最优的新Kubernetes版本发布。
|
||||
|
||||
## 选择合适的集群数
|
||||
|
||||
Kubernetes集群数量选择也许是一个相对静止的选择,因为对其重新审核的情况很少。相比之下,一个集群中的节点数和一个服务中的pods数可能会根据负载和增长频繁变化。
|
||||
|
||||
选择集群的数量,首先,需要决定哪些区域对于将要运行在Kubernetes上的服务,可以有足够的时间到达所有的终端用户(如果使用内容分发网络,则不需要考虑CDN-hosted内容的延迟需求)。法律问题也可能影响这一点。例如,拥有全球客户群的公司可能会对于在美国、欧盟、亚太和南非地区拥有集群起到决定权。使用`R`代表区域的数量。
|
||||
|
||||
其次,决定有多少集群在同一时间不可用,而一些仍然可用。使用`U`代表不可用的数量。如果不确定,最好选择1。
|
||||
|
||||
如果允许负载均衡在集群故障发生时将通信引导到任何区域,那么至少需要较大的`R`或`U + 1`集群。若非如此(例如,若要在集群故障发生时确保所有用户的低延迟),则需要`R * (U + 1)`集群(在每一个`R`区域里都有`U + 1`)。在任何情况下,尝试将每个集群放在不同的区域中。
|
||||
|
||||
最后,如果你的集群需求超过一个Kubernetes集群推荐的最大节点数,那么你可能需要更多的集群。Kubernetes1.3版本支持多达1000个节点的集群规模。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
* 进一步学习[联邦提案](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/multicluster/federation.md)。
|
||||
* 集群联邦参考该[配置指导](/docs/tutorials/federation/set-up-cluster-federation-kubefed/)。
|
||||
* 查看[Kubecon2016浅谈联邦](https://www.youtube.com/watch?v=pq9lbkmxpS8)
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: Kubernetes 中的代理
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
本文讲述了 Kubernetes 中所使用的代理。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 代理
|
||||
|
||||
用户在使用 Kubernetes 的过程中可能遇到几种不同的代理(proxy):
|
||||
|
||||
1. [kubectl proxy](/docs/tasks/access-application-cluster/access-cluster/#directly-accessing-the-rest-api):
|
||||
|
||||
- 运行在用户的桌面或 pod 中
|
||||
- 从本机地址到 Kubernetes apiserver 的代理
|
||||
- 客户端到代理使用 HTTP 协议
|
||||
- 代理到 apiserver 使用 HTTPS 协议
|
||||
- 指向 apiserver
|
||||
- 添加认证头信息
|
||||
|
||||
1. [apiserver proxy](/docs/tasks/access-application-cluster/access-cluster/#discovering-builtin-services):
|
||||
|
||||
- 是一个建立在 apiserver 内部的“堡垒”
|
||||
- 将集群外部的用户与群集 IP 相连接,这些IP是无法通过其他方式访问的
|
||||
- 运行在 apiserver 进程内
|
||||
- 客户端到代理使用 HTTPS 协议 (如果配置 apiserver 使用 HTTP 协议,则使用 HTTP 协议)
|
||||
- 通过可用信息进行选择,代理到目的地可能使用 HTTP 或 HTTPS 协议
|
||||
- 可以用来访问 Node、 Pod 或 Service
|
||||
- 当用来访问 Service 时,会进行负载均衡
|
||||
|
||||
1. [kube proxy](/docs/concepts/services-networking/service/#ips-and-vips):
|
||||
|
||||
- 在每个节点上运行
|
||||
- 代理 UDP 和 TCP
|
||||
- 不支持 HTTP
|
||||
- 提供负载均衡能力
|
||||
- 只用来访问 Service
|
||||
|
||||
1. apiserver 之前的代理/负载均衡器:
|
||||
|
||||
- 在不同集群间的存在形式和实现不同 (如 nginx)
|
||||
- 位于所有客户端和一个或多个 apiserver 之间
|
||||
- 存在多个 apiserver 时,扮演负载均衡器的角色
|
||||
|
||||
1. 外部服务的云负载均衡器:
|
||||
|
||||
- 由一些云供应商提供 (如AWS ELB、 Google Cloud Load Balancer)
|
||||
- Kubernetes service 为 `LoadBalancer` 类型时自动创建
|
||||
- 只使用 UDP/TCP 协议
|
||||
- 不同云供应商的实现不同。
|
||||
|
||||
Kubernetes 用户通常只需要关心前两种类型的代理,集群管理员通常需要确保后面几种类型的代理设置正确。
|
||||
|
||||
## 请求重定向
|
||||
|
||||
代理已经取代重定向功能,重定向已被弃用。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
approvers:
|
||||
- sttts
|
||||
title: Kubernetes集群中使用Sysctls
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
这篇文章描述了如何在Kubernetes集群中使用Sysctls。
|
||||
|
||||
## 什么是Sysctl?
|
||||
|
||||
在Linux中,Sysctl接口允许管理员在内核运行时修改内核参数。这些可用参数都存在于虚拟进程文件系统中的`/proc/sys/`目录。这些内核参数作用于各种子系统中,例如:
|
||||
|
||||
- 内核 (通用前缀:`kernel.`)
|
||||
- 网络 (通用前缀:`net.`)
|
||||
- 虚拟内存 (通用前缀:`vm.`)
|
||||
- 设备专用 (通用前缀:`dev.`)
|
||||
- 更多子系统描述见 [Kernel docs](https://www.kernel.org/doc/Documentation/sysctl/README).
|
||||
|
||||
获取所有参数列表,可运行
|
||||
|
||||
```
|
||||
$ sudo sysctl -a
|
||||
```
|
||||
|
||||
## 命名空间级vs.节点级Sysctls
|
||||
|
||||
在今天的Linux内核系统中有一些Sysctls是 _命名空间级_ 的。这意味着他们在同节点的不同pod间是可配置成独立的。在kubernetes里,命名空间级是Sysctls的一个必要条件,以使其在一个pod语境里易于理解。
|
||||
|
||||
以下列出了Sysctls中已知的 _命名空间级_ :
|
||||
|
||||
- `kernel.shm*`(内核中共享内存相关参数),
|
||||
- `kernel.msg*`(内核中SystemV消息队列相关参数),
|
||||
- `kernel.sem`(内核中信号量参数),
|
||||
- `fs.mqueue.*`(内核中POSIX消息队列相关参数),
|
||||
- `net.*`(内核中网络配置项相关参数)。
|
||||
|
||||
Sysctls中非命名空间级的被称为 _节点级_ ,其必须由集群管理员手动设置,要么通过节点的底层Linux分布方式(例如,通过 `/etc/sysctls.conf`),亦或在特权容器中使用Daemonset。
|
||||
|
||||
**注意**: 这是很好的做法,考虑在一个集群里给有特殊sysctl的节点设置为 _污点_ ,并且给他们安排仅需要这些sysctl设置的pods。 建议采用Kubernetes [_污点和容点_
|
||||
特征](/docs/user-guide/kubectl/{{< param "version" >}}/#taint) 来实现。
|
||||
|
||||
## 安全的 vs. 不安全的 Sysctls
|
||||
|
||||
Sysctls被分为 _安全的_ 和 _不安全的_ sysctls。同一节点上的pods间除了适当命名空间命名一个 _安全的_ sysctl,还必须适当的 _隔离_ 。 这意味着给一个pod设置一个 _安全的_ sysctl
|
||||
|
||||
- 不能对相同节点上其他pod产生任何影响
|
||||
- 不能对节点的健康造成损害
|
||||
- 不能在pod资源限制以外获取更多的CPU和内存资源
|
||||
|
||||
目前看来,大多数的 _命名空间级_ sysctls 不一定被认为是 _安全的_ 。
|
||||
|
||||
在Kubernetes 1.4版本中,以下sysctls提供了 _安全的_ 配置:
|
||||
|
||||
- `kernel.shm_rmid_forced`,
|
||||
- `net.ipv4.ip_local_port_range`,
|
||||
- `net.ipv4.tcp_syncookies`.
|
||||
|
||||
该列表在未来的Kubernetes版本里还会继续扩充,当kubelet提供更好的隔离机制时。
|
||||
|
||||
所有 _安全的_ sysctls 都是默认启用的。
|
||||
|
||||
所有 _不安全的_ sysctls 默认是关闭的,且必须通过每个节点基础上的集群管理手动开启。禁用不安全的sysctls的Pods将会被计划,但不会启动。
|
||||
|
||||
**警告**: 由于他们的本质是 _不安全的_ ,使用 _不安全的_ sysctls是自担风险的,并且会导致严重的问题,例如容器的错误行为,资源短缺或者是一个节点的完全破损。
|
||||
|
||||
## 使能不安全的Sysctls
|
||||
|
||||
牢记上面的警告, 在非常特殊的情况下,例如高性能指标或是实时应用程序优化,集群管理员可以允许 _不安全的_
|
||||
sysctls。 _不安全的_ sysctls 会打上kubelet标识,在逐节点的基础上被启用,例如:
|
||||
|
||||
```shell
|
||||
$ kubelet --experimental-allowed-unsafe-sysctls 'kernel.msg*,net.ipv4.route.min_pmtu' ...
|
||||
```
|
||||
|
||||
只有 _命名空间级_ sysctls 可以使用该方法启用。
|
||||
|
||||
## 给Pod配置Sysctls
|
||||
|
||||
在Kubernetes 1.4版本中,sysctl特性是一个alpha API。因此,sysctls被设置为在pods上使用注释。它们适用于同一个pod上的所有容器。
|
||||
|
||||
这里列举了一个例子, _安全的_ 和 _不安全的_ sysctls使用不同的注释:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: sysctl-example
|
||||
annotations:
|
||||
security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1
|
||||
security.alpha.kubernetes.io/unsafe-sysctls: net.ipv4.route.min_pmtu=1000,kernel.msgmax=1 2 3
|
||||
spec:
|
||||
...
|
||||
```
|
||||
|
||||
**注意**: 包含以上规定的 _不安全的_ sysctls的一个Pod, 将无法启动任何不能使这两个 _不安全的_ sysctls明确的节点。 推荐
|
||||
_节点级_ sysctls使用 [_容点和污点_
|
||||
特征](/docs/user-guide/kubectl/v1.6/#taint) or [taints on nodes](/docs/concepts/configuration/taint-and-toleration/)
|
||||
来将这些pods分配到正确的nodes上。
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: command-demo
|
||||
labels:
|
||||
purpose: demonstrate-command
|
||||
spec:
|
||||
containers:
|
||||
- name: command-demo-container
|
||||
image: debian
|
||||
command: ["printenv"]
|
||||
args: ["HOSTNAME", "KUBERNETES_PORT"]
|
||||
restartPolicy: OnFailure
|
||||
@@ -0,0 +1,299 @@
|
||||
---
|
||||
title: Managing Compute Resources for Containers
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
当您定义 [Pod](/docs/user-guide/pods) 的时候可以选择为每个容器指定需要的 CPU 和内存(RAM)大小。当为容器指定了资源请求后,调度器就能够更好的判断出将容器调度到哪个节点上。如果您还为容器指定了资源限制,节点上的资源就可以按照指定的方式做竞争。关于资源请求和限制的不同点和更多资料请参考 [Resource QoS](https://git.k8s.io/community/contributors/design-proposals/resource-qos.md)。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 资源类型
|
||||
|
||||
*CPU* 和 *内存* 都是 *资源类型*。资源类型具有基本单位。CPU 的单位是 core,内存的单位是 byte。
|
||||
|
||||
CPU和内存统称为*计算资源*,也可以称为*资源*。计算资源的数量是可以被请求、分配、消耗和可测量的。它们与 [API 资源](/docs/api/) 不同。 API 资源(如 Pod 和 [Service](/docs/user-guide/services))是可通过 Kubernetes API server 读取和修改的对象。
|
||||
|
||||
## Pod 和 容器的资源请求和限制
|
||||
|
||||
Pod 中的每个容器都可以指定以下的一个或者多个值:
|
||||
|
||||
- `spec.containers[].resources.limits.cpu`
|
||||
- `spec.containers[].resources.limits.memory`
|
||||
- `spec.containers[].resources.requests.cpu`
|
||||
- `spec.containers[].resources.requests.memory`
|
||||
|
||||
尽管只能在个别容器上指定请求和限制,但是我们可以方便地计算出 Pod 资源请求和限制。特定资源类型的Pod 资源请求/限制是 Pod 中每个容器的该类型的资源请求/限制的总和。
|
||||
|
||||
## CPU 的含义
|
||||
|
||||
CPU 资源的限制和请求以 *cpu* 为单位。
|
||||
|
||||
Kubernetes 中的一个 cpu 等于:
|
||||
|
||||
- 1 AWS vCPU
|
||||
- 1 GCP Core
|
||||
- 1 Azure vCore
|
||||
- 1 *Hyperthread* 在带有超线程的裸机 Intel 处理器上
|
||||
|
||||
允许浮点数请求。具有 `spec.containers[].resources.requests.cpu` 为 0.5 的容器保证了一半 CPU 要求 1 CPU的一半。表达式 `0.1` 等价于表达式 `100m`,可以看作 “100 millicpu”。有些人说成是“一百毫 cpu”,其实说的是同样的事情。具有小数点(如 `0.1`)的请求由 API 转换为`100m`,精度不超过 `1m`。因此,可能会优先选择 `100m` 的形式。
|
||||
|
||||
CPU 总是要用绝对数量,不可以使用相对数量;0.1 的 CPU 在单核、双核、48核的机器中的意义是一样的。
|
||||
|
||||
## 内存的含义
|
||||
|
||||
内存的限制和请求以字节为单位。您可以使用以下后缀之一作为平均整数或定点整数表示内存:E,P,T,G,M,K。您还可以使用两个字母的等效的幂数:Ei,Pi,Ti ,Gi,Mi,Ki。例如,以下代表大致相同的值:
|
||||
|
||||
```shell
|
||||
128974848, 129e6, 129M, 123Mi
|
||||
```
|
||||
|
||||
下面是个例子。
|
||||
|
||||
以下 Pod 有两个容器。每个容器的请求为 0.25 cpu 和 64MiB(2<sup>26</sup> 字节)内存,每个容器的限制为 0.5 cpu 和 128MiB 内存。您可以说该 Pod 请求 0.5 cpu 和 128 MiB 的内存,限制为 1 cpu 和 256MiB 的内存。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: db
|
||||
image: mysql
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
- name: wp
|
||||
image: wordpress
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
## 具有资源请求的 Pod 如何调度
|
||||
|
||||
当您创建一个 Pod 时,Kubernetes 调度程序将为 Pod 选择一个节点。每个节点具有每种资源类型的最大容量:可为 Pod 提供的 CPU 和内存量。调度程序确保对于每种资源类型,调度的容器的资源请求的总和小于节点的容量。请注意,尽管节点上的实际内存或 CPU 资源使用量非常低,但如果容量检查失败,则调度程序仍然拒绝在该节点上放置 Pod。当资源使用量稍后增加时,例如在请求率的每日峰值期间,这可以防止节点上的资源短缺。
|
||||
|
||||
## 具有资源限制的 Pod 如何运行
|
||||
|
||||
当 kubelet 启动一个 Pod 的容器时,它会将 CPU 和内存限制传递到容器运行时。
|
||||
|
||||
当使用 Docker 时:
|
||||
|
||||
- `spec.containers[].resources.requests.cpu` 的值将转换成 millicore 值,这是个浮点数,并乘以1024,这个数字中的较大者或2用作 `docker run` 命令中的[ `--cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint) 标志的值。
|
||||
- `spec.containers[].resources.limits.cpu` 被转换成 millicore 值。被乘以 100000 然后 除以 1000。这个数字用作 `docker run` 命令中的 [`--cpu-quota`](https://docs.docker.com/engine/reference/run/#/cpu-quota-constraint) 标志的值。[`--cpu-quota` ] 标志被设置成了 100000,表示测量配额使用的默认100ms 周期。如果 [`--cpu-cfs-quota`] 标志设置为 true,则 kubelet 会强制执行 cpu 限制。从 Kubernetes 1.2 版本起,此标志默认为 true。
|
||||
- `spec.containers[].resources.limits.memory` 被转换为整型,作为 `docker run` 命令中的 [`--memory`](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) 标志的值。
|
||||
|
||||
如果容器超过其内存限制,则可能会被终止。如果可重新启动,则与所有其他类型的运行时故障一样,kubelet 将重新启动它。
|
||||
|
||||
如果一个容器超过其内存请求,那么当节点内存不足时,它的 Pod 可能被逐出。
|
||||
|
||||
容器可能被允许也可能不被允许超过其 CPU 限制时间。但是,由于 CPU 使用率过高,不会被杀死。
|
||||
|
||||
要确定容器是否由于资源限制而无法安排或被杀死,请参阅 [疑难解答](#troubleshooting) 部分。
|
||||
|
||||
## 监控计算资源使用
|
||||
|
||||
Pod 的资源使用情况被报告为 Pod 状态的一部分。
|
||||
|
||||
如果为集群配置了 [可选监控](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/cluster-monitoring/README.md),则可以从监控系统检索 Pod 资源的使用情况。
|
||||
|
||||
## 疑难解答
|
||||
|
||||
### 我的 Pod 处于 pending 状态且事件信息显示 failedScheduling
|
||||
|
||||
如果调度器找不到任何该 Pod 可以匹配的节点,则该 Pod 将保持不可调度状态,直到找到一个可以被调度到的位置。每当调度器找不到 Pod 可以调度的地方时,会产生一个事件,如下所示:
|
||||
|
||||
```shell
|
||||
$ kubectl describe pod frontend | grep -A 3 Events
|
||||
Events:
|
||||
FirstSeen LastSeen Count From Subobject PathReason Message
|
||||
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
|
||||
```
|
||||
|
||||
在上述示例中,由于节点上的 CPU 资源不足,名为 “frontend” 的 Pod 将无法调度。由于内存不足(PodExceedsFreeMemory),类似的错误消息也可能会导致失败。一般来说,如果有这种类型的消息而处于 pending 状态,您可以尝试如下几件事情:
|
||||
|
||||
```shell
|
||||
$ kubectl describe nodes e2e-test-minion-group-4lw4
|
||||
Name: e2e-test-minion-group-4lw4
|
||||
[ ... lines removed for clarity ...]
|
||||
Capacity:
|
||||
alpha.kubernetes.io/nvidia-gpu: 0
|
||||
cpu: 2
|
||||
memory: 7679792Ki
|
||||
pods: 110
|
||||
Allocatable:
|
||||
alpha.kubernetes.io/nvidia-gpu: 0
|
||||
cpu: 1800m
|
||||
memory: 7474992Ki
|
||||
pods: 110
|
||||
[ ... lines removed for clarity ...]
|
||||
Non-terminated Pods: (5 in total)
|
||||
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
--------- ---- ------------ ---------- --------------- -------------
|
||||
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
|
||||
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
|
||||
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
|
||||
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
|
||||
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
|
||||
Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
CPU Requests CPU Limits Memory Requests Memory Limits
|
||||
------------ ---------- --------------- -------------
|
||||
680m (34%) 400m (20%) 920Mi (12%) 1070Mi (14%)
|
||||
```
|
||||
|
||||
在上面的输出中,您可以看到如果 Pod 请求超过 1120m CPU 或者 6.23Gi 内存,节点将无法满足。
|
||||
|
||||
通过查看 `Pods` 部分,您将看到哪些 Pod 占用的节点上的资源。
|
||||
|
||||
Pod 可用的资源量小于节点容量,因为系统守护程序使用一部分可用资源。 [NodeStatus](/docs/resources-reference/{{< param "version" >}}/#nodestatus-v1-core) 的 `allocatable` 字段给出了可用于 Pod 的资源量。有关更多信息,请参阅 [节点可分配资源](https://git.k8s.io/community/contributors/design-proposals/node-allocatable.md)。
|
||||
|
||||
可以将 [资源配额](/docs/concepts/policy/resource-quotas/) 功能配置为限制可以使用的资源总量。如果与 namespace 配合一起使用,就可以防止一个团队占用所有资源。
|
||||
|
||||
## 我的容器被终止了
|
||||
|
||||
您的容器可能因为资源枯竭而被终止了。要查看容器是否因为遇到资源限制而被杀死,请在相关的 Pod 上调用 `kubectl describe pod`:
|
||||
|
||||
```shell
|
||||
[12:54:41] $ kubectl describe pod simmemleak-hra99
|
||||
Name: simmemleak-hra99
|
||||
Namespace: default
|
||||
Image(s): saadali/simmemleak
|
||||
Node: kubernetes-node-tf0f/10.240.216.66
|
||||
Labels: name=simmemleak
|
||||
Status: Running
|
||||
Reason:
|
||||
Message:
|
||||
IP: 10.244.2.75
|
||||
Replication Controllers: simmemleak (1/1 replicas created)
|
||||
Containers:
|
||||
simmemleak:
|
||||
Image: saadali/simmemleak
|
||||
Limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
State: Running
|
||||
Started: Tue, 07 Jul 2015 12:54:41 -0700
|
||||
Last Termination State: Terminated
|
||||
Exit Code: 1
|
||||
Started: Fri, 07 Jul 2015 12:54:30 -0700
|
||||
Finished: Fri, 07 Jul 2015 12:54:33 -0700
|
||||
Ready: False
|
||||
Restart Count: 5
|
||||
Conditions:
|
||||
Type Status
|
||||
Ready False
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Reason Message
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {scheduler } scheduled Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD pulled Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD created Created with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD started Started with docker id 6a41280f516d
|
||||
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
|
||||
```
|
||||
|
||||
在上面的例子中,`Restart Count: 5` 意味着 Pod 中的 `simmemleak` 容器被终止并重启了五次。
|
||||
|
||||
您可以使用 `kubectl get pod` 命令加上 `-o go-template=...` 选项来获取之前终止容器的状态。
|
||||
|
||||
```shell
|
||||
[13:59:01] $ kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-60xbc
|
||||
Container Name: simmemleak
|
||||
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
|
||||
```
|
||||
|
||||
您可以看到容器因为 `reason:OOM killed` 被终止,`OOM` 表示 Out Of Memory。
|
||||
|
||||
## 不透明整型资源(Alpha功能)
|
||||
|
||||
Kubernetes 1.5 版本中引入不透明整型资源。不透明的整数资源允许集群运维人员发布新的节点级资源,否则系统将不了解这些资源。
|
||||
|
||||
用户可以在 Pod 的 spec 中消费这些资源,就像 CPU 和内存一样。调度器负责资源计量,以便在不超过可用量的同时分配给 Pod。
|
||||
|
||||
**注意:** 不透明整型资源在 kubernetes 1.5 中还是 Alpha 版本。只实现了资源计量,节点级别的隔离还处于积极的开发阶段。
|
||||
|
||||
不透明整型资源是以 `pod.alpha.kubernetes.io/opaque-int-resource-` 为前缀的资源。API server 将限制这些资源的数量为整数。*有效* 数量的例子有 `3`、`3000m` 和 `3Ki`。*无效*数量的例子有 `0.5` 和 `1500m`。
|
||||
|
||||
申请使用不透明整型资源需要两步。首先,集群运维人员必须在一个或多个节点上通告每个节点不透明的资源。然后,用户必须在 Pod 中请求不透明资源。
|
||||
|
||||
要发布新的不透明整型资源,集群运维人员应向 API server 提交 `PATCH` HTTP请求,以指定集群中节点的`status.capacity` 的可用数量。在此操作之后,节点的 `status.capacity` 将包括一个新的资源。 `status.allocatable` 字段由 kubelet 异步地使用新资源自动更新。请注意,由于调度器在评估 Pod 适应度时使用节点 `status.allocatable` 值,所以在使用新资源修补节点容量和请求在该节点上调度资源的第一个 pod 之间可能会有短暂的延迟。
|
||||
|
||||
**示例**
|
||||
|
||||
这是一个 HTTP 请求,master 节点是 k8s-master,在 k8s-node-1 节点上通告 5 个 “foo” 资源。
|
||||
|
||||
```http
|
||||
PATCH /api/v1/nodes/k8s-node-1/status HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json-patch+json
|
||||
Host: k8s-master:8080
|
||||
|
||||
```
|
||||
|
||||
```shell
|
||||
curl --header "Content-Type: application/json-patch+json" \
|
||||
--request PATCH \
|
||||
--data '[{"op": "add", "path": "/status/capacity/pod.alpha.kubernetes.io~1opaque-int-resource-foo", "value": "5"}]' \
|
||||
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
|
||||
```
|
||||
|
||||
**注意:** 在前面的请求中,`~1` 是 patch 路径中 `/` 字符的编码。JSON-Patch 中的操作路径值被解释为 JSON-Pointer。更多详细信息请参阅 [IETF RFC 6901, section 3](https://tools.ietf.org/html/rfc6901#section-3)。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: my-container
|
||||
image: myimage
|
||||
resources:
|
||||
requests:
|
||||
cpu: 2
|
||||
pod.alpha.kubernetes.io/opaque-int-resource-foo: 1
|
||||
```
|
||||
|
||||
## 计划改进
|
||||
|
||||
在 kubernetes 1.5 版本中仅允许在容器上指定资源量。计划改进对所有容器在 Pod 中共享资源的计量,如 [emptyDir volume](/docs/concepts/storage/volumes/#emptydir)。
|
||||
|
||||
在 kubernetes 1.5 版本中仅支持容器对 CPU 和内存的申请和限制。计划增加新的资源类型,包括节点磁盘空间资源和一个可支持自定义 [资源类型](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/design-proposals/resources.md) 的框架。
|
||||
|
||||
Kubernetes 通过支持通过多级别的 [服务质量](http://issue.k8s.io/168) 来支持资源的过度使用。
|
||||
|
||||
在 kubernetes 1.5 版本中,一个 CPU 单位在不同的云提供商和同一云提供商的不同机器类型中的意味都不同。例如,在 AWS 上,节点的容量报告为 [ECU](http://aws.amazon.com/ec2/faqs/),而在 GCE 中报告为逻辑内核。我们计划修改 cpu 资源的定义,以便在不同的提供商和平台之间保持一致。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
- 获取将 [CPU 和内存资源分配给容器](/docs/tasks/configure-pod-container/assign-cpu-ram-container/) 的实践经验
|
||||
- [容器](/docs/api-reference/{{< param "version" >}}/#container-v1-core)
|
||||
- [ResourceRequirements](/docs/resources-reference/{{< param "version" >}}/#resourcerequirements-v1-core)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
- [容器](/docs/api-reference/{{< param "version" >}}/#container-v1-core)
|
||||
- [ResourceRequirements](/docs/resources-reference/{{< param "version" >}}/#resourcerequirements-v1-core)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: with-node-affinity
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/e2e-az-name
|
||||
operator: In
|
||||
values:
|
||||
- e2e-az1
|
||||
- e2e-az2
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 1
|
||||
preference:
|
||||
matchExpressions:
|
||||
- key: another-node-label-key
|
||||
operator: In
|
||||
values:
|
||||
- another-node-label-value
|
||||
containers:
|
||||
- name: with-node-affinity
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,29 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: with-pod-affinity
|
||||
spec:
|
||||
affinity:
|
||||
podAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
- labelSelector:
|
||||
matchExpressions:
|
||||
- key: security
|
||||
operator: In
|
||||
values:
|
||||
- S1
|
||||
topologyKey: failure-domain.beta.kubernetes.io/zone
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: security
|
||||
operator: In
|
||||
values:
|
||||
- S2
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: with-pod-affinity
|
||||
image: k8s.gcr.io/pause:2.0
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
env: test
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
imagePullPolicy: IfNotPresent
|
||||
nodeSelector:
|
||||
disktype: ssd
|
||||
@@ -0,0 +1,586 @@
|
||||
---
|
||||
approvers:
|
||||
- mikedanese
|
||||
title: Secret
|
||||
---
|
||||
|
||||
`Secret` 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。将这些信息放在 `secret` 中比放在 `pod` 的定义或者 docker 镜像中来说更加安全和灵活。参阅 [Secret 设计文档](https://git.k8s.io/community/contributors/design-proposals/secrets.md) 获取更多详细信息。
|
||||
|
||||
{{< toc >}}
|
||||
## Secret 概览
|
||||
|
||||
Secret 是一种包含少量敏感信息例如密码、token 或 key 的对象。这样的信息可能会被放在 Pod spec 中或者镜像中;将其放在一个 secret 对象中可以更好地控制它的用途,并降低意外暴露的风险。
|
||||
|
||||
用户可以创建 secret,同时系统也创建了一些 secret。
|
||||
|
||||
要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:作为 [volume](/docs/concepts/storage/volumes/) 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。
|
||||
|
||||
### 内置 secret
|
||||
|
||||
#### Service Account 使用 API 凭证自动创建和附加 secret
|
||||
|
||||
Kubernetes 自动创建包含访问 API 凭据的 secret,并自动修改您的 pod 以使用此类型的 secret。
|
||||
|
||||
如果需要,可以禁用或覆盖自动创建和使用API凭据。但是,如果您需要的只是安全地访问 apiserver,我们推荐这样的工作流程。
|
||||
|
||||
参阅 [Service Account](/docs/user-guide/service-accounts) 文档获取关于 Service Account 如何工作的更多信息。
|
||||
|
||||
### 创建您自己的 Secret
|
||||
|
||||
#### 使用 kubectl 创建 Secret
|
||||
|
||||
假设有些 pod 需要访问数据库。这些 pod 需要使用的用户名和密码在您本地机器的 `./username.txt` 和 `./password.txt` 文件里。
|
||||
|
||||
```shell
|
||||
# Create files needed for rest of example.
|
||||
$ echo -n "admin" > ./username.txt
|
||||
$ echo -n "1f2d1e2e67df" > ./password.txt
|
||||
```
|
||||
|
||||
`kubectl create secret` 命令将这些文件打包到一个 Secret 中并在 API server 中创建了一个对象。
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
|
||||
secret "db-user-pass" created
|
||||
```
|
||||
|
||||
您可以这样检查刚创建的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA AGE
|
||||
db-user-pass Opaque 2 51s
|
||||
|
||||
$ kubectl describe secrets/db-user-pass
|
||||
Name: db-user-pass
|
||||
Namespace: default
|
||||
Labels: <none>
|
||||
Annotations: <none>
|
||||
|
||||
Type: Opaque
|
||||
|
||||
Data
|
||||
====
|
||||
password.txt: 12 bytes
|
||||
username.txt: 5 bytes
|
||||
```
|
||||
|
||||
请注意,默认情况下,`get` 和 `describe` 命令都不会显示文件的内容。这是为了防止将 secret 中的内容被意外暴露给从终端日志记录中刻意寻找它们的人。
|
||||
|
||||
请参阅 [解码 secret](#decoding-a-secret) 了解如何查看它们的内容。
|
||||
|
||||
#### 手动创建 Secret
|
||||
|
||||
您也可以先以 json 或 yaml 格式在文件中创建一个 secret 对象,然后创建该对象。
|
||||
|
||||
每一项必须是 base64 编码:
|
||||
|
||||
```shell
|
||||
$ echo -n "admin" | base64
|
||||
YWRtaW4=
|
||||
$ echo -n "1f2d1e2e67df" | base64
|
||||
MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
现在可以像这样写一个 secret 对象:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: mysecret
|
||||
type: Opaque
|
||||
data:
|
||||
username: YWRtaW4=
|
||||
password: MWYyZDFlMmU2N2Rm
|
||||
```
|
||||
|
||||
数据字段是一个映射。它的键必须匹配 [`DNS_SUBDOMAIN`](https://git.k8s.io/community/contributors/design-proposals/identifiers.md),前导点也是可以的。这些值可以是任意数据,使用 base64 进行编码。
|
||||
|
||||
使用 [`kubectl create`](/docs/user-guide/kubectl/v1.7/#create) 创建 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./secret.yaml
|
||||
secret "mysecret" created
|
||||
```
|
||||
|
||||
**编码注意:** secret 数据的序列化 JSON 和 YAML 值使用 base64 编码成字符串。换行符在这些字符串中无效,必须省略。当在 Darwin/OS X 上使用 `base64` 实用程序时,用户应避免使用 `-b` 选项来拆分长行。另外,对于 Linux 用户如果 `-w` 选项不可用的话,应该添加选项 `-w 0` 到 `base64` 命令或管道 `base64 | tr -d '\n' ` 。
|
||||
|
||||
#### 解码 Secret
|
||||
|
||||
可以使用 `kubectl get secret` 命令获取 secret。例如,获取在上一节中创建的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl get secret mysecret -o yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
username: YWRtaW4=
|
||||
password: MWYyZDFlMmU2N2Rm
|
||||
kind: Secret
|
||||
metadata:
|
||||
creationTimestamp: 2016-01-22T18:41:56Z
|
||||
name: mysecret
|
||||
namespace: default
|
||||
resourceVersion: "164619"
|
||||
selfLink: /api/v1/namespaces/default/secrets/mysecret
|
||||
uid: cfee02d6-c137-11e5-8d73-42010af00002
|
||||
type: Opaque
|
||||
```
|
||||
|
||||
解码密码字段:
|
||||
|
||||
```shell
|
||||
$ echo "MWYyZDFlMmU2N2Rm" | base64 --decode
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
### 使用 Secret
|
||||
|
||||
Secret 可以作为数据卷被挂载,或作为环境变量暴露出来以供 pod 中的容器使用。它们也可以被系统的其他部分使用,而不直接暴露在 pod 内。例如,它们可以保存凭据,系统的其他部分应该用它来代表您与外部系统进行交互。
|
||||
|
||||
#### 在 Pod 中使用 Secret 文件
|
||||
|
||||
在 Pod 中的 volume 里使用 Secret:
|
||||
|
||||
1. 创建一个 secret 或者使用已有的 secret。多个 pod 可以引用同一个 secret。
|
||||
2. 修改您的 pod 的定义在 `spec.volumes[]` 下增加一个 volume。可以给这个 volume 随意命名,它的 `spec.volumes[].secret.secretName` 必须等于 secret 对象的名字。
|
||||
3. 将 `spec.containers[].volumeMounts[]` 加到需要用到该 secret 的容器中。指定 `spec.containers[].volumeMounts[].readOnly = true` 和 `spec.containers[].volumeMounts[].mountPath` 为您想要该 secret 出现的尚未使用的目录。
|
||||
4. 修改您的镜像并且/或者命令行让程序从该目录下寻找文件。Secret 的 `data` 映射中的每一个键都成为了 `mountPath` 下的一个文件名。
|
||||
|
||||
这是一个在 pod 中使用 volume 挂在 secret 的例子:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
```
|
||||
|
||||
您想要用的每个 secret 都需要在 `spec.volumes` 中指明。
|
||||
|
||||
如果 pod 中有多个容器,每个容器都需要自己的 `volumeMounts` 配置块,但是每个 secret 只需要一个 `spec.volumes`。
|
||||
|
||||
您可以打包多个文件到一个 secret 中,或者使用的多个 secret,怎样方便就怎样来。
|
||||
|
||||
**向特性路径映射 secret 密钥**
|
||||
|
||||
我们还可以控制 Secret key 映射在 volume 中的路径。您可以使用 `spec.volumes[].secret.items` 字段修改每个 key 的目标路径:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
items:
|
||||
- key: username
|
||||
path: my-group/my-username
|
||||
```
|
||||
|
||||
将会发生什么呢:
|
||||
|
||||
- `username` secret 存储在 `/etc/foo/my-group/my-username` 文件中而不是 `/etc/foo/username` 中。
|
||||
- `password` secret 没有被映射
|
||||
|
||||
如果使用了 `spec.volumes[].secret.items`,只有在 `items` 中指定的 key 被映射。要使用 secret 中所有的 key,所有这些都必须列在 `items` 字段中。所有列出的密钥必须存在于相应的 secret 中。否则,不会创建卷。
|
||||
|
||||
**Secret 文件权限**
|
||||
|
||||
您还可以指定 secret 将拥有的权限模式位文件。如果不指定,默认使用 `0644`。您可以为整个保密卷指定默认模式,如果需要,可以覆盖每个密钥。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
defaultMode: 256
|
||||
```
|
||||
|
||||
然后,secret 将被挂载到 `/etc/foo` 目录,所有通过该 secret volume 挂载创建的文件的权限都是 `0400`。
|
||||
|
||||
请注意,JSON 规范不支持八进制符号,因此使用 256 值作为 0400 权限。如果您使用 yaml 而不是 json 作为 pod,则可以使用八进制符号以更自然的方式指定权限。
|
||||
|
||||
您还可以使用映射,如上一个示例,并为不同的文件指定不同的权限,如下所示:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: mypod
|
||||
spec:
|
||||
containers:
|
||||
- name: mypod
|
||||
image: redis
|
||||
volumeMounts:
|
||||
- name: foo
|
||||
mountPath: "/etc/foo"
|
||||
volumes:
|
||||
- name: foo
|
||||
secret:
|
||||
secretName: mysecret
|
||||
items:
|
||||
- key: username
|
||||
path: my-group/my-username
|
||||
mode: 511
|
||||
```
|
||||
|
||||
在这种情况下,导致 `/etc/foo/my-group/my-username` 的文件的权限值为 `0777`。由于 JSON 限制,必须以十进制格式指定模式。
|
||||
|
||||
请注意,如果稍后阅读此权限值可能会以十进制格式显示。
|
||||
|
||||
**从 Volume 中消费 secret 值**
|
||||
|
||||
在挂载的 secret volume 的容器内,secret key 将作为文件,并且 secret 的值使用 base-64 解码并存储在这些文件中。这是在上面的示例容器内执行的命令的结果:
|
||||
|
||||
```shell
|
||||
$ ls /etc/foo/
|
||||
username
|
||||
password
|
||||
$ cat /etc/foo/username
|
||||
admin
|
||||
$ cat /etc/foo/password
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
容器中的程序负责从文件中读取 secret。
|
||||
|
||||
**挂载的 secret 被自动更新**
|
||||
|
||||
当已经在 volume 中被消费的 secret 被更新时,被映射的 key 也将被更新。
|
||||
|
||||
Kubelet 在周期性同步时检查被挂载的 secret 是不是最新的。但是,它正在使用其基于本地 ttl 的缓存来获取当前的 secret 值。结果是,当 secret 被更新的时刻到将新的 secret 映射到 pod 的时刻的总延迟可以与 kubelet 中的secret 缓存的 kubelet sync period + ttl 一样长。
|
||||
|
||||
#### Secret 作为环境变量
|
||||
|
||||
将 secret 作为 pod 中的环境变量使用:
|
||||
|
||||
1. 创建一个 secret 或者使用一个已存在的 secret。多个 pod 可以引用同一个 secret。
|
||||
2. 修改 Pod 定义,为每个要使用 secret 的容器添加对应 secret key 的环境变量。消费secret key 的环境变量应填充 secret 的名称,并键入 `env[x].valueFrom.secretKeyRef`。
|
||||
3. 修改镜像并/或者命令行,以便程序在指定的环境变量中查找值。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: secret-env-pod
|
||||
spec:
|
||||
containers:
|
||||
- name: mycontainer
|
||||
image: redis
|
||||
env:
|
||||
- name: SECRET_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysecret
|
||||
key: username
|
||||
- name: SECRET_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: mysecret
|
||||
key: password
|
||||
restartPolicy: Never
|
||||
```
|
||||
|
||||
**消费环境变量里的 Secret 值**
|
||||
|
||||
在一个消耗环境变量 secret 的容器中,secret key 作为包含 secret 数据的 base-64 解码值的常规环境变量。这是从上面的示例在容器内执行的命令的结果:
|
||||
|
||||
```shell
|
||||
$ echo $SECRET_USERNAME
|
||||
admin
|
||||
$ echo $SECRET_PASSWORD
|
||||
1f2d1e2e67df
|
||||
```
|
||||
|
||||
#### 使用 imagePullSecret
|
||||
|
||||
imagePullSecret 是将包含 Docker(或其他)镜像注册表密码的 secret 传递给 Kubelet 的一种方式,因此可以代表您的 pod 拉取私有镜像。
|
||||
|
||||
**手动指定 imagePullSecret**
|
||||
|
||||
imagePullSecret 的使用在 [镜像文档](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) 中说明。
|
||||
|
||||
### 安排 imagePullSecrets 自动附加
|
||||
|
||||
您可以手动创建 imagePullSecret,并从 serviceAccount 引用它。使用该 serviceAccount 创建的任何 pod 和默认使用该 serviceAccount 的 pod 将会将其的 imagePullSecret 字段设置为服务帐户的 imagePullSecret 字段。有关该过程的详细说明,请参阅 [将 ImagePullSecrets 添加到服务帐户](/docs/tasks/configure-pod-container/configure-service-account/#adding-imagepullsecrets-to-a-service-account)。
|
||||
|
||||
#### 自动挂载手动创建的 Secret
|
||||
|
||||
手动创建的 secret(例如包含用于访问 github 帐户的令牌)可以根据其服务帐户自动附加到 pod。请参阅 [使用 PodPreset 向 Pod 中注入信息](/docs/tasks/run-application/podpreset/) 以获取该进程的详细说明。
|
||||
|
||||
## 详细
|
||||
|
||||
### 限制
|
||||
|
||||
验证 secret volume 来源确保指定的对象引用实际上指向一个类型为 Secret 的对象。因此,需要在依赖于它的任何 pod 之前创建一个 secret。
|
||||
|
||||
Secret API 对象驻留在命名空间中。它们只能由同一命名空间中的 pod 引用。
|
||||
|
||||
每个 secret 的大小限制为1MB。这是为了防止创建非常大的 secret 会耗尽 apiserver 和 kubelet 的内存。然而,创建许多较小的 secret 也可能耗尽内存。更全面得限制 secret 对内存使用的功能还在计划中。
|
||||
|
||||
Kubelet 仅支持从 API server 获取的 Pod 使用 secret。这包括使用 kubectl 创建的任何 pod,或间接通过 replication controller 创建的 pod。它不包括通过 kubelet `--manifest-url` 标志,其 `--config` 标志或其 REST API 创建的pod(这些不是创建 pod 的常用方法)。
|
||||
|
||||
必须先创建 secret,除非将它们标记为可选项,否则必须在将其作为环境变量在 pod 中使用之前创建 secret。对不存在的 secret 的引用将阻止其启动。
|
||||
|
||||
使用 `secretKeyRef` ,引用指定的 secret 中的不存在的 key ,这会阻止 pod 的启动。
|
||||
|
||||
对于通过 `envFrom` 填充环境变量的 secret,这些环境变量具有被认为是无效环境变量名称的 key 将跳过这些键。该 pod 将被允许启动。将会有一个事件,其原因是 `InvalidVariableNames`,该消息将包含被跳过的无效键的列表。该示例显示一个 pod,它指的是包含2个无效键,1badkey 和 2alsobad 的默认/mysecret ConfigMap。
|
||||
|
||||
```shell
|
||||
$ kubectl get events
|
||||
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON
|
||||
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names.
|
||||
```
|
||||
|
||||
### Secret 与 Pod 生命周期的联系
|
||||
|
||||
通过 API 创建 Pod 时,不会检查应用的 secret 是否存在。一旦 Pod 被调度,kubelet 就会尝试获取该 secret 的值。如果获取不到该 secret,或者暂时无法与 API server 建立连接,kubelet 将会定期重试。Kubelet 将会报告关于 pod 的事件,并解释它无法启动的原因。一旦获取到 secret,kubelet将创建并装载一个包含它的卷。在所有 pod 的卷被挂载之前,都不会启动 pod 的容器。
|
||||
|
||||
## 使用案例
|
||||
|
||||
### 使用案例:包含 ssh 密钥的 pod
|
||||
|
||||
创建一个包含 ssh key 的 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
|
||||
```
|
||||
|
||||
**安全性注意事项**:发送自己的 ssh 密钥之前要仔细思考:集群的其他用户可能有权访问该密钥。使用您想要共享 Kubernetes 群集的所有用户可以访问的服务帐户,如果它们遭到入侵,可以撤销。
|
||||
|
||||
现在我们可以创建一个使用 ssh 密钥引用 secret 的pod,并在一个卷中使用它:
|
||||
|
||||
```yaml
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: secret-test-pod
|
||||
labels:
|
||||
name: secret-test
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: ssh-key-secret
|
||||
containers:
|
||||
- name: ssh-test-container
|
||||
image: mySshImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
当容器中的命令运行时,密钥的片段将可在以下目录:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/ssh-publickey
|
||||
/etc/secret-volume/ssh-privatekey
|
||||
```
|
||||
|
||||
然后容器可以自由使用密钥数据建立一个 ssh 连接。
|
||||
|
||||
### 使用案例:包含 prod/test 凭据的 pod
|
||||
|
||||
下面的例子说明一个 pod 消费一个包含 prod 凭据的 secret,另一个 pod 使用测试环境凭据消费 secret。
|
||||
|
||||
创建 secret:
|
||||
|
||||
```shell
|
||||
$ kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
|
||||
secret "prod-db-secret" created
|
||||
$ kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
|
||||
secret "test-db-secret" created
|
||||
```
|
||||
|
||||
创建 pod :
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: List
|
||||
items:
|
||||
- kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: prod-db-client-pod
|
||||
labels:
|
||||
name: prod-db-client
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: prod-db-secret
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
- kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: test-db-client-pod
|
||||
labels:
|
||||
name: test-db-client
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: test-db-secret
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
这两个容器将在其文件系统上显示以下文件,其中包含每个容器环境的值:
|
||||
|
||||
```shell
|
||||
/etc/secret-volume/username
|
||||
/etc/secret-volume/password
|
||||
```
|
||||
|
||||
请注意,两个 pod 的 spec 配置中仅有一个字段有所不同;这有助于使用普通的 pod 配置模板创建具有不同功能的 pod。您可以使用两个 service account 进一步简化基本 pod spec:一个名为 `prod-user` 拥有 `prod-db-secret` ,另一个称为 `test-user` 拥有 `test-db-secret` 。然后,pod spec 可以缩短为,例如:
|
||||
|
||||
```yaml
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: prod-db-client-pod
|
||||
labels:
|
||||
name: prod-db-client
|
||||
spec:
|
||||
serviceAccount: prod-db-client
|
||||
containers:
|
||||
- name: db-client-container
|
||||
image: myClientImage
|
||||
```
|
||||
|
||||
### 使用案例:Secret 卷中以点号开头的文件
|
||||
|
||||
为了将数据“隐藏”起来(即文件名以点号开头的文件),简单地说让该键以一个点开始。例如,当如下 secret 被挂载到卷中:
|
||||
|
||||
```yaml
|
||||
kind: Secret
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: dotfile-secret
|
||||
data:
|
||||
.secret-file: dmFsdWUtMg0KDQo=
|
||||
---
|
||||
kind: Pod
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: secret-dotfiles-pod
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: dotfile-secret
|
||||
containers:
|
||||
- name: dotfile-test-container
|
||||
image: k8s.gcr.io/busybox
|
||||
command:
|
||||
- ls
|
||||
- "-l"
|
||||
- "/etc/secret-volume"
|
||||
volumeMounts:
|
||||
- name: secret-volume
|
||||
readOnly: true
|
||||
mountPath: "/etc/secret-volume"
|
||||
```
|
||||
|
||||
`Secret-volume` 将包含一个单独的文件,叫做 `.secret-file`,`dotfile-test-container` 的 `/etc/secret-volume/.secret-file` 路径下将有该文件。
|
||||
|
||||
**注意**
|
||||
|
||||
以点号开头的文件在 `ls -l` 的输出中被隐藏起来了;列出目录内容时,必须使用 `ls -la` 才能查看它们。
|
||||
|
||||
### 使用案例:Secret 仅对 pod 中的一个容器可见
|
||||
|
||||
考虑以下一个需要处理 HTTP 请求的程序,执行一些复杂的业务逻辑,然后使用 HMAC 签署一些消息。因为它具有复杂的应用程序逻辑,所以在服务器中可能会出现一个未被注意的远程文件读取漏洞,这可能会将私钥暴露给攻击者。
|
||||
|
||||
这可以在两个容器中分为两个进程:前端容器,用于处理用户交互和业务逻辑,但无法看到私钥;以及可以看到私钥的签名者容器,并且响应来自前端的简单签名请求(例如通过本地主机网络)。
|
||||
|
||||
使用这种分割方法,攻击者现在必须欺骗应用程序服务器才能进行任意的操作,这可能比使其读取文件更难。
|
||||
|
||||
<!-- TODO: explain how to do this while still using automation. -->
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 客户端使用 Secret API
|
||||
|
||||
当部署与 secret API 交互的应用程序时,应使用诸如 [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/) 之类的 [授权策略](https://kubernetes.io/docs/admin/authorization/) 来限制访问。
|
||||
|
||||
Secret 中的值对于不同的环境来说重要性可能不同,例如对于 Kubernetes 集群内部(例如 service account 令牌)和集群外部来说就不一样。即使一个应用程序可以理解其期望的与之交互的 secret 有多大的能力,但是同一命名空间中的其他应用程序却可能不这样认为。
|
||||
|
||||
由于这些原因,在命名空间中 `watch` 和 `list` secret 的请求是非常强大的功能,应该避免这样的行为,因为列出 secret 可以让客户端检查所有 secret 是否在该命名空间中。在群集中`watch` 和 `list` 所有 secret 的能力应该只保留给最有特权的系统级组件。
|
||||
|
||||
需要访问 secrets API 的应用程序应该根据他们需要的 secret 执行 `get` 请求。这允许管理员限制对所有 secret 的访问,同时设置 [白名单访问](https://kubernetes.io/docs/admin/authorization/rbac/#referring-to-resources) 应用程序需要的各个实例。
|
||||
|
||||
为了提高循环获取的性能,客户端可以设计引用 secret 的资源,然后 `watch` 资源,在引用更改时重新请求 secret。此外,还提出了一种 [”批量监控“ API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/bulk_watch.md) 来让客户端 `watch` 每个资源,该功能可能会在将来的 Kubernetes 版本中提供。
|
||||
|
||||
## 安全属性
|
||||
|
||||
### 保护
|
||||
|
||||
因为 `secret` 对象可以独立于使用它们的 `pod` 而创建,所以在创建、查看和编辑 pod 的流程中 secret 被暴露的风险较小。系统还可以对 `secret` 对象采取额外的预防措施,例如避免将其写入到磁盘中可能的位置。
|
||||
|
||||
只有当节点上的 pod 需要用到该 secret 时,该 secret 才会被发送到该节点上。它不会被写入磁盘,而是存储在 tmpfs 中。一旦依赖于它的 pod 被删除,它就被删除。
|
||||
|
||||
在大多数 Kubernetes 项目维护的发行版中,用户与 API server 之间的通信以及从 API server 到 kubelet 的通信都受到 SSL/TLS 的保护。通过这些通道传输时,secret 受到保护。
|
||||
|
||||
节点上的 secret 数据存储在 tmpfs 卷中,因此不会传到节点上的其他磁盘。
|
||||
|
||||
同一节点上的很多个 pod 可能拥有多个 secret。但是,只有 pod 请求的 secret 在其容器中才是可见的。因此,一个 pod 不能访问另一个 Pod 的 secret。
|
||||
|
||||
Pod 中有多个容器。但是,pod 中的每个容器必须请求其挂载卷中的 secret 卷才能在容器内可见。这可以用于 [在 Pod 级别构建安全分区](#使用案例secret-仅对-pod-中的一个容器可见)。
|
||||
|
||||
### 风险
|
||||
|
||||
- API server 的 secret 数据以纯文本的方式存储在 etcd 中,因此:
|
||||
- 管理员应该限制 admin 用户访问 etcd;
|
||||
- API server 中的 secret 数据位于 etcd 使用的磁盘上;管理员可能希望在不再使用时擦除/粉碎 etcd 使用的磁盘
|
||||
- 如果您将 secret 数据编码为 base64 的清单(JSON 或 YAML)文件,共享该文件或将其检入代码库,这样的话该密码将会被泄露。 Base64 编码不是一种加密方式,一样也是纯文本。
|
||||
- 应用程序在从卷中读取 secret 后仍然需要保护 secret 的值,例如不会意外记录或发送给不信任方。
|
||||
- 可以创建和使用 secret 的 pod 的用户也可以看到该 secret 的值。即使 API server 策略不允许用户读取 secret 对象,用户也可以运行暴露 secret 的 pod。
|
||||
- 如果运行了多个副本,那么这些 secret 将在它们之间共享。默认情况下,etcd 不能保证与 SSL/TLS 的对等通信,尽管可以进行配置。
|
||||
- 目前,任何节点的 root 用户都可以通过模拟 kubelet 来读取 API server 中的任何 secret。只有向实际需要它们的节点发送 secret 才能限制单个节点的根漏洞的影响,该功能还在计划中。
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
approvers:
|
||||
- mikedanese
|
||||
- thockin
|
||||
title: 容器环境变量
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本文介绍容器环境中对容器可用的资源。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 容器环境
|
||||
|
||||
Kubernetes 容器环境为容器提供了几类重要的资源:
|
||||
|
||||
* 一个文件系统,其中包含一个[镜像](/docs/concepts/containers/images/)和一个或多个[卷](/docs/concepts/storage/volumes/)。
|
||||
* 容器本身相关的信息。
|
||||
* 集群中其他对象相关的信息。
|
||||
|
||||
### 容器信息
|
||||
|
||||
容器的 *hostname* 是容器所在的 Pod 名称。 可以通过 `hostname` 命令或调用 libc 中的
|
||||
[`gethostname`](http://man7.org/linux/man-pages/man2/gethostname.2.html)
|
||||
函数来获取。
|
||||
|
||||
Pod 名称和名字空间可以通过
|
||||
[downward API](/docs/tasks/inject-data-application/downward-api-volume-expose-pod-information/) 以环境变量方式访问。
|
||||
|
||||
与 Docker 镜像中静态指定的环境变量一样,Pod 中用户定义的环境变量也可用于容器。
|
||||
|
||||
### 集群信息
|
||||
|
||||
容器创建时运行的所有服务的列表都会作为环境变量提供给容器。
|
||||
这些环境变量与 Docker 链接语法相匹配。
|
||||
|
||||
对一个名为 *foo*,映射到名为 *bar* 的容器端口的服务,
|
||||
会定义如下变量:
|
||||
|
||||
```shell
|
||||
FOO_SERVICE_HOST=<服务所在的主机地址>
|
||||
FOO_SERVICE_PORT=<服务所启用的端口>
|
||||
```
|
||||
|
||||
服务具有专用 IP 地址,如果启用了 [DNS 插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/),还可以在容器中通过 DNS 进行访问。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 查看[容器生命周期挂钩(hooks)](/docs/concepts/containers/container-lifecycle-hooks/)了解更多。
|
||||
* 获取[为容器生命周期事件附加处理程序](/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/)的实践经验。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
- thockin
|
||||
title: 镜像
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
在Kubernetes pod中引用镜像前,请创建Docker镜像,并将之推送到镜像仓库中。
|
||||
容器的“image”属性支持和Docker命令行相同的语法,包括私有仓库和标签。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 升级镜像
|
||||
默认的镜像拉取策略是“IfNotPresent”,在镜像已经存在的情况下,kubelet将不在去拉取镜像。
|
||||
如果总是想要拉取镜像,必须设置拉取策略为“Always”或者设置镜像标签为“:latest”。
|
||||
|
||||
如果没有指定镜像的标签,它会被假定为“:latest”,同时拉取策略为“Always”。
|
||||
|
||||
注意应避免使用“:latest”标签,参见 [Best Practices for Configuration](/docs/concepts/configuration/overview/#container-images) 获取更多信息。
|
||||
|
||||
## 使用私有仓库
|
||||
|
||||
从私有仓库读取镜像时可能需要密钥。
|
||||
凭证可以用以下方式提供:
|
||||
|
||||
- 使用Google Container Registry
|
||||
- 每个集群分别配置
|
||||
- 在Google Compute Engine 或者 Google Kubernetes Engine上自动配置
|
||||
- 所有的pod都能读取项目的私有仓库
|
||||
- 使用 AWS EC2 Container Registry (ECR)
|
||||
- 使用IAM角色和策略来控制对ECR仓库的访问
|
||||
- 自动刷新ECR的登录凭证
|
||||
- 使用 Azure Container Registry (ACR)
|
||||
- 配置节点对私有仓库认证
|
||||
- 所有的pod都可以读取已配置的私有仓库
|
||||
- 需要集群管理员提供node的配置
|
||||
- 提前拉取镜像
|
||||
- 所有的pod都可以使用node上缓存的镜像
|
||||
- 需要以root进入node操作
|
||||
- pod上指定 ImagePullSecrets
|
||||
- 只有提供了密钥的pod才能接入私有仓库
|
||||
下面将详细描述每一项
|
||||
|
||||
|
||||
### 使用 Google Container Registry
|
||||
Kuberetes运行在Google Compute Engine (GCE)时原生支持[Google ContainerRegistry (GCR)]
|
||||
(https://cloud.google.com/tools/container-registry/)。如果kubernetes集群运行在GCE
|
||||
或者Google Kubernetes Engine 上,使用镜像全名(e.g. gcr.io/my_project/image:tag)即可。
|
||||
|
||||
集群中的所有pod都会有读取这个仓库中镜像的权限。
|
||||
|
||||
Kubelet将使用实例的Google service account向GCR认证。实例的service account拥有
|
||||
`https://www.googleapis.com/auth/devstorage.read_only`,所以它可以从项目的GCR拉取,但不能推送。
|
||||
|
||||
### 使用 AWS EC2 Container Registry
|
||||
|
||||
当Node是AWS EC2实例时,Kubernetes原生支持[AWS EC2 ContainerRegistry](https://aws.amazon.com/ecr/)。
|
||||
|
||||
在pod定义中,使用镜像全名即可 (例如 `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`)
|
||||
|
||||
集群中可以创建pod的用户都可以使用ECR中的任意镜像运行pod。
|
||||
|
||||
Kubelet会获取并且定期刷新ECR的凭证。它需要以下权限
|
||||
|
||||
- `ecr:GetAuthorizationToken`
|
||||
- `ecr:BatchCheckLayerAvailability`
|
||||
- `ecr:GetDownloadUrlForLayer`
|
||||
- `ecr:GetRepositoryPolicy`
|
||||
- `ecr:DescribeRepositories`
|
||||
- `ecr:ListImages`
|
||||
- `ecr:BatchGetImage`
|
||||
|
||||
要求:
|
||||
|
||||
- 必须使用kubelet 1.2.0及以上版本
|
||||
- 如果node在区域A,而镜像仓库在另一个区域B,需要1.3.0及以上版本
|
||||
- 区域中必须提供ECR
|
||||
|
||||
诊断
|
||||
|
||||
- 验证是否满足以上要求
|
||||
- 获取工作站的$REGION (例如 `us-west-2`)凭证,使用凭证SSH到主机手动运行docker,检查是否运行
|
||||
- 验证kublet是否使用参数`--cloud-provider=aws`运行
|
||||
- 检查kubelet日志(例如 `journalctl -u kubelet`),是否有类似的行
|
||||
- `plugins.go:56] Registering credential provider: aws-ecr-key`
|
||||
- `provider.go:91] Refreshing cache for provider: *aws_credentials.ecrProvider`
|
||||
|
||||
### 使用 Azure Container Registry (ACR)
|
||||
当使用[Azure Container Registry](https://azure.microsoft.com/en-us/services/container-registry/)时,可以使用admin user或者service principal认证。
|
||||
任何一种情况,认证都通过标准的Dokcer authentication完成。本指南假设使用[azure-cli](https://github.com/azure/azure-cli)
|
||||
命令行工具。
|
||||
|
||||
首先,需要创建仓库并获取凭证,完整的文档请参考
|
||||
[Azure container registry documentation](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-azure-cli)。
|
||||
|
||||
创建好容器仓库后,可以使用以下凭证登录:
|
||||
|
||||
* `DOCKER_USER` : service principal, or admin username
|
||||
* `DOCKER_PASSWORD`: service principal password, or admin user password
|
||||
* `DOCKER_REGISTRY_SERVER`: `${some-registry-name}.azurecr.io`
|
||||
* `DOCKER_EMAIL`: `${some-email-address}`
|
||||
|
||||
填写以上变量后,就可以
|
||||
[configure a Kubernetes Secret and use it to deploy a Pod](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod)。
|
||||
|
||||
|
||||
### 配置Nodes对私有仓库认证
|
||||
|
||||
**注意:** 如果在Google Kubernetes Engine 上运行集群,每个节点上都会有`.dockercfg`文件,它包含对Google Container Registry的凭证。
|
||||
不需要使用以下方法。
|
||||
|
||||
**注意:** 如果在AWS EC2上运行集群且准备使用EC2 Container Registry (ECR),每个node上的kubelet会管理和更新ECR的登录凭证。不需要使用以下方法。
|
||||
|
||||
**注意:** 该方法适用于能够对节点进行配置的情况。该方法在GCE及在其它能自动配置节点的云平台上并不适合。
|
||||
|
||||
Docker将私有仓库的密钥存放在`$HOME/.dockercfg`或`$HOME/.docker/config.json`文件中。Kubelet上,docker会使用root用户`$HOME`路径下的密钥。
|
||||
|
||||
推荐如下步骤来为node配置私有仓库。以下示例在PC或笔记本电脑中操作
|
||||
|
||||
1.对于想要使用的每一种凭证,运行 `docker login [server]`,它会更新`$HOME/.docker/config.json`。
|
||||
1.使用编辑器查看`$HOME/.docker/config.json`,保证文件中包含了想要使用的凭证
|
||||
1.获取node列表,例如
|
||||
- 如果使用node名称,`nodes=$(kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}')`
|
||||
- 如果使用node IP ,`nodes=$(kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}')`
|
||||
1.将本地的`.docker/config.json`拷贝到每个节点root用户目录下
|
||||
- 例如: `for n in $nodes; do scp ~/.docker/config.json root@$n:/root/.docker/config.json; done`
|
||||
|
||||
创建使用私有仓库的pod来验证,例如:
|
||||
|
||||
```yaml
|
||||
$ cat <<EOF > /tmp/private-image-test-1.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: private-image-test-1
|
||||
spec:
|
||||
containers:
|
||||
- name: uses-private-image
|
||||
image: $PRIVATE_IMAGE_NAME
|
||||
imagePullPolicy: Always
|
||||
command: [ "echo", "SUCCESS" ]
|
||||
EOF
|
||||
$ kubectl create -f /tmp/private-image-test-1.yaml
|
||||
pod "private-image-test-1" created
|
||||
$
|
||||
```
|
||||
|
||||
如果一切正常,一段时间后,可以看到:
|
||||
|
||||
```shell
|
||||
$ kubectl logs private-image-test-1
|
||||
SUCCESS
|
||||
```
|
||||
|
||||
如果失败,则可以看到:
|
||||
|
||||
```shell
|
||||
$ kubectl describe pods/private-image-test-1 | grep "Failed"
|
||||
Fri, 26 Jun 2015 15:36:13 -0700 Fri, 26 Jun 2015 15:39:13 -0700 19 {kubelet node-i2hq} spec.containers{uses-private-image} failed Failed to pull image "user/privaterepo:v1": Error: image user/privaterepo:v1 not found
|
||||
```
|
||||
|
||||
|
||||
必须保证集群中所有的节点都有相同的`.docker/config.json`文件。否则,pod会在一些节点上正常运行而在另一些节点上无法启动
|
||||
例如,如果使用node自动弹缩,那么每个实例模板都需要包含`.docker/config.json`,或者挂载一个包含这个文件的驱动器。
|
||||
|
||||
在`.docker/config.json`中配置了私有仓库密钥后,所有pod都会能读取私有仓库中的镜像。
|
||||
|
||||
**该方法已在6月26日的docker私有仓库和kubernetes v0.19.3上测试通过,其他私有仓库,如quay.io应该也可以运行,但未测试过。**
|
||||
|
||||
### 提前拉取镜像
|
||||
|
||||
**注意:** 如果在Google Kubernetes Engine 上运行集群,每个节点上都会有`.dockercfg`文件,它包含对Google Container Registry的凭证。
|
||||
不需要使用以下方法。
|
||||
|
||||
**注意:** 该方法适用于能够对节点进行配置的情况。该方法在GCE及在其它能自动配置节点的云平台上并不适合。
|
||||
|
||||
默认情况下,kubelet会尝试从指定的仓库拉取每一个镜像
|
||||
但是,如果容器属性`imagePullPolicy`设置为`IfNotPresent`或者`Never`,
|
||||
则会使用本地镜像(优先、唯一、分别)。
|
||||
|
||||
如果依赖提前拉取镜像代替仓库认证,
|
||||
必须保证集群所有的节点提前拉取的镜像是相同的。
|
||||
|
||||
可以用于提前载入指定的镜像以提高速度,或者作为私有仓库认证的一种替代方案
|
||||
|
||||
所有的pod都可以使用node上缓存的镜像
|
||||
|
||||
### 在pod上指定ImagePullSecrets
|
||||
|
||||
**注意:** Google Kubernetes Engine,GCE及其他自动创建node的云平台上,推荐使用本方法。
|
||||
|
||||
Kubernetes支持在pod中指定仓库密钥。
|
||||
|
||||
#### 使用Docker Config创建Secret
|
||||
|
||||
运行以下命令,将大写字母代替为合适的值
|
||||
|
||||
```shell
|
||||
$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
|
||||
secret "myregistrykey" created.
|
||||
```
|
||||
|
||||
如果需要接入多个仓库,可以为每个仓库创建一个secret。
|
||||
当为pod拉取镜像时,kubelet会将`imagePullSecrets`合入一个独立虚拟的`.docker/config.json`。
|
||||
|
||||
Pod只能引用和它相同namespace的ImagePullSecrets,
|
||||
所以需要为每一个namespace做配置
|
||||
|
||||
#### 通过kubectl创建secret
|
||||
|
||||
由于某种原因在一个`.docker/config.json`中需要多个项或者需要非上述命令给出的secret,可以[create a secret using
|
||||
json or yaml](/docs/user-guide/secrets/#creating-a-secret-manually)。
|
||||
|
||||
请保证:
|
||||
|
||||
- 设置data项的名称为`.dockerconfigjson`
|
||||
- 使用base64对docker文件编码,并将字符准确黏贴到`data[".dockerconfigjson"]`里
|
||||
- 设置`type`为`kubernetes.io/dockerconfigjson`
|
||||
|
||||
示例:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: myregistrykey
|
||||
namespace: awesomeapps
|
||||
data:
|
||||
.dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
```
|
||||
|
||||
如果收到错误消息`error: no objects passed to create`,可能是 base64 编码后的字符串非法。
|
||||
如果收到错误消息类似`Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ...`,
|
||||
说明数据已经解码成功,但是不满足`.docker/config.json`文件的语法。
|
||||
|
||||
#### 在pod中引用imagePullSecrets
|
||||
|
||||
现在,在创建pod时,可以在pod定义中增加`imagePullSecrets`小节来引用secret
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: foo
|
||||
namespace: awesomeapps
|
||||
spec:
|
||||
containers:
|
||||
- name: foo
|
||||
image: janedoe/awesomeapp:v1
|
||||
imagePullSecrets:
|
||||
- name: myregistrykey
|
||||
```
|
||||
|
||||
对每一个使用私有仓库的pod,都需要做以上操作。
|
||||
|
||||
也可以在[serviceAccount](/docs/user-guide/service-accounts) 资源中设置imagePullSecrets自动设置`imagePullSecrets`
|
||||
|
||||
`imagePullSecrets`可以和每个node上的`.docker/config.json`一起使用,他们将共同生效。本方法在Google Kubernetes Engine
|
||||
也能正常工作。
|
||||
|
||||
### 使用场景
|
||||
|
||||
配置私有仓库有多种方案,以下是一些常用场景和建议的解决方案。
|
||||
|
||||
1. 集群运行非专有(例如 开源镜像)镜像。镜像不需要隐藏。
|
||||
- 使用Docker hub上的公有镜像
|
||||
- 无需配置
|
||||
- 在GCE/GKE上会自动使用高稳定性和高速的Docker hub的本地mirror
|
||||
1. 集群运行一些专有镜像,这些镜像对外部公司需要隐藏,对集群用户可见
|
||||
- 使用自主的私有[Docker registry](https://docs.docker.com/registry/).
|
||||
- 可以放置在[Docker Hub](https://hub.docker.com/account/signup/),或者其他地方。
|
||||
- 按照上面的描述,在每个节点手动配置.docker/config.json
|
||||
- 或者,在防火墙内运行一个内置的私有仓库,并开放读取权限
|
||||
- 不需要配置Kubenretes
|
||||
- 或者,在GCE/GKE上时,使用项目的Google Container Registry
|
||||
- 使用集群自动伸缩比手动配置node工作的更好
|
||||
- 或者,在更改集群node配置不方便时,使用`imagePullSecrets`
|
||||
1. 使用专有镜像的集群,有更严格的访问控制
|
||||
- 保证[AlwaysPullImages admission controller](/docs/admin/admission-controllers/#alwayspullimages)开启。否则,所有的pod都可以使用镜像
|
||||
- 将敏感数据存储在"Secret"资源中,而不是打包在镜像里
|
||||
1. 多租户集群下,每个租户需要自己的私有仓库
|
||||
- 保证[AlwaysPullImages admission controller](/docs/admin/admission-controllers/#alwayspullimages)开启。否则,所有租户的所有的pod都可以使用镜像
|
||||
- 私有仓库开启认证
|
||||
- 为每个租户获取仓库凭证,放置在secret中,并发布到每个租户的namespace下
|
||||
- 租户将secret增加到每个namespace下的imagePullSecrets中
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: 概念模板示例
|
||||
approvers:
|
||||
- chenopis
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
**注意:** 注意为新文档 [create an entry in the table of contents](/docs/home/contribute/write-new-topic/#creating-an-entry-in-the-table-of-contents) 。
|
||||
|
||||
本页解释了 ...
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## 了解 ...
|
||||
|
||||
Kubernetes 提供 ...
|
||||
|
||||
## 使用 ...
|
||||
|
||||
使用 ...
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
**[可选章节]**
|
||||
|
||||
* 了解更多 [Writing a New Topic](/docs/home/contribute/write-new-topic/)。
|
||||
* 查看 [Using Page Templates - Concept template](/docs/home/contribute/page-templates/#concept_template) 了解如何使用本模板。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
approvers:
|
||||
- lavalamp
|
||||
title: Kubernetes 组件
|
||||
redirect_from:
|
||||
- "/docs/admin/cluster-components/"
|
||||
- "/docs/admin/cluster-components.html"
|
||||
content_template: templates/concept
|
||||
---
|
||||
{{% capture overview %}}
|
||||
本文档概述了 Kubernetes 所需的各种二进制组件, 用于提供齐全的功能。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Master 组件
|
||||
|
||||
Master 组件提供的集群控制。Master 组件对集群做出全局性决策(例如:调度),以及检测和响应集群事件(副本控制器的`replicas`字段不满足时,启动新的副本)。
|
||||
|
||||
Master 组件可以在集群中的任何节点上运行。然而,为了简单起见,设置脚本通常会启动同一个虚拟机上所有 Master 组件,并且不会在此虚拟机上运行用户容器。请参阅[构建高可用性群集](/docs/admin/high-availability)示例对于多主机 VM 的设置。
|
||||
|
||||
### API服务器
|
||||
|
||||
[kube-apiserver](/docs/admin/kube-apiserver)对外暴露了Kubernetes API。它是的 Kubernetes 前端控制层。它被设计为水平扩展,即通过部署更多实例来缩放。请参阅[构建高可用性群集](/docs/admin/high-availability).
|
||||
|
||||
### etcd
|
||||
|
||||
[etcd](/docs/admin/etcd) 用于 Kubernetes 的后端存储。所有集群数据都存储在此处,始终为您的 Kubernetes 集群的 etcd 数据提供备份计划。
|
||||
|
||||
### kube-controller-manager
|
||||
|
||||
[kube-controller-manager](/docs/admin/kube-controller-manager)运行控制器,它们是处理集群中常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成独立的可执行文件,并在单个进程中运行。
|
||||
|
||||
这些控制器包括:
|
||||
|
||||
* 节点控制器: 当节点移除时,负责注意和响应。
|
||||
* 副本控制器: 负责维护系统中每个副本控制器对象正确数量的 Pod。
|
||||
* 端点控制器: 填充 端点(Endpoints) 对象(即连接 Services & Pods)。
|
||||
* 服务帐户和令牌控制器: 为新的命名空间创建默认帐户和 API 访问令牌.
|
||||
|
||||
### 云控制器管理器-(cloud-controller-manager)
|
||||
|
||||
cloud-controller-manager 是用于与底层云提供商交互的控制器。云控制器管理器可执行组件是 Kubernetes v1.6 版本中引入的 Alpha 功能。
|
||||
|
||||
cloud-controller-manager 仅运行云提供商特定的控制器循环。您必须在 kube-controller-manager 中禁用这些控制器循环,您可以通过在启动 kube-controller-manager 时将 `--cloud-provider` 标志设置为`external`来禁用控制器循环。
|
||||
|
||||
cloud-controller-manager 允许云供应商代码和 Kubernetes 核心彼此独立发展,在以前的版本中,Kubernetes 核心代码依赖于云提供商特定的功能代码。在未来的版本中,云供应商的特定代码应由云供应商自己维护,并与运行 Kubernetes 的云控制器管理器相关联。
|
||||
|
||||
以下控制器具有云提供商依赖关系:
|
||||
|
||||
* 节点控制器: 用于检查云提供商以确定节点是否在云中停止响应后被删除
|
||||
* 路由控制器: 用于在底层云基础架构中设置路由
|
||||
* 服务控制器: 用于创建,更新和删除云提供商负载平衡器
|
||||
* 数据卷控制器: 用于创建,附加和装载卷,并与云提供商进行交互以协调卷
|
||||
|
||||
### 调度器 - (kube-scheduler)
|
||||
|
||||
[kube-scheduler](/docs/admin/kube-scheduler)监视没有分配节点的新创建的 Pod,选择一个节点供他们运行。
|
||||
|
||||
### 插件(addons)
|
||||
|
||||
插件是实现集群功能的 Pod 和 Service。 Pods 可以通过 Deployments,ReplicationControllers 管理。插件对象本身是受命名空间限制的,被创建于 `kube-system` 命名空间。
|
||||
|
||||
Addon 管理器用于创建和维护附加资源. 有关详细信息,请参阅[here](http://releases.k8s.io/HEAD/cluster/addons).
|
||||
|
||||
#### DNS
|
||||
|
||||
虽然其他插件并不是必需的,但所有 Kubernetes 集群都应该具有[Cluster DNS](/docs/concepts/services-networking/dns-pod-service/),许多示例依赖于它。
|
||||
|
||||
Cluster DNS 是一个 DNS 服务器,和您部署环境中的其他 DNS 服务器一起工作,为 Kubernetes 服务提供DNS记录。
|
||||
|
||||
Kubernetes 启动的容器自动将 DNS 服务器包含在 DNS 搜索中。
|
||||
|
||||
#### 用户界面
|
||||
|
||||
dashboard 提供了集群状态的只读概述。有关更多信息,请参阅[使用HTTP代理访问 Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api/)
|
||||
|
||||
|
||||
#### 容器资源监控
|
||||
|
||||
[容器资源监控](/docs/user-guide/monitoring)将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中,并提供用于浏览这些数据的界面。
|
||||
|
||||
#### 集群层面日志
|
||||
|
||||
[集群层面日志](/docs/user-guide/logging/overview) 机制负责将容器的日志数据保存到一个集中的日志存储中,该存储能够提供搜索和浏览接口。
|
||||
|
||||
## 节点组件
|
||||
|
||||
节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行时环境。
|
||||
|
||||
### kubelet
|
||||
|
||||
[kubelet](/docs/admin/kubelet)是主要的节点代理,它监测已分配给其节点的 Pod(通过 apiserver 或通过本地配置文件),提供如下功能:
|
||||
|
||||
* 挂载 Pod 所需要的数据卷(Volume)。
|
||||
* 下载 Pod 的 secrets。
|
||||
* 通过 Docker 运行(或通过 rkt)运行 Pod 的容器。
|
||||
* 周期性的对容器生命周期进行探测。
|
||||
* 如果需要,通过创建 *镜像 Pod(Mirror Pod)* 将 Pod 的状态报告回系统的其余部分。
|
||||
* 将节点的状态报告回系统的其余部分。
|
||||
|
||||
### kube-proxy
|
||||
|
||||
[kube-proxy](/docs/admin/kube-proxy)通过维护主机上的网络规则并执行连接转发,实现了Kubernetes服务抽象。
|
||||
|
||||
|
||||
### docker
|
||||
|
||||
Docker 用于运行容器。
|
||||
|
||||
### rkt
|
||||
|
||||
支持 rkt 运行容器作为 Docker 的试验性替代方案。
|
||||
|
||||
### supervisord
|
||||
|
||||
supervisord 是一个轻量级的进程监控系统,可以用来保证 kubelet 和 docker 运行。
|
||||
|
||||
### fluentd
|
||||
|
||||
fluentd 是一个守护进程,它有助于提供[集群层面日志](#cluster-level-logging) 集群层面的日志。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# Kubernetes API 概述
|
||||
|
||||
[API协议文档](https://git.k8s.io/community/contributors/devel/api-conventions.md)描述了主系统和API概念。
|
||||
|
||||
[API参考文档](https://kubernetes.io/docs/reference)描述了API整体规范。
|
||||
|
||||
[访问文档](https://kubernetes.io/docs/admin/accessing-the-api)讨论了通过远程访问API的相关问题。
|
||||
|
||||
Kubernetes API是系统描述性配置的基础。 [Kubectl](https://kubernetes.io/docs/user-guide/kubectl/) 命令行工具被用于创建、更新、删除、获取API对象。
|
||||
|
||||
Kubernetes 通过API资源存储自己序列化状态(现在存储在[etcd](https://coreos.com/docs/distributed-configuration/getting-started-with-etcd/))。
|
||||
|
||||
Kubernetes 被分成多个组件,各部分通过API相互交互。
|
||||
|
||||
## API 变更
|
||||
|
||||
根据经验,任何成功的系统都需要随着新的用例出现或现有用例发生变化的情况下,进行相应的进化与调整。因此,我们希望Kubernetes API也可以保持持续的进化和调整。同时,在较长一段时间内,我们也希望与现有客户端版本保持良好的向下兼容性。一般情况下,增加新的API资源和资源字段不会导致向下兼容性问题发生;但如果是需要删除一个已有的资源或者字段,那么必须通过[API废弃流程](/docs/reference/deprecation-policy/)来进行。
|
||||
|
||||
参考[API变更文档](https://git.k8s.io/community/contributors/devel/api_changes.md),了解兼容性变更的要素以及如何变更API的流程。
|
||||
|
||||
## API Swagger 定义
|
||||
|
||||
Kubernetes使用 [Swagger v1.2](http://swagger.io/) 与 [OpenAPI](https://www.openapis.org/) 记录API所有细节。Kubernetes apiserver (即 “master”)提供了一个API接口用于获取 Swagger 1.2 Kubernetes API 规范 ,默认在路径 **`/swaggerapi`** 下。你也可以为API服务器可以设置 **`-enable-swagger-ui=true`** 来启用API界面,之后使用浏览器访问 **`/swagger-ui`**,浏览API文档。
|
||||
|
||||
|
||||
Kubernetes从1.4版本开始,也支持通过 [**`/swagger.json`**](https://git.k8s.io/kubernetes/api/openapi-spec/swagger.json) 来访问 OpenAPI 形式给出的API文档。在我们将 Swagger v1.2 切换到 OpenAPI (aka Swagger v2.0) 期间,一部分工具(如 kubectl 与 swagger-ui )会继续使用 1.2 版本规范。Kubernetes 1.5 版本中的 OpenAPI 规范是 Beta 版本。
|
||||
|
||||
Kubernetes实现了另一种基于Protobuf的序列化格式,该格式主要用于集群内通信,并在[设计方案](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/api-machinery/protobuf.md)中进行了说明,每个模式的IDL文件位于定义API对象的Go软件包中。
|
||||
|
||||
## API 版本
|
||||
|
||||
为了使删除字段或者重构资源表示更加容易,Kubernetes 支持多个API版本。每一个版本都在不同API路径下,例如 **`/api/v1`** 或者 **`/apis/extensions/v1beta1`**。
|
||||
|
||||
我们选择在API级别进行版本化,而不是在资源或字段级别进行版本化,以确保API提供清晰,一致的系统资源和行为视图,并控制对已废止的API和/或实验性API的访问。 JSON和Protobuf序列化模式遵循架构更改的相同准则 - 下面的所有描述都同时适用于这两种格式。
|
||||
|
||||
请注意,API版本控制和软件版本控制只有间接相关性。 [API和发行版本建议](https://git.k8s.io/community/contributors/design-proposals/release/versioning.md)描述了API版本与软件版本之间的关系。
|
||||
|
||||
不同的API版本名称意味着不同级别的软件稳定性和支持程度。 每个级别的标准在[API变更文档](https://git.k8s.io/community/contributors/devel/api_changes.md#alpha-beta-and-stable-versions)中有更详细的描述。 内容主要概括如下:
|
||||
|
||||
* Alpha 测试版本:
|
||||
|
||||
* 版本名称包含了 **`alpha`** (例如:**`v1alpha1`**)。
|
||||
|
||||
* 可能是有缺陷的。启用该功能可能会带来隐含的问题,默认情况是关闭的。
|
||||
|
||||
* 支持的功能可能在没有通知的情况下随时删除。
|
||||
|
||||
* API的更改可能会带来兼容性问题,但是在后续的软件发布中不会有任何通知。
|
||||
|
||||
* 由于bugs风险的增加和缺乏长期的支持,推荐在短暂的集群测试中使用。
|
||||
|
||||
* Beta 测试版本:
|
||||
|
||||
* 版本名称包含了 **`beta`** (例如: **`v2beta3`**)。
|
||||
|
||||
* 代码已经测试过。启用该功能被认为是安全的,功能默认已启用。
|
||||
|
||||
* 所有已支持的功能不会被删除,细节可能会发生变化。
|
||||
|
||||
* 对象的模式和/或语义可能会在后续的beta测试版或稳定版中以不兼容的方式进行更改。 发生这种情况时,我们将提供迁移到下一个版本的说明。 这可能需要删除、编辑和重新创建API对象。执行编辑操作时需要谨慎行事,这可能需要停用依赖该功能的应用程序。
|
||||
|
||||
* 建议仅用于非业务关键型用途,因为后续版本中可能存在不兼容的更改。 如果您有多个可以独立升级的群集,则可以放宽此限制。
|
||||
|
||||
* **请尝试我们的 beta 版本功能并且给出反馈!一旦他们退出 beta 测试版,我们可能不会做出更多的改变。**
|
||||
|
||||
* 稳定版本:
|
||||
|
||||
* 版本名称是 **`vX`**,其中 **`X`** 是整数。
|
||||
|
||||
* 功能的稳定版本将出现在许多后续版本的发行软件中。
|
||||
|
||||
## API 组
|
||||
|
||||
为了更容易地扩展Kubernetes API,我们实现了[*`API组`*](https://git.k8s.io/community/contributors/design-proposals/api-machinery/api-group.md)。 API组在REST路径和序列化对象的 **`apiVersion`** 字段中指定。
|
||||
|
||||
目前有几个API组正在使用中:
|
||||
|
||||
1. 核心组(通常被称为遗留组)位于REST路径 **`/api/v1`** 并使用 **`apiVersion:v1`**。
|
||||
|
||||
1. 指定的组位于REST路径 **`/apis/$GROUP_NAME/$VERSION`**,并使用 **`apiVersion:$GROUP_NAME/$VERSION`**(例如 **`apiVersion:batch/v1`**)。 在[Kubernetes API参考](https://kubernetes.io/docs/reference/)中可以看到支持的API组的完整列表。
|
||||
|
||||
社区支持使用以下两种方式来提供自定义资源对API进行扩展[自定义资源](https://kubernetes.io/docs/concepts/api-extension/custom-resources/):
|
||||
|
||||
1. [CustomResourceDefinition](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/)适用于具有非常基本的CRUD需求的用户。
|
||||
|
||||
1. 即将推出:需要全套Kubernetes API语义的用户可以实现自己的apiserver,并使用[聚合器](https://git.k8s.io/community/contributors/design-proposals/api-machinery/aggregated-api-servers.md)为客户提供无缝的服务。
|
||||
|
||||
## 启用 API 组
|
||||
|
||||
某些资源和API组默认情况下处于启用状态。 可以通过在apiserver上设置 **`--runtime-config`** 来启用或禁用它们。 **`--runtime-config`** 接受逗号分隔的值。 例如:要禁用batch/v1,请设置**`--runtime-config=batch/v1=false`**,以启用batch/v2alpha1,请设置**`--runtime-config=batch/v2alpha1`**。 该标志接受描述apiserver的运行时配置的逗号分隔的一组键值对。
|
||||
|
||||
重要:启用或禁用组或资源需要重新启动apiserver和控制器管理器来使得 **`--runtime-config`** 更改生效。
|
||||
|
||||
## 启用组中资源
|
||||
|
||||
DaemonSets,Deployments,HorizontalPodAutoscalers,Ingress,Jobs和ReplicaSets是默认启用的。 其他扩展资源可以通过在apiserver上设置 **`--runtime-config`** 来启用。**`--runtime-config`** 接受逗号分隔的值。
|
||||
|
||||
例如:要禁用 Deployment 和 Ingress,请设置 **`--runtime-config=extensions/v1beta1/deployments=false,extensions/v1beta1/ingress=false`**
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
approvers:
|
||||
- k8s-merge-robot
|
||||
|
||||
title: 认识 Kubernetes?
|
||||
---
|
||||
|
||||
Kubernetes 是一个跨主机集群的 [开源的容器调度平台,它可以自动化应用容器的部署、扩展和操作](http://www.slideshare.net/BrianGrant11/wso2con-us-2015-kubernetes-a-platform-for-automating-deployment-scaling-and-operations) , 提供以容器为中心的基础架构。
|
||||
|
||||
使用 Kubernetes, 您可以快速高效地响应客户需求:
|
||||
|
||||
- 快速、可预测地部署您的应用程序
|
||||
- 拥有即时扩展应用程序的能力
|
||||
- 不影响现有业务的情况下,无缝地发布新功能
|
||||
- 优化硬件资源,降低成本
|
||||
|
||||
我们的目标是构建一个软件和工具的生态系统,以减轻您在公共云或私有云运行应用程序的负担。
|
||||
|
||||
#### Kubernetes 具有如下特点:
|
||||
|
||||
* **便携性**: 无论公有云、私有云、混合云还是多云架构都全面支持
|
||||
* **可扩展**: 它是模块化、可插拔、可挂载、可组合的,支持各种形式的扩展
|
||||
* **自修复**: 它可以自保持应用状态、可自重启、自复制、自缩放的,通过声明式语法提供了强大的自修复能力
|
||||
|
||||
Kubernetes 项目由 Google 公司在 2014 年启动。Kubernetes 建立在 [Google 公司超过十余年的运维经验基础之上,Google 所有的应用都运行在容器上](https://research.google.com/pubs/pub43438.html), 再与社区中最好的想法和实践相结合,也许它是最受欢迎的容器平台。
|
||||
|
||||
##### 准备好 [开始](/docs/getting-started-guides/)?
|
||||
|
||||
## 为什么是容器?
|
||||
|
||||
查看此文,可以了解为什么您要使用容器 [容器](http://aucouranton.com/2014/06/13/linux-containers-parallels-lxc-openvz-docker-and-more/)?
|
||||
|
||||

|
||||
|
||||
*传统* 部署应用程序的方式,一般是使用操作系统自带的包管理器在主机上安装应用依赖,之后再安装应用程序。这无疑将应用程序的可执行文件、应用的配置、应用依赖库和应用的生命周期与宿主机操作系统进行了紧耦合。在此情境下,可以通过构建不可改变的虚拟机镜像版本,通过镜像版本实现可预测的发布和回滚,但是虚拟机实在是太重量级了,且镜像体积太庞大,便捷性差。
|
||||
|
||||
*新方式* 是基于操作系统级虚拟化而不是硬件级虚拟化方法来部署容器。容器之间彼此隔离并与主机隔离:它们具有自己的文件系统,不能看到彼此的进程,并且它们所使用的计算资源是可以被限制的。它们比虚拟机更容易构建,并且因为它们与底层基础架构和主机文件系统隔离,所以它们可以跨云和操作系统快速分发。
|
||||
|
||||
由于容器体积小且启动快,因此可以在每个容器镜像中打包一个应用程序。这种一对一的应用镜像关系拥有很多好处。使用容器,不需要与外部的基础架构环境绑定, 因为每一个应用程序都不需要外部依赖,更不需要与外部的基础架构环境依赖。完美解决了从开发到生产环境的一致性问题。
|
||||
|
||||
容器同样比虚拟机更加透明,这有助于监测和管理。尤其是容器进程的生命周期由基础设施管理,而不是由容器内的进程对外隐藏时更是如此。最后,每个应用程序用容器封装,管理容器部署就等同于管理应用程序部署。
|
||||
|
||||
容器优点摘要:
|
||||
|
||||
* **敏捷的应用程序创建和部署**:
|
||||
与虚拟机镜像相比,容器镜像更容易创建,提升了硬件的使用效率。
|
||||
* **持续开发、集成和部署**:
|
||||
提供可靠与频繁的容器镜像构建和部署,可以很方便及快速的回滚 (由于镜像不可变性).
|
||||
* **关注开发与运维的分离**:
|
||||
在构建/发布时创建应用程序容器镜像,从而将应用程序与基础架构分离。
|
||||
* **开发、测试和生产环境的一致性**:
|
||||
在笔记本电脑上运行与云中一样。
|
||||
* **云和操作系统的可移植性**:
|
||||
可运行在 Ubuntu, RHEL, CoreOS, 内部部署, Google 容器引擎和其他任何地方。
|
||||
* **以应用为中心的管理**:
|
||||
提升了操作系统的抽象级别,以便在使用逻辑资源的操作系统上运行应用程序。
|
||||
* **松耦合、分布式、弹性伸缩 [微服务](http://martinfowler.com/articles/microservices.html)**:
|
||||
应用程序被分成更小,更独立的部分,可以动态部署和管理 - 而不是巨型单体应用运行在专用的大型机上。
|
||||
* **资源隔离**:
|
||||
通过对应用进行资源隔离,可以很容易的预测应用程序性能。
|
||||
* **资源利用**:
|
||||
高效率和高密度。
|
||||
|
||||
#### 为什么我们需要 Kubernetes,它能做什么?
|
||||
|
||||
最基础的,Kubernetes 可以在物理或虚拟机集群上调度和运行应用程序容器。然而,Kubernetes 还允许开发人员从物理和虚拟机'脱离',从以**主机为中心**的基础架构转移到以**容器为中心**的基础架构,这样可以提供容器固有的全部优点和益处。Kubernetes 提供了基础设施来构建一个真正以**容器为中心**的开发环境。
|
||||
|
||||
Kubernetes 满足了生产中运行应用程序的许多常见的需求,例如:
|
||||
|
||||
* [Pod](/docs/user-guide/pods/) 提供复合应用并保留一个应用一个容器的容器模型,
|
||||
* [挂载外部存储](/docs/user-guide/volumes/),
|
||||
* [Secret管理](/docs/user-guide/secrets/),
|
||||
* [应用健康检查](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),
|
||||
* [副本应用实例](/docs/user-guide/replication-controller/),
|
||||
* [横向自动扩缩容](/docs/user-guide/horizontal-pod-autoscaling/),
|
||||
* [服务发现](/docs/user-guide/connecting-applications/),
|
||||
* [负载均衡](/docs/user-guide/services/),
|
||||
* [滚动更新](/docs/user-guide/update-demo/),
|
||||
* [资源监测](/docs/user-guide/monitoring/),
|
||||
* [日志采集和存储](/docs/user-guide/logging/overview/),
|
||||
* [支持自检和调试](/docs/user-guide/introspection-and-debugging/),
|
||||
* [认证和鉴权](/docs/admin/authorization/).
|
||||
|
||||
这提供了平台即服务 (PAAS) 的简单性以及基础架构即服务 (IAAS) 的灵活性,并促进跨基础设施供应商的可移植性。
|
||||
|
||||
有关详细信息,请参阅 [用户指南](/docs/user-guide/).
|
||||
|
||||
#### 为什么 Kubernetes 是一个平台?
|
||||
|
||||
Kubernetes 提供了很多的功能,总会有新的场景受益于新特性。它可以简化应用程序的工作流,加快开发速度。被大家认可的应用编排通常需要有较强的自动化能力。这就是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。
|
||||
|
||||
[Label](/docs/user-guide/labels/) 允许用户按照自己的方式组织管理对应的资源。 [注解](/docs/user-guide/annotations/) 使用户能够以自定义的描述信息来修饰资源,以适用于自己的工作流,并为管理工具提供检查点状态的简单方法。
|
||||
|
||||
此外,[Kubernetes 控制面 (Control Plane)](/docs/admin/cluster-components) 是构建在相同的 [APIs](/docs/api/) 上面,开发人员和用户都可以用。用户可以编写自己的控制器, [调度器](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/docs/devel/scheduler.md)等等,如果这么做,根据新加的[自定义 API](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/docs/design/extending-api.md) ,可以扩展当前的通用 [CLI 命令行工具](/docs/user-guide/kubectl-overview/)。
|
||||
|
||||
这种 [设计](https://git.k8s.io/community/contributors/design-proposals/architecture/principles.md) 使得许多其他系统可以构建在 Kubernetes 之上。
|
||||
|
||||
#### Kubernetes 不是什么:
|
||||
|
||||
Kubernetes 不是一个传统意义上,包罗万象的 PaaS (平台即服务) 系统。我们保留用户选择的自由,这非常重要。
|
||||
|
||||
* Kubernetes 不限制支持的应用程序类型。 它不插手应用程序框架 (例如 [Wildfly](http://wildfly.org/)), 不限制支持的语言运行时 (例如 Java, Python, Ruby),只迎合符合 [12种因素的应用程序](http://12factor.net/),也不区分"应用程序"与"服务"。Kubernetes 旨在支持极其多样化的工作负载,包括无状态、有状态和数据处理工作负载。如果应用可以在容器中运行,它就可以在 Kubernetes 上运行。
|
||||
* Kubernetes 不提供作为内置服务的中间件 (例如 消息中间件)、数据处理框架 (例如 Spark)、数据库 (例如 mysql)或集群存储系统 (例如 Ceph)。这些应用可以运行在 Kubernetes 上。
|
||||
* Kubernetes 没有提供点击即部署的服务市场
|
||||
* Kubernetes 从源代码到镜像都是非垄断的。 它不部署源代码且不构建您的应用程序。 持续集成 (CI) 工作流是一个不同用户和项目都有自己需求和偏好的领域。 所以我们支持在 Kubernetes 分层的 CI 工作流,但不指定它应该如何工作。
|
||||
* Kubernetes 允许用户选择其他的日志记录,监控和告警系统 (虽然我们提供一些集成作为概念验证)
|
||||
* Kubernetes 不提供或授权一个全面的应用程序配置语言/系统 (例如 [jsonnet](https://github.com/google/jsonnet)).
|
||||
* Kubernetes 不提供也不采用任何全面机器配置、保养、管理或自我修复系统
|
||||
|
||||
另一方面,许多 PaaS 系统*运行*在 Kubernetes 上面,例如 [Openshift](https://github.com/openshift/origin), [Deis](http://deis.io/), and [Eldarion](http://eldarion.cloud/)。 您也可以自定义您自己的 PaaS, 与您选择的 CI 系统集成,或与 Kubernetes 一起使用: 将您的容器镜像部署到 Kubernetes。
|
||||
|
||||
由于 Kubernetes 在应用级别而不仅仅在硬件级别上运行,因此它提供 PaaS 产品通用的一些功能,例如部署、扩展、负载均衡、日志记录、监控等。但是,Kubernetes 不是单一的,默认解决方案是可选和可插拔的。
|
||||
|
||||
此处,Kubernetes 不仅仅是一个 "编排系统";它消除了编排的需要。 "编排"技术定义的是工作流的执行: 从 A 到 B,然后到 C。相反,Kubernetes 是包括一套独立、可组合的控制过程,通过声明式语法使其连续地朝着期望状态驱动当前状态。 不需要告诉它具体从 A 到 C 的过程,只要告诉到 C 的状态即可。 也不需要集中控制;该方法更类似于"编舞"。这使得系统更容易使用并且更强大、更可靠、更具弹性和可扩展性。
|
||||
|
||||
#### *Kubernetes* 是什么意思? K8s?
|
||||
|
||||
名称 **Kubernetes** 源于希腊语,意为 "舵手" 或 "飞行员", 且是英文 "governor" 和 ["cybernetic"](http://www.etymonline.com/index.php?term=cybernetics)的词根。 **K8s** 是通过将 8 个字母 "ubernete" 替换为 8 而导出的缩写。另外,在中文里,k8s 的发音与 Kubernetes 的发音比较接近。
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
title: 理解 Kubernetes 对象
|
||||
|
||||
redirect_from:
|
||||
- "/docs/concepts/abstractions/overview/"
|
||||
- "/docs/concepts/abstractions/overview.html"
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本页说明了 Kubernetes 对象在 Kubernetes API 中是如何表示的,以及如何在 `.yaml` 格式的文件中表示。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
|
||||
|
||||
|
||||
## 理解 Kubernetes 对象
|
||||
|
||||
在 Kubernetes 系统中,*Kubernetes 对象* 是持久化的实体。Kubernetes 使用这些实体去表示整个集群的状态。特别地,它们描述了如下信息:
|
||||
|
||||
* 哪些容器化应用在运行(以及在哪个 Node 上)
|
||||
* 可以被应用使用的资源
|
||||
* 关于应用运行时表现的策略,比如重启策略、升级策略,以及容错策略
|
||||
|
||||
|
||||
|
||||
Kubernetes 对象是 “目标性记录” —— 一旦创建对象,Kubernetes 系统将持续工作以确保对象存在。通过创建对象,本质上是在告知 Kubernetes 系统,所需要的集群工作负载看起来是什么样子的,这就是 Kubernetes 集群的 **期望状态(Desired State)**。
|
||||
|
||||
操作 Kubernetes 对象 —— 是否创建、修改,或者删除 —— 需要使用 [Kubernetes API](https://git.k8s.io/community/contributors/devel/api-conventions.md)。比如,当使用 `kubectl` 命令行接口时,CLI 会执行必要的 Kubernetes API 调用,也可以在程序中直接调用 Kubernetes API。为了实现该目标,Kubernetes 当前提供了一个 `golang` [客户端库](https://github.com/kubernetes/client-go)
|
||||
,其它语言库(例如[Python](https://github.com/kubernetes-incubator/client-python))也正在开发中。
|
||||
|
||||
|
||||
|
||||
### 对象规约(Spec)与状态(Status)
|
||||
|
||||
每个 Kubernetes 对象包含两个嵌套的对象字段,它们负责管理对象的配置:对象 *spec* 和 对象 *status*。
|
||||
*spec* 是必需的,它描述了对象的 *期望状态(Desired State)* —— 希望对象所具有的特征。
|
||||
*status* 描述了对象的 *实际状态(Actual State)*,它是由 Kubernetes 系统提供和更新的。在任何时刻,Kubernetes 控制面一直努力地管理着对象的实际状态以与期望状态相匹配。
|
||||
|
||||
|
||||
|
||||
例如,Kubernetes Deployment 对象能够表示运行在集群中的应用。
|
||||
当创建 Deployment 时,可能需要设置 Deployment 的规约,以指定该应用需要有 3 个副本在运行。
|
||||
Kubernetes 系统读取 Deployment 规约,并启动我们所期望的该应用的 3 个实例 —— 更新状态以与规约相匹配。
|
||||
如果那些实例中有失败的(一种状态变更),Kubernetes 系统通过修正来响应规约和状态之间的不一致 —— 这种情况,会启动一个新的实例来替换。
|
||||
|
||||
关于对象 spec、status 和 metadata 的更多信息,查看 [Kubernetes API 约定](https://git.k8s.io/community/contributors/devel/api-conventions.md)。
|
||||
|
||||
|
||||
|
||||
### 描述 Kubernetes 对象
|
||||
|
||||
当创建 Kubernetes 对象时,必须提供对象的规约,用来描述该对象的期望状态,以及关于对象的一些基本信息(例如名称)。
|
||||
当使用 Kubernetes API 创建对象时(或者直接创建,或者基于`kubectl`),API 请求必须在请求体中包含 JSON 格式的信息。
|
||||
**大多数情况下,需要在 .yaml 文件中为 `kubectl` 提供这些信息**。
|
||||
`kubectl` 在发起 API 请求时,将这些信息转换成 JSON 格式。
|
||||
|
||||
这里有一个 `.yaml` 示例文件,展示了 Kubernetes Deployment 的必需字段和对象规约:
|
||||
|
||||
{{< code file="nginx-deployment.yaml" >}}
|
||||
|
||||
使用类似于上面的 `.yaml` 文件来创建 Deployment,一种方式是使用 `kubectl` 命令行接口(CLI)中的 [`kubectl create`](/docs/user-guide/kubectl/v1.7/#create) 命令,将 `.yaml` 文件作为参数。下面是一个示例:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/nginx-deployment.yaml --record
|
||||
```
|
||||
|
||||
|
||||
输出类似如下这样:
|
||||
|
||||
```shell
|
||||
deployment "nginx-deployment" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 必需字段
|
||||
|
||||
在想要创建的 Kubernetes 对象对应的 `.yaml` 文件中,需要配置如下的字段:
|
||||
|
||||
* `apiVersion` - 创建该对象所使用的 Kubernetes API 的版本
|
||||
* `kind` - 想要创建的对象的类型
|
||||
* `metadata` - 帮助识别对象唯一性的数据,包括一个 `name` 字符串、UID 和可选的 `namespace`
|
||||
|
||||
|
||||
|
||||
也需要提供对象的 `spec` 字段。对象 `spec` 的精确格式对每个 Kubernetes 对象来说是不同的,包含了特定于该对象的嵌套字段。[Kubernetes API 参考](/docs/api/)能够帮助我们找到任何我们想创建的对象的 spec 格式。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 了解最重要的基本 Kubernetes 对象,例如 [Pod](/docs/concepts/abstractions/pod/)。
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
ports:
|
||||
- containerPort: 80
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
approvers:
|
||||
- pweil-
|
||||
title: Pod 安全策略
|
||||
redirect_from:
|
||||
- "/docs/user-guide/pod-security-policy/"
|
||||
- "/docs/user-guide/pod-security-policy/index.html"
|
||||
---
|
||||
|
||||
|
||||
|
||||
`PodSecurityPolicy` 类型的对象能够控制,是否可以向 Pod 发送请求,该 Pod 能够影响被应用到 Pod 和容器的 `SecurityContext`。
|
||||
查看 [Pod 安全策略建议](https://git.k8s.io/community/contributors/design-proposals/security-context-constraints.md) 获取更多信息。
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
## 什么是 Pod 安全策略?
|
||||
|
||||
_Pod 安全策略_ 是集群级别的资源,它能够控制 Pod 运行的行为,以及它具有访问什么的能力。
|
||||
`PodSecurityPolicy` 对象定义了一组条件,指示 Pod 必须按系统所能接受的顺序运行。
|
||||
它们允许管理员控制如下方面:
|
||||
|
||||
|
||||
|
||||
| 控制面 | 字段名称 |
|
||||
| ------------------------------------------------------------- | --------------------------------- |
|
||||
| 已授权容器的运行 | `privileged` |
|
||||
| 为容器添加默认的一组能力 | `defaultAddCapabilities` |
|
||||
| 为容器去掉某些能力 | `requiredDropCapabilities` |
|
||||
| 容器能够请求添加某些能力 | `allowedCapabilities` |
|
||||
| 控制卷类型的使用 | [`volumes`](#controlling-volumes) |
|
||||
| 主机网络的使用 | [`hostNetwork`](#host-network) |
|
||||
| 主机端口的使用 | `hostPorts` |
|
||||
| 主机 PID namespace 的使用 | `hostPID` |
|
||||
| 主机 IPC namespace 的使用 | `hostIPC` |
|
||||
| 主机路径的使用 | [`allowedHostPaths`](#allowed-host-paths) |
|
||||
| 容器的 SELinux 上下文 | [`seLinux`](#selinux) |
|
||||
| 用户 ID | [`runAsUser`](#runasuser) |
|
||||
| 配置允许的补充组 | [`supplementalGroups`](#supplementalgroups) |
|
||||
| 分配拥有 Pod 数据卷的 FSGroup | [`fsGroup`](#fsgroup) |
|
||||
| 必须使用一个只读的 root 文件系统 | `readOnlyRootFilesystem` |
|
||||
|
||||
|
||||
|
||||
_Pod 安全策略_ 由设置和策略组成,它们能够控制 Pod 访问的安全特征。这些设置分为如下三类:
|
||||
|
||||
- *基于布尔值控制*:这种类型的字段默认为最严格限制的值。
|
||||
- *基于被允许的值集合控制*:这种类型的字段会与这组值进行对比,以确认值被允许。
|
||||
- *基于策略控制*:设置项通过一种策略提供的机制来生成该值,这种机制能够确保指定的值落在被允许的这组值中。
|
||||
|
||||
|
||||
|
||||
### RunAsUser
|
||||
|
||||
|
||||
|
||||
- *MustRunAs* - 必须配置一个 `range`。使用该范围内的第一个值作为默认值。验证是否不在配置的该范围内。
|
||||
- *MustRunAsNonRoot* - 要求提交的 Pod 具有非零 `runAsUser` 值,或在镜像中定义了 `USER` 环境变量。不提供默认值。
|
||||
- *RunAsAny* - 没有提供默认值。允许指定任何 `runAsUser` 。
|
||||
|
||||
|
||||
|
||||
### SELinux
|
||||
|
||||
- *MustRunAs* - 如果没有使用预分配的值,必须配置 `seLinuxOptions`。默认使用 `seLinuxOptions`。验证 `seLinuxOptions`。
|
||||
- *RunAsAny* - 没有提供默认值。允许任意指定的 `seLinuxOptions` ID。
|
||||
|
||||
|
||||
|
||||
### SupplementalGroups
|
||||
|
||||
- *MustRunAs* - 至少需要指定一个范围。默认使用第一个范围的最小值。验证所有范围的值。
|
||||
- *RunAsAny* - 没有提供默认值。允许任意指定的 `supplementalGroups` ID。
|
||||
|
||||
|
||||
|
||||
### FSGroup
|
||||
|
||||
- *MustRunAs* - 至少需要指定一个范围。默认使用第一个范围的最小值。验证在第一个范围内的第一个 ID。
|
||||
- *RunAsAny* - 没有提供默认值。允许任意指定的 `fsGroup` ID。
|
||||
|
||||
|
||||
|
||||
### 控制卷
|
||||
|
||||
通过设置 PSP 卷字段,能够控制具体卷类型的使用。当创建一个卷的时候,与该字段相关的已定义卷可以允许设置如下值:
|
||||
|
||||
1. azureFile
|
||||
1. azureDisk
|
||||
1. flocker
|
||||
1. flexVolume
|
||||
1. hostPath
|
||||
1. emptyDir
|
||||
1. gcePersistentDisk
|
||||
1. awsElasticBlockStore
|
||||
1. gitRepo
|
||||
1. secret
|
||||
1. nfs
|
||||
1. iscsi
|
||||
1. glusterfs
|
||||
1. persistentVolumeClaim
|
||||
1. rbd
|
||||
1. cinder
|
||||
1. cephFS
|
||||
1. downwardAPI
|
||||
1. fc
|
||||
1. configMap
|
||||
1. vsphereVolume
|
||||
1. quobyte
|
||||
1. photonPersistentDisk
|
||||
1. projected
|
||||
1. portworxVolume
|
||||
1. scaleIO
|
||||
1. storageos
|
||||
1. \* (allow all volumes)
|
||||
|
||||
|
||||
|
||||
对新的 PSP,推荐允许的卷的最小集合包括:configMap、downwardAPI、emptyDir、persistentVolumeClaim、secret 和 projected。
|
||||
|
||||
|
||||
|
||||
### 主机网络
|
||||
- *HostPorts*, 默认为 `empty`。`HostPortRange` 列表通过 `min`(包含) and `max`(包含) 来定义,指定了被允许的主机端口。
|
||||
|
||||
### 允许的主机路径
|
||||
- *AllowedHostPaths* 是一个被允许的主机路径前缀的白名单。空值表示所有的主机路径都可以使用。
|
||||
|
||||
|
||||
|
||||
## 许可
|
||||
|
||||
包含 `PodSecurityPolicy` 的 _许可控制_,允许控制集群资源的创建和修改,基于这些资源在集群范围内被许可的能力。
|
||||
|
||||
许可使用如下的方式为 Pod 创建最终的安全上下文:
|
||||
1. 检索所有可用的 PSP。
|
||||
1. 生成在请求中没有指定的安全上下文设置的字段值。
|
||||
1. 基于可用的策略,验证最终的设置。
|
||||
|
||||
如果某个策略能够匹配上,该 Pod 就被接受。如果请求与 PSP 不匹配,则 Pod 被拒绝。
|
||||
|
||||
Pod 必须基于 PSP 验证每个字段。
|
||||
|
||||
|
||||
|
||||
## 创建 Pod 安全策略
|
||||
|
||||
下面是一个 Pod 安全策略的例子,所有字段的设置都被允许:
|
||||
|
||||
{{< code file="psp.yaml" >}}
|
||||
|
||||
|
||||
|
||||
下载示例文件可以创建该策略,然后执行如下命令:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./psp.yaml
|
||||
podsecuritypolicy "permissive" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 获取 Pod 安全策略列表
|
||||
|
||||
获取已存在策略列表,使用 `kubectl get`:
|
||||
|
||||
```shell
|
||||
$ kubectl get psp
|
||||
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
|
||||
permissive false [] RunAsAny RunAsAny RunAsAny RunAsAny false [*]
|
||||
privileged true [] RunAsAny RunAsAny RunAsAny RunAsAny false [*]
|
||||
restricted false [] RunAsAny MustRunAsNonRoot RunAsAny RunAsAny false [emptyDir secret downwardAPI configMap persistentVolumeClaim projected]
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 修改 Pod 安全策略
|
||||
|
||||
通过交互方式修改策略,使用 `kubectl edit`:
|
||||
|
||||
```shell
|
||||
$ kubectl edit psp permissive
|
||||
```
|
||||
|
||||
|
||||
|
||||
该命令将打开一个默认文本编辑器,在这里能够修改策略。
|
||||
|
||||
|
||||
|
||||
## 删除 Pod 安全策略
|
||||
|
||||
一旦不再需要一个策略,很容易通过 `kubectl` 删除它:
|
||||
|
||||
```shell
|
||||
$ kubectl delete psp permissive
|
||||
podsecuritypolicy "permissive" deleted
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 启用 Pod 安全策略
|
||||
|
||||
为了能够在集群中使用 Pod 安全策略,必须确保满足如下条件:
|
||||
|
||||
|
||||
|
||||
1. 已经启用 API 类型 `extensions/v1beta1/podsecuritypolicy`(仅对 1.6 之前的版本)
|
||||
1. 已经启用许可控制器 `PodSecurityPolicy`
|
||||
1. 已经定义了自己的策略
|
||||
|
||||
|
||||
|
||||
## 使用 RBAC
|
||||
|
||||
在 Kubernetes 1.5 或更新版本,可以使用 PodSecurityPolicy 来控制,对基于用户角色和组的已授权容器的访问。访问不同的 PodSecurityPolicy 对象,可以基于认证来控制。基于 Deployment、ReplicaSet 等创建的 Pod,限制访问 PodSecurityPolicy 对象,[Controller Manager](/docs/admin/kube-controller-manager/) 必须基于安全 API 端口运行,并且不能够具有超级用户权限。
|
||||
|
||||
PodSecurityPolicy 认证使用所有可用的策略,包括创建 Pod 的用户,Pod 上指定的服务账户(Service Acount)。当 Pod 基于 Deployment、ReplicaSet 创建时,它是创建 Pod 的 Controller Manager,所以如果基于非安全 API 端口运行,允许所有的 PodSecurityPolicy 对象,并且不能够有效地实现细分权限。用户访问给定的 PSP 策略有效,仅当是直接部署 Pod 的情况。更多详情,查看 [PodSecurityPolicy RBAC 示例](https://git.k8s.io/kubernetes/examples/podsecuritypolicy/rbac/README.md),当直接部署 Pod 时,应用 PodSecurityPolicy 控制基于角色和组的已授权容器的访问 。
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: PodSecurityPolicy
|
||||
metadata:
|
||||
name: permissive
|
||||
spec:
|
||||
seLinux:
|
||||
rule: RunAsAny
|
||||
supplementalGroups:
|
||||
rule: RunAsAny
|
||||
runAsUser:
|
||||
rule: RunAsAny
|
||||
fsGroup:
|
||||
rule: RunAsAny
|
||||
hostPorts:
|
||||
- min: 8000
|
||||
max: 8080
|
||||
volumes:
|
||||
- '*'
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
approvers:
|
||||
- derekwaynecarr
|
||||
title: 资源配额
|
||||
---
|
||||
|
||||
当多个用户或团队共享具有固定数目节点的集群时,人们会担心有人使用的资源超出应有的份额。
|
||||
|
||||
资源配额是帮助管理员解决这一问题的工具。
|
||||
|
||||
资源配额, 通过 `ResourceQuota` 对象来定义, 对每个namespace的资源消耗总量提供限制。 它可以按类型限制namespace下可以创建的对象的数量,也可以限制可被该项目以资源形式消耗的计算资源的总量。
|
||||
|
||||
资源配额的工作方式如下:
|
||||
|
||||
- 不同的团队在不同的namespace下工作。 目前这是自愿的, 但计划通过ACL (Access Control List 访问控制列表)
|
||||
使其变为强制性的。
|
||||
- 管理员为每个namespace创建一个或多个资源配额对象。
|
||||
- 用户在namespace下创建资源 (pods、 services等),同时配额系统会跟踪使用情况,来确保其不超过
|
||||
资源配额中定义的硬性资源限额。
|
||||
- 如果资源的创建或更新违反了配额约束,则请求会失败,并返回 HTTP状态码 `403 FORBIDDEN` ,以及说明违反配额
|
||||
约束的信息。
|
||||
- 如果namespace下的计算资源 (如 `cpu` 和 `memory`)的配额被启用,则用户必须为这些资源设定请求值(request)
|
||||
和约束值(limit),否则配额系统将拒绝Pod的创建。
|
||||
提示: 可使用 LimitRange 准入控制器来为没有设置计算资源需求的Pod设置默认值。
|
||||
作为示例,请参考 [演练](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/) 来避免这个问题。
|
||||
|
||||
下面是使用namespace和配额构建策略的示例:
|
||||
|
||||
- 在具有 32 GiB 内存 和 16 核CPU资源的集群中, 允许A团队使用 20 GiB 内存 和 10 核的CPU资源,
|
||||
允许B团队使用 10GiB 内存和 4 核的CPU资源, 并且预留 2GiB 内存和 2 核的CPU资源供将来分配。
|
||||
- 限制 "testing" namespace使用 1 核CPU资源和 1GiB 内存。 允许 "production" namespace使用任意数量。
|
||||
|
||||
在集群容量小于各namespace配额总和的情况下,可能存在资源竞争。 Kubernetes采用先到先服务的方式处理这类问题。
|
||||
|
||||
无论是资源竞争还是配额的变更都不会影响已经创建的资源。
|
||||
|
||||
## 启用资源配额
|
||||
|
||||
资源配额的支持在很多Kubernetes版本中是默认开启的。 当 apiserver 的
|
||||
`--admission-control=` 参数中包含 `ResourceQuota` 时,资源配额会被启用。
|
||||
|
||||
当namespace中存在一个 `ResourceQuota` 对象时,该namespace即开始实施资源配额管理。
|
||||
一个namespace中最多只应存在一个 `ResourceQuota` 对象
|
||||
|
||||
## 计算资源配额
|
||||
|
||||
用户可以对给定namespace下的 [计算资源](/docs/user-guide/compute-resources) 总量进行限制。
|
||||
|
||||
配额机制所支持的资源类型:
|
||||
|
||||
| 资源名称 | 描述 |
|
||||
| --------------------- | ----------------------------------------------------------- |
|
||||
| `cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 |
|
||||
| `limits.cpu` | 所有非终止状态的Pod中,其CPU限额总量不能超过该值。 |
|
||||
| `limits.memory` | 所有非终止状态的Pod中,其内存限额总量不能超过该值。 |
|
||||
| `memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 |
|
||||
| `requests.cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 |
|
||||
| `requests.memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 |
|
||||
|
||||
## 存储资源配额
|
||||
|
||||
用户可以对给定namespace下的 [存储资源](/docs/user-guide/persistent-volumes) 总量进行限制。
|
||||
|
||||
此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。
|
||||
|
||||
| 资源名称 | 描述 |
|
||||
| --------------------- | ----------------------------------------------------------- |
|
||||
| `requests.storage` | 所有的PVC中,存储资源的需求不能超过该值。 |
|
||||
| `persistentvolumeclaims` | namespace中所允许的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 总量。 |
|
||||
| `<storage-class-name>.storageclass.storage.k8s.io/requests.storage` | 所有该storage-class-name相关的PVC中, 存储资源的需求不能超过该值。 |
|
||||
| `<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims` | namespace中所允许的该storage-class-name相关的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的总量。 |
|
||||
|
||||
例如,如果一个操作人员针对 "黄金" 存储类型与 "铜" 存储类型设置配额,操作员可以
|
||||
定义配额如下:
|
||||
|
||||
* `gold.storageclass.storage.k8s.io/requests.storage: 500Gi`
|
||||
* `bronze.storageclass.storage.k8s.io/requests.storage: 100Gi`
|
||||
|
||||
## 对象数量配额
|
||||
|
||||
给定类型的对象数量可以被限制。 支持以下类型:
|
||||
|
||||
| 资源名称 | 描述 |
|
||||
| ------------------------------- | ------------------------------------------------- |
|
||||
| `configmaps` | namespace下允许存在的configmap的数量。 |
|
||||
| `persistentvolumeclaims` | namespace下允许存在的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的数量。 |
|
||||
| `pods` | namespace下允许存在的非终止状态的pod数量。 如果pod 的 `status.phase 为 Failed 或 Succeeded` , 那么其处于终止状态。 |
|
||||
| `replicationcontrollers` | namespace下允许存在的replication controllers的数量。 |
|
||||
| `resourcequotas` | namespace下允许存在的 [resource quotas](/docs/admin/admission-controllers/#resourcequota) 的数量。 |
|
||||
| `services` | namespace下允许存在的service的数量。 |
|
||||
| `services.loadbalancers` | namespace下允许存在的load balancer类型的service的数量。 |
|
||||
| `services.nodeports` | namespace下允许存在的node port类型的service的数量。 |
|
||||
| `secrets` | namespace下允许存在的secret的数量。 |
|
||||
|
||||
例如 `pods` 配额统计并保证单个namespace下创建 `pods` 的最大数量。
|
||||
|
||||
用户可能希望在namespace中为pod设置配额,来避免有用户创建很多小的pod,从而耗尽集群提供的pod IP地址。
|
||||
|
||||
## 配额作用域
|
||||
|
||||
每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。
|
||||
|
||||
当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。
|
||||
如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。
|
||||
|
||||
| 范围 | 描述 |
|
||||
| ----- | ----------- |
|
||||
| `Terminating` | 匹配 `spec.activeDeadlineSeconds >= 0` 的pod。 |
|
||||
| `NotTerminating` | 匹配 `spec.activeDeadlineSeconds is nil` 的pod。 |
|
||||
| `BestEffort` | 匹配"尽力而为(best effort)"服务类型的pod。 |
|
||||
| `NotBestEffort` | 匹配非"尽力而为(best effort)"服务类型的pod。 |
|
||||
|
||||
`BestEffort` 作用域限制配额跟踪以下资源: `pods`
|
||||
|
||||
`Terminating`、 `NotTerminating` 和 `NotBestEffort` 限制配额跟踪以下资源:
|
||||
|
||||
* `cpu`
|
||||
* `limits.cpu`
|
||||
* `limits.memory`
|
||||
* `memory`
|
||||
* `pods`
|
||||
* `requests.cpu`
|
||||
* `requests.memory`
|
||||
|
||||
## 请求/约束
|
||||
|
||||
分配计算资源时,每个容器可以为CPU或内存指定请求和约束。
|
||||
也可以设置两者中的任何一个。
|
||||
|
||||
如果配额中指定了 `requests.cpu` 或 `requests.memory` 的值,那么它要求每个进来的容器针对这些资源有明确的请求。 如果配额中指定了 `limits.cpu` 或 `limits.memory`的值,那么它要求每个进来的容器针对这些资源指定明确的约束。
|
||||
|
||||
## 查看和设置配额
|
||||
|
||||
Kubectl 支持创建、更新和查看配额:
|
||||
|
||||
```shell
|
||||
$ kubectl create namespace myspace
|
||||
|
||||
$ cat <<EOF > compute-resources.yaml
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: compute-resources
|
||||
spec:
|
||||
hard:
|
||||
pods: "4"
|
||||
requests.cpu: "1"
|
||||
requests.memory: 1Gi
|
||||
limits.cpu: "2"
|
||||
limits.memory: 2Gi
|
||||
EOF
|
||||
$ kubectl create -f ./compute-resources.yaml --namespace=myspace
|
||||
|
||||
$ cat <<EOF > object-counts.yaml
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: object-counts
|
||||
spec:
|
||||
hard:
|
||||
configmaps: "10"
|
||||
persistentvolumeclaims: "4"
|
||||
replicationcontrollers: "20"
|
||||
secrets: "10"
|
||||
services: "10"
|
||||
services.loadbalancers: "2"
|
||||
EOF
|
||||
$ kubectl create -f ./object-counts.yaml --namespace=myspace
|
||||
|
||||
$ kubectl get quota --namespace=myspace
|
||||
NAME AGE
|
||||
compute-resources 30s
|
||||
object-counts 32s
|
||||
|
||||
$ kubectl describe quota compute-resources --namespace=myspace
|
||||
Name: compute-resources
|
||||
Namespace: myspace
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 0 2
|
||||
limits.memory 0 2Gi
|
||||
pods 0 4
|
||||
requests.cpu 0 1
|
||||
requests.memory 0 1Gi
|
||||
|
||||
$ kubectl describe quota object-counts --namespace=myspace
|
||||
Name: object-counts
|
||||
Namespace: myspace
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
configmaps 0 10
|
||||
persistentvolumeclaims 0 4
|
||||
replicationcontrollers 0 20
|
||||
secrets 1 10
|
||||
services 0 10
|
||||
services.loadbalancers 0 2
|
||||
```
|
||||
|
||||
## 配额和集群容量
|
||||
|
||||
配额对象是独立于集群容量的。它们通过绝对的单位来表示。 所以,为集群添加节点, *不会*
|
||||
自动赋予每个namespace消耗更多资源的能力。
|
||||
|
||||
有时可能需要更复杂的策略,比如:
|
||||
|
||||
- 在几个团队中按比例划分总的集群资源。
|
||||
- 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止意外资源耗尽。
|
||||
- 在namespace中添加节点、提高配额的额外需求。
|
||||
|
||||
这些策略可以基于 ResourceQuota,通过编写一个检测配额使用,并根据其他信号调整各namespace下的配额硬性限制的 "控制器" 来实现。
|
||||
|
||||
注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自多个namespace的Pod可能在同一节点上运行。
|
||||
|
||||
## 示例
|
||||
|
||||
查看 [如何使用资源配额的详细示例](/docs/tasks/administer-cluster/quota-api-object/)。
|
||||
|
||||
## 更多信息
|
||||
|
||||
查看 [资源配额设计文档](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md) 了解更多信息。
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
---
|
||||
approvers:
|
||||
- rickypai
|
||||
- thockin
|
||||
title: 使用 HostAliases 向 Pod /etc/hosts 文件添加条目
|
||||
redirect_from:
|
||||
- "/docs/user-guide/add-entries-to-pod-etc-hosts-with-host-aliases/"
|
||||
- "/docs/user-guide/add-entries-to-pod-etc-hosts-with-host-aliases.md"
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
当 DNS 配置以及其它选项不合理的时候,通过向 Pod 的 /etc/hosts 文件中添加条目,可以在 Pod 级别覆盖对主机名的解析。在 1.7 版本,用户可以通过 PodSpec 的 HostAliases 字段来添加这些自定义的条目。
|
||||
|
||||
建议通过使用 HostAliases 来进行修改,因为该文件由 Kubelet 管理,并且可以在 Pod 创建/重启过程中被重写。
|
||||
|
||||
|
||||
|
||||
## 默认 hosts 文件内容
|
||||
|
||||
让我们从一个 Nginx Pod 开始,给该 Pod 分配一个 IP:
|
||||
|
||||
```
|
||||
$ kubectl get pods --output=wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
nginx 1/1 Running 0 13s 10.200.0.4 worker0
|
||||
```
|
||||
|
||||
|
||||
|
||||
默认,hosts 文件只包含 ipv4 和 ipv6 的样板内容,像 `localhost` 和主机名称。
|
||||
|
||||
## 通过 HostAliases 增加额外的条目
|
||||
|
||||
|
||||
|
||||
除了默认的样板内容,我们可以向 hosts 文件添加额外的条目,将 `foo.local`、 `bar.local` 解析为`127.0.0.1`,将 `foo.remote`、 `bar.remote` 解析为 `10.1.2.3`,我们可以在 `.spec.hostAliases` 下为 Pod 添加 HostAliases。
|
||||
|
||||
{{< code file="hostaliases-pod.yaml" >}}
|
||||
|
||||
hosts 文件的内容看起来类似如下这样:
|
||||
|
||||
```
|
||||
$ kubectl logs hostaliases-pod
|
||||
# Kubernetes-managed hosts file.
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
fe00::0 ip6-mcastprefix
|
||||
fe00::1 ip6-allnodes
|
||||
fe00::2 ip6-allrouters
|
||||
10.200.0.4 hostaliases-pod
|
||||
127.0.0.1 foo.local
|
||||
127.0.0.1 bar.local
|
||||
10.1.2.3 foo.remote
|
||||
10.1.2.3 bar.remote
|
||||
```
|
||||
|
||||
|
||||
|
||||
在最下面额外添加了一些条目。
|
||||
|
||||
## 限制
|
||||
|
||||
在 1.7 版本,如果 Pod 启用 hostNetwork,那么将不能使用这个特性,因为 kubelet 只管理非 hostNetwork 类型 Pod 的 hosts 文件。目前正在讨论要改变这个情况。
|
||||
|
||||
|
||||
|
||||
## 为什么 Kubelet 管理 hosts文件?
|
||||
|
||||
kubelet [管理](https://github.com/kubernetes/kubernetes/issues/14633) Pod 中每个容器的 hosts 文件,避免 Docker 在容器已经启动之后去 [修改](https://github.com/moby/moby/issues/17190) 该文件。
|
||||
|
||||
因为该文件是托管性质的文件,无论容器重启或 Pod 重新调度,用户修改该 hosts 文件的任何内容,都会在 Kubelet 重新安装后被覆盖。因此,不建议修改该文件的内容。
|
||||
@@ -0,0 +1,371 @@
|
||||
---
|
||||
approvers:
|
||||
- caesarxuchao
|
||||
- lavalamp
|
||||
- thockin
|
||||
title: 应用连接到 Service
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
## Kubernetes 连接容器模型
|
||||
|
||||
既然有了一个持续运行、可复制的应用,我们就能够将它暴露到网络上。
|
||||
在讨论 Kubernetes 网络连接的方式之前,非常值得与 Docker 中 “正常” 方式的网络进行对比。
|
||||
|
||||
|
||||
|
||||
默认情况下,Docker 使用私有主机网络连接,只能与同在一台机器上的容器进行通信。
|
||||
为了实现容器的跨节点通信,必须在机器自己的 IP 上为这些容器分配端口,为容器进行端口转发或者代理。
|
||||
|
||||
多个开发人员之间协调端口的使用很难做到规模化,那些难以控制的集群级别的问题,都会交由用户自己去处理。
|
||||
Kubernetes 假设 Pod 可与其它 Pod 通信,不管它们在哪个主机上。
|
||||
我们给 Pod 分配属于自己的集群私有 IP 地址,所以没必要在 Pod 或映射到的容器的端口和主机端口之间显式地创建连接。
|
||||
这表明了在 Pod 内的容器都能够连接到本地的每个端口,集群中的所有 Pod 不需要通过 NAT 转换就能够互相看到。
|
||||
文档的剩余部分将详述如何在一个网络模型之上运行可靠的服务。
|
||||
|
||||
该指南使用一个简单的 Nginx server 来演示并证明谈到的概念。同样的原则也体现在一个更加完整的 [Jenkins CI 应用](http://blog.kubernetes.io/2015/07/strong-simple-ssl-for-kubernetes.html) 中。
|
||||
|
||||
|
||||
|
||||
## 在集群中暴露 Pod
|
||||
|
||||
我们在之前的示例中已经做过,然而再让我重试一次,这次聚焦在网络连接的视角。
|
||||
创建一个 Nginx Pod,指示它具有一个容器端口的说明:
|
||||
|
||||
{{< code file="run-my-nginx.yaml" >}}
|
||||
|
||||
|
||||
|
||||
这使得可以从集群中任何一个节点来访问它。检查节点,该 Pod 正在运行:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./run-my-nginx.yaml
|
||||
$ kubectl get pods -l run=my-nginx -o wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
my-nginx-3800858182-jr4a2 1/1 Running 0 13s 10.244.3.4 kubernetes-minion-905m
|
||||
my-nginx-3800858182-kna2y 1/1 Running 0 13s 10.244.2.5 kubernetes-minion-ljyd
|
||||
```
|
||||
|
||||
|
||||
|
||||
检查 Pod 的 IP 地址:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods -l run=my-nginx -o yaml | grep podIP
|
||||
podIP: 10.244.3.4
|
||||
podIP: 10.244.2.5
|
||||
```
|
||||
|
||||
|
||||
|
||||
应该能够通过 ssh 登录到集群中的任何一个节点上,使用 curl 也能调通所有 IP 地址。
|
||||
需要注意的是,容器不会使用该节点上的 80 端口,也不会使用任何特定的 NAT 规则去路由流量到 Pod 上。
|
||||
这意味着可以在同一个节点上运行多个 Pod,使用相同的容器端口,并且可以从集群中任何其他的 Pod 或节点上使用 IP 的方式访问到它们。
|
||||
像 Docker 一样,端口能够被发布到主机节点的接口上,但是出于网络模型的原因应该从根本上减少这种用法。
|
||||
|
||||
如果对此好奇,可以获取更多关于 [如何实现网络模型](/docs/concepts/cluster-administration/networking/#how-to-achieve-this) 的内容。
|
||||
|
||||
|
||||
|
||||
## 创建 Service
|
||||
|
||||
我们有 Pod 在一个扁平的、集群范围的地址空间中运行 Nginx 服务,可以直接连接到这些 Pod,但如果某个节点死掉了会发生什么呢?
|
||||
Pod 会终止,Deployment 将创建新的 Pod,且使用不同的 IP。这正是 Service 要解决的问题。
|
||||
|
||||
Kubernetes Service 从逻辑上定义了运行在集群中的一组 Pod,这些 Pod 提供了相同的功能。
|
||||
当每个 Service 创建时,会被分配一个唯一的 IP 地址(也称为 clusterIP)。
|
||||
这个 IP 地址与一个 Service 的生命周期绑定在一起,当 Service 存在的时候它也不会改变。
|
||||
可以配置 Pod 使它与 Service 进行通信,Pod 知道与 Service 通信将被自动地负载均衡到该 Service 中的某些 Pod 上。
|
||||
|
||||
可以使用 `kubectl expose` 命令为 2个 Nginx 副本创建一个 Service:
|
||||
|
||||
```shell
|
||||
$ kubectl expose deployment/my-nginx
|
||||
service "my-nginx" exposed
|
||||
```
|
||||
|
||||
|
||||
|
||||
这等价于使用 `kubectl create -f` 命令创建,对应如下的 yaml 文件:
|
||||
|
||||
{{< code file="nginx-svc.yaml" >}}
|
||||
|
||||
|
||||
|
||||
上述规约将创建一个 Service,对应具有标签 `run: my-nginx` 的 Pod,目标 TCP 端口 80,并且在一个抽象的 Service 端口(`targetPort`:容器接收流量的端口;`port`:抽象的 Service 端口,可以使任何其它 Pod 访问该 Service 的端口)上暴露。
|
||||
查看 [Service API 对象](/docs/api-reference/{{< param "version" >}}/#service-v1-core) 了解 Service 定义支持的字段列表。
|
||||
|
||||
```shell
|
||||
$ kubectl get svc my-nginx
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
my-nginx 10.0.162.149 <none> 80/TCP 21s
|
||||
```
|
||||
|
||||
|
||||
|
||||
正如前面所提到的,一个 Service 由一组 backend Pod 组成。这些 Pod 通过 `endpoints` 暴露出来。
|
||||
Service Selector 将持续评估,结果被 POST 到一个名称为 `my-nginx` 的 Endpoint 对象上。
|
||||
当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。
|
||||
检查该 Endpoint,注意到 IP 地址与在第一步创建的 Pod 是相同的。
|
||||
|
||||
```shell
|
||||
$ kubectl describe svc my-nginx
|
||||
Name: my-nginx
|
||||
Namespace: default
|
||||
Labels: run=my-nginx
|
||||
Selector: run=my-nginx
|
||||
Type: ClusterIP
|
||||
IP: 10.0.162.149
|
||||
Port: <unset> 80/TCP
|
||||
Endpoints: 10.244.2.5:80,10.244.3.4:80
|
||||
Session Affinity: None
|
||||
No events.
|
||||
|
||||
$ kubectl get ep my-nginx
|
||||
NAME ENDPOINTS AGE
|
||||
my-nginx 10.244.2.5:80,10.244.3.4:80 1m
|
||||
```
|
||||
|
||||
|
||||
|
||||
现在,能够从集群中任意节点上使用 curl 命令请求 Nginx Service `<CLUSTER-IP>:<PORT>` 。
|
||||
注意 Service IP 完全是虚拟的,它从来没有走过网络,如果对它如何工作的原理感到好奇,可以阅读更多关于 [服务代理](/docs/user-guide/services/#virtual-ips-and-service-proxies) 的内容。
|
||||
|
||||
|
||||
|
||||
## 访问 Service
|
||||
|
||||
Kubernetes 支持两种主要的服务发现模式 —— 环境变量和 DNS。前者在单个节点上可用使用,然而后者必须使用 [kube-dns 集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md)。
|
||||
|
||||
|
||||
|
||||
### 环境变量
|
||||
|
||||
当 Pod 在 Node 上运行时,kubelet 会为每个活跃的 Service 添加一组环境变量。这会有一个顺序的问题。想了解为何,检查正在运行的 Nginx Pod 的环境变量(Pod 名称将不会相同):
|
||||
|
||||
```shell
|
||||
$ kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
|
||||
KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||
```
|
||||
|
||||
|
||||
|
||||
注意,还没有谈及到 Service。这是因为创建副本先于 Service。
|
||||
这样做的另一个缺点是,调度器可能在同一个机器上放置所有 Pod,如果该机器宕机则所有的 Service 都会挂掉。
|
||||
正确的做法是,我们杀掉 2 个 Pod,等待 Deployment 去创建它们。
|
||||
这次 Service 会 *先于* 副本存在。这将实现调度器级别的 Service,能够使 Pod 分散创建(假定所有的 Node 都具有同样的容量),以及正确的环境变量:
|
||||
|
||||
```shell
|
||||
$ kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;
|
||||
|
||||
$ kubectl get pods -l run=my-nginx -o wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
my-nginx-3800858182-e9ihh 1/1 Running 0 5s 10.244.2.7 kubernetes-minion-ljyd
|
||||
my-nginx-3800858182-j4rm4 1/1 Running 0 5s 10.244.3.8 kubernetes-minion-905m
|
||||
```
|
||||
|
||||
|
||||
|
||||
可能注意到,Pod 具有不同的名称,因为它们被杀掉后并被重新创建。
|
||||
|
||||
```shell
|
||||
$ kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
MY_NGINX_SERVICE_HOST=10.0.162.149
|
||||
KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
MY_NGINX_SERVICE_PORT=80
|
||||
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||
```
|
||||
|
||||
### DNS
|
||||
|
||||
|
||||
|
||||
Kubernetes 提供了一个 DNS 插件 Service,它使用 skydns 自动为其它 Service 指派 DNS 名字。
|
||||
如果它在集群中处于运行状态,可以通过如下命令来检查:
|
||||
|
||||
```shell
|
||||
$ kubectl get services kube-dns --namespace=kube-system
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 8m
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果没有在运行,可以 [启用它](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md#how-do-i-configure-it)。
|
||||
本段剩余的内容,将假设已经有一个 Service,它具有一个长久存在的 IP(my-nginx),一个为该 IP 指派名称的 DNS 服务器(kube-dns 集群插件),所以可以通过标准做法,使在集群中的任何 Pod 都能与该 Service 通信(例如:gethostbyname)。
|
||||
让我们运行另一个 curl 应用来进行测试:
|
||||
|
||||
```shell
|
||||
$ kubectl run curl --image=radial/busyboxplus:curl -i --tty
|
||||
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
|
||||
Hit enter for command prompt
|
||||
```
|
||||
|
||||
|
||||
然后,按回车并执行命令 `nslookup my-nginx`:
|
||||
|
||||
```shell
|
||||
[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10
|
||||
|
||||
Name: my-nginx
|
||||
Address 1: 10.0.162.149
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Service 安全
|
||||
|
||||
到现在为止,我们只在集群内部访问了 Nginx server。在将 Service 暴露到 Internet 之前,我们希望确保通信信道是安全的。对于这可能需要:
|
||||
|
||||
|
||||
|
||||
* https 自签名证书(除非已经有了一个识别身份的证书)
|
||||
* 使用证书配置的 Nginx server
|
||||
* 使证书可以访问 Pod 的[秘钥](/docs/user-guide/secrets)
|
||||
|
||||
可以从 [Nginx https 示例](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/examples/https-nginx/) 获取所有上述内容,简明示例如下:
|
||||
|
||||
```shell
|
||||
$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
|
||||
$ kubectl create -f /tmp/secret.json
|
||||
secret "nginxsecret" created
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA AGE
|
||||
default-token-il9rc kubernetes.io/service-account-token 1 1d
|
||||
nginxsecret Opaque 2 1m
|
||||
```
|
||||
|
||||
|
||||
|
||||
现在修改 Nginx 副本,启动一个使用在秘钥中的证书的 https 服务器和 Servcie,都暴露端口(80 和 443):
|
||||
|
||||
{{< code file="nginx-secure-app.yaml" >}}
|
||||
|
||||
|
||||
|
||||
关于 nginx-secure-app manifest 值得注意的点如下:
|
||||
|
||||
|
||||
|
||||
- 它在相同的文件中包含了 Deployment 和 Service 的规格
|
||||
- [Nginx server](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/examples/https-nginx/default.conf) 处理 80 端口上的 http 流量,以及 443 端口上的 https 流量,Nginx Service 暴露了这两个端口。
|
||||
- 每个容器访问挂载在 /etc/nginx/ssl 卷上的秘钥。这需要在 Nginx server 启动之前安装好。
|
||||
|
||||
```shell
|
||||
$ kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
这时可以从任何节点访问到 Nginx server。
|
||||
|
||||
```shell
|
||||
$ kubectl get pods -o yaml | grep -i podip
|
||||
podIP: 10.244.3.5
|
||||
node $ curl -k https://10.244.3.5
|
||||
...
|
||||
<h1>Welcome to nginx!</h1>
|
||||
```
|
||||
|
||||
|
||||
|
||||
注意最后一步我们是如何提供 `-k` 参数执行 curl命令的,这是因为在证书生成时,我们不知道任何关于运行 Nginx 的 Pod 的信息,所以不得不在执行 curl 命令时忽略 CName 不匹配的情况。
|
||||
通过创建 Service,我们连接了在证书中的 CName 与在 Service 查询时被 Pod使用的实际 DNS 名字。
|
||||
让我们从一个 Pod 来测试(为了简化使用同一个秘钥,Pod 仅需要使用 nginx.crt 去访问 Service):
|
||||
|
||||
{{< code file="curlpod.yaml" >}}
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./curlpod.yaml
|
||||
$ kubectl get pods -l app=curlpod
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
curl-deployment-1515033274-1410r 1/1 Running 0 1m
|
||||
$ kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt
|
||||
...
|
||||
<title>Welcome to nginx!</title>
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## 暴露 Service
|
||||
|
||||
对我们应用的某些部分,可能希望将 Service 暴露在一个外部 IP 地址上。
|
||||
Kubernetes 支持两种实现方式:NodePort 和 LoadBalancer。
|
||||
在上一段创建的 Service 使用了 `NodePort`,因此 Nginx https 副本已经就绪,如果使用一个公网 IP,能够处理 Internet 上的流量。
|
||||
|
||||
```shell
|
||||
$ kubectl get svc my-nginx -o yaml | grep nodePort -C 5
|
||||
uid: 07191fb3-f61a-11e5-8ae5-42010af00002
|
||||
spec:
|
||||
clusterIP: 10.0.162.149
|
||||
ports:
|
||||
- name: http
|
||||
nodePort: 31704
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
- name: https
|
||||
nodePort: 32453
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 443
|
||||
selector:
|
||||
run: my-nginx
|
||||
|
||||
$ kubectl get nodes -o yaml | grep ExternalIP -C 1
|
||||
- address: 104.197.41.11
|
||||
type: ExternalIP
|
||||
allocatable:
|
||||
--
|
||||
- address: 23.251.152.56
|
||||
type: ExternalIP
|
||||
allocatable:
|
||||
...
|
||||
|
||||
$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
|
||||
...
|
||||
<h1>Welcome to nginx!</h1>
|
||||
```
|
||||
|
||||
|
||||
|
||||
让我们重新创建一个 Service,使用一个云负载均衡器,只需要将 `my-nginx` Service 的 `Type` 由 `NodePort` 改成 `LoadBalancer`。
|
||||
|
||||
```shell
|
||||
$ kubectl edit svc my-nginx
|
||||
$ kubectl get svc my-nginx
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
my-nginx 10.0.162.149 162.222.184.144 80/TCP,81/TCP,82/TCP 21s
|
||||
|
||||
$ curl https://<EXTERNAL-IP> -k
|
||||
...
|
||||
<title>Welcome to nginx!</title>
|
||||
```
|
||||
|
||||
|
||||
|
||||
在 `EXTERNAL-IP` 列指定的 IP 地址是在公网上可用的。`CLUSTER-IP` 只在集群/私有云网络中可用。
|
||||
|
||||
注意,在 AWS 上类型 `LoadBalancer` 创建一个 ELB,它使用主机名(比较长),而不是 IP。
|
||||
它太长以至于不能适配标准 `kubectl get svc` 的输出,事实上需要通过执行 `kubectl describe service my-nginx` 命令来查看它。
|
||||
可以看到类似如下内容:
|
||||
|
||||
```shell
|
||||
$ kubectl describe service my-nginx
|
||||
...
|
||||
LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
|
||||
...
|
||||
```
|
||||
|
||||
## 进一步阅读
|
||||
|
||||
Kubernetes 也支持联合 Service,能够跨多个集群和云提供商,为 Service 提供逐步增强的可用性、更优的容错、更好的可伸缩性。
|
||||
查看 [联合 Service 用户指南](/docs/concepts/cluster-administration/federation-service-discovery/) 获取更进一步信息。
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: curl-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: curlpod
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: nginxsecret
|
||||
containers:
|
||||
- name: curlpod
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- while true; do sleep 1; done
|
||||
image: radial/busyboxplus:curl
|
||||
volumeMounts:
|
||||
- mountPath: /etc/nginx/ssl
|
||||
name: secret-volume
|
||||
@@ -0,0 +1,419 @@
|
||||
---
|
||||
approvers:
|
||||
- davidopp
|
||||
- thockin
|
||||
title: DNS Pod 与 Service
|
||||
redirect_from:
|
||||
- "/docs/admin/dns/"
|
||||
- "/docs/admin/dns.html"
|
||||
---
|
||||
|
||||
|
||||
|
||||
## 介绍
|
||||
|
||||
Kubernetes 从 1.3 版本起, DNS 是内置的服务,通过插件管理器 [集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/README.md) 自动被启动。
|
||||
|
||||
Kubernetes DNS 在集群中调度 DNS Pod 和 Service ,配置 kubelet 以通知个别容器使用 DNS Service 的 IP 解析 DNS 名字。
|
||||
|
||||
|
||||
|
||||
|
||||
## 怎样获取 DNS 名字?
|
||||
|
||||
在集群中定义的每个 Service(包括 DNS 服务器自身)都会被指派一个 DNS 名称。
|
||||
默认,一个客户端 Pod 的 DNS 搜索列表将包含该 Pod 自己的 Namespace 和集群默认域。
|
||||
通过如下示例可以很好地说明:
|
||||
|
||||
假设在 Kubernetes 集群的 Namespace `bar` 中,定义了一个Service `foo`。
|
||||
运行在Namespace `bar` 中的一个 Pod,可以简单地通过 DNS 查询 `foo` 来找到该 Service。
|
||||
运行在 Namespace `quux` 中的一个 Pod 可以通过 DNS 查询 `foo.bar` 找到该 Service。
|
||||
|
||||
|
||||
|
||||
## 支持的 DNS 模式
|
||||
|
||||
下面各段详细说明支持的记录类型和布局。
|
||||
如果任何其它的布局、名称或查询,碰巧也能够使用,这就需要研究下它们的实现细节,以免后续修改它们又不能使用了。
|
||||
|
||||
|
||||
|
||||
### Service
|
||||
|
||||
#### A 记录
|
||||
|
||||
“正常” Service(除了 Headless Service)会以 `my-svc.my-namespace.svc.cluster.local` 这种名字的形式被指派一个 DNS A 记录。这会解析成该 Service 的 Cluster IP。
|
||||
|
||||
“Headless” Service(没有Cluster IP)也会以 `my-svc.my-namespace.svc.cluster.local` 这种名字的形式被指派一个 DNS A 记录。
|
||||
不像正常 Service,它会解析成该 Service 选择的一组 Pod 的 IP。
|
||||
希望客户端能够使用这一组 IP,否则就使用标准的 round-robin 策略从这一组 IP 中进行选择。
|
||||
|
||||
|
||||
|
||||
#### SRV 记录
|
||||
|
||||
命名端口需要创建 SRV 记录,这些端口是正常 Service或 [Headless
|
||||
Services](/docs/concepts/services-networking/service/#headless-services) 的一部分。
|
||||
对每个命名端口,SRV 记录具有 `_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local` 这种形式。
|
||||
对普通 Service,这会被解析成端口号和 CNAME:`my-svc.my-namespace.svc.cluster.local`。
|
||||
对 Headless Service,这会被解析成多个结果,Service 对应的每个 backend Pod 各一个,包含 `auto-generated-name.my-svc.my-namespace.svc.cluster.local` 这种形式 Pod 的端口号和 CNAME。
|
||||
|
||||
#### 后向兼容性
|
||||
|
||||
上一版本的 kube-dns 使用 `my-svc.my-namespace.cluster.local` 这种形式的名字(后续会增加 'svc' 这一级),以后这将不再被支持。
|
||||
|
||||
|
||||
|
||||
### Pod
|
||||
|
||||
#### A 记录
|
||||
|
||||
如果启用,Pod 会以 `pod-ip-address.my-namespace.pod.cluster.local` 这种形式被指派一个 DNS A 记录。
|
||||
|
||||
例如,`default` Namespace 具有 DNS 名字 `cluster.local`,在该 Namespace 中一个 IP 为 `1.2.3.4` 的 Pod 将具有一个条目:`1-2-3-4.default.pod.cluster.local`。
|
||||
|
||||
|
||||
|
||||
#### 基于 Pod hostname、subdomain 字段的 A 记录和主机名
|
||||
|
||||
当前,创建 Pod 后,它的主机名是该 Pod 的 `metadata.name` 值。
|
||||
|
||||
在 v1.2 版本中,用户可以配置 Pod annotation, 通过 `pod.beta.kubernetes.io/hostname` 来设置 Pod 的主机名。
|
||||
如果为 Pod 配置了 annotation,会优先使用 Pod 的名称作为主机名。
|
||||
例如,给定一个 Pod,它具有 annotation `pod.beta.kubernetes.io/hostname: my-pod-name`,该 Pod 的主机名被设置为 “my-pod-name”。
|
||||
|
||||
|
||||
|
||||
在 v1.3 版本中,PodSpec 具有 `hostname` 字段,可以用来指定 Pod 的主机名。这个字段的值优先于 annotation `pod.beta.kubernetes.io/hostname`。
|
||||
在 v1.2 版本中引入了 beta 特性,用户可以为 Pod 指定 annotation,其中 `pod.beta.kubernetes.io/subdomain` 指定了 Pod 的子域名。
|
||||
最终的域名将是 “<hostname>.<subdomain>.<pod namespace>.svc.<cluster domain>”。
|
||||
举个例子,Pod 的主机名 annotation 设置为 “foo”,子域名 annotation 设置为 “bar”,在 Namespace “my-namespace” 中对应的 FQDN 为 “foo.bar.my-namespace.svc.cluster.local”。
|
||||
|
||||
|
||||
|
||||
在 v1.3 版本中,PodSpec 具有 `subdomain` 字段,可以用来指定 Pod 的子域名。
|
||||
这个字段的值优先于 annotation `pod.beta.kubernetes.io/subdomain` 的值。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: default-subdomain
|
||||
spec:
|
||||
selector:
|
||||
name: busybox
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: foo # Actually, no port is needed.
|
||||
port: 1234
|
||||
targetPort: 1234
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox1
|
||||
labels:
|
||||
name: busybox
|
||||
spec:
|
||||
hostname: busybox-1
|
||||
subdomain: default-subdomain
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
name: busybox
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox2
|
||||
labels:
|
||||
name: busybox
|
||||
spec:
|
||||
hostname: busybox-2
|
||||
subdomain: default-subdomain
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
name: busybox
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果 Headless Service 与 Pod 在同一个 Namespace 中,它们具有相同的子域名,集群的 KubeDNS 服务器也会为该 Pod 的完整合法主机名返回 A 记录。
|
||||
在同一个 Namespace 中,给定一个主机名为 “busybox-1” 的 Pod,子域名设置为 “default-subdomain”,名称为 “default-subdomain” 的 Headless Service ,Pod 将看到自己的 FQDN 为 “busybox-1.default-subdomain.my-namespace.svc.cluster.local”。
|
||||
DNS 会为那个名字提供一个 A 记录,指向该 Pod 的 IP。
|
||||
“busybox1” 和 “busybox2” 这两个 Pod 分别具有它们自己的 A 记录。
|
||||
|
||||
|
||||
|
||||
在Kubernetes v1.2 版本中,`Endpoints` 对象也具有 annotation `endpoints.beta.kubernetes.io/hostnames-map`。
|
||||
它的值是 map[string(IP)][endpoints.HostRecord] 的 JSON 格式,例如: '{"10.245.1.6":{HostName: "my-webserver"}}'。
|
||||
|
||||
如果是 Headless Service 的 `Endpoints`,会以 <hostname>.<service name>.<pod namespace>.svc.<cluster domain> 的格式创建 A 记录。
|
||||
对示例中的 JSON 字符串,如果 `Endpoints` 是为名称为 “bar” 的 Headless Service 而创建的,其中一个 `Endpoints` 的 IP 是 “10.245.1.6”,则会创建一个名称为 “my-webserver.bar.my-namespace.svc.cluster.local” 的 A 记录,该 A 记录查询将返回 “10.245.1.6”。
|
||||
|
||||
`Endpoints` annotation 通常没必要由最终用户指定,但可以被内部的 Service Controller 用来提供上述功能。
|
||||
|
||||
|
||||
|
||||
在 v1.3 版本中,`Endpoints` 对象可以为任何 endpoint 指定 `hostname` 和 IP。
|
||||
`hostname` 字段优先于通过 `endpoints.beta.kubernetes.io/hostnames-map` annotation 指定的主机名。
|
||||
|
||||
在 v1.3 版本中,下面的 annotation 是过时的:`pod.beta.kubernetes.io/hostname`、`pod.beta.kubernetes.io/subdomain`、`endpoints.beta.kubernetes.io/hostnames-map`。
|
||||
|
||||
|
||||
|
||||
## 如何测试它是否可以使用?
|
||||
|
||||
### 创建一个简单的 Pod 作为测试环境
|
||||
|
||||
创建 `busybox.yaml` 文件,内容如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: busybox
|
||||
restartPolicy: Always
|
||||
```
|
||||
|
||||
|
||||
|
||||
然后,用该文件创建一个 Pod:
|
||||
|
||||
```
|
||||
kubectl create -f busybox.yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 等待这个 Pod 变成运行状态
|
||||
|
||||
获取它的状态,执行如下命令:
|
||||
|
||||
```
|
||||
kubectl get pods busybox
|
||||
```
|
||||
|
||||
|
||||
|
||||
可以看到如下内容:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
busybox 1/1 Running 0 <some-time>
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 验证 DNS 已经生效
|
||||
|
||||
一旦 Pod 处于运行中状态,可以在测试环境中执行如下 nslookup 查询:
|
||||
|
||||
```
|
||||
kubectl exec -ti busybox -- nslookup kubernetes.default
|
||||
```
|
||||
|
||||
|
||||
|
||||
可以看到类似如下的内容:
|
||||
|
||||
```
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10
|
||||
|
||||
Name: kubernetes.default
|
||||
Address 1: 10.0.0.1
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果看到了,说明 DNS 已经可以正确工作了。
|
||||
|
||||
### 问题排查技巧
|
||||
|
||||
如果执行 nslookup 命令失败,检查如下内容:
|
||||
|
||||
#### 先检查本地 DNS 配置
|
||||
|
||||
查看配置文件 resolv.conf。(关于更多信息,参考下面的 “从 Node 继承 DNS” 和 “已知问题”。)
|
||||
|
||||
```
|
||||
kubectl exec busybox cat /etc/resolv.conf
|
||||
```
|
||||
|
||||
|
||||
|
||||
按照如下方法(注意搜索路径可能会因为云提供商不同而变化)验证搜索路径和 Name Server 的建立:
|
||||
|
||||
```
|
||||
search default.svc.cluster.local svc.cluster.local cluster.local google.internal c.gce_project_id.internal
|
||||
nameserver 10.0.0.10
|
||||
options ndots:5
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 快速诊断
|
||||
|
||||
出现类似如下指示的错误,说明 kube-dns 插件或相关 Service 存在问题:
|
||||
|
||||
```
|
||||
$ kubectl exec -ti busybox -- nslookup kubernetes.default
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10
|
||||
|
||||
nslookup: can't resolve 'kubernetes.default'
|
||||
```
|
||||
|
||||
|
||||
|
||||
或者
|
||||
|
||||
```
|
||||
$ kubectl exec -ti busybox -- nslookup kubernetes.default
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
|
||||
|
||||
nslookup: can't resolve 'kubernetes.default'
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 检查是否 DNS Pod 正在运行
|
||||
|
||||
使用 `kubectl get pods` 命令验证 DNS Pod 正在运行:
|
||||
|
||||
```
|
||||
kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
|
||||
```
|
||||
|
||||
|
||||
|
||||
应该能够看到类似如下信息:
|
||||
|
||||
```
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
...
|
||||
kube-dns-v19-ezo1y 3/3 Running 0 1h
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果看到没有 Pod 运行,或 Pod 失败/结束,DNS 插件不能默认部署到当前的环境,必须手动部署。
|
||||
|
||||
#### 检查 DNS Pod 中的错误信息
|
||||
|
||||
使用 `kubectl logs` 命令查看 DNS 后台进程的日志:
|
||||
|
||||
```
|
||||
kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c kubedns
|
||||
kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c dnsmasq
|
||||
kubectl logs --namespace=kube-system $(kubectl get pods --namespace=kube-system -l k8s-app=kube-dns -o name) -c healthz
|
||||
```
|
||||
|
||||
|
||||
|
||||
查看是否有任何可疑的日志。在行开头的字母 W、E、F 分别表示 警告、错误、失败。请搜索具有这些日志级别的日志行,通过 [Kubernetes 问题](https://github.com/kubernetes/kubernetes/issues) 报告意外的错误。
|
||||
|
||||
#### DNS 服务是否运行?
|
||||
|
||||
通过使用 `kubectl get service` 命令,验证 DNS 服务是否运行:
|
||||
|
||||
```
|
||||
kubectl get svc --namespace=kube-system
|
||||
```
|
||||
|
||||
|
||||
|
||||
应该能够看到:
|
||||
|
||||
```
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
...
|
||||
kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 1h
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果服务已经创建,或在这个例子中默认被创建,但是并没有看到,可以查看 [调试 Service 页面](/docs/tasks/debug-application-cluster/debug-service/) 获取更多信息。
|
||||
|
||||
```
|
||||
kubectl get ep kube-dns --namespace=kube-system
|
||||
```
|
||||
|
||||
|
||||
|
||||
应该能够看到类似如下信息:
|
||||
|
||||
```
|
||||
NAME ENDPOINTS AGE
|
||||
kube-dns 10.180.3.17:53,10.180.3.17:53 1h
|
||||
```
|
||||
|
||||
|
||||
|
||||
如果没有看到 Endpoint,查看 [调试 Service 文档](/docs/tasks/debug-application-cluster/debug-service/) 中的 Endpoint 段内容。
|
||||
|
||||
关于更多 Kubernetes DNS 的示例,参考 Kubernetes GitHub 仓库中 [集群 DNS 示例](https://git.k8s.io/kubernetes/examples/cluster-dns)。
|
||||
|
||||
## Kubernetes Federation(多 Zone 支持)
|
||||
|
||||
在1.3 发行版本中,为多站点 Kubernetes 安装引入了集群 Federation 支持。这需要对 Kubernetes 集群 DNS 服务器处理 DNS 查询的方式,做出一些微小(后向兼容)改变,从而便利了对联合 Service 的查询(跨多个 Kubernetes 集群)。参考 [集群 Federation 管理员指南](/docs/concepts/cluster-administration/federation/) 获取更多关于集群 Federation 和多站点支持的细节。
|
||||
|
||||
|
||||
|
||||
## 工作原理
|
||||
|
||||
运行的 Kubernetes DNS Pod 包含 3 个容器 —— kubedns、dnsmasq 和负责健康检查的 healthz。
|
||||
kubedns 进程监视 Kubernetes master 对 Service 和 Endpoint 操作的变更,并维护一个内存查询结构去处理 DNS 请求。dnsmasq 容器增加了一个 DNS 缓存来改善性能。为执行对 dnsmasq 和 kubedns 的健康检查,healthz 容器提供了一个单独的健康检查 Endpoint。
|
||||
|
||||
DNS Pod 通过一个静态 IP 暴露为一个 Service。一旦 IP 被分配,kubelet 会通过 `--cluster-dns=10.0.0.10` 标志将配置的 DNS 传递给每一个容器。
|
||||
|
||||
DNS 名字也需要域名,本地域名是可配置的,在 kubelet 中使用 `--cluster-domain=<default local domain>` 标志。
|
||||
|
||||
Kubernetes 集群 DNS 服务器(根据 [SkyDNS](https://github.com/skynetservices/skydns) 库)支持正向查询(A 记录),Service 查询(SRV 记录)和反向 IP 地址查询(PTR 记录)。
|
||||
|
||||
|
||||
|
||||
## 从 Node 继承 DNS
|
||||
当运行 Pod 时,kubelet 将集群 DNS 服务器和搜索路径追加到 Node 自己的 DNS 设置中。如果 Node 能够在大型环境中解析 DNS 名字,Pod 也应该没问题。参考下面 "已知问题” 中给出的更多说明。
|
||||
|
||||
如果不想这样,或者希望 Pod 有一个不同的 DNS 配置,可以使用 kubelet 的 `--resolv-conf` 标志。设置为 "" 表示 Pod 将不继承自 DNS。设置为一个合法的文件路径,表示 kubelet 将使用这个文件而不是 `/etc/resolv.conf` 。
|
||||
|
||||
|
||||
|
||||
## 已知问题
|
||||
|
||||
Kubernetes 安装但并不配置 Node 的 resolv.conf 文件,而是默认使用集群 DNS的,因为那个过程本质上就是和特定的发行版本相关的。最终应该会被实现。
|
||||
|
||||
Linux libc 在限制为3个 DNS `nameserver` 记录和3个 DNS `search` 记录是不可能卡住的([查看 2005 年的一个 Bug](https://bugzilla.redhat.com/show_bug.cgi?id=168253))。Kubernetes 需要使用1个 `nameserver` 记录和3个 `search` 记录。这意味着如果本地安装已经使用了3个 `nameserver` 或使用了3个以上 `search`,那些设置将会丢失。作为部分解决方法, Node 可以运行 `dnsmasq` ,它能提供更多 `nameserver` 条目,但不能运行更多 `search` 条目。可以使用 kubelet 的 `--resolv-conf` 标志。
|
||||
|
||||
如果使用 3.3 版本的 Alpine 或更早版本作为 base 镜像,由于 Alpine 的一个已知问题,DNS 可能不会正确工作。查看 [这里](https://github.com/kubernetes/kubernetes/issues/30215) 获取更多信息。
|
||||
|
||||
|
||||
|
||||
## 参考
|
||||
|
||||
- [DNS 集群插件文档](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md)
|
||||
|
||||
|
||||
|
||||
## 下一步
|
||||
|
||||
- [集群中 DNS Service 自动伸缩](/docs/tasks/administer-cluster/dns-horizontal-autoscaling/)
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: hostaliases-pod
|
||||
spec:
|
||||
hostAliases:
|
||||
- ip: "127.0.0.1"
|
||||
hostnames:
|
||||
- "foo.local"
|
||||
- "bar.local"
|
||||
- ip: "10.1.2.3"
|
||||
hostnames:
|
||||
- "foo.remote"
|
||||
- "bar.remote"
|
||||
containers:
|
||||
- name: cat-hosts
|
||||
image: busybox
|
||||
command:
|
||||
- cat
|
||||
args:
|
||||
- "/etc/hosts"
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test-ingress
|
||||
spec:
|
||||
backend:
|
||||
serviceName: testsvc
|
||||
servicePort: 80
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
approvers:
|
||||
- thockin
|
||||
- caseydavenport
|
||||
- danwinship
|
||||
title: 网络策略
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
网络策略(NetworkPolicy)是一种关于pod间及pod与其他网络端点间所允许的通信规则的规范。
|
||||
|
||||
`NetworkPolicy` 资源使用标签选择pod,并定义选定pod所允许的通信规则。
|
||||
|
||||
## 前提
|
||||
|
||||
网络策略通过网络插件来实现,所以用户必须使用支持 `NetworkPolicy` 的网络解决方案 - 简单地创建资源对象,而没有控制器来使它生效的话,是没有任何作用的。
|
||||
|
||||
## 隔离和非隔离的Pod
|
||||
|
||||
默认情况下,Pod是非隔离的,它们接受任何来源的流量。
|
||||
|
||||
Pod可以通过相关的网络策略进行隔离。一旦命名空间中有网络策略选择了特定的Pod,该Pod会拒绝网络策略所不允许的连接。 (命名空间下其他未被网络策略所选择的Pod会继续接收所有的流量)
|
||||
|
||||
## `NetworkPolicy` 资源
|
||||
|
||||
通过[api参考](/docs/api-reference/{{< param "version" >}}/#networkpolicy-v1-networking)来了解资源定义。
|
||||
|
||||
下面是一个 `NetworkPolicy` 的示例:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: test-network-policy
|
||||
namespace: default
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
role: db
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
project: myproject
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
role: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
```
|
||||
|
||||
除非选择支持网络策略的网络解决方案,否则将上述示例发送到API服务器没有任何效果。
|
||||
|
||||
__必填字段__: 与所有其他的Kubernetes配置一样,`NetworkPolicy` 需要 `apiVersion`、 `kind`和 `metadata` 字段。 关于配置文件操作的一般信息,请参考 [这里](/docs/user-guide/simple-yaml)、 [这里](/docs/user-guide/configuring-containers)和 [这里](/docs/user-guide/working-with-resources)。
|
||||
|
||||
__spec__: `NetworkPolicy` [spec](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status) 中包含了在一个命名空间中定义特定网络策略所需的所有信息
|
||||
|
||||
__podSelector__: 每个 `NetworkPolicy` 都包括一个 `podSelector` ,它对该策略所应用的一组Pod进行选择。因为 `NetworkPolicy` 目前只支持定义 `ingress` 规则,这里的 `podSelector` 本质上是为该策略定义 "目标pod" 。示例中的策略选择带有 "role=db" 标签的pod。空的 `podSelector` 选择命名空间下的所有pod。
|
||||
|
||||
__ingress__: 每个 `NetworkPolicy` 包含一个 `ingress` 规则的白名单列表。 (其中的)规则允许同时匹配 `from` 和 `ports` 部分的流量。示例策略中包含一条简单的规则: 它匹配一个单一的端口,来自两个来源中的一个, 第一个通过 `namespaceSelector` 指定,第二个通过 `podSelector` 指定。
|
||||
|
||||
所以,示例网络策略:
|
||||
|
||||
1. 隔离 "default" 命名空间下 "role=db" 的pod (如果它们不是已经被隔离的话)。
|
||||
2. 允许从 "default" 命名空间下带有 "role=frontend" 标签的pod到 "default" 命名空间下的pod的6379 TCP端口的连接。
|
||||
3. 允许从带有 "project=myproject" 标签的命名空间下的任何pod到 "default" 命名空间下的pod的6379 TCP端口的连接。
|
||||
|
||||
查看 [网络策略入门指南](/docs/getting-started-guides/network-policy/walkthrough) 了解更多示例。
|
||||
|
||||
## 默认策略
|
||||
|
||||
用户可以通过创建一个选择所有Pod,但是不允许任何通信的网络策略,来为一个命名空间创建 "默认的" 隔离策略:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny
|
||||
spec:
|
||||
podSelector:
|
||||
```
|
||||
|
||||
这可以确保即使Pod在未被其他任何网络策略所选择的情况下仍能被隔离。
|
||||
|
||||
或者,如果用户希望允许一个命名空间下的所有Pod的所有通信 (即使已经添加了策略,使得一些pod被 "隔离"),仍可以创建一个明确允许所有通信的策略:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-all
|
||||
spec:
|
||||
podSelector:
|
||||
ingress:
|
||||
- {}
|
||||
```
|
||||
|
||||
## 下一步呢?
|
||||
|
||||
- 查看 [声明网络策略](/docs/tasks/administer-cluster/declare-network-policy/)
|
||||
来进行更多的示例演练
|
||||
@@ -0,0 +1,46 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 80
|
||||
protocol: TCP
|
||||
name: http
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
run: my-nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
run: my-nginx
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: nginxsecret
|
||||
containers:
|
||||
- name: nginxhttps
|
||||
image: bprashanth/nginxhttps:1.0
|
||||
ports:
|
||||
- containerPort: 443
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- mountPath: /etc/nginx/ssl
|
||||
name: secret-volume
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
selector:
|
||||
run: my-nginx
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
run: my-nginx
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: my-nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
@@ -0,0 +1,630 @@
|
||||
---
|
||||
approvers:
|
||||
- bprashanth
|
||||
title: Service
|
||||
redirect_from:
|
||||
- "/docs/user-guide/services/"
|
||||
- "/docs/user-guide/services/index.html"
|
||||
---
|
||||
|
||||
|
||||
|
||||
Kubernetes [`Pod`](/docs/user-guide/pods) 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。
|
||||
通过 [`ReplicationController`](/docs/user-guide/replication-controller) 能够动态地创建和销毁 `Pod`(例如,需要进行扩缩容,或者执行 [滚动升级](/docs/user-guide/kubectl/v1.7/#rolling-update))。
|
||||
每个 `Pod` 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。
|
||||
这会导致一个问题:在 Kubernetes 集群中,如果一组 `Pod`(称为 backend)为其它 `Pod` (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 `Pod` 中的哪些 backend 呢?
|
||||
|
||||
|
||||
|
||||
关于 `Service`
|
||||
|
||||
|
||||
|
||||
Kubernetes `Service` 定义了这样一种抽象:一个 `Pod` 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。
|
||||
这一组 `Pod` 能够被 `Service` 访问到,通常是通过 [`Label Selector`](/docs/concepts/overview/working-with-objects/labels/#label-selectors)(查看下面了解,为什么可能需要没有 selector 的 `Service`)实现的。
|
||||
|
||||
|
||||
|
||||
举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。
|
||||
然而组成这一组 backend 程序的 `Pod` 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。
|
||||
`Service` 定义的抽象能够解耦这种关联。
|
||||
|
||||
|
||||
|
||||
对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 `Endpoints` API,只要 `Service` 中的一组 `Pod` 发生变更,应用程序就会被更新。
|
||||
对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 `Service`,再由 `Service` 重定向到 backend `Pod`。
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
## 定义 Service
|
||||
|
||||
|
||||
|
||||
一个 `Service` 在 Kubernetes 中是一个 REST 对象,和 `Pod` 类似。
|
||||
像所有的 REST 对象一样, `Service` 定义可以基于 POST 方式,请求 apiserver 创建新的实例。
|
||||
例如,假定有一组 `Pod`,它们对外暴露了 9376 端口,同时还被打上 `"app=MyApp"` 标签。
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
```
|
||||
|
||||
|
||||
|
||||
上述配置将创建一个名称为 “my-service” 的 `Service` 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 `"app=MyApp"` 的 `Pod` 上。
|
||||
这个 `Service` 将被指派一个 IP 地址(通常称为 “Cluster IP”),它会被服务的代理使用(见下面)。
|
||||
该 `Service` 的 selector 将会持续评估,处理结果将被 POST 到一个名称为 “my-service” 的 `Endpoints` 对象上。
|
||||
|
||||
|
||||
|
||||
需要注意的是, `Service` 能够将一个接收端口映射到任意的 `targetPort`。
|
||||
默认情况下,`targetPort` 将被设置为与 `port` 字段相同的值。
|
||||
可能更有趣的是,`targetPort` 可以是一个字符串,引用了 backend `Pod` 的一个端口的名称。
|
||||
但是,实际指派给该端口名称的端口号,在每个 backend `Pod` 中可能并不相同。
|
||||
对于部署和设计 `Service` ,这种方式会提供更大的灵活性。
|
||||
例如,可以在 backend 软件下一个版本中,修改 Pod 暴露的端口,并不会中断客户端的调用。
|
||||
|
||||
|
||||
|
||||
Kubernetes `Service` 能够支持 `TCP` 和 `UDP` 协议,默认 `TCP` 协议。
|
||||
|
||||
|
||||
|
||||
### 没有 selector 的 Service
|
||||
|
||||
|
||||
|
||||
Servcie 抽象了该如何访问 Kubernetes `Pod`,但也能够抽象其它类型的 backend,例如:
|
||||
|
||||
* 希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
|
||||
* 希望服务指向另一个 [`Namespace`](/docs/user-guide/namespaces) 中或其它集群中的服务。
|
||||
* 正在将工作负载转移到 Kubernetes 集群,和运行在 Kubernetes 集群之外的 backend。
|
||||
|
||||
在任何这些场景中,都能够定义没有 selector 的 `Service` :
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
```
|
||||
|
||||
|
||||
由于这个 `Service` 没有 selector,就不会创建相关的 `Endpoints` 对象。可以手动将 `Service` 映射到指定的 `Endpoints`:
|
||||
|
||||
```yaml
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 1.2.3.4
|
||||
ports:
|
||||
- port: 9376
|
||||
```
|
||||
|
||||
|
||||
|
||||
注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。
|
||||
|
||||
|
||||
|
||||
访问没有 selector 的 `Service`,与有 selector 的 `Service` 的原理相同。请求将被路由到用户定义的 Endpoint(该示例中为 `1.2.3.4:9376`)。
|
||||
|
||||
|
||||
|
||||
ExternalName `Service` 是 `Service` 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。
|
||||
相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
namespace: prod
|
||||
spec:
|
||||
type: ExternalName
|
||||
externalName: my.database.example.com
|
||||
```
|
||||
|
||||
|
||||
|
||||
当查询主机 `my-service.prod.svc.CLUSTER`时,集群的 DNS 服务将返回一个值为 `my.database.example.com` 的 `CNAME` 记录。
|
||||
访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。
|
||||
如果后续决定要将数据库迁移到 Kubernetes 集群中,可以启动对应的 Pod,增加合适的 Selector 或 Endpoint,修改 `Service` 的 `type`。
|
||||
|
||||
|
||||
|
||||
## VIP 和 Service 代理
|
||||
|
||||
|
||||
|
||||
在 Kubernetes 集群中,每个 Node 运行一个 `kube-proxy` 进程。`kube-proxy` 负责为 `Service` 实现了一种 VIP(虚拟 IP)的形式,而不是 `ExternalName` 的形式。
|
||||
在 Kubernetes v1.0 版本,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。
|
||||
从 Kubernetes v1.2 起,默认就是 iptables 代理。
|
||||
|
||||
|
||||
|
||||
在 Kubernetes v1.0 版本,`Service` 是 “4层”(TCP/UDP over IP)概念。
|
||||
在 Kubernetes v1.1 版本,新增了 `Ingress` API(beta 版),用来表示 “7层”(HTTP)服务。
|
||||
|
||||
|
||||
|
||||
### userspace 代理模式
|
||||
|
||||
|
||||
|
||||
这种模式,kube-proxy 会监视 Kubernetes master 对 `Service` 对象和 `Endpoints` 对象的添加和移除。
|
||||
对每个 `Service`,它会在本地 Node 上打开一个端口(随机选择)。
|
||||
任何连接到“代理端口”的请求,都会被代理到 `Service` 的backend `Pods` 中的某个上面(如 `Endpoints` 所报告的一样)。
|
||||
使用哪个 backend `Pod`,是基于 `Service` 的 `SessionAffinity` 来确定的。
|
||||
最后,它安装 iptables 规则,捕获到达该 `Service` 的 `clusterIP`(是虚拟 IP)和 `Port` 的请求,并重定向到代理端口,代理端口再代理请求到 backend `Pod`。
|
||||
|
||||
|
||||
|
||||
网络返回的结果是,任何到达 `Service` 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、`Service`、或 `Pod` 的任何信息。
|
||||
|
||||
|
||||
|
||||
默认的策略是,通过 round-robin 算法来选择 backend `Pod`。
|
||||
实现基于客户端 IP 的会话亲和性,可以通过设置 `service.spec.sessionAffinity` 的值为 `"ClientIP"` (默认值为 `"None"`)。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### iptables 代理模式
|
||||
|
||||
|
||||
|
||||
这种模式,kube-proxy 会监视 Kubernetes master 对 `Service` 对象和 `Endpoints` 对象的添加和移除。
|
||||
对每个 `Service`,它会安装 iptables 规则,从而捕获到达该 `Service` 的 `clusterIP`(虚拟 IP)和端口的请求,进而将请求重定向到 `Service` 的一组 backend 中的某个上面。
|
||||
对于每个 `Endpoints` 对象,它也会安装 iptables 规则,这个规则会选择一个 backend `Pod`。
|
||||
|
||||
|
||||
|
||||
默认的策略是,随机选择一个 backend。
|
||||
实现基于客户端 IP 的会话亲和性,可以将 `service.spec.sessionAffinity` 的值设置为 `"ClientIP"` (默认值为 `"None"`)。
|
||||
|
||||
|
||||
|
||||
和 userspace 代理类似,网络返回的结果是,任何到达 `Service` 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、`Service`、或 `Pod` 的任何信息。
|
||||
这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 `Pod` 没有响应,iptables 代理能够自动地重试另一个 `Pod`,所以它需要依赖 [readiness probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-readiness-probes)。
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 多端口 Service
|
||||
|
||||
|
||||
|
||||
很多 `Service` 需要暴露多个端口。对于这种情况,Kubernetes 支持在 `Service` 对象中定义多个端口。
|
||||
当使用多个端口时,必须给出所有的端口的名称,这样 Endpoint 就不会产生歧义,例如:
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
- name: https
|
||||
protocol: TCP
|
||||
port: 443
|
||||
targetPort: 9377
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 选择自己的 IP 地址
|
||||
|
||||
|
||||
|
||||
在 `Service` 创建的请求中,可以通过设置 `spec.clusterIP` 字段来指定自己的集群 IP 地址。
|
||||
比如,希望替换一个已经已存在的 DNS 条目,或者遗留系统已经配置了一个固定的 IP 且很难重新配置。
|
||||
用户选择的 IP 地址必须合法,并且这个 IP 地址在 `service-cluster-ip-range` CIDR 范围内,这对 API Server 来说是通过一个标识来指定的。
|
||||
如果 IP 地址不合法,API Server 会返回 HTTP 状态码 422,表示值不合法。
|
||||
|
||||
|
||||
|
||||
### 为何不使用 round-robin DNS?
|
||||
|
||||
|
||||
|
||||
一个不时出现的问题是,为什么我们都使用 VIP 的方式,而不使用标准的 round-robin DNS,有如下几个原因:
|
||||
|
||||
* 长久以来,DNS 库都没能认真对待 DNS TTL、缓存域名查询结果
|
||||
* 很多应用只查询一次 DNS 并缓存了结果
|
||||
* 就算应用和库能够正确查询解析,每个客户端反复重解析造成的负载也是非常难以管理的
|
||||
|
||||
我们尽力阻止用户做那些对他们没有好处的事情,如果很多人都来问这个问题,我们可能会选择实现它。
|
||||
|
||||
|
||||
|
||||
## 服务发现
|
||||
|
||||
|
||||
|
||||
Kubernetes 支持2种基本的服务发现模式 —— 环境变量和 DNS。
|
||||
|
||||
|
||||
|
||||
### 环境变量
|
||||
|
||||
|
||||
|
||||
当 `Pod` 运行在 `Node` 上,kubelet 会为每个活跃的 `Service` 添加一组环境变量。
|
||||
它同时支持 [Docker links兼容](https://docs.docker.com/userguide/dockerlinks/) 变量(查看 [makeLinkVariables](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/kubelet/envvars/envvars.go#L49))、简单的 `{SVCNAME}_SERVICE_HOST` 和 `{SVCNAME}_SERVICE_PORT` 变量,这里 `Service` 的名称需大写,横线被转换成下划线。
|
||||
|
||||
|
||||
|
||||
举个例子,一个名称为 `"redis-master"` 的 Service 暴露了 TCP 端口 6379,同时给它分配了 Cluster IP 地址 10.0.0.11,这个 Service 生成了如下环境变量:
|
||||
|
||||
```shell
|
||||
REDIS_MASTER_SERVICE_HOST=10.0.0.11
|
||||
REDIS_MASTER_SERVICE_PORT=6379
|
||||
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
|
||||
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
|
||||
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
|
||||
REDIS_MASTER_PORT_6379_TCP_PORT=6379
|
||||
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
|
||||
```
|
||||
|
||||
|
||||
*这意味着需要有顺序的要求* —— `Pod` 想要访问的任何 `Service` 必须在 `Pod` 自己之前被创建,否则这些环境变量就不会被赋值。DNS 并没有这个限制。
|
||||
|
||||
### DNS
|
||||
|
||||
|
||||
|
||||
一个可选(尽管强烈推荐)[集群插件](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/README.md) 是 DNS 服务器。
|
||||
DNS 服务器监视着创建新 `Service` 的 Kubernetes API,从而为每一个 `Service` 创建一组 DNS 记录。
|
||||
如果整个集群的 DNS 一直被启用,那么所有的 `Pod` 应该能够自动对 `Service` 进行名称解析。
|
||||
|
||||
|
||||
|
||||
例如,有一个名称为 `"my-service"` 的 `Service`,它在 Kubernetes 集群中名为 `"my-ns"` 的 `Namespace` 中,为 `"my-service.my-ns"` 创建了一条 DNS 记录。
|
||||
在名称为 `"my-ns"` 的 `Namespace` 中的 `Pod` 应该能够简单地通过名称查询找到 `"my-service"`。
|
||||
在另一个 `Namespace` 中的 `Pod` 必须限定名称为 `"my-service.my-ns"`。
|
||||
这些名称查询的结果是 Cluster IP。
|
||||
|
||||
|
||||
|
||||
Kubernetes 也支持对端口名称的 DNS SRV(Service)记录。
|
||||
如果名称为 `"my-service.my-ns"` 的 `Service` 有一个名为 `"http"` 的 `TCP` 端口,可以对 `"_http._tcp.my-service.my-ns"` 执行 DNS SRV 查询,得到 `"http"` 的端口号。
|
||||
|
||||
|
||||
|
||||
Kubernetes DNS 服务器是唯一的一种能够访问 `ExternalName` 类型的 Service 的方式。
|
||||
更多信息可以查看[DNS Pod 和 Service](/docs/concepts/services-networking/dns-pod-service/)。
|
||||
|
||||
|
||||
|
||||
## Headless Service
|
||||
|
||||
|
||||
|
||||
有时不需要或不想要负载均衡,以及单独的 Service IP。
|
||||
遇到这种情况,可以通过指定 Cluster IP(`spec.clusterIP`)的值为 `"None"` 来创建 `Headless` Service。
|
||||
|
||||
|
||||
|
||||
这个选项允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。
|
||||
应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。
|
||||
|
||||
|
||||
|
||||
对这类 `Service` 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。
|
||||
DNS 如何实现自动配置,依赖于 `Service` 是否定义了 selector。
|
||||
|
||||
|
||||
|
||||
### 配置 Selector
|
||||
|
||||
|
||||
|
||||
对定义了 selector 的 Headless Service,Endpoint 控制器在 API 中创建了 `Endpoints` 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 `Service` 的后端 `Pod` 上。
|
||||
|
||||
|
||||
|
||||
### 不配置 Selector
|
||||
|
||||
|
||||
|
||||
对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建 `Endpoints` 记录。
|
||||
然而 DNS 系统会查找和配置,无论是:
|
||||
|
||||
* `ExternalName` 类型 Service 的 CNAME 记录
|
||||
* 记录:与 Service 共享一个名称的任何 `Endpoints`,以及所有其它类型
|
||||
|
||||
|
||||
|
||||
## 发布服务 —— 服务类型
|
||||
|
||||
对一些应用(如 Frontend)的某些部分,可能希望通过外部(Kubernetes 集群外部)IP 地址暴露 Service。
|
||||
|
||||
|
||||
|
||||
Kubernetes `ServiceTypes` 允许指定一个需要的类型的 Service,默认是 `ClusterIP` 类型。
|
||||
|
||||
`Type` 的取值以及行为如下:
|
||||
|
||||
* `ClusterIP`:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 `ServiceType`。
|
||||
* `NodePort`:通过每个 Node 上的 IP 和静态端口(`NodePort`)暴露服务。`NodePort` 服务会路由到 `ClusterIP` 服务,这个 `ClusterIP` 服务会自动创建。通过请求 `<NodeIP>:<NodePort>`,可以从集群的外部访问一个 `NodePort` 服务。
|
||||
* `LoadBalancer`:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 `NodePort` 服务和 `ClusterIP` 服务。
|
||||
* `ExternalName`:通过返回 `CNAME` 和它的值,可以将服务映射到 `externalName` 字段的内容(例如, `foo.bar.example.com`)。
|
||||
没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 `kube-dns` 才支持。
|
||||
|
||||
|
||||
|
||||
### NodePort 类型
|
||||
|
||||
如果设置 `type` 的值为 `"NodePort"`,Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 `Service`。该端口将通过 `Service` 的 `spec.ports[*].nodePort` 字段被指定。
|
||||
|
||||
|
||||
|
||||
|
||||
如果需要指定的端口号,可以配置 `nodePort` 的值,系统将分配这个端口,否则调用 API 将会失败(比如,需要关心端口冲突的可能性)。
|
||||
|
||||
|
||||
|
||||
这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的 IP 地址。
|
||||
|
||||
|
||||
|
||||
需要注意的是,Service 将能够通过 `<NodeIP>:spec.ports[*].nodePort` 和 `spec.clusterIp:spec.ports[*].port` 而对外可见。
|
||||
|
||||
|
||||
|
||||
### LoadBalancer 类型
|
||||
|
||||
|
||||
|
||||
使用支持外部负载均衡器的云提供商的服务,设置 `type` 的值为 `"LoadBalancer"`,将为 `Service` 提供负载均衡器。
|
||||
负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 `Service` 的 `status.loadBalancer` 字段被发布出去。
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
nodePort: 30061
|
||||
clusterIP: 10.0.171.239
|
||||
loadBalancerIP: 78.11.24.19
|
||||
type: LoadBalancer
|
||||
status:
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- ip: 146.148.47.155
|
||||
```
|
||||
|
||||
|
||||
来自外部负载均衡器的流量将直接打到 backend `Pod` 上,不过实际它们是如何工作的,这要依赖于云提供商。
|
||||
在这些情况下,将根据用户设置的 `loadBalancerIP` 来创建负载均衡器。
|
||||
某些云提供商允许设置 `loadBalancerIP`。如果没有设置 `loadBalancerIP`,将会给负载均衡器指派一个临时 IP。
|
||||
如果设置了 `loadBalancerIP`,但云提供商并不支持这种特性,那么设置的 `loadBalancerIP` 值将会被忽略掉。
|
||||
|
||||
|
||||
|
||||
### AWS 内部负载均衡器
|
||||
在混合云环境中,有时从虚拟私有云(VPC)环境中的服务路由流量是非常有必要的。
|
||||
可以通过在 `Service` 中增加 `annotation` 来实现,如下所示:
|
||||
|
||||
```yaml
|
||||
[...]
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
|
||||
[...]
|
||||
```
|
||||
|
||||
|
||||
在水平分割的 DNS 环境中,需要两个 `Service` 来将外部和内部的流量路由到 Endpoint 上。
|
||||
|
||||
|
||||
|
||||
### AWS SSL 支持
|
||||
对运行在 AWS 上部分支持 SSL 的集群,从 1.3 版本开始,可以为 `LoadBalancer` 类型的 `Service` 增加两个 annotation:
|
||||
|
||||
```
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
|
||||
```
|
||||
|
||||
|
||||
|
||||
第一个 annotation 指定了使用的证书。它可以是第三方发行商发行的证书,这个证书或者被上传到 IAM,或者由 AWS 的证书管理器创建。
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
|
||||
```
|
||||
|
||||
|
||||
第二个 annotation 指定了 `Pod` 使用的协议。
|
||||
对于 HTTPS 和 SSL,ELB 将期望该 `Pod` 基于加密的连接来认证自身。
|
||||
|
||||
|
||||
|
||||
HTTP 和 HTTPS 将选择7层代理:ELB 将中断与用户的连接,当转发请求时,会解析 Header 信息并添加上用户的 IP 地址(`Pod` 将只能在连接的另一端看到该 IP 地址)。
|
||||
|
||||
TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信息。
|
||||
|
||||
|
||||
|
||||
### 外部 IP
|
||||
|
||||
如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes `Service` 会被暴露给这些 `externalIPs`。
|
||||
通过外部 IP(作为目的 IP 地址)进入到集群,打到 `Service` 的端口上的流量,将会被路由到 `Service` 的 Endpoint 上。
|
||||
`externalIPs` 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
|
||||
|
||||
根据 `Service` 的规定,`externalIPs` 可以同任意的 `ServiceType` 来一起指定。
|
||||
在上面的例子中,`my-service` 可以在 80.11.12.10:80(外部 IP:端口)上被客户端访问。
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
externalIPs:
|
||||
- 80.11.12.10
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 不足之处
|
||||
|
||||
为 VIP 使用 userspace 代理,将只适合小型到中型规模的集群,不能够扩展到上千 `Service` 的大型集群。
|
||||
查看 [最初设计方案](http://issue.k8s.io/1107) 获取更多细节。
|
||||
|
||||
|
||||
|
||||
使用 userspace 代理,隐藏了访问 `Service` 的数据包的源 IP 地址。
|
||||
这使得一些类型的防火墙无法起作用。
|
||||
iptables 代理不会隐藏 Kubernetes 集群内部的 IP 地址,但却要求客户端请求必须通过一个负载均衡器或 Node 端口。
|
||||
|
||||
|
||||
|
||||
`Type` 字段支持嵌套功能 —— 每一层需要添加到上一层里面。
|
||||
不会严格要求所有云提供商(例如,GCE 就没必要为了使一个 `LoadBalancer` 能工作而分配一个 `NodePort`,但是 AWS 需要 ),但当前 API 是强制要求的。
|
||||
|
||||
|
||||
|
||||
## 未来工作
|
||||
|
||||
未来我们能预见到,代理策略可能会变得比简单的 round-robin 均衡策略有更多细微的差别,比如 master 选举或分片。
|
||||
我们也能想到,某些 `Service` 将具有 “真正” 的负载均衡器,这种情况下 VIP 将简化数据包的传输。
|
||||
|
||||
|
||||
|
||||
我们打算为 L7(HTTP)`Service` 改进我们对它的支持。
|
||||
|
||||
我们打算为 `Service` 实现更加灵活的请求进入模式,这些 `Service` 包含当前 `ClusterIP`、`NodePort` 和 `LoadBalancer` 模式,或者更多。
|
||||
|
||||
|
||||
|
||||
## VIP 的那些骇人听闻的细节
|
||||
|
||||
对很多想使用 `Service` 的人来说,前面的信息应该足够了。
|
||||
然而,有很多内部原理性的内容,还是值去理解的。
|
||||
|
||||
|
||||
|
||||
### 避免冲突
|
||||
|
||||
Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致他们操作失败、但又不是他们的过错的场景。
|
||||
这种场景下,让我们来看一下网络端口 —— 用户不应该必须选择一个端口号,而且该端口还有可能与其他用户的冲突。
|
||||
这就是说,在彼此隔离状态下仍然会出现失败。
|
||||
|
||||
|
||||
|
||||
为了使用户能够为他们的 `Service` 选择一个端口号,我们必须确保不能有2个 `Service` 发生冲突。
|
||||
我们可以通过为每个 `Service` 分配它们自己的 IP 地址来实现。
|
||||
|
||||
|
||||
|
||||
为了保证每个 `Service` 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 etcd 中的一个全局分配映射表,这个更新操作要先于创建每一个 `Service`。
|
||||
为了使 `Service` 能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 `Service` 将会失败,指示一个 IP 不能被分配。
|
||||
一个后台 Controller 的职责是创建映射表(从 Kubernetes 的旧版本迁移过来,旧版本中是通过在内存中加锁的方式实现),并检查由于管理员干预和清除任意 IP 造成的不合理分配,这些 IP 被分配了但当前没有 `Service` 使用它们。
|
||||
|
||||
|
||||
|
||||
### IP 和 VIP
|
||||
|
||||
不像 `Pod` 的 IP 地址,它实际路由到一个固定的目的地,`Service` 的 IP 实际上不能通过单个主机来进行应答。
|
||||
相反,我们使用 `iptables`(Linux 中的数据包处理逻辑)来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。
|
||||
当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。
|
||||
环境变量和 DNS,实际上会根据 `Service` 的 VIP 和端口来进行填充。
|
||||
|
||||
|
||||
|
||||
#### Userspace
|
||||
|
||||
作为一个例子,考虑前面提到的图片处理应用程序。
|
||||
当创建 backend `Service` 时,Kubernetes master 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。
|
||||
假设 `Service` 的端口是 1234,该 `Service` 会被集群中所有的 `kube-proxy` 实例观察到。
|
||||
当代理看到一个新的 `Service`, 它会打开一个新的端口,建立一个从该 VIP 重定向到新端口的 iptables,并开始接收请求连接。
|
||||
|
||||
|
||||
|
||||
当一个客户端连接到一个 VIP,iptables 规则开始起作用,它会重定向该数据包到 `Service代理` 的端口。
|
||||
`Service代理` 选择一个 backend,并将客户端的流量代理到 backend 上。
|
||||
|
||||
这意味着 `Service` 的所有者能够选择任何他们想使用的端口,而不存在冲突的风险。
|
||||
客户端可以简单地连接到一个 IP 和端口,而不需要知道实际访问了哪些 `Pod`。
|
||||
|
||||
|
||||
|
||||
#### Iptables
|
||||
|
||||
再次考虑前面提到的图片处理应用程序。
|
||||
当创建 backend `Service` 时,Kubernetes master 会给它指派一个虚拟 IP 地址,比如 10.0.0.1。
|
||||
假设 `Service` 的端口是 1234,该 `Service` 会被集群中所有的 `kube-proxy` 实例观察到。
|
||||
当代理看到一个新的 `Service`, 它会安装一系列的 iptables 规则,从 VIP 重定向到 per-`Service` 规则。
|
||||
该 per-`Service` 规则连接到 per-`Endpoint` 规则,该 per-`Endpoint` 规则会重定向(目标 NAT)到 backend。
|
||||
|
||||
|
||||
|
||||
当一个客户端连接到一个 VIP,iptables 规则开始起作用。一个 backend 会被选择(或者根据会话亲和性,或者随机),数据包被重定向到这个 backend。
|
||||
不像 userspace 代理,数据包从来不拷贝到用户空间,kube-proxy 不是必须为该 VIP 工作而运行,并且客户端 IP 是不可更改的。
|
||||
当流量打到 Node 的端口上,或通过负载均衡器,会执行相同的基本流程,但是在那些案例中客户端 IP 是可以更改的。
|
||||
|
||||
|
||||
|
||||
## API 对象
|
||||
|
||||
在 Kubernetes REST API 中,Service 是 top-level 资源。关于 API 对象的更多细节可以查看:[Service API 对象](/docs/api-reference/{{< param "version" >}}/#service-v1-core)。
|
||||
|
||||
|
||||
|
||||
## 更多信息
|
||||
|
||||
阅读 [使用 Service 连接 Frontend 到 Backend](/docs/tutorials/connecting-apps/connecting-frontend-backend/)。
|
||||
@@ -0,0 +1,212 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
- soltysh
|
||||
- janetkuo
|
||||
title: Cron Job
|
||||
redirect_from:
|
||||
- "/docs/concepts/jobs/cron-jobs/"
|
||||
- "/docs/concepts/jobs/cron-jobs.html"
|
||||
- "/docs/user-guide/cron-jobs/"
|
||||
- "/docs/user-guide/cron-jobs.html"
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
## Cron Job 是什么?
|
||||
|
||||
_Cron Job_ 管理基于时间的 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/),即:
|
||||
|
||||
* 在给定时间点只运行一次
|
||||
* 在给定时间点周期性地运行
|
||||
|
||||
一个 CronJob 对象类似于 _crontab_ (cron table)文件中的一行。它根据指定的预定计划周期性地运行一个 Job,格式可以参考 [Cron](https://en.wikipedia.org/wiki/Cron) 。
|
||||
|
||||
|
||||
|
||||
**注意:** 在预定计划中,问号(`?`)和星号(`*`)的意义是相同的,表示给定字段的取值是任意可用值。
|
||||
|
||||
**注意:** 在 Kubernetes 1.4 版本引入了 ScheduledJob 资源,但从 1.5 版本开始改成了 CronJob。
|
||||
|
||||
典型的用法如下所示:
|
||||
|
||||
|
||||
|
||||
* 在给定的时间点调度 Job 运行
|
||||
* 创建周期性运行的 Job,例如:数据库备份、发送邮件。
|
||||
|
||||
### 前提条件
|
||||
|
||||
|
||||
|
||||
当使用的 Kubernetes 集群,版本 >= 1.4(对 ScheduledJob),>= 1.5(对 CronJob),当启动 API Server(参考 [为集群开启或关闭 API 版本](/docs/admin/cluster-management/#turn-on-or-off-an-api-version-for-your-cluster) 获取更多信息)时,通过传递选项 `--runtime-config=batch/v2alpha1=true` 可以开启 batch/v2alpha1 API。
|
||||
|
||||
## 创建 Cron Job
|
||||
|
||||
下面是一个 Cron Job 的例子。它会每分钟运行一个 Job,打印出当前时间并输出问候语 hello。
|
||||
|
||||
% include code.html language="yaml" file="cronjob.yaml" ghlink="/docs/concepts/workloads/controllers/cronjob.yaml" %}
|
||||
|
||||
下载并运行该示例 Cron Job,然后执行如下命令:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./cronjob.yaml
|
||||
cronjob "hello" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
可选地,使用 `kubectl run` 创建一个 Cron Job,不需要写完整的配置:
|
||||
|
||||
```shell
|
||||
$ kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
|
||||
cronjob "hello" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
创建该 Cron Job 之后,通过如下命令获取它的状态信息:
|
||||
|
||||
```shell
|
||||
$ kubectl get cronjob hello
|
||||
NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE
|
||||
hello */1 * * * * False 0 <none>
|
||||
```
|
||||
|
||||
|
||||
|
||||
如上所示,既没有 active 的 Job,也没有被调度的 Job。
|
||||
|
||||
等待并观察创建的 Job,大约一分钟时间:
|
||||
|
||||
```shell
|
||||
$ kubectl get jobs --watch
|
||||
NAME DESIRED SUCCESSFUL AGE
|
||||
hello-4111706356 1 1 2s
|
||||
```
|
||||
|
||||
|
||||
|
||||
现在能看到一个名称为 hello 的 Job 在运行。我们可以停止观察,并再次获取该 Job 的状态信息:
|
||||
|
||||
```shell
|
||||
$ kubectl get cronjob hello
|
||||
NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE
|
||||
hello */1 * * * * False 0 Mon, 29 Aug 2016 14:34:00 -0700
|
||||
```
|
||||
|
||||
|
||||
应该能够看到名称为 “hello” 的 Job 在 `LAST-SCHEDULE` 指定的时间点被调度了。当前存在 0 个活跃(Active)的 Job,说明该 Job 已经被调度运行完成或失败。
|
||||
|
||||
现在,找到最近一次被调度的 Job 创建的 Pod,能够看到其中一个 Pod 的标准输出。注意,Job 名称和 Pod 名称是不一样的。
|
||||
|
||||
```shell
|
||||
# Replace "hello-4111706356" with the job name in your system
|
||||
$ pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items..metadata.name})
|
||||
|
||||
$ echo $pods
|
||||
hello-4111706356-o9qcm
|
||||
|
||||
$ kubectl logs $pods
|
||||
Mon Aug 29 21:34:09 UTC 2016
|
||||
Hello from the Kubernetes cluster
|
||||
```
|
||||
|
||||
|
||||
## 删除 Cron Job
|
||||
|
||||
一旦不再需要 Cron Job,简单地可以使用 `kubectl` 命令删除它:
|
||||
|
||||
```shell
|
||||
$ kubectl delete cronjob hello
|
||||
cronjob "hello" deleted
|
||||
```
|
||||
|
||||
|
||||
|
||||
这将会终止正在创建的 Job。然而,运行中的 Job 将不会被终止,不会删除 Job 或 它们的 Pod。为了清理那些 Job 和 Pod,需要列出该 Cron Job 创建的全部 Job,然后删除它们:
|
||||
|
||||
```shell
|
||||
$ kubectl get jobs
|
||||
NAME DESIRED SUCCESSFUL AGE
|
||||
hello-1201907962 1 1 11m
|
||||
hello-1202039034 1 1 8m
|
||||
...
|
||||
|
||||
$ kubectl delete jobs hello-1201907962 hello-1202039034 ...
|
||||
job "hello-1201907962" deleted
|
||||
job "hello-1202039034" deleted
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
一旦 Job 被删除,由 Job 创建的 Pod 也会被删除。注意,所有由名称为 “hello” 的 Cron Job 创建的 Job 会以前缀字符串 “hello-” 进行命名。如果想要删除当前 Namespace 中的所有 Job,可以通过命令 `kubectl delete jobs --all` 立刻删除它们。
|
||||
|
||||
|
||||
|
||||
## Cron Job 限制
|
||||
|
||||
Cron Job 在每次调度运行时间内 _大概_ 会创建一个 Job 对象。我们之所以说 _大概_ ,是因为在特定的环境下可能会创建两个 Job,或者一个 Job 都没创建。我们尝试少发生这种情况,但却不能完全避免。因此,创建 Job 操作应该是 _幂等的_。
|
||||
|
||||
Job 根据它所创建的 Pod 的并行度,负责重试创建 Pod,并就决定这一组 Pod 的成功或失败。Cron Job 根本不会去检查 Pod。
|
||||
|
||||
|
||||
|
||||
## 编写 Cron Job 规约
|
||||
|
||||
和其它 Kubernetes 配置一样,Cron Job 需要 `apiVersion`、 `kind`、和 `metadata` 这三个字段。
|
||||
关于如何实现一个配置文件的更新信息,参考文档 [部署应用](/docs/user-guide/deploying-applications)、
|
||||
[配置容器](/docs/user-guide/configuring-containers) 和
|
||||
[使用 kubectl 管理资源](/docs/user-guide/working-with-resources)。
|
||||
|
||||
Cron Job 也需要 [`.spec` 段](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status)。
|
||||
|
||||
**注意:** 对一个 Cron Job 的所有修改,尤其是对其 `.spec` 的修改,仅会在下一次运行的时候生效。
|
||||
|
||||
|
||||
### 调度
|
||||
|
||||
`.spec.schedule` 是 `.spec` 中必需的字段,它的值是 [Cron](https://en.wikipedia.org/wiki/Cron) 格式字的符串,例如:`0 * * * *`,或者 `@hourly`,根据指定的调度时间 Job 会被创建和执行。
|
||||
|
||||
|
||||
|
||||
### Job 模板
|
||||
|
||||
`.spec.jobTemplate` 是另一个 `.spec` 中必需的字段。它是 Job 的模板。
|
||||
除了它可以是嵌套的,并且不具有 `apiVersion` 或 `kind` 字段之外,它和 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/) 一样具有完全相同的模式(schema)。
|
||||
参考 [编写 Job 规格](/docs/concepts/jobs/run-to-completion-finite-workloads/#writing-a-job-spec)。
|
||||
|
||||
|
||||
|
||||
### 启动 Job 的期限(秒级别)
|
||||
|
||||
`.spec.startingDeadlineSeconds` 字段是可选的。它表示启动 Job 的期限(秒级别),如果因为任何原因而错过了被调度的时间,那么错过执行时间的 Job 将被认为是失败的。如果没有指定,则没有期限。
|
||||
|
||||
|
||||
|
||||
### 并发策略
|
||||
|
||||
`.spec.concurrencyPolicy` 字段也是可选的。它指定了如何处理被 Cron Job 创建的 Job 的并发执行。只允许指定下面策略中的一种:
|
||||
|
||||
* `Allow`(默认):允许并发运行 Job
|
||||
* `Forbid`:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
|
||||
* `Replace`:取消当前正在运行的 Job,用一个新的来替换
|
||||
|
||||
注意,当前策略只能应用于同一个 Cron Job 创建的 Job。如果存在多个 Cron Job,它们创建的 Job 之间总是允许并发运行。
|
||||
|
||||
|
||||
|
||||
### 挂起
|
||||
|
||||
`.spec.suspend` 字段也是可选的。如果设置为 `true`,后续所有执行都将被挂起。它对已经开始执行的 Job 不起作用。默认值为 `false`。
|
||||
|
||||
|
||||
|
||||
### Job 历史限制
|
||||
|
||||
`.spec.successfulJobsHistoryLimit` 和 `.spec.failedJobsHistoryLimit` 这两个字段是可选的。它们指定了可以保留完成和失败 Job 数量的限制。
|
||||
|
||||
默认没有限制,所有成功和失败的 Job 都会被保留。然而,当运行一个 Cron Job 时,很快就会堆积很多 Job,推荐设置这两个字段的值。设置限制值为 `0`,相关类型的 Job 完成后将不会被保留。
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
title: DaemonSet
|
||||
redirect_from:
|
||||
- "/docs/admin/daemons/"
|
||||
- "/docs/admin/daemons.html"
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
|
||||
## 什么是 DaemonSet?
|
||||
|
||||
_DaemonSet_ 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时,也会为他们新增一个 Pod 。
|
||||
当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
|
||||
|
||||
|
||||
|
||||
使用 DaemonSet 的一些典型用法:
|
||||
|
||||
- 运行集群存储 daemon,例如在每个节点上运行 `glusterd`、`ceph`。
|
||||
- 在每个节点上运行日志收集 daemon,例如`fluentd`、`logstash`。
|
||||
- 在每个节点上运行监控 daemon,例如 [Prometheus Node Exporter](https://github.com/prometheus/node_exporter)、`collectd`、Datadog 代理、New Relic 代理,或 Ganglia `gmond`。
|
||||
|
||||
一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用。
|
||||
一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志,和/或对不同硬件类型具有不同的内存、CPU要求。
|
||||
|
||||
|
||||
|
||||
## 编写 DaemonSet 规约
|
||||
|
||||
### 必需字段
|
||||
|
||||
|
||||
|
||||
和其它所有 Kubernetes 配置一样,DaemonSet 需要 `apiVersion`、`kind` 和 `metadata` 字段。
|
||||
有关配置文件的基本信息,详见文档 [deploying applications](/docs/user-guide/deploying-applications/)、[配置容器](/docs/user-guide/configuring-containers/) 和 [资源管理](/docs/concepts/tools/kubectl/object-management-overview/) 。
|
||||
|
||||
DaemonSet 也需要一个 [`.spec`](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status) 配置段。
|
||||
|
||||
|
||||
|
||||
### Pod 模板
|
||||
|
||||
`.spec` 唯一必需的字段是 `.spec.template`。
|
||||
|
||||
|
||||
|
||||
`.spec.template` 是一个 [Pod 模板](/docs/user-guide/replication-controller/#pod-template)。
|
||||
它与 [Pod](/docs/user-guide/pods) 具有相同的 schema,除了它是嵌套的,而且不具有 `apiVersion` 或 `kind` 字段。
|
||||
|
||||
除了 Pod 必需字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签(查看 [Pod Selector](#pod-selector))。
|
||||
|
||||
在 DaemonSet 中的 Pod 模板必须具有一个值为 `Always` 的 [`RestartPolicy`](/docs/user-guide/pod-states),或者未指定它的值,默认是 `Always`。
|
||||
|
||||
|
||||
|
||||
### Pod Selector
|
||||
|
||||
`.spec.selector` 字段表示 Pod Selector,它与 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/) 或其它资源的 `.spec.selector` 的作用是相同的。
|
||||
|
||||
`spec.selector` 表示一个对象,它由如下两个字段组成:
|
||||
|
||||
* `matchLabels` - 与 [ReplicationController](/docs/concepts/workloads/controllers/replicationcontroller/) 的 `.spec.selector` 的作用相同。
|
||||
* `matchExpressions` - 允许构建更加复杂的 Selector,可以通过指定 key、value 列表,以及与 key 和 value 列表相关的操作符。
|
||||
|
||||
|
||||
|
||||
当上述两个字段都指定时,结果表示的是 AND 关系。
|
||||
|
||||
如果指定了 `.spec.selector`,必须与 `.spec.template.metadata.labels` 相匹配。如果没有指定,它们默认是等价的。如果与它们配置的不匹配,则会被 API 拒绝。
|
||||
|
||||
如果 Pod 的 label 与 selector 匹配,或者直接基于其它的 DaemonSet、或者 Controller(例如 ReplicationController),也不可以创建任何 Pod。
|
||||
否则 DaemonSet Controller 将认为那些 Pod 是它创建的。Kubernetes 不会阻止这样做。一个场景是,可能希望在一个具有不同值的、用来测试用的节点上手动创建 Pod。
|
||||
|
||||
|
||||
|
||||
### 仅在某些节点上运行 Pod
|
||||
|
||||
如果指定了 `.spec.template.spec.nodeSelector`,DaemonSet Controller 将在能够与 [Node Selector](/docs/concepts/configuration/assign-pod-node/) 匹配的节点上创建 Pod。
|
||||
类似这种情况,可以指定 `.spec.template.spec.affinity`,然后 DaemonSet Controller 将在能够与 [Node Affinity](/docs/concepts/configuration/assign-pod-node/) 匹配的节点上创建 Pod。
|
||||
如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。
|
||||
|
||||
|
||||
|
||||
## 如何调度 Daemon Pod
|
||||
|
||||
正常情况下,Pod 运行在哪个机器上是由 Kubernetes 调度器来选择的。然而,由 Daemon Controller 创建的 Pod 已经确定了在哪个机器上(Pod 创建时指定了 `.spec.nodeName`),因此:
|
||||
|
||||
- DaemonSet Controller 并不关心一个节点的 [`unschedulable`](/docs/admin/node/#manual-node-administration) 字段。
|
||||
- DaemonSet Controller 可以创建 Pod,即使调度器还没有启动,这对集群启动是非常有帮助的。
|
||||
|
||||
|
||||
|
||||
Daemon Pod 关心 [Taint 和 Toleration](/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature),它们会为没有指定 `tolerationSeconds` 的 `node.kubernetes.io/not-ready` 和 `node.alpha.kubernetes.io/unreachable` 的 Taint,创建具有 `NoExecute` 的 Toleration。这确保了当 alpha 特性的 `TaintBasedEvictions` 被启用时,发生节点故障,比如网络分区,这时它们将不会被清除掉(当 `TaintBasedEvictions` 特性没有启用,在这些场景下也不会被清除,但会因为 NodeController 的硬编码行为而被清除,而不会因为 Toleration 导致被清除)。
|
||||
|
||||
|
||||
|
||||
## 与 Daemon Pod 通信
|
||||
|
||||
与 DaemonSet 中的 Pod 进行通信,几种可能的模式如下:
|
||||
|
||||
- **Push**:配置 DaemonSet 中的 Pod 向其它 Service 发送更新,例如统计数据库。它们没有客户端。
|
||||
- **NodeIP 和已知端口**:DaemonSet 中的 Pod 可以使用 `hostPort`,从而可以通过节点 IP 访问到 Pod。客户端能通过某种方法知道节点 IP 列表,并且基于此也可以知道端口。
|
||||
- **DNS**:创建具有相同 Pod Selector 的 [Headless Service](/docs/user-guide/services/#headless-services),然后通过使用 `endpoints` 资源或从 DNS 检索到多个 A 记录来发现 DaemonSet。
|
||||
- **Service**:创建具有相同 Pod Selector 的 Service,并使用该 Service 随机访问到某个节点上的 daemon(没有办法访问到特定节点)。
|
||||
|
||||
|
||||
|
||||
## 更新 DaemonSet
|
||||
|
||||
如果修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除新近不能够匹配的节点上的 Pod。
|
||||
|
||||
我们可以修改 DaemonSet 创建的 Pod。然而,不允许对 Pod 的所有字段进行更新。当下次节点(即使具有相同的名称)被创建时,DaemonSet Controller 还会使用最初的模板。
|
||||
|
||||
|
||||
|
||||
可以删除一个 DaemonSet。如果使用 `kubectl` 并指定 `--cascade=false` 选项,则 Pod 将被保留在节点上。然后可以创建具有不同模板的新 DaemonSet。具有不同模板的新 DaemonSet 将能够通过标签匹配并识别所有已经存在的 Pod。它不会修改或删除它们,即使是错误匹配了 Pod 模板。通过删除 Pod 或者删除节点,可以强制创建新的 Pod。
|
||||
|
||||
在 Kubernetes 1.6 或以后版本,可以在 DaemonSet 上 [执行滚动升级](/docs/tasks/manage-daemon/update-daemon-set/)。
|
||||
|
||||
未来的 Kubernetes 版本将支持节点的可控更新。
|
||||
|
||||
|
||||
|
||||
## DaemonSet 的可替代选择
|
||||
|
||||
### init 脚本
|
||||
|
||||
我们很可能希望直接在一个节点上启动 daemon 进程(例如,使用 `init`、`upstartd`、或 `systemd`)。这非常好,但基于 DaemonSet 来运行这些进程有如下一些好处:
|
||||
|
||||
|
||||
|
||||
- 像对待应用程序一样,具备为 daemon 提供监控和管理日志的能力。
|
||||
- 为 daemon 和应用程序使用相同的配置语言和工具(如 Pod 模板、`kubectl`)。
|
||||
- Kubernetes 未来版本可能会支持对 DaemonSet 创建 Pod 与节点升级工作流进行集成。
|
||||
- 在资源受限的容器中运行 daemon,能够增加 daemon 和应用容器的隔离性。然而,这也实现了在容器中运行 daemon,但却不能在 Pod 中运行(例如,直接基于 Docker 启动)。
|
||||
|
||||
|
||||
|
||||
### 裸 Pod
|
||||
|
||||
可能要直接创建 Pod,同时指定其运行在特定的节点上。
|
||||
然而,DaemonSet 替换了由于任何原因被删除或终止的 Pod,例如节点失败、例行节点维护、内核升级。由于这个原因,我们应该使用 DaemonSet 而不是单独创建 Pod。
|
||||
|
||||
|
||||
|
||||
### 静态 Pod
|
||||
|
||||
可能需要通过在一个指定目录下编写文件来创建 Pod,该目录受 Kubelet 所监视。这些 Pod 被称为 [静态 Pod](/docs/concepts/cluster-administration/static-pod/)。
|
||||
不像 DaemonSet,静态 Pod 不受 kubectl 和其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。
|
||||
而且,未来静态 Pod 可能会被废弃掉。
|
||||
|
||||
|
||||
|
||||
### Replication Controller
|
||||
|
||||
DaemonSet 与 [Replication Controller](/docs/user-guide/replication-controller) 非常类似,它们都能创建 Pod,这些 Pod 对应的进程都不希望被终止掉(例如,Web 服务器、存储服务器)。
|
||||
为无状态的 Service 使用 Replication Controller,比如前端(Frontend)服务,实现对副本的数量进行扩缩容、平滑升级,比之于精确控制 Pod 运行在某个主机上要重要得多。
|
||||
需要 Pod 副本总是运行在全部或特定主机上,并需要先于其他 Pod 启动,当这被认为非常重要时,应该使用 Daemon Controller。
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: fluentd-elasticsearch
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: fluentd-logging
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: fluentd-elasticsearch
|
||||
spec:
|
||||
containers:
|
||||
- name: fluentd-elasticsearch
|
||||
image: k8s.gcr.io/fluentd-elasticsearch:1.20
|
||||
resources:
|
||||
limits:
|
||||
memory: 200Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
volumeMounts:
|
||||
- name: varlog
|
||||
mountPath: /var/log
|
||||
- name: varlibdockercontainers
|
||||
mountPath: /var/lib/docker/containers
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 30
|
||||
volumes:
|
||||
- name: varlog
|
||||
hostPath:
|
||||
path: /var/log
|
||||
- name: varlibdockercontainers
|
||||
hostPath:
|
||||
path: /var/lib/docker/containers
|
||||
@@ -0,0 +1,947 @@
|
||||
---
|
||||
approvers:
|
||||
- bgrant0607
|
||||
- janetkuo
|
||||
title: Deployments
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
A _Deployment_ controller provides declarative updates for [Pods](/docs/concepts/workloads/pods/pod/) and
|
||||
[ReplicaSets](/docs/concepts/workloads/controllers/replicaset/).
|
||||
|
||||
You describe a _desired state_ in a Deployment object, and the Deployment controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** You should not manage ReplicaSets owned by a Deployment. All the use cases should be covered by manipulating the Deployment object. Consider opening an issue in the main Kubernetes repository if your use case is not covered below.
|
||||
{{< /note >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Use Case
|
||||
|
||||
The following are typical use cases for Deployments:
|
||||
|
||||
* [Create a Deployment to rollout a ReplicaSet](#creating-a-deployment). The ReplicaSet creates Pods in the background. Check the status of the rollout to see if it succeeds or not.
|
||||
* [Declare the new state of the Pods](#updating-a-deployment) by updating the PodTemplateSpec of the Deployment. A new ReplicaSet is created and the Deployment manages moving the Pods from the old ReplicaSet to the new one at a controlled rate. Each new ReplicaSet updates the revision of the Deployment.
|
||||
* [Rollback to an earlier Deployment revision](#rolling-back-a-deployment) if the current state of the Deployment is not stable. Each rollback updates the revision of the Deployment.
|
||||
* [Scale up the Deployment to facilitate more load.](#scaling-a-deployment)
|
||||
* [Pause the Deployment](#pausing-and-resuming-a-deployment) to apply multiple fixes to its PodTemplateSpec and then resume it to start a new rollout.
|
||||
* [Use the status of the Deployment](#deployment-status) as an indicator that a rollout has stuck
|
||||
* [Clean up older ReplicaSets](#clean-up-policy) that you don't need anymore
|
||||
|
||||
|
||||
## Creating a Deployment
|
||||
|
||||
Here is an example Deployment. It creates a ReplicaSet to bring up three nginx Pods.
|
||||
|
||||
{{< code file="nginx-deployment.yaml" >}}
|
||||
|
||||
Run the example by downloading the example file and then running this command:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f docs/user-guide/nginx-deployment.yaml --record
|
||||
deployment "nginx-deployment" created
|
||||
```
|
||||
|
||||
Setting the kubectl flag `--record` to `true` allows you to record current command in the annotations of
|
||||
the resources being created or updated. It is useful for future introspection: for example, to see the
|
||||
commands executed in each Deployment revision.
|
||||
|
||||
Then running `get` immediately will give:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployments
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 3 0 0 0 1s
|
||||
```
|
||||
|
||||
This indicates that the Deployment's number of desired replicas is 3 (according to deployment's `.spec.replicas`),
|
||||
the number of current replicas (`.status.replicas`) is 0, the number of up-to-date replicas (`.status.updatedReplicas`)
|
||||
is 0, and the number of available replicas (`.status.availableReplicas`) is also 0.
|
||||
|
||||
To see the Deployment rollout status, run:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout status deployment/nginx-deployment
|
||||
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
|
||||
deployment "nginx-deployment" successfully rolled out
|
||||
```
|
||||
|
||||
Running the `get` again a few seconds later should give:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployments
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 3 3 3 3 18s
|
||||
```
|
||||
|
||||
This indicates that the Deployment has created all three replicas, and all replicas are up-to-date (contains the
|
||||
latest pod template) and available (pod status is ready for at least Deployment's `.spec.minReadySeconds`). Running
|
||||
`kubectl get rs` and `kubectl get pods` will show the ReplicaSet (RS) and Pods created.
|
||||
|
||||
```shell
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-deployment-2035384211 3 3 3 18s
|
||||
```
|
||||
|
||||
You may notice that the name of the ReplicaSet is always `<the name of the Deployment>-<hash value of the pod template>`.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --show-labels
|
||||
NAME READY STATUS RESTARTS AGE LABELS
|
||||
nginx-deployment-2035384211-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=2035384211
|
||||
nginx-deployment-2035384211-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=2035384211
|
||||
nginx-deployment-2035384211-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=2035384211
|
||||
```
|
||||
|
||||
The created ReplicaSet ensures that there are three nginx Pods at all times.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** You must specify an appropriate selector and pod template labels in a Deployment (in this case,
|
||||
`app = nginx`). That is, don't overlap with other controllers (including other Deployments, ReplicaSets,
|
||||
StatefulSets, etc.). Kubernetes doesn't stop you from overlapping, and if multiple
|
||||
controllers have overlapping selectors, those controllers may fight with each other and won't behave
|
||||
correctly.
|
||||
{{< /note >}}
|
||||
|
||||
### Pod-template-hash label
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Do not change this label.
|
||||
{{< /note >}}
|
||||
|
||||
Note the pod-template-hash label in the example output in the pod labels above. This label is added by the
|
||||
Deployment controller to every ReplicaSet that a Deployment creates or adopts. Its purpose is to make sure that child
|
||||
ReplicaSets of a Deployment do not overlap. It is computed by hashing the PodTemplate of the ReplicaSet
|
||||
and using the resulting hash as the label value that will be added in the ReplicaSet selector, pod template labels,
|
||||
and in any existing Pods that the ReplicaSet may have.
|
||||
|
||||
## Updating a Deployment
|
||||
|
||||
{{< note >}}
|
||||
**Note:** A Deployment's rollout is triggered if and only if the Deployment's pod template (that is, `.spec.template`)
|
||||
is changed, for example if the labels or container images of the template are updated. Other updates, such as scaling the Deployment, do not trigger a rollout.
|
||||
{{< /note >}}
|
||||
|
||||
Suppose that we now want to update the nginx Pods to use the `nginx:1.9.1` image
|
||||
instead of the `nginx:1.7.9` image.
|
||||
|
||||
```shell
|
||||
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
|
||||
deployment "nginx-deployment" image updated
|
||||
```
|
||||
|
||||
Alternatively, we can `edit` the Deployment and change `.spec.template.spec.containers[0].image` from `nginx:1.7.9` to `nginx:1.9.1`:
|
||||
|
||||
```shell
|
||||
$ kubectl edit deployment/nginx-deployment
|
||||
deployment "nginx-deployment" edited
|
||||
```
|
||||
|
||||
To see the rollout status, run:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout status deployment/nginx-deployment
|
||||
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
|
||||
deployment "nginx-deployment" successfully rolled out
|
||||
```
|
||||
|
||||
After the rollout succeeds, you may want to `get` the Deployment:
|
||||
|
||||
```shell
|
||||
$ kubectl get deployments
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 3 3 3 3 36s
|
||||
```
|
||||
|
||||
The number of up-to-date replicas indicates that the Deployment has updated the replicas to the latest configuration.
|
||||
The current replicas indicates the total replicas this Deployment manages, and the available replicas indicates the
|
||||
number of current replicas that are available.
|
||||
|
||||
We can run `kubectl get rs` to see that the Deployment updated the Pods by creating a new ReplicaSet and scaling it
|
||||
up to 3 replicas, as well as scaling down the old ReplicaSet to 0 replicas.
|
||||
|
||||
```shell
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-deployment-1564180365 3 3 3 6s
|
||||
nginx-deployment-2035384211 0 0 0 36s
|
||||
```
|
||||
|
||||
Running `get pods` should now show only the new Pods:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
|
||||
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
|
||||
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
|
||||
```
|
||||
|
||||
Next time we want to update these Pods, we only need to update the Deployment's pod template again.
|
||||
|
||||
Deployment can ensure that only a certain number of Pods may be down while they are being updated. By
|
||||
default, it ensures that at least 1 less than the desired number of Pods are up (1 max unavailable).
|
||||
|
||||
Deployment can also ensure that only a certain number of Pods may be created above the desired number of
|
||||
Pods. By default, it ensures that at most 1 more than the desired number of Pods are up (1 max surge).
|
||||
|
||||
In a future version of Kubernetes, the defaults will change from 1-1 to 25%-25%.
|
||||
|
||||
For example, if you look at the above Deployment closely, you will see that it first created a new Pod,
|
||||
then deleted some old Pods and created new ones. It does not kill old Pods until a sufficient number of
|
||||
new Pods have come up, and does not create new Pods until a sufficient number of old Pods have been killed.
|
||||
It makes sure that number of available Pods is at least 2 and the number of total Pods is at most 4.
|
||||
|
||||
```shell
|
||||
$ kubectl describe deployments
|
||||
Name: nginx-deployment
|
||||
Namespace: default
|
||||
CreationTimestamp: Tue, 15 Mar 2016 12:01:06 -0700
|
||||
Labels: app=nginx
|
||||
Selector: app=nginx
|
||||
Replicas: 3 updated | 3 total | 3 available | 0 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
36s 36s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
|
||||
23s 23s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
|
||||
23s 23s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
|
||||
23s 23s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
|
||||
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
|
||||
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
|
||||
```
|
||||
|
||||
Here we see that when we first created the Deployment, it created a ReplicaSet (nginx-deployment-2035384211)
|
||||
and scaled it up to 3 replicas directly. When we updated the Deployment, it created a new ReplicaSet
|
||||
(nginx-deployment-1564180365) and scaled it up to 1 and then scaled down the old ReplicaSet to 2, so that at
|
||||
least 2 Pods were available and at most 4 Pods were created at all times. It then continued scaling up and down
|
||||
the new and the old ReplicaSet, with the same rolling update strategy. Finally, we'll have 3 available replicas
|
||||
in the new ReplicaSet, and the old ReplicaSet is scaled down to 0.
|
||||
|
||||
### Rollover (aka multiple updates in-flight)
|
||||
|
||||
Each time a new deployment object is observed by the deployment controller, a ReplicaSet is created to bring up
|
||||
the desired Pods if there is no existing ReplicaSet doing so. Existing ReplicaSet controlling Pods whose labels
|
||||
match `.spec.selector` but whose template does not match `.spec.template` are scaled down. Eventually, the new
|
||||
ReplicaSet will be scaled to `.spec.replicas` and all old ReplicaSets will be scaled to 0.
|
||||
|
||||
If you update a Deployment while an existing rollout is in progress, the Deployment will create a new ReplicaSet
|
||||
as per the update and start scaling that up, and will roll over the ReplicaSet that it was scaling up previously
|
||||
-- it will add it to its list of old ReplicaSets and will start scaling it down.
|
||||
|
||||
For example, suppose you create a Deployment to create 5 replicas of `nginx:1.7.9`,
|
||||
but then updates the Deployment to create 5 replicas of `nginx:1.9.1`, when only 3
|
||||
replicas of `nginx:1.7.9` had been created. In that case, Deployment will immediately start
|
||||
killing the 3 `nginx:1.7.9` Pods that it had created, and will start creating
|
||||
`nginx:1.9.1` Pods. It will not wait for 5 replicas of `nginx:1.7.9` to be created
|
||||
before changing course.
|
||||
|
||||
### Label selector updates
|
||||
|
||||
It is generally discouraged to make label selector updates and it is suggested to plan your selectors up front.
|
||||
In any case, if you need to perform a label selector update, exercise great caution and make sure you have grasped
|
||||
all of the implications.
|
||||
|
||||
* Selector additions require the pod template labels in the Deployment spec to be updated with the new label too,
|
||||
otherwise a validation error is returned. This change is a non-overlapping one, meaning that the new selector does
|
||||
not select ReplicaSets and Pods created with the old selector, resulting in orphaning all old ReplicaSets and
|
||||
creating a new ReplicaSet.
|
||||
* Selector updates -- that is, changing the existing value in a selector key -- result in the same behavior as additions.
|
||||
* Selector removals -- that is, removing an existing key from the Deployment selector -- do not require any changes in the
|
||||
pod template labels. No existing ReplicaSet is orphaned, and a new ReplicaSet is not created, but note that the
|
||||
removed label still exists in any existing Pods and ReplicaSets.
|
||||
|
||||
## Rolling Back a Deployment
|
||||
|
||||
Sometimes you may want to rollback a Deployment; for example, when the Deployment is not stable, such as crash looping.
|
||||
By default, all of the Deployment's rollout history is kept in the system so that you can rollback anytime you want
|
||||
(you can change that by modifying revision history limit).
|
||||
|
||||
{{< note >}}
|
||||
**Note:** A Deployment's revision is created when a Deployment's rollout is triggered. This means that the
|
||||
new revision is created if and only if the Deployment's pod template (`.spec.template`) is changed,
|
||||
for example if you update the labels or container images of the template. Other updates, such as scaling the Deployment,
|
||||
do not create a Deployment revision, so that we can facilitate simultaneous manual- or auto-scaling.
|
||||
This means that when you roll back to an earlier revision, only the Deployment's pod template part is
|
||||
rolled back.
|
||||
{{< /note >}}
|
||||
|
||||
Suppose that we made a typo while updating the Deployment, by putting the image name as `nginx:1.91` instead of `nginx:1.9.1`:
|
||||
|
||||
```shell
|
||||
$ kubectl set image deployment/nginx-deployment nginx=nginx:1.91
|
||||
deployment "nginx-deployment" image updated
|
||||
```
|
||||
|
||||
The rollout will be stuck.
|
||||
|
||||
```shell
|
||||
$ kubectl rollout status deployments nginx-deployment
|
||||
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
|
||||
```
|
||||
|
||||
Press Ctrl-C to stop the above rollout status watch. For more information on stuck rollouts,
|
||||
[read more here](#deployment-status).
|
||||
|
||||
You will also see that both the number of old replicas (nginx-deployment-1564180365 and
|
||||
nginx-deployment-2035384211) and new replicas (nginx-deployment-3066724191) are 2.
|
||||
|
||||
```shell
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-deployment-1564180365 2 2 0 25s
|
||||
nginx-deployment-2035384211 0 0 0 36s
|
||||
nginx-deployment-3066724191 2 2 2 6s
|
||||
```
|
||||
|
||||
Looking at the Pods created, you will see that the 2 Pods created by new ReplicaSet are stuck in an image pull loop.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
|
||||
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
|
||||
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
|
||||
nginx-deployment-3066724191-eocby 0/1 ImagePullBackOff 0 6s
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
**Note:** The Deployment controller will stop the bad rollout automatically, and will stop scaling up the new
|
||||
ReplicaSet. This depends on the rollingUpdate parameters (`maxUnavailable` specifically) that you have specified.
|
||||
Kubernetes by default sets the value to 1 and spec.replicas to 1 so if you haven't cared about setting those
|
||||
parameters, your Deployment can have 100% unavailability by default! This will be fixed in Kubernetes in a future
|
||||
version.
|
||||
{{< /note >}}
|
||||
|
||||
```shell
|
||||
$ kubectl describe deployment
|
||||
Name: nginx-deployment
|
||||
Namespace: default
|
||||
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
|
||||
Labels: app=nginx
|
||||
Selector: app=nginx
|
||||
Replicas: 2 updated | 3 total | 2 available | 2 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
OldReplicaSets: nginx-deployment-1564180365 (2/2 replicas created)
|
||||
NewReplicaSet: nginx-deployment-3066724191 (2/2 replicas created)
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
|
||||
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
|
||||
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
|
||||
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
|
||||
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
|
||||
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
|
||||
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
|
||||
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-1564180365 to 2
|
||||
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 2
|
||||
```
|
||||
|
||||
To fix this, we need to rollback to a previous revision of Deployment that is stable.
|
||||
|
||||
### Checking Rollout History of a Deployment
|
||||
|
||||
First, check the revisions of this deployment:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout history deployment/nginx-deployment
|
||||
deployments "nginx-deployment"
|
||||
REVISION CHANGE-CAUSE
|
||||
1 kubectl create -f docs/user-guide/nginx-deployment.yaml --record
|
||||
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
|
||||
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.91
|
||||
```
|
||||
|
||||
Because we recorded the command while creating this Deployment using `--record`, we can easily see
|
||||
the changes we made in each revision.
|
||||
|
||||
To further see the details of each revision, run:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout history deployment/nginx-deployment --revision=2
|
||||
deployments "nginx-deployment" revision 2
|
||||
Labels: app=nginx
|
||||
pod-template-hash=1159050644
|
||||
Annotations: kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
|
||||
Containers:
|
||||
nginx:
|
||||
Image: nginx:1.9.1
|
||||
Port: 80/TCP
|
||||
QoS Tier:
|
||||
cpu: BestEffort
|
||||
memory: BestEffort
|
||||
Environment Variables: <none>
|
||||
No volumes.
|
||||
```
|
||||
|
||||
### Rolling Back to a Previous Revision
|
||||
|
||||
Now we've decided to undo the current rollout and rollback to the previous revision:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout undo deployment/nginx-deployment
|
||||
deployment "nginx-deployment" rolled back
|
||||
```
|
||||
|
||||
Alternatively, you can rollback to a specific revision by specify that in `--to-revision`:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout undo deployment/nginx-deployment --to-revision=2
|
||||
deployment "nginx-deployment" rolled back
|
||||
```
|
||||
|
||||
For more details about rollout related commands, read [`kubectl rollout`](/docs/user-guide/kubectl/{{< param "version" >}}/#rollout).
|
||||
|
||||
The Deployment is now rolled back to a previous stable revision. As you can see, a `DeploymentRollback` event
|
||||
for rolling back to revision 2 is generated from Deployment controller.
|
||||
|
||||
```shell
|
||||
$ kubectl get deployment
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 3 3 3 3 30m
|
||||
|
||||
$ kubectl describe deployment
|
||||
Name: nginx-deployment
|
||||
Namespace: default
|
||||
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
|
||||
Labels: app=nginx
|
||||
Selector: app=nginx
|
||||
Replicas: 3 updated | 3 total | 3 available | 0 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
30m 30m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 2
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
|
||||
29m 29m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-1564180365 to 2
|
||||
2m 2m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-3066724191 to 0
|
||||
2m 2m 1 {deployment-controller } Normal DeploymentRollback Rolled back deployment "nginx-deployment" to revision 2
|
||||
29m 2m 2 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
|
||||
```
|
||||
|
||||
## Scaling a Deployment
|
||||
|
||||
You can scale a Deployment by using the following command:
|
||||
|
||||
```shell
|
||||
$ kubectl scale deployment nginx-deployment --replicas=10
|
||||
deployment "nginx-deployment" scaled
|
||||
```
|
||||
|
||||
Assuming [horizontal pod autoscaling](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/) is enabled
|
||||
in your cluster, you can setup an autoscaler for your Deployment and choose the minimum and maximum number of
|
||||
Pods you want to run based on the CPU utilization of your existing Pods.
|
||||
|
||||
```shell
|
||||
$ kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
|
||||
deployment "nginx-deployment" autoscaled
|
||||
```
|
||||
|
||||
### Proportional scaling
|
||||
|
||||
RollingUpdate Deployments support running multiple versions of an application at the same time. When you
|
||||
or an autoscaler scales a RollingUpdate Deployment that is in the middle of a rollout (either in progress
|
||||
or paused), then the Deployment controller will balance the additional replicas in the existing active
|
||||
ReplicaSets (ReplicaSets with Pods) in order to mitigate risk. This is called *proportional scaling*.
|
||||
|
||||
For example, you are running a Deployment with 10 replicas, [maxSurge](#max-surge)=3, and [maxUnavailable](#max-unavailable)=2.
|
||||
|
||||
```shell
|
||||
$ kubectl get deploy
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 10 10 10 10 50s
|
||||
```
|
||||
|
||||
You update to a new image which happens to be unresolvable from inside the cluster.
|
||||
|
||||
```shell
|
||||
$ kubectl set image deploy/nginx-deployment nginx=nginx:sometag
|
||||
deployment "nginx-deployment" image updated
|
||||
```
|
||||
|
||||
The image update starts a new rollout with ReplicaSet nginx-deployment-1989198191, but it's blocked due to the
|
||||
maxUnavailable requirement that we mentioned above.
|
||||
|
||||
```shell
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-deployment-1989198191 5 5 0 9s
|
||||
nginx-deployment-618515232 8 8 8 1m
|
||||
```
|
||||
|
||||
Then a new scaling request for the Deployment comes along. The autoscaler increments the Deployment replicas
|
||||
to 15. The Deployment controller needs to decide where to add these new 5 replicas. If we weren't using
|
||||
proportional scaling, all 5 of them would be added in the new ReplicaSet. With proportional scaling, we
|
||||
spread the additional replicas across all ReplicaSets. Bigger proportions go to the ReplicaSets with the
|
||||
most replicas and lower proportions go to ReplicaSets with less replicas. Any leftovers are added to the
|
||||
ReplicaSet with the most replicas. ReplicaSets with zero replicas are not scaled up.
|
||||
|
||||
In our example above, 3 replicas will be added to the old ReplicaSet and 2 replicas will be added to the
|
||||
new ReplicaSet. The rollout process should eventually move all replicas to the new ReplicaSet, assuming
|
||||
the new replicas become healthy.
|
||||
|
||||
```shell
|
||||
$ kubectl get deploy
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx-deployment 15 18 7 8 7m
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-deployment-1989198191 7 7 0 7m
|
||||
nginx-deployment-618515232 11 11 11 7m
|
||||
```
|
||||
|
||||
## Pausing and Resuming a Deployment
|
||||
|
||||
You can pause a Deployment before triggering one or more updates and then resume it. This will allow you to
|
||||
apply multiple fixes in between pausing and resuming without triggering unnecessary rollouts.
|
||||
|
||||
For example, with a Deployment that was just created:
|
||||
|
||||
```shell
|
||||
$ kubectl get deploy
|
||||
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
|
||||
nginx 3 3 3 3 1m
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-2142116321 3 3 3 1m
|
||||
```
|
||||
|
||||
Pause by running the following command:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout pause deployment/nginx-deployment
|
||||
deployment "nginx-deployment" paused
|
||||
```
|
||||
|
||||
Then update the image of the Deployment:
|
||||
|
||||
```shell
|
||||
$ kubectl set image deploy/nginx-deployment nginx=nginx:1.9.1
|
||||
deployment "nginx-deployment" image updated
|
||||
```
|
||||
|
||||
Notice that no new rollout started:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout history deploy/nginx-deployment
|
||||
deployments "nginx"
|
||||
REVISION CHANGE-CAUSE
|
||||
1 <none>
|
||||
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-2142116321 3 3 3 2m
|
||||
```
|
||||
|
||||
You can make as many updates as you wish, for example, update the resources that will be used:
|
||||
|
||||
```shell
|
||||
$ kubectl set resources deployment nginx -c=nginx --limits=cpu=200m,memory=512Mi
|
||||
deployment "nginx" resource requirements updated
|
||||
```
|
||||
|
||||
The initial state of the Deployment prior to pausing it will continue its function, but new updates to
|
||||
the Deployment will not have any effect as long as the Deployment is paused.
|
||||
|
||||
Eventually, resume the Deployment and observe a new ReplicaSet coming up with all the new updates:
|
||||
|
||||
```shell
|
||||
$ kubectl rollout resume deploy/nginx-deployment
|
||||
deployment "nginx" resumed
|
||||
$ kubectl get rs -w
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-2142116321 2 2 2 2m
|
||||
nginx-3926361531 2 2 0 6s
|
||||
nginx-3926361531 2 2 1 18s
|
||||
nginx-2142116321 1 2 2 2m
|
||||
nginx-2142116321 1 2 2 2m
|
||||
nginx-3926361531 3 2 1 18s
|
||||
nginx-3926361531 3 2 1 18s
|
||||
nginx-2142116321 1 1 1 2m
|
||||
nginx-3926361531 3 3 1 18s
|
||||
nginx-3926361531 3 3 2 19s
|
||||
nginx-2142116321 0 1 1 2m
|
||||
nginx-2142116321 0 1 1 2m
|
||||
nginx-2142116321 0 0 0 2m
|
||||
nginx-3926361531 3 3 3 20s
|
||||
^C
|
||||
$ kubectl get rs
|
||||
NAME DESIRED CURRENT READY AGE
|
||||
nginx-2142116321 0 0 0 2m
|
||||
nginx-3926361531 3 3 3 28s
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
**Note:** You cannot rollback a paused Deployment until you resume it.
|
||||
{{< /note >}}
|
||||
|
||||
## Deployment status
|
||||
|
||||
A Deployment enters various states during its lifecycle. It can be [progressing](#progressing-deployment) while
|
||||
rolling out a new ReplicaSet, it can be [complete](#complete-deployment), or it can [fail to progress](#failed-deployment).
|
||||
|
||||
### Progressing Deployment
|
||||
|
||||
Kubernetes marks a Deployment as _progressing_ when one of the following tasks is performed:
|
||||
|
||||
* The Deployment creates a new ReplicaSet.
|
||||
* The Deployment is scaling up its newest ReplicaSet.
|
||||
* The Deployment is scaling down its older ReplicaSet(s).
|
||||
* New Pods become ready or available (ready for at least [MinReadySeconds](#min-ready-seconds)).
|
||||
|
||||
You can monitor the progress for a Deployment by using `kubectl rollout status`.
|
||||
|
||||
### Complete Deployment
|
||||
|
||||
Kubernetes marks a Deployment as _complete_ when it has the following characteristics:
|
||||
|
||||
* All of the replicas associated with the Deployment have been updated to the latest version you've specified, meaning any
|
||||
updates you've requested have been completed.
|
||||
* All of the replicas associated with the Deployment are available.
|
||||
* No old replicas for the Deployment are running.
|
||||
|
||||
You can check if a Deployment has completed by using `kubectl rollout status`. If the rollout completed
|
||||
successfully, `kubectl rollout status` returns a zero exit code.
|
||||
|
||||
```shell
|
||||
$ kubectl rollout status deploy/nginx-deployment
|
||||
Waiting for rollout to finish: 2 of 3 updated replicas are available...
|
||||
deployment "nginx" successfully rolled out
|
||||
$ echo $?
|
||||
0
|
||||
```
|
||||
|
||||
### Failed Deployment
|
||||
|
||||
Your Deployment may get stuck trying to deploy its newest ReplicaSet without ever completing. This can occur
|
||||
due to some of the following factors:
|
||||
|
||||
* Insufficient quota
|
||||
* Readiness probe failures
|
||||
* Image pull errors
|
||||
* Insufficient permissions
|
||||
* Limit ranges
|
||||
* Application runtime misconfiguration
|
||||
|
||||
One way you can detect this condition is to specify a deadline parameter in your Deployment spec:
|
||||
([`spec.progressDeadlineSeconds`](#progress-deadline-seconds)). `spec.progressDeadlineSeconds` denotes the
|
||||
number of seconds the Deployment controller waits before indicating (in the Deployment status) that the
|
||||
Deployment progress has stalled.
|
||||
|
||||
The following `kubectl` command sets the spec with `progressDeadlineSeconds` to make the controller report
|
||||
lack of progress for a Deployment after 10 minutes:
|
||||
|
||||
```shell
|
||||
$ kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
|
||||
"nginx-deployment" patched
|
||||
```
|
||||
Once the deadline has been exceeded, the Deployment controller adds a DeploymentCondition with the following
|
||||
attributes to the Deployment's `status.conditions`:
|
||||
|
||||
* Type=Progressing
|
||||
* Status=False
|
||||
* Reason=ProgressDeadlineExceeded
|
||||
|
||||
See the [Kubernetes API conventions](https://git.k8s.io/community/contributors/devel/api-conventions.md#typical-status-properties) for more information on status conditions.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Kubernetes will take no action on a stalled Deployment other than to report a status condition with
|
||||
`Reason=ProgressDeadlineExceeded`. Higher level orchestrators can take advantage of it and act accordingly, for
|
||||
example, rollback the Deployment to its previous version.
|
||||
{{< /note >}}
|
||||
|
||||
{{< note >}}
|
||||
**Note:** If you pause a Deployment, Kubernetes does not check progress against your specified deadline. You can
|
||||
safely pause a Deployment in the middle of a rollout and resume without triggering the condition for exceeding the
|
||||
deadline.
|
||||
{{< /note >}}
|
||||
|
||||
You may experience transient errors with your Deployments, either due to a low timeout that you have set or
|
||||
due to any other kind of error that can be treated as transient. For example, let's suppose you have
|
||||
insufficient quota. If you describe the Deployment you will notice the following section:
|
||||
|
||||
```shell
|
||||
$ kubectl describe deployment nginx-deployment
|
||||
<...>
|
||||
Conditions:
|
||||
Type Status Reason
|
||||
---- ------ ------
|
||||
Available True MinimumReplicasAvailable
|
||||
Progressing True ReplicaSetUpdated
|
||||
ReplicaFailure True FailedCreate
|
||||
<...>
|
||||
```
|
||||
|
||||
If you run `kubectl get deployment nginx-deployment -o yaml`, the Deployment status might look like this:
|
||||
|
||||
```
|
||||
status:
|
||||
availableReplicas: 2
|
||||
conditions:
|
||||
- lastTransitionTime: 2016-10-04T12:25:39Z
|
||||
lastUpdateTime: 2016-10-04T12:25:39Z
|
||||
message: Replica set "nginx-deployment-4262182780" is progressing.
|
||||
reason: ReplicaSetUpdated
|
||||
status: "True"
|
||||
type: Progressing
|
||||
- lastTransitionTime: 2016-10-04T12:25:42Z
|
||||
lastUpdateTime: 2016-10-04T12:25:42Z
|
||||
message: Deployment has minimum availability.
|
||||
reason: MinimumReplicasAvailable
|
||||
status: "True"
|
||||
type: Available
|
||||
- lastTransitionTime: 2016-10-04T12:25:39Z
|
||||
lastUpdateTime: 2016-10-04T12:25:39Z
|
||||
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
|
||||
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
|
||||
reason: FailedCreate
|
||||
status: "True"
|
||||
type: ReplicaFailure
|
||||
observedGeneration: 3
|
||||
replicas: 2
|
||||
unavailableReplicas: 2
|
||||
```
|
||||
|
||||
Eventually, once the Deployment progress deadline is exceeded, Kubernetes updates the status and the
|
||||
reason for the Progressing condition:
|
||||
|
||||
```
|
||||
Conditions:
|
||||
Type Status Reason
|
||||
---- ------ ------
|
||||
Available True MinimumReplicasAvailable
|
||||
Progressing False ProgressDeadlineExceeded
|
||||
ReplicaFailure True FailedCreate
|
||||
```
|
||||
|
||||
You can address an issue of insufficient quota by scaling down your Deployment, by scaling down other
|
||||
controllers you may be running, or by increasing quota in your namespace. If you satisfy the quota
|
||||
conditions and the Deployment controller then completes the Deployment rollout, you'll see the
|
||||
Deployment's status update with a successful condition (`Status=True` and `Reason=NewReplicaSetAvailable`).
|
||||
|
||||
```
|
||||
Conditions:
|
||||
Type Status Reason
|
||||
---- ------ ------
|
||||
Available True MinimumReplicasAvailable
|
||||
Progressing True NewReplicaSetAvailable
|
||||
```
|
||||
|
||||
`Type=Available` with `Status=True` means that your Deployment has minimum availability. Minimum availability is dictated
|
||||
by the parameters specified in the deployment strategy. `Type=Progressing` with `Status=True` means that your Deployment
|
||||
is either in the middle of a rollout and it is progressing or that it has successfully completed its progress and the minimum
|
||||
required new replicas are available (see the Reason of the condition for the particulars - in our case
|
||||
`Reason=NewReplicaSetAvailable` means that the Deployment is complete).
|
||||
|
||||
You can check if a Deployment has failed to progress by using `kubectl rollout status`. `kubectl rollout status`
|
||||
returns a non-zero exit code if the Deployment has exceeded the progression deadline.
|
||||
|
||||
```shell
|
||||
$ kubectl rollout status deploy/nginx-deployment
|
||||
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
|
||||
error: deployment "nginx" exceeded its progress deadline
|
||||
$ echo $?
|
||||
1
|
||||
```
|
||||
|
||||
### Operating on a failed deployment
|
||||
|
||||
All actions that apply to a complete Deployment also apply to a failed Deployment. You can scale it up/down, roll back
|
||||
to a previous revision, or even pause it if you need to apply multiple tweaks in the Deployment pod template.
|
||||
|
||||
## Clean up Policy
|
||||
|
||||
You can set `.spec.revisionHistoryLimit` field in a Deployment to specify how many old ReplicaSets for
|
||||
this Deployment you want to retain. The rest will be garbage-collected in the background. By default,
|
||||
all revision history will be kept. In a future version, it will default to switch to 2.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** Explicitly setting this field to 0, will result in cleaning up all the history of your Deployment
|
||||
thus that Deployment will not be able to roll back.
|
||||
{{< /note >}}
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Canary Deployment
|
||||
|
||||
If you want to roll out releases to a subset of users or servers using the Deployment, you
|
||||
can create multiple Deployments, one for each release, following the canary pattern described in
|
||||
[managing resources](/docs/concepts/cluster-administration/manage-deployment/#canary-deployments).
|
||||
|
||||
## Writing a Deployment Spec
|
||||
|
||||
As with all other Kubernetes configs, a Deployment needs `apiVersion`, `kind`, and `metadata` fields.
|
||||
For general information about working with config files, see [deploying applications](/docs/tutorials/stateless-application/run-stateless-application-deployment/),
|
||||
configuring containers, and [using kubectl to manage resources](/docs/tutorials/object-management-kubectl/object-management/) documents.
|
||||
|
||||
A Deployment also needs a [`.spec` section](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status).
|
||||
|
||||
### Pod Template
|
||||
|
||||
The `.spec.template` is the only required field of the `.spec`.
|
||||
|
||||
The `.spec.template` is a [pod template](/docs/concepts/workloads/pods/pod-overview/#pod-templates). It has exactly the same schema as a [Pod](/docs/concepts/workloads/pods/pod/), except it is nested and does not have an
|
||||
`apiVersion` or `kind`.
|
||||
|
||||
In addition to required fields for a Pod, a pod template in a Deployment must specify appropriate
|
||||
labels and an appropriate restart policy. For labels, make sure not to overlap with other controllers. See [selector](#selector)).
|
||||
|
||||
Only a [`.spec.template.spec.restartPolicy`](/docs/concepts/workloads/pods/pod-lifecycle/) equal to `Always` is
|
||||
allowed, which is the default if not specified.
|
||||
|
||||
### Replicas
|
||||
|
||||
`.spec.replicas` is an optional field that specifies the number of desired Pods. It defaults to 1.
|
||||
|
||||
### Selector
|
||||
|
||||
`.spec.selector` is an optional field that specifies a [label selector](/docs/concepts/overview/working-with-objects/labels/)
|
||||
for the Pods targeted by this deployment.
|
||||
|
||||
If specified, `.spec.selector` must match `.spec.template.metadata.labels`, or it will be rejected by
|
||||
the API. If `.spec.selector` is unspecified, `.spec.selector.matchLabels` defaults to
|
||||
`.spec.template.metadata.labels`.
|
||||
|
||||
A Deployment may terminate Pods whose labels match the selector if their template is different
|
||||
from `.spec.template` or if the total number of such Pods exceeds `.spec.replicas`. It brings up new
|
||||
Pods with `.spec.template` if the number of Pods is less than the desired number.
|
||||
|
||||
{{< note >}}
|
||||
**Note:** You should not create other pods whose labels match this selector, either directly, by creating
|
||||
another Deployment, or by creating another controller such as a ReplicaSet or a ReplicationController. If you
|
||||
do so, the first Deployment thinks that it created these other pods. Kubernetes does not stop you from doing this.
|
||||
{{< /note >}}
|
||||
|
||||
If you have multiple controllers that have overlapping selectors, the controllers will fight with each
|
||||
other and won't behave correctly.
|
||||
|
||||
### Strategy
|
||||
|
||||
`.spec.strategy` specifies the strategy used to replace old Pods by new ones.
|
||||
`.spec.strategy.type` can be "Recreate" or "RollingUpdate". "RollingUpdate" is
|
||||
the default value.
|
||||
|
||||
#### Recreate Deployment
|
||||
|
||||
All existing Pods are killed before new ones are created when `.spec.strategy.type==Recreate`.
|
||||
|
||||
#### Rolling Update Deployment
|
||||
|
||||
The Deployment updates Pods in a [rolling update](/docs/tasks/run-application/rolling-update-replication-controller/)
|
||||
fashion when `.spec.strategy.type==RollingUpdate`. You can specify `maxUnavailable` and `maxSurge` to control
|
||||
the rolling update process.
|
||||
|
||||
##### Max Unavailable
|
||||
|
||||
`.spec.strategy.rollingUpdate.maxUnavailable` is an optional field that specifies the maximum number
|
||||
of Pods that can be unavailable during the update process. The value can be an absolute number (for example, 5)
|
||||
or a percentage of desired Pods (for example, 10%). The absolute number is calculated from percentage by
|
||||
rounding down. The value cannot be 0 if `.spec.strategy.rollingUpdate.maxSurge` is 0. The default value is 25%.
|
||||
|
||||
For example, when this value is set to 30%, the old ReplicaSet can be scaled down to 70% of desired
|
||||
Pods immediately when the rolling update starts. Once new Pods are ready, old ReplicaSet can be scaled
|
||||
down further, followed by scaling up the new ReplicaSet, ensuring that the total number of Pods available
|
||||
at all times during the update is at least 70% of the desired Pods.
|
||||
|
||||
##### Max Surge
|
||||
|
||||
`.spec.strategy.rollingUpdate.maxSurge` is an optional field that specifies the maximum number of Pods
|
||||
that can be created over the desired number of Pods. The value can be an absolute number (for example, 5) or a
|
||||
percentage of desired Pods (for example, 10%). The value cannot be 0 if `MaxUnavailable` is 0. The absolute number
|
||||
is calculated from the percentage by rounding up. The default value is 25%.
|
||||
|
||||
For example, when this value is set to 30%, the new ReplicaSet can be scaled up immediately when the
|
||||
rolling update starts, such that the total number of old and new Pods does not exceed 130% of desired
|
||||
Pods. Once old Pods have been killed, the new ReplicaSet can be scaled up further, ensuring that the
|
||||
total number of Pods running at any time during the update is at most 130% of desired Pods.
|
||||
|
||||
### Progress Deadline Seconds
|
||||
|
||||
`.spec.progressDeadlineSeconds` is an optional field that specifies the number of seconds you want
|
||||
to wait for your Deployment to progress before the system reports back that the Deployment has
|
||||
[failed progressing](#failed-deployment) - surfaced as a condition with `Type=Progressing`, `Status=False`.
|
||||
and `Reason=ProgressDeadlineExceeded` in the status of the resource. The deployment controller will keep
|
||||
retrying the Deployment. In the future, once automatic rollback will be implemented, the deployment
|
||||
controller will roll back a Deployment as soon as it observes such a condition.
|
||||
|
||||
If specified, this field needs to be greater than `.spec.minReadySeconds`.
|
||||
|
||||
### Min Ready Seconds
|
||||
|
||||
`.spec.minReadySeconds` is an optional field that specifies the minimum number of seconds for which a newly
|
||||
created Pod should be ready without any of its containers crashing, for it to be considered available.
|
||||
This defaults to 0 (the Pod will be considered available as soon as it is ready). To learn more about when
|
||||
a Pod is considered ready, see [Container Probes](/docs/concepts/workloads/pods/pod-lifecycle/#container-probes).
|
||||
|
||||
### Rollback To
|
||||
|
||||
`.spec.rollbackTo` is an optional field with the configuration the Deployment
|
||||
should roll back to. Setting this field triggers a rollback, and this field will
|
||||
be cleared by the server after a rollback is done.
|
||||
|
||||
Because this field will be cleared by the server, it should not be used
|
||||
declaratively. For example, you should not perform `kubectl apply` with a
|
||||
manifest with `.spec.rollbackTo` field set.
|
||||
|
||||
#### Revision
|
||||
|
||||
`.spec.rollbackTo.revision` is an optional field specifying the revision to roll
|
||||
back to. Setting to 0 means rolling back to the last revision in history;
|
||||
otherwise, means rolling back to the specified revision. This defaults to 0 when
|
||||
[`spec.rollbackTo`](#rollback-to) is set.
|
||||
|
||||
### Revision History Limit
|
||||
|
||||
A Deployment's revision history is stored in the replica sets it controls.
|
||||
|
||||
`.spec.revisionHistoryLimit` is an optional field that specifies the number of old ReplicaSets to retain
|
||||
to allow rollback. Its ideal value depends on the frequency and stability of new Deployments. All old
|
||||
ReplicaSets will be kept by default, consuming resources in `etcd` and crowding the output of `kubectl get rs`,
|
||||
if this field is not set. The configuration of each Deployment revision is stored in its ReplicaSets;
|
||||
therefore, once an old ReplicaSet is deleted, you lose the ability to rollback to that revision of Deployment.
|
||||
|
||||
More specifically, setting this field to zero means that all old ReplicaSets with 0 replica will be cleaned up.
|
||||
In this case, a new Deployment rollout cannot be undone, since its revision history is cleaned up.
|
||||
|
||||
### Paused
|
||||
|
||||
`.spec.paused` is an optional boolean field for pausing and resuming a Deployment. The only difference between
|
||||
a paused Deployment and one that is not paused, is that any changes into the PodTemplateSpec of the paused
|
||||
Deployment will not trigger new rollouts as long as it is paused. A Deployment is not paused by default when
|
||||
it is created.
|
||||
|
||||
## Alternative to Deployments
|
||||
|
||||
### kubectl rolling update
|
||||
|
||||
[Kubectl rolling update](/docs/user-guide/kubectl/{{< param "version" >}}/#rolling-update) updates Pods and ReplicationControllers
|
||||
in a similar fashion. But Deployments are recommended, since they are declarative, server side, and have
|
||||
additional features, such as rolling back to any previous revision even after the rolling update is done.
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: frontend
|
||||
# these labels can be applied automatically
|
||||
# from the labels in the pod template if not set
|
||||
# labels:
|
||||
# app: guestbook
|
||||
# tier: frontend
|
||||
spec:
|
||||
# this replicas value is default
|
||||
# modify it according to your case
|
||||
replicas: 3
|
||||
# selector can be applied automatically
|
||||
# from the labels in the pod template if not set,
|
||||
# but we are specifying the selector here to
|
||||
# demonstrate its usage.
|
||||
selector:
|
||||
matchLabels:
|
||||
tier: frontend
|
||||
matchExpressions:
|
||||
- {key: tier, operator: In, values: [frontend]}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: guestbook
|
||||
tier: frontend
|
||||
spec:
|
||||
containers:
|
||||
- name: php-redis
|
||||
image: gcr.io/google_samples/gb-frontend:v3
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 100Mi
|
||||
env:
|
||||
- name: GET_HOSTS_FROM
|
||||
value: dns
|
||||
# If your cluster config does not include a dns service, then to
|
||||
# instead access environment variables to find service host
|
||||
# info, comment out the 'value: dns' line above, and uncomment the
|
||||
# line below.
|
||||
# value: env
|
||||
ports:
|
||||
- containerPort: 80
|
||||
@@ -0,0 +1,181 @@
|
||||
---
|
||||
title: 垃圾收集
|
||||
redirect_from:
|
||||
- "/docs/concepts/abstractions/controllers/garbage-collection/"
|
||||
- "/docs/concepts/abstractions/controllers/garbage-collection.html"
|
||||
- "/docs/user-guide/garbage-collection/"
|
||||
- "/docs/user-guide/garbage-collection.html"
|
||||
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
|
||||
Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。
|
||||
|
||||
**注意**:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
|
||||
## Owner 和 Dependent
|
||||
|
||||
某些 Kubernetes 对象是其它一些对象的 Owner。例如,一个 ReplicaSet 是一组 Pod 的 Owner。
|
||||
具有 Owner 的对象被称为是 Owner 的 *Dependent*。
|
||||
每个 Dependent 对象具有一个指向其所属对象的 `metadata.ownerReferences` 字段。
|
||||
|
||||
有时,Kubernetes 会自动设置 `ownerReference` 的值。
|
||||
例如,当创建一个 ReplicaSet 时,Kubernetes 自动设置 ReplicaSet 中每个 Pod 的 `ownerReference` 字段值。
|
||||
在 1.6 版本,Kubernetes 会自动为某些对象设置 `ownerReference` 的值,这些对象是由 ReplicationController、ReplicaSet、StatefulSet、DaemonSet 和 Deployment 所创建或管理。
|
||||
|
||||
|
||||
|
||||
也可以通过手动设置 `ownerReference` 的值,来指定 Owner 和 Dependent 之间的关系。
|
||||
|
||||
这里有一个配置文件,表示一个具有 3 个 Pod 的 ReplicaSet:
|
||||
|
||||
{{< code file="my-repset.yaml" >}}
|
||||
|
||||
|
||||
|
||||
如果创建该 ReplicaSet,然后查看 Pod 的 metadata 字段,能够看到 OwnerReferences 字段:
|
||||
|
||||
```shell
|
||||
kubectl create -f https://k8s.io/docs/concepts/controllers/my-repset.yaml
|
||||
kubectl get pods --output=yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
输出显示了 Pod 的 Owner 是名为 my-repset 的 ReplicaSet:
|
||||
|
||||
```shell
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
...
|
||||
ownerReferences:
|
||||
- apiVersion: extensions/v1beta1
|
||||
controller: true
|
||||
blockOwnerDeletion: true
|
||||
kind: ReplicaSet
|
||||
name: my-repset
|
||||
uid: d9607e19-f88f-11e6-a518-42010a800195
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
## 控制垃圾收集器删除 Dependent
|
||||
|
||||
当删除对象时,可以指定是否该对象的 Dependent 也自动删除掉。
|
||||
自动删除 Dependent 也称为 *级联删除*。
|
||||
Kubernetes 中有两种 *级联删除* 的模式:*background* 模式和 *foreground* 模式。
|
||||
|
||||
如果删除对象时,不自动删除它的 Dependent,这些 Dependent 被称作是原对象的 *孤儿*。
|
||||
|
||||
|
||||
|
||||
### Background 级联删除
|
||||
|
||||
在 *background 级联删除* 模式下,Kubernetes 会立即删除 Owner 对象,然后垃圾收集器会在后台删除这些 Dependent。
|
||||
|
||||
|
||||
|
||||
### Foreground 级联删除
|
||||
|
||||
在 *foreground 级联删除* 模式下,根对象首先进入 “删除中” 状态。在 “删除中” 状态会有如下的情况:
|
||||
|
||||
* 对象仍然可以通过 REST API 可见。
|
||||
* 会设置对象的 `deletionTimestamp` 字段。
|
||||
* 对象的 `metadata.finalizers` 字段包含了值 "foregroundDeletion"。
|
||||
|
||||
一旦对象被设置为 “删除中” 状态,垃圾收集器会删除对象的所有 Dependent。
|
||||
垃圾收集器在删除了所有 “Blocking” 状态的 Dependent(对象的 `ownerReference.blockOwnerDeletion=true`)之后,它会删除 Owner 对象。
|
||||
|
||||
|
||||
|
||||
注意,在 “foreground 删除” 模式下,只有设置了 `ownerReference.blockOwnerDeletion` 值得 Dependent 才能阻止删除 Owner 对象。
|
||||
在 Kubernetes 1.7 版本中将增加许可控制器(Admission Controller),基于 Owner 对象上的删除权限来控制用户去设置 `blockOwnerDeletion` 的值为 true,所以未授权的 Dependent 不能够延迟 Owner 对象的删除。
|
||||
|
||||
如果一个对象的 `ownerReferences` 字段被一个 Controller(例如 Deployment 或 ReplicaSet)设置,`blockOwnerDeletion` 会被自动设置,不需要手动修改这个字段。
|
||||
|
||||
|
||||
|
||||
### 设置级联删除策略
|
||||
|
||||
通过为 Owner 对象设置 `deleteOptions.propagationPolicy` 字段,可以控制级联删除策略。
|
||||
可能的取值包括:“orphan”、“Foreground” 或 “Background”。
|
||||
|
||||
对很多 Controller 资源,包括 ReplicationController、ReplicaSet、StatefulSet、DaemonSet 和 Deployment,默认的垃圾收集策略是 `orphan`。
|
||||
因此,除非指定其它的垃圾收集策略,否则所有 Dependent 对象使用的都是 `orphan` 策略。
|
||||
|
||||
下面是一个在后台删除 Dependent 对象的例子:
|
||||
|
||||
```shell
|
||||
kubectl proxy --port=8080
|
||||
curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \
|
||||
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
|
||||
|
||||
下面是一个在前台删除 Dependent 对象的例子:
|
||||
|
||||
```shell
|
||||
kubectl proxy --port=8080
|
||||
curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \
|
||||
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
|
||||
下面是一个孤儿 Dependent 的例子:
|
||||
|
||||
```shell
|
||||
kubectl proxy --port=8080
|
||||
curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \
|
||||
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
|
||||
|
||||
kubectl 也支持级联删除。
|
||||
通过设置 `--cascade` 为 true,可以使用 kubectl 自动删除 Dependent 对象。
|
||||
设置 `--cascade` 为 false,会使 Dependent 对象成为孤儿 Dependent 对象。
|
||||
`--cascade` 的默认值是 true。
|
||||
|
||||
下面是一个例子,使一个 ReplicaSet 的 Dependent 对象成为孤儿 Dependent:
|
||||
|
||||
|
||||
```shell
|
||||
kubectl delete replicaset my-repset --cascade=false
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 已知的问题
|
||||
* 1.7 版本,垃圾收集不支持 [自定义资源](/docs/concepts/api-extension/custom-resources/),比如那些通过 CustomResourceDefinition 新增,或者通过 API server 聚集而成的资源对象。
|
||||
|
||||
[其它已知的问题](https://github.com/kubernetes/kubernetes/issues/26120)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
|
||||
|
||||
[设计文档 1](https://git.k8s.io/community/contributors/design-proposals/garbage-collection.md)
|
||||
[设计文档 2](https://git.k8s.io/community/contributors/design-proposals/synchronous-garbage-collection.md)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: autoscaling/v1
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: frontend-scaler
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
kind: ReplicaSet
|
||||
name: frontend
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 50
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: pi
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: pi
|
||||
spec:
|
||||
containers:
|
||||
- name: pi
|
||||
image: perl
|
||||
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
|
||||
restartPolicy: Never
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: ReplicaSet
|
||||
metadata:
|
||||
name: my-repset
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
pod-is-for: garbage-collection-example
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
pod-is-for: garbage-collection-example
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.7.9
|
||||
ports:
|
||||
- containerPort: 80
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
@@ -0,0 +1,331 @@
|
||||
---
|
||||
approvers:
|
||||
- erictune
|
||||
title: Init 容器
|
||||
redirect_from:
|
||||
- "/docs/concepts/abstractions/init-containers/"
|
||||
- "/docs/concepts/abstractions/init-containers.html"
|
||||
- "/docs/user-guide/pods/init-container/"
|
||||
- "/docs/user-guide/pods/init-container.html"
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本页提供了 Init 容器的概览,它是一种专用的容器,在应用容器启动之前运行,并包括一些应用镜像中不存在的实用工具和安装脚本。
|
||||
{{% /capture %}}
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
|
||||
这个特性在 1.6 版本已经退出 beta 版本。Init 容器可以在 PodSpec 中同应用的 `containers` 数组一起来指定。
|
||||
beta 注解的值将仍然需要保留,并覆盖 PodSpec 字段值。
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
|
||||
## 理解 Init 容器
|
||||
|
||||
|
||||
|
||||
[Pod](/docs/concepts/abstractions/pod/) 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器。
|
||||
|
||||
Init 容器与普通的容器非常像,除了如下两点:
|
||||
|
||||
|
||||
|
||||
* 它们总是运行到完成。
|
||||
* 每个都必须在下一个启动之前成功完成。
|
||||
|
||||
|
||||
|
||||
如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 `restartPolicy` 值为 Never,它不会重新启动。
|
||||
|
||||
指定容器为 Init 容器,需要在 PodSpec 中添加 `initContainers` 字段,以 [v1.Container](/docs/api-reference/v1.6/#container-v1-core) 类型对象的 JSON 数组的形式,还有 app 的 `containers` 数组。
|
||||
Init 容器的状态在 `status.initContainerStatuses` 字段中以容器状态数组的格式返回(类似 `status.containerStatuses` 字段)。
|
||||
|
||||
|
||||
|
||||
### 与普通容器的不同之处
|
||||
|
||||
Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。
|
||||
然而,Init 容器对资源请求和限制的处理稍有不同,在下面 [资源](#resources) 处有说明。
|
||||
而且 Init 容器不支持 Readiness Probe,因为它们必须在 Pod 就绪之前运行完成。
|
||||
|
||||
如果为一个 Pod 指定了多个 Init 容器,那些容器会按顺序一次运行一个。
|
||||
每个 Init 容器必须运行成功,下一个才能够运行。
|
||||
当所有的 Init 容器运行完成时,Kubernetes 初始化 Pod 并像平常一样运行应用容器。
|
||||
|
||||
|
||||
|
||||
## Init 容器能做什么?
|
||||
|
||||
因为 Init 容器具有与应用容器分离的单独镜像,它们的启动相关代码具有如下优势:
|
||||
|
||||
* 它们可以包含并运行实用工具,处于安全考虑,是不建议在应用容器镜像中包含这些实用工具的。
|
||||
* 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用镜像中。例如,创建镜像没必要 `FROM` 另一个镜像,只需要在安装过程中使用类似 `sed`、 `awk`、 `python` 或 `dig` 这样的工具。
|
||||
* 应用镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
|
||||
* 它们使用 Linux Namespace,所以对应用容器具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用容器不能够访问。
|
||||
* 它们在应用容器启动之前运行完成,然而应用容器并行运行,所以 Init 容器提供了一种简单的方式来阻塞或延迟应用容器的启动,直到满足了一组先决条件。
|
||||
|
||||
|
||||
|
||||
### 示例
|
||||
|
||||
下面是一些如何使用 Init 容器的想法:
|
||||
|
||||
* 等待一个 Service 完成创建,通过类似如下 shell 命令:
|
||||
|
||||
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; exit 1
|
||||
|
||||
* 注册这个 Pod 到远程服务器,通过在命令中调用 API,类似如下:
|
||||
|
||||
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
|
||||
|
||||
* 在启动应用容器之前等一段时间,使用类似 `sleep 60` 的命令。
|
||||
* 克隆 Git 仓库到数据卷。
|
||||
* 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。
|
||||
|
||||
更多详细用法示例,可以在 [StatefulSet 文档](/docs/concepts/abstractions/controllers/statefulsets/) 和 [Pod 初始化](/docs/tasks/configure-pod-container/configure-pod-initialization) 中找到。
|
||||
|
||||
|
||||
|
||||
### 使用 Init 容器
|
||||
|
||||
下面是 Kubernetes 1.5 版本 yaml 文件,展示了一个具有 2 个 Init 容器的简单 Pod。
|
||||
第一个等待 `myservice` 启动,第二个等待 `mydb` 启动。
|
||||
一旦这两个 Service 都启动完成,Pod 将开始启动。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod
|
||||
labels:
|
||||
app: myapp
|
||||
annotations:
|
||||
pod.beta.kubernetes.io/init-containers: '[
|
||||
{
|
||||
"name": "init-myservice",
|
||||
"image": "busybox",
|
||||
"command": ["sh", "-c", "until nslookup myservice; do echo waiting for myservice; sleep 2; done;"]
|
||||
},
|
||||
{
|
||||
"name": "init-mydb",
|
||||
"image": "busybox",
|
||||
"command": ["sh", "-c", "until nslookup mydb; do echo waiting for mydb; sleep 2; done;"]
|
||||
}
|
||||
]'
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp-container
|
||||
image: busybox
|
||||
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
|
||||
```
|
||||
|
||||
|
||||
|
||||
这是 Kubernetes 1.6 版本的新语法,尽管老的 annotation 语法仍然可以使用。我们已经把 Init 容器的声明移到 `spec` 中:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: myapp-pod
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp-container
|
||||
image: busybox
|
||||
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
|
||||
initContainers:
|
||||
- name: init-myservice
|
||||
image: busybox
|
||||
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
|
||||
- name: init-mydb
|
||||
image: busybox
|
||||
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
|
||||
```
|
||||
|
||||
|
||||
|
||||
1.5 版本的语法在 1.6 版本仍然可以使用,但是我们推荐使用 1.6 版本的新语法。
|
||||
在 Kubernetes 1.6 版本中,Init 容器在 API 中新建了一个字段。
|
||||
虽然期望使用 beta 版本的 annotation,但在未来发行版将会被废弃掉。
|
||||
|
||||
下面的 yaml 文件展示了 `mydb` 和 `myservice` 两个 Service:
|
||||
|
||||
```
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: myservice
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
---
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: mydb
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9377
|
||||
```
|
||||
|
||||
|
||||
|
||||
这个 Pod 可以使用下面的命令进行启动和调试:
|
||||
|
||||
```
|
||||
$ kubectl create -f myapp.yaml
|
||||
pod "myapp-pod" created
|
||||
$ kubectl get -f myapp.yaml
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
myapp-pod 0/1 Init:0/2 0 6m
|
||||
$ kubectl describe -f myapp.yaml
|
||||
Name: myapp-pod
|
||||
Namespace: default
|
||||
[...]
|
||||
Labels: app=myapp
|
||||
Status: Pending
|
||||
[...]
|
||||
Init Containers:
|
||||
init-myservice:
|
||||
[...]
|
||||
State: Running
|
||||
[...]
|
||||
init-mydb:
|
||||
[...]
|
||||
State: Waiting
|
||||
Reason: PodInitializing
|
||||
Ready: False
|
||||
[...]
|
||||
Containers:
|
||||
myapp-container:
|
||||
[...]
|
||||
State: Waiting
|
||||
Reason: PodInitializing
|
||||
Ready: False
|
||||
[...]
|
||||
Events:
|
||||
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
|
||||
--------- -------- ----- ---- ------------- -------- ------ -------
|
||||
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
|
||||
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
|
||||
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
|
||||
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
|
||||
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
|
||||
$ kubectl logs myapp-pod -c init-myservice # Inspect the first init container
|
||||
$ kubectl logs myapp-pod -c init-mydb # Inspect the second init container
|
||||
```
|
||||
|
||||
|
||||
|
||||
一旦我们启动了 `mydb` 和 `myservice` 这两个 Service,我们能够看到 Init 容器完成,并且 `myapp-pod` 被创建:
|
||||
|
||||
```
|
||||
$ kubectl create -f services.yaml
|
||||
service "myservice" created
|
||||
service "mydb" created
|
||||
$ kubectl get -f myapp.yaml
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
myapp-pod 1/1 Running 0 9m
|
||||
```
|
||||
|
||||
|
||||
|
||||
这个例子非常简单,但是应该能够为创建自己的 Init 容器提供一些启发。
|
||||
|
||||
|
||||
|
||||
## 具体行为
|
||||
|
||||
在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。
|
||||
每个容器必须在下一个容器启动之前成功退出。
|
||||
如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 `restartPolicy` 指定的策略进行重试。
|
||||
然而,如果 Pod 的 `restartPolicy` 设置为 Always,Init 容器失败时会使用 `RestartPolicy` 策略。
|
||||
|
||||
|
||||
|
||||
在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。
|
||||
Init 容器的端口将不会在 Service 中进行聚集。
|
||||
正在初始化中的 Pod 处于 `Pending` 状态,但应该会将条件 `Initializing` 设置为 true。
|
||||
|
||||
如果 Pod [重启](#pod-restart-reasons),所有 Init 容器必须重新执行。
|
||||
|
||||
对 Init 容器 spec 的修改,被限制在容器 image 字段中。
|
||||
更改 Init 容器的 image 字段,等价于重启该 Pod。
|
||||
|
||||
|
||||
|
||||
因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。
|
||||
特别地,被写到 `EmptyDirs` 中文件的代码,应该对输出文件可能已经存在做好准备。
|
||||
|
||||
Init 容器具有应用容器的所有字段。
|
||||
然而 Kubernetes 禁止使用 `readinessProbe`,因为 Init 容器不能够定义不同于完成(completion)的就绪(readiness)。
|
||||
这会在验证过程中强制执行。
|
||||
|
||||
|
||||
|
||||
在 Pod 上使用 `activeDeadlineSeconds`,在容器上使用 `livenessProbe`,这样能够避免 Init 容器一直失败。
|
||||
这就为 Init 容器活跃设置了一个期限。
|
||||
|
||||
在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误。
|
||||
|
||||
|
||||
|
||||
### 资源
|
||||
|
||||
为 Init 容器指定顺序和执行逻辑,下面对资源使用的规则将被应用:
|
||||
|
||||
|
||||
|
||||
* 在所有 Init 容器上定义的,任何特殊资源请求或限制的最大值,是 *有效初始请求/限制*
|
||||
* Pod 对资源的 *有效请求/限制* 要高于:
|
||||
* 所有应用容器对某个资源的请求/限制之和
|
||||
* 对某个资源的有效初始请求/限制
|
||||
* 基于有效请求/限制完成调度,这意味着 Init 容器能够为初始化预留资源,这些资源在 Pod 生命周期过程中并没有被使用。
|
||||
* Pod 的 *有效 QoS 层*,是 Init 容器和应用容器相同的 QoS 层。
|
||||
|
||||
|
||||
|
||||
基于有效 Pod 请求和限制来应用配额和限制。
|
||||
Pod 级别的 cgroups 是基于有效 Pod 请求和限制,和调度器相同。
|
||||
|
||||
|
||||
|
||||
### Pod 重启的原因
|
||||
|
||||
Pod 能够重启,会导致 Init 容器重新执行,主要有如下几个原因:
|
||||
|
||||
* 用户更新 PodSpec 导致 Init 容器镜像发生改变。应用容器镜像的变更只会重启应用容器。
|
||||
* Pod 基础设施容器被重启。这不多见,但某些具有 root 权限可访问 Node 的人可能会这样做。
|
||||
* 当 `restartPolicy` 设置为 Always,Pod 中所有容器会终止,强制重启,由于垃圾收集导致 Init 容器完成的记录丢失。
|
||||
|
||||
|
||||
|
||||
## 支持与兼容性
|
||||
|
||||
Apiserver 版本为 1.6 或更高版本的集群,通过使用 `spec.initContainers` 字段来支持 Init 容器。
|
||||
之前的版本可以使用 alpha 和 beta 注解支持 Init 容器。
|
||||
`spec.initContainers` 字段也被加入到 alpha 和 beta 注解中,所以 Kubernetes 1.3.0 版本或更高版本可以执行 Init 容器,并且 1.6 版本的 apiserver 能够安全的回退到 1.5.x 版本,而不会使存在的已创建 Pod 失去 Init 容器的功能。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
|
||||
|
||||
* [创建具有 Init 容器的 Pod](/docs/tasks/configure-pod-container/configure-pod-initialization/#creating-a-pod-that-has-an-init-container)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
title: Pod 的生命周期
|
||||
redirect_from:
|
||||
- "/docs/user-guide/pod-states/"
|
||||
- "/docs/user-guide/pod-states.html"
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
{{< comment >}}Updated: 4/14/2015{{< /comment >}}
|
||||
{{< comment >}}Edited and moved to Concepts section: 2/2/17{{< /comment >}}
|
||||
|
||||
该页面将描述 Pod 的生命周期。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Pod phase
|
||||
|
||||
Pod 的 `status` 定义在 [PodStatus](/docs/resources-reference/v1.7/#podstatus-v1-core) 对象中,其中有一个 `phase` 字段。
|
||||
|
||||
Pod 的运行阶段(phase)是 Pod 在其生命周期中的简单宏观概述。该阶段并不是对容器或 Pod 的综合汇总,也不是为了做为综合状态机。
|
||||
|
||||
Pod 相位的数量和含义是严格指定的。除了本文档中列举的内容外,不应该再假定 Pod 有其他的 `phase` 值。
|
||||
|
||||
下面是 `phase` 可能的值:
|
||||
|
||||
- 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度 Pod 的时间和通过网络下载镜像的时间,这可能需要花点时间。
|
||||
- 运行中(Running):该 Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
|
||||
- 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。
|
||||
- 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
|
||||
- 未知(Unknown):因为某些原因无法取得 Pod 的状态,通常是因为与 Pod 所在主机通信失败。
|
||||
|
||||
## Pod 状态
|
||||
|
||||
Pod 有一个 PodStatus 对象,其中包含一个 [PodCondition](/docs/resources-reference/v1.7/#podcondition-v1-core) 数组。 PodCondition 数组的每个元素都有一个 `type` 字段和一个 `status` 字段。`type` 字段是字符串,可能的值有 PodScheduled、Ready、Initialized 和 Unschedulable。`status` 字段是一个字符串,可能的值有 True、False 和 Unknown。
|
||||
|
||||
## 容器探针
|
||||
|
||||
[探针](/docs/resources-reference/v1.7/#probe-v1-core) 是由 [kubelet](/docs/admin/kubelet/) 对容器执行的定期诊断。要执行诊断,kubelet 调用由容器实现的 [Handler](https://godoc.org/k8s.io/kubernetes/pkg/api/v1#Handler)。有三种类型的处理程序:
|
||||
|
||||
- [ExecAction](/docs/resources-reference/v1.7/#execaction-v1-core):在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
|
||||
- [TCPSocketAction](/docs/resources-reference/v1.7/#tcpsocketaction-v1-core):对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
|
||||
- [HTTPGetAction](/docs/resources-reference/v1.7/#httpgetaction-v1-core):对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
|
||||
|
||||
每次探测都将获得以下三种结果之一:
|
||||
|
||||
- 成功:容器通过了诊断。
|
||||
- 失败:容器未通过诊断。
|
||||
- 未知:诊断失败,因此不会采取任何行动。
|
||||
|
||||
Kubelet 可以选择是否执行在容器上运行的两种探针执行和做出反应:
|
||||
|
||||
- `livenessProbe`:指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 [重启策略](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) 的影响。如果容器不提供存活探针,则默认状态为 `Success`。
|
||||
- `readinessProbe`:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 `Failure`。如果容器不提供就绪探针,则默认状态为 `Success`。
|
||||
|
||||
### 该什么时候使用存活(liveness)和就绪(readiness)探针?
|
||||
|
||||
如果容器中的进程能够在遇到问题或不健康的情况下自行崩溃,则不一定需要存活探针; kubelet 将根据 Pod 的`restartPolicy` 自动执行正确的操作。
|
||||
|
||||
如果您希望容器在探测失败时被杀死并重新启动,那么请指定一个存活探针,并指定`restartPolicy` 为 Always 或 OnFailure。
|
||||
|
||||
如果要仅在探测成功时才开始向 Pod 发送流量,请指定就绪探针。在这种情况下,就绪探针可能与存活探针相同,但是 spec 中的就绪探针的存在意味着 Pod 将在没有接收到任何流量的情况下启动,并且只有在探针探测成功后才开始接收流量。
|
||||
|
||||
如果您希望容器能够自行维护,您可以指定一个就绪探针,该探针检查与存活探针不同的端点。
|
||||
|
||||
请注意,如果您只想在 Pod 被删除时能够排除请求,则不一定需要使用就绪探针;在删除 Pod 时,Pod 会自动将自身置于未完成状态,无论就绪探针是否存在。当等待 Pod 中的容器停止时,Pod 仍处于未完成状态。
|
||||
|
||||
## Pod 和容器状态
|
||||
|
||||
有关 Pod 容器状态的详细信息,请参阅 [PodStatus](/docs/resources-reference/v1.7/#podstatus-v1-core) 和 [ContainerStatus](/docs/resources-reference/v1.7/#containerstatus-v1-core)。请注意,报告的 Pod 状态信息取决于当前的 [ContainerState](/docs/resources-reference/v1.7/#containerstatus-v1-core)。
|
||||
|
||||
## 重启策略
|
||||
|
||||
PodSpec 中有一个 `restartPolicy` 字段,可能的值为 Always、OnFailure 和 Never。默认为 Always。 `restartPolicy` 适用于 Pod 中的所有容器。`restartPolicy` 仅指通过同一节点上的 kubelet 重新启动容器。失败的容器由 kubelet 以五分钟为上限的指数退避延迟(10秒,20秒,40秒...)重新启动,并在成功执行十分钟后重置。如 [Pod 文档](/docs/user-guide/pods/#durability-of-pods-or-lack-thereof) 中所述,一旦绑定到一个节点,Pod 将永远不会重新绑定到另一个节点。
|
||||
|
||||
## Pod 的生命
|
||||
|
||||
一般来说,Pod 不会消失,直到人为销毁他们。这可能是一个人或控制器。这个规则的唯一例外是成功或失败的 `phase` 超过一段时间(由 master 确定)的Pod将过期并被自动销毁。
|
||||
|
||||
有三种可用的控制器:
|
||||
|
||||
- 使用 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/) 运行预期会终止的 Pod,例如批量计算。Job 仅适用于重启策略为 `OnFailure` 或 `Never` 的 Pod。
|
||||
|
||||
|
||||
- 对预期不会终止的 Pod 使用 [ReplicationController](/docs/concepts/workloads/controllers/replicationcontroller/)、[ReplicaSet](/docs/concepts/workloads/controllers/replicaset/) 和 [Deployment](/docs/concepts/workloads/controllers/deployment/) ,例如 Web 服务器。 ReplicationController 仅适用于具有 `restartPolicy` 为 Always 的 Pod。
|
||||
- 提供特定于机器的系统服务,使用 [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) 为每台机器运行一个 Pod 。
|
||||
|
||||
所有这三种类型的控制器都包含一个 PodTemplate。建议创建适当的控制器,让它们来创建 Pod,而不是直接自己创建 Pod。这是因为单独的 Pod 在机器故障的情况下没有办法自动复原,而控制器却可以。
|
||||
|
||||
如果节点死亡或与集群的其余部分断开连接,则 Kubernetes 将应用一个策略将丢失节点上的所有 Pod 的 `phase` 设置为 Failed。
|
||||
|
||||
## 示例
|
||||
|
||||
### 高级 liveness 探针示例
|
||||
|
||||
存活探针由 kubelet 来执行,因此所有的请求都在 kubelet 的网络命名空间中进行。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
test: liveness
|
||||
name: liveness-http
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- /server
|
||||
image: k8s.gcr.io/liveness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
# when "host" is not defined, "PodIP" will be used
|
||||
# host: my-host
|
||||
# when "scheme" is not defined, "HTTP" scheme will be used. Only "HTTP" and "HTTPS" are allowed
|
||||
# scheme: HTTPS
|
||||
path: /healthz
|
||||
port: 8080
|
||||
httpHeaders:
|
||||
- name: X-Custom-Header
|
||||
value: Awesome
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 1
|
||||
name: liveness
|
||||
```
|
||||
|
||||
### 状态示例
|
||||
|
||||
- Pod 中只有一个容器并且正在运行。容器成功退出。
|
||||
- 记录完成事件。
|
||||
- 如果 `restartPolicy` 为:
|
||||
- Always:重启容器;Pod `phase` 仍为 Running。
|
||||
- OnFailure:Pod `phase` 变成 Succeeded。
|
||||
- Never:Pod `phase` 变成 Succeeded。
|
||||
- Pod 中只有一个容器并且正在运行。容器退出失败。
|
||||
- 记录失败事件。
|
||||
- 如果 `restartPolicy` 为:
|
||||
- Always:重启容器;Pod `phase` 仍为 Running。
|
||||
- OnFailure:重启容器;Pod `phase` 仍为 Running。
|
||||
- Never:Pod `phase` 变成 Failed。
|
||||
- Pod 中有两个容器并且正在运行。有一个容器退出失败。
|
||||
- 记录失败事件。
|
||||
- 如果 restartPolicy 为:
|
||||
- Always:重启容器;Pod `phase` 仍为 Running。
|
||||
- OnFailure:重启容器;Pod `phase` 仍为 Running。
|
||||
- Never:不重启容器;Pod `phase` 仍为 Running。
|
||||
- 如果有一个容器没有处于运行状态,并且两个容器退出:
|
||||
- 记录失败事件。
|
||||
- 如果 `restartPolicy` 为:
|
||||
- Always:重启容器;Pod `phase` 仍为 Running。
|
||||
- OnFailure:重启容器;Pod `phase` 仍为 Running。
|
||||
- Never:Pod `phase` 变成 Failed。
|
||||
- Pod 中只有一个容器并处于运行状态。容器运行时内存超出限制:
|
||||
- 容器以失败状态终止。
|
||||
- 记录 OOM 事件。
|
||||
- 如果 `restartPolicy` 为:
|
||||
- Always:重启容器;Pod `phase` 仍为 Running。
|
||||
- OnFailure:重启容器;Pod `phase` 仍为 Running。
|
||||
- Never: 记录失败事件;Pod `phase` 仍为 Failed。
|
||||
- Pod 正在运行,磁盘故障:
|
||||
- 杀掉所有容器。
|
||||
- 记录适当事件。
|
||||
- Pod `phase` 变成 Failed。
|
||||
- 如果使用控制器来运行,Pod 将在别处重建。
|
||||
- Pod 正在运行,其节点被分段。
|
||||
- 节点控制器等待直到超时。
|
||||
- 节点控制器将 Pod `phase` 设置为 Failed。
|
||||
- 如果是用控制器来运行,Pod 将在别处重建。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
approvers:
|
||||
- jessfraz
|
||||
title: Pod Preset
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
本文提供了 PodPreset 的概述。 在 pod 创建时,用户可以使用 `podpreset` 对象将特定信息注入
|
||||
pod 中,这些信息可以包括 secret、 卷、卷挂载和环境变量。
|
||||
{{% /capture %}}
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
{{% capture body %}}
|
||||
## 理解 Pod Preset
|
||||
|
||||
`Pod Preset` 是一种 API 资源,在 pod 创建时,用户可以用它将额外的运行时需求信息注入 pod。
|
||||
使用[标签选择器(label selector)](/docs/concepts/overview/working-with-objects/labels/#label-selectors)来指定 Pod Preset 所适用的 pod。
|
||||
|
||||
使用 Pod Preset 使得 pod 模板编写者不必显式地为每个 pod 设置信息。
|
||||
这样,使用特定服务的 pod 模板编写者不需要了解该服务的所有细节。
|
||||
|
||||
了解更多的相关背景信息,请参考 [ PodPreset 设计提案](https://git.k8s.io/community/contributors/design-proposals/service-catalog/pod-preset.md)。
|
||||
|
||||
## PodPreset 如何工作
|
||||
|
||||
Kubernetes 提供了准入控制器 (`PodPreset`),该控制器被启用时,会将 Pod Preset
|
||||
应用于接收到的 pod 创建请求中。
|
||||
当出现 pod 创建请求时,系统会执行以下操作:
|
||||
|
||||
1. 检索所有可用 `PodPresets` 。
|
||||
1. 检查 `PodPreset` 的标签选择器与要创建的 pod 的标签是否匹配。
|
||||
1. 尝试合并 `PodPreset` 中定义的各种资源,并注入要创建的 pod。
|
||||
1. 发生错误时抛出事件,该事件记录了 pod 信息合并错误,同时在 _不注入_ `PodPreset` 信息的情况下创建 pod。
|
||||
1. 为改动的 pod spec 添加注解,来表明它被 `PodPreset` 所修改。 注解形如:
|
||||
`podpreset.admission.kubernetes.io/podpreset-<pod-preset name>": "<resource version>"`。
|
||||
|
||||
一个 Pod 可能不与任何 Pod Preset 匹配,也可能匹配多个 Pod Preset。 同时,一个 `PodPreset`
|
||||
可能不应用于任何 Pod,也可能应用于多个 Pod。 当 `PodPreset` 应用于一个或多个 Pod 时,Kubernetes
|
||||
修改 pod spec。 对于 `Env`、 `EnvFrom` 和 `VolumeMounts` 的改动, Kubernetes 修改 pod
|
||||
中所有容器的规格,对于卷的改动,Kubernetes 修改 Pod spec。
|
||||
|
||||
{{< note >}}
|
||||
**注意:** Pod Preset 能够在适当的时候修改 Pod spec 的 `spec.containers` 字段,
|
||||
但是不会应用于 `initContainers` 字段。
|
||||
{{< /note >}}
|
||||
|
||||
### 为特定 Pod 禁用 Pod Preset
|
||||
|
||||
在一些情况下,用户不希望 pod 被 pod preset 所改动,这时,用户可以在 pod spec 中添加形如
|
||||
`podpreset.admission.kubernetes.io/exclude: "true"` 的注解。
|
||||
|
||||
## 启用 Pod Preset
|
||||
|
||||
为了在集群中使用 Pod Preset,必须确保以下几点:
|
||||
|
||||
1. 已启用 api 类型 `settings.k8s.io/v1alpha1/podpreset`。 这可以通过在 API 服务器的
|
||||
`--runtime-config` 配置项中包含 `settings.k8s.io/v1alpha1=true` 来实现。
|
||||
1. 已启用准入控制器 `PodPreset`。 启用的一种方式是在 API 服务器的 `--admission-control`
|
||||
配置项中包含 `PodPreset` 。
|
||||
1. 已经通过在相应的名字空间中创建 `PodPreset` 对象,定义了 Pod preset。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [使用 PodPreset 将信息注入 Pods](/docs/tasks/inject-data-application/podpreset/)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: 知名标签(Label)、注解(Annotation)和 Taints
|
||||
---
|
||||
|
||||
Kubernetes 保留了 kubernetes.io 名字空间下的所有标签和注解。 本文描述了知名的
|
||||
kubernetes.io 标签和注解。
|
||||
|
||||
本文既作为这些标签和注解值的参考,也就这些标签和注解的赋值进行了说明。
|
||||
|
||||
**目录:**
|
||||
<!-- BEGIN MUNGE: GENERATED_TOC -->
|
||||
|
||||
- [知名标签、注解和 Taints](#well-known-labels-annotations-and-taints)
|
||||
- [beta.kubernetes.io/arch](#betakubernetesioarch)
|
||||
- [beta.kubernetes.io/os](#betakubernetesioos)
|
||||
- [kubernetes.io/hostname](#kubernetesiohostname)
|
||||
- [beta.kubernetes.io/instance-type](#betakubernetesioinstance-type)
|
||||
- [failure-domain.beta.kubernetes.io/region](#failure-domainbetakubernetesioregion)
|
||||
- [failure-domain.beta.kubernetes.io/zone](#failure-domainbetakubernetesiozone)
|
||||
|
||||
<!-- END MUNGE: GENERATED_TOC -->
|
||||
|
||||
|
||||
## beta.kubernetes.io/arch
|
||||
|
||||
示例:`beta.kubernetes.io/arch=amd64`
|
||||
|
||||
用于:节点
|
||||
|
||||
Kubelet 用 Go 中定义的 `runtime.GOARCH` 值来填充该标签。 这在诸如混用 arm 和 x86 节点的情况下很有用。
|
||||
|
||||
## beta.kubernetes.io/os
|
||||
|
||||
示例:`beta.kubernetes.io/os=linux`
|
||||
|
||||
用于:节点
|
||||
|
||||
Kubelet 用该 Go 中定义的 `runtime.GOOS` 值来填充该标签。 这在集群中存在不同操作系统的节点时很有用(尽管当前 Kubernetes 只支持 Linux 操作系统)。
|
||||
|
||||
## kubernetes.io/hostname
|
||||
|
||||
示例:`kubernetes.io/hostname=ip-172-20-114-199.ec2.internal`
|
||||
|
||||
用于:节点
|
||||
|
||||
Kubelet 用 hostname 值来填充该标签。 注意:可以通过向 kubelet 传入 `--hostname-override`
|
||||
参数对 “真正的” hostname 进行修改。
|
||||
|
||||
## beta.kubernetes.io/instance-type
|
||||
|
||||
示例:`beta.kubernetes.io/instance-type=m3.medium`
|
||||
|
||||
用于:节点
|
||||
|
||||
Kubelet 用 `cloudprovider` 中定义的实例类型来填充该标签。 未使用 `cloudprovider` 时不会设置该标签。
|
||||
该标签在想要将某些负载定向到特定实例类型的节点上时会很有用,但通常用户更希望依赖 Kubernetes 调度器来执行基于资源的调度,所以用户应该致力于基于属性而不是实例类型来进行调度(例如:需要一个 CPU,而不是 `g2.2xlarge`)。
|
||||
|
||||
|
||||
## failure-domain.beta.kubernetes.io/region
|
||||
|
||||
参考 [failure-domain.beta.kubernetes.io/zone](#failure-domainbetakubernetesiozone).
|
||||
|
||||
## failure-domain.beta.kubernetes.io/zone
|
||||
|
||||
示例:
|
||||
|
||||
`failure-domain.beta.kubernetes.io/region=us-east-1`
|
||||
|
||||
`failure-domain.beta.kubernetes.io/zone=us-east-1c`
|
||||
|
||||
用于:节点、PersistentVolume
|
||||
|
||||
用于节点: Kubelet 用 `cloudprovider` 中定义的区域(zone)信息来填充该标签。 未使用 `cloudprovider`
|
||||
时不会设置该标签,但如果该标签在你的拓扑中有意义的话,应该考虑设置。
|
||||
|
||||
用于 PersistentVolume:在 GCE 和 AWS 中,`PersistentVolumeLabel` 准入控制器会自动添加区域标签。
|
||||
|
||||
在单区的集群中,Kubernetes 会自动将同一副本控制器或服务下的 pod 分散到不同的节点上 (以降低故障的影响)。
|
||||
在多区的集群中,这种分散的行为扩展到跨区的层面 (以降低区域故障的影响)。 跨区分散通过 SelectorSpreadPriority
|
||||
来实现。
|
||||
|
||||
这是一种尽力而为(best-effort)的处置方式, 如果集群中的区域是异构的 (例如:不同区域之间的节点数量、
|
||||
节点类型或 pod 资源需求不同),可能使得 pod 在各区域间无法均匀分布。 如有需要,用户可以使用同质的区域
|
||||
(节点数量和类型相同) 来减小 pod 分布不均的可能性。
|
||||
|
||||
由于卷不能跨区域挂载(attach),调度器 (通过 VolumeZonePredicate 断言) 也会保证需要特定卷的 pod
|
||||
被调度到卷所在的区域中。
|
||||
|
||||
|
||||
区域和地域(region)的实际值无关紧要,两者的层次含义也没有严格的定义。 最终期望是,除非整个地域故障,
|
||||
否则某一区域节点的故障不应该影响到其他区域的节点。 例如,通常区域间应该避免共用同一个网络交换机。
|
||||
具体的规划取决于特定的基础设备—— three-rack 设备所选择的设置与多数据中心截然不同。
|
||||
|
||||
如果 `PersistentVolumeLabel` 准入控制器不支持自动为 PersistentVolume 打标签,且用户希望防止 pod
|
||||
跨区域进行卷的挂载,应考虑手动打标签 (或对 `PersistentVolumeLabel` 增加支持)。 如果用户的基础设施没有这种约束,则不需要为卷添加区域标签。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title: 同 Pod 内的容器使用共享卷通信
|
||||
redirect_from:
|
||||
- "/docs/user-guide/pods/multi-container/"
|
||||
- "/docs/user-guide/pods/multi-container.html"
|
||||
- "/docs/tasks/configure-pod-container/communicate-containers-same-pod/"
|
||||
- "/docs/tasks/configure-pod-container/communicate-containers-same-pod.html"
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
|
||||
本文旨在说明如何让一个 Pod 内的两个容器使用一个卷(Volume)进行通信。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
|
||||
## 创建一个包含两个容器的 Pod
|
||||
|
||||
|
||||
|
||||
|
||||
在这个练习中,你会创建一个包含两个容器的 Pod。两个容器共享一个卷用于他们之间的通信。
|
||||
Pod 的配置文件如下:
|
||||
|
||||
{{< code file="two-container-pod.yaml" >}}
|
||||
|
||||
|
||||
|
||||
在配置文件中,你可以看到 Pod 有一个共享卷,名为 `shared-data`。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
配置文件中的第一个容器运行了一个 nginx 服务器。共享卷的挂载路径是 `/usr/share/nginx/html`。
|
||||
第二个容器是基于 debian 镜像的,有一个 `/pod-data` 的挂载路径。第二个容器运行了下面的命令然后终止。
|
||||
|
||||
echo Hello from the debian container > /pod-data/index.html
|
||||
|
||||
|
||||
|
||||
注意,第二个容器在 nginx 服务器的根目录下写了 `index.html` 文件。
|
||||
|
||||
|
||||
创建一个包含两个容器的 Pod:
|
||||
|
||||
kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/two-container-pod.yaml
|
||||
|
||||
|
||||
查看 Pod 和容器的信息:
|
||||
|
||||
kubectl get pod two-containers --output=yaml
|
||||
|
||||
|
||||
这是输出的一部分:
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
...
|
||||
name: two-containers
|
||||
namespace: default
|
||||
...
|
||||
spec:
|
||||
...
|
||||
containerStatuses:
|
||||
|
||||
- containerID: docker://c1d8abd1 ...
|
||||
image: debian
|
||||
...
|
||||
lastState:
|
||||
terminated:
|
||||
...
|
||||
name: debian-container
|
||||
...
|
||||
|
||||
- containerID: docker://96c1ff2c5bb ...
|
||||
image: nginx
|
||||
...
|
||||
name: nginx-container
|
||||
...
|
||||
state:
|
||||
running:
|
||||
...
|
||||
|
||||
|
||||
|
||||
你可以看到 debian 容器已经被终止了,而 nginx 服务器依然在运行。
|
||||
|
||||
|
||||
进入 nginx 容器的 shell:
|
||||
|
||||
kubectl exec -it two-containers -c nginx-container -- /bin/bash
|
||||
|
||||
|
||||
在 shell 中,确认 nginx 还在运行。
|
||||
|
||||
root@two-containers:/# ps aux
|
||||
|
||||
|
||||
输出类似于这样:
|
||||
|
||||
USER PID ... STAT START TIME COMMAND
|
||||
root 1 ... Ss 21:12 0:00 nginx: master process nginx -g daemon off;
|
||||
|
||||
|
||||
|
||||
回忆一下,debian 容器在 nginx 的根目录下创建了 `index.html` 文件。
|
||||
使用 `curl` 向 nginx 服务器发送一个 GET 请求:
|
||||
|
||||
root@two-containers:/# apt-get update
|
||||
root@two-containers:/# apt-get install curl
|
||||
root@two-containers:/# curl localhost
|
||||
|
||||
|
||||
输出表示 nginx 提供了 debian 容器写的页面:
|
||||
|
||||
Hello from the debian container
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
|
||||
## 讨论
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Pod 能有多个容器的主要原因是为了支持辅助应用(helper applications),以协助主应用(primary application)。
|
||||
辅助应用的典型例子是数据抽取,数据推送和代理。辅助应用和主应用经常需要相互通信。
|
||||
就如这个练习所示,通信通常是通过共享文件系统完成的,或者,也通过回环网络接口 localhost 完成。
|
||||
举个网络接口的例子,web 服务器带有一个协助程序用于拉取 Git 仓库的更新。
|
||||
|
||||
|
||||
|
||||
|
||||
在本练习中的卷为 Pod 生命周期中的容器相互通信提供了一种方法。如果 Pod 被删除或者重建了,
|
||||
任何共享卷中的数据都会丢失。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
|
||||
|
||||
* 更多学习内容
|
||||
[混合容器的方式](http://blog.kubernetes.io/2015/06/the-distributed-system-toolkit-patterns.html)。
|
||||
|
||||
|
||||
|
||||
* 学习 [模块化架构的混合容器](http://www.slideshare.net/Docker/slideshare-burns)。
|
||||
|
||||
|
||||
|
||||
* 参见 [配置一个使用存储卷的 Pod](/docs/tasks/configure-pod-container/configure-volume-storage/)。
|
||||
|
||||
|
||||
* 参见 [卷](/docs/api-reference/{{< param "version" >}}/#volume-v1-core)。
|
||||
|
||||
|
||||
* 参见 [Pod](/docs/api-reference/{{< param "version" >}}/#pod-v1-core).
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
---
|
||||
title: 配置对多集群的访问
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本文展示如何使用配置文件来配置对多个集群的访问。 在将集群、用户和上下文定义在一个或多个配置文件中之后,用户可以使用 `kubectl config use-context` 命令快速地在集群之间进行切换。
|
||||
|
||||
{{< note >}}
|
||||
**注意:** 用于配置集群访问的文件有时被称为 *kubeconfig 文件*。
|
||||
这是一种引用配置文件的通用方式,并不意味着存在一个名为 `kubeconfig` 的文件。
|
||||
{{< /note >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
需要安装 [`kubectl`](/docs/tasks/tools/install-kubectl/) 命令行工具。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## 定义集群、用户和上下文
|
||||
|
||||
假设用户有两个集群,一个用于正式开发工作,一个用于其它临时用途(scratch)。
|
||||
在 `development` 集群中,前端开发者在名为 `frontend` 的名字空间下工作,
|
||||
存储开发者在名为 `storage` 的名字空间下工作。 在 `scratch` 集群中,
|
||||
开发人员可能在默认名字空间下工作,也可能视情况创建附加的名字空间。 访问开发集群需要通过证书进行认证。 访问其它临时用途的集群需要通过用户名和密码进行认证。
|
||||
|
||||
创建名为 `config-exercise` 的目录。 在
|
||||
`config-exercise` 目录中,创建名为 `config-demo` 的文件,其内容为:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
preferences: {}
|
||||
|
||||
clusters:
|
||||
- cluster:
|
||||
name: development
|
||||
- cluster:
|
||||
name: scratch
|
||||
|
||||
users:
|
||||
- name: developer
|
||||
- name: experimenter
|
||||
|
||||
contexts:
|
||||
- context:
|
||||
name: dev-frontend
|
||||
- context:
|
||||
name: dev-storage
|
||||
- context:
|
||||
name: exp-scratch
|
||||
```
|
||||
|
||||
配置文件描述了集群、用户名和上下文。 `config-demo` 文件中含有描述两个集群、两个用户和三个上下文的框架。
|
||||
|
||||
进入 `config-exercise` 目录。 输入以下命令,将群集详细信息添加到配置文件中:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo set-cluster development --server=https://1.2.3.4 --certificate-authority=fake-ca-file
|
||||
kubectl config --kubeconfig=config-demo set-cluster scratch --server=https://5.6.7.8 --insecure-skip-tls-verify
|
||||
```
|
||||
|
||||
将用户详细信息添加到配置文件中:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo set-credentials developer --client-certificate=fake-cert-file --client-key=fake-key-seefile
|
||||
kubectl config --kubeconfig=config-demo set-credentials experimenter --username=exp --password=some-password
|
||||
```
|
||||
|
||||
将上下文详细信息添加到配置文件中:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo set-context dev-frontend --cluster=development --namespace=frontend --user=developer
|
||||
kubectl config --kubeconfig=config-demo set-context dev-storage --cluster=development --namespace=storage --user=developer
|
||||
kubectl config --kubeconfig=config-demo set-context exp-scratch --cluster=scratch --namespace=default --user=experimenter
|
||||
```
|
||||
|
||||
打开 `config-demo` 文件查看添加的详细信息。 也可以使用 `config view` 命令进行查看:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo view
|
||||
```
|
||||
|
||||
输出展示了两个集群、两个用户和三个上下文:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority: fake-ca-file
|
||||
server: https://1.2.3.4
|
||||
name: development
|
||||
- cluster:
|
||||
insecure-skip-tls-verify: true
|
||||
server: https://5.6.7.8
|
||||
name: scratch
|
||||
contexts:
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: frontend
|
||||
user: developer
|
||||
name: dev-frontend
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: storage
|
||||
user: developer
|
||||
name: dev-storage
|
||||
- context:
|
||||
cluster: scratch
|
||||
namespace: default
|
||||
user: experimenter
|
||||
name: exp-scratch
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: developer
|
||||
user:
|
||||
client-certificate: fake-cert-file
|
||||
client-key: fake-key-file
|
||||
- name: experimenter
|
||||
user:
|
||||
password: some-password
|
||||
username: exp
|
||||
```
|
||||
|
||||
每个上下文包含三部分(集群、用户和名字空间),例如,
|
||||
`dev-frontend` 上下文表明:使用 `developer` 用户的凭证来访问 `development` 集群的 `frontend` 名字空间。
|
||||
|
||||
设置当前上下文:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo use-context dev-frontend
|
||||
```
|
||||
|
||||
现在当输入 `kubectl` 命令时,相应动作会应用于 `dev-frontend` 上下文中所列的集群和名字空间,同时,命令会使用 `dev-frontend` 上下文中所列用户的凭证。
|
||||
|
||||
使用 `--minify` 参数,来查看与当前上下文相关联的配置信息。
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo view --minify
|
||||
```
|
||||
|
||||
输出结果展示了 `dev-frontend` 上下文相关的配置信息:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority: fake-ca-file
|
||||
server: https://1.2.3.4
|
||||
name: development
|
||||
contexts:
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: frontend
|
||||
user: developer
|
||||
name: dev-frontend
|
||||
current-context: dev-frontend
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: developer
|
||||
user:
|
||||
client-certificate: fake-cert-file
|
||||
client-key: fake-key-file
|
||||
```
|
||||
|
||||
现在假设用户希望在其它临时用途集群中工作一段时间。
|
||||
|
||||
将当前上下文更改为 `exp-scratch`:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo use-context exp-scratch
|
||||
```
|
||||
|
||||
现在用户 `kubectl` 下达的任何命令都将应用于 `scratch` 集群的默认名字空间。 同时,命令会使用 `exp-scratch` 上下文中所列用户的凭证。
|
||||
|
||||
查看更新后的当前上下文 `exp-scratch` 相关的配置:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo view --minify
|
||||
```
|
||||
|
||||
最后,假设用户希望在 `development` 集群中的 `storage` 名字空间下工作一段时间。
|
||||
|
||||
将当前上下文更改为 `dev-storage`:
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo use-context dev-storage
|
||||
```
|
||||
|
||||
查看更新后的当前上下文 `dev-storage` 相关的配置:
|
||||
|
||||
|
||||
```shell
|
||||
kubectl config --kubeconfig=config-demo view --minify
|
||||
```
|
||||
|
||||
## 创建第二个配置文件
|
||||
|
||||
在 `config-exercise` 目录中,创建名为 `config-demo-2` 的文件,其中包含以下内容:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
preferences: {}
|
||||
|
||||
contexts:
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: ramp
|
||||
user: developer
|
||||
name: dev-ramp-up
|
||||
```
|
||||
|
||||
上述配置文件定义了一个新的上下文,名为 `dev-ramp-up`。
|
||||
|
||||
## 设置 KUBECONFIG 环境变量
|
||||
|
||||
查看是否有名为 `KUBECONFIG` 的环境变量。 如有,保存 `KUBECONFIG` 环境变量当前的值,以便稍后恢复。
|
||||
例如,在 Linux 中:
|
||||
|
||||
```shell
|
||||
export KUBECONFIG_SAVED=$KUBECONFIG
|
||||
```
|
||||
|
||||
`KUBECONFIG` 环境变量是配置文件路径的列表,该列表在 Linux 和 Mac 中以冒号分隔,在 Windows 中以分号分隔。 如果有 `KUBECONFIG` 环境变量,请熟悉列表中的配置文件。
|
||||
|
||||
临时添加两条路径到 `KUBECONFIG` 环境变量中。 例如,在 Linux 中:
|
||||
|
||||
```shell
|
||||
export KUBECONFIG=$KUBECONFIG:config-demo:config-demo-2
|
||||
```
|
||||
|
||||
在 `config-exercise` 目录中输入以下命令:
|
||||
|
||||
```shell
|
||||
kubectl config view
|
||||
```
|
||||
|
||||
输出展示了 `KUBECONFIG` 环境变量中所列举的所有文件合并后的信息。 特别地, 注意合并信息中包含来自 `config-demo-2` 文件的 `dev-ramp-up` 上下文和来自 `config-demo` 文件的三个上下文:
|
||||
|
||||
```yaml
|
||||
contexts:
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: frontend
|
||||
user: developer
|
||||
name: dev-frontend
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: ramp
|
||||
user: developer
|
||||
name: dev-ramp-up
|
||||
- context:
|
||||
cluster: development
|
||||
namespace: storage
|
||||
user: developer
|
||||
name: dev-storage
|
||||
- context:
|
||||
cluster: scratch
|
||||
namespace: default
|
||||
user: experimenter
|
||||
name: exp-scratch
|
||||
```
|
||||
|
||||
更多关于 kubeconfig 文件如何合并的信息,请参考
|
||||
[使用 kubeconfig 文件组织集群访问](/docs/concepts/configuration/organize-cluster-access-kubeconfig/)
|
||||
|
||||
## 探索 $HOME/.kube 目录
|
||||
|
||||
如果用户已经拥有一个集群,可以使用 `kubectl` 与集群进行交互。 那么很可能在 `$HOME/.kube` 目录下有一个名为 `config` 的文件。
|
||||
|
||||
进入 `$HOME/.kube` 目录, 看看那里有什么文件。 通常会有一个名为
|
||||
`config` 的文件,目录中可能还有其他配置文件。 请简单地熟悉这些文件的内容。
|
||||
|
||||
## 将 $HOME/.kube/config 追加到 KUBECONFIG 环境变量中
|
||||
|
||||
如果有 `$HOME/.kube/config` 文件,并且还未列在 `KUBECONFIG` 环境变量中,
|
||||
那么现在将它追加到 `KUBECONFIG` 环境变量中。
|
||||
例如,在 Linux 中:
|
||||
|
||||
```shell
|
||||
export KUBECONFIG=$KUBECONFIG:$HOME/.kube/config
|
||||
```
|
||||
|
||||
在配置练习目录中输入以下命令,来查看当前 `KUBECONFIG` 环境变量中列举的所有文件合并后的配置信息:
|
||||
|
||||
```shell
|
||||
kubectl config view
|
||||
```
|
||||
|
||||
## 清理
|
||||
|
||||
将 `KUBECONFIG` 环境变量还原为原始值。 例如,在 Linux 中:
|
||||
|
||||
```shell
|
||||
export KUBECONFIG=$KUBECONFIG_SAVED
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* [使用 kubeconfig 文件组织集群访问](/docs/concepts/configuration/organize-cluster-access-kubeconfig/)
|
||||
* [kubectl 配置](/docs/user-guide/kubectl/{{< param "version" >}}/)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
---
|
||||
approvers:
|
||||
- bprashanth
|
||||
- davidopp
|
||||
title: 配置你的云平台防火墙
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
许多云服务商(比如 Google Compute Engine)定义防火墙以防止服务无意间暴露到 internet 上。
|
||||
当暴露服务给外网时,你可能需要在防火墙上开启一个或者更多的端口来支持服务。
|
||||
本文描述了这个过程,以及其他云服务商的具体信息。
|
||||
|
||||
|
||||
## 负载均衡(LoadBalancer)服务的访问限制
|
||||
|
||||
|
||||
|
||||
|
||||
当以 `spec.type: LoadBalancer` 使用服务时,你可以使用 `spec.loadBalancerSourceRanges` 指定允许访问负载均衡的 IP 段。
|
||||
这个字段采用 CIDR 的 IP 段,Kubernetes 会使用这个段配置防火墙。支持这个功能的平台目前有 Google Compute Engine,Google Kubernetes Engine 和 AWS。
|
||||
如果云服务商不支持这个功能,这个字段会被忽略。
|
||||
|
||||
|
||||
|
||||
假设 10.0.0.0/8 是内部的子网。在下面这个例子中,会创建一个只有集群内部 ip 可以访问的负载均衡器。
|
||||
集群外部的客户端是无法访问这个负载均衡器的。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
ports:
|
||||
- port: 8765
|
||||
targetPort: 9376
|
||||
selector:
|
||||
app: example
|
||||
type: LoadBalancer
|
||||
loadBalancerSourceRanges:
|
||||
- 10.0.0.0/8
|
||||
```
|
||||
|
||||
|
||||
这个例子中,会创建一个只能被 IP 为 130.211.204.1 和 130.211.204.2 的客户端访问的负载据衡器。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
ports:
|
||||
- port: 8765
|
||||
targetPort: 9376
|
||||
selector:
|
||||
app: example
|
||||
type: LoadBalancer
|
||||
loadBalancerSourceRanges:
|
||||
- 130.211.204.1/32
|
||||
- 130.211.204.2/32
|
||||
```
|
||||
|
||||
|
||||
### 谷歌计算引擎(Google Compute Engine)
|
||||
|
||||
|
||||
|
||||
|
||||
当以 `spec.type: LoadBalancer` 使用服务时,防火墙会被自动打开。
|
||||
然而,当以 `spec.type: NodePort` 使用服务时,防火墙默认 *不会* 被打开。
|
||||
|
||||
|
||||
Google Compute Engine 的防火墙文档在[别处](https://cloud.google.com/compute/docs/networking#firewalls_1)。
|
||||
|
||||
|
||||
你可以使用 `gcloud` 命令行工具添加一个防火墙:
|
||||
|
||||
```shell
|
||||
$ gcloud compute firewall-rules create my-rule --allow=tcp:<port>
|
||||
```
|
||||
|
||||
|
||||
|
||||
**注意**
|
||||
使用 Google Compute Engine 平台的防火墙时有一个重要的关于安全的注意点:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
在 Kubernetes v1.0.0 版本,GCE 防火墙是定义按虚拟机(VM)来的,而不是按 ip 来的。
|
||||
这就意味着当你在防火墙上打开一个服务端口时,任何在那台虚拟机 IP 上的同一端口的服务
|
||||
都有被外部访问的潜在可能。注意,这对于其他 Kubernetes 服务来说不是问题,因为他们监
|
||||
听的 IP 地址与主机节点的外部 IP 地址不同。
|
||||
|
||||
|
||||
考虑一下:
|
||||
|
||||
* 你创建了一个服务,使用了外部服务均衡 (IP 地址为 1.2.3.4) 和 80 端口。
|
||||
* 你在防火墙上为集群的所有节点都打开了 80 端口,所以外部的服务可以向你的
|
||||
服务发送数据包。
|
||||
* 你又在虚拟机(IP 为2.3.4.5)上使用 80 端口启动了一台 nginx 服务器.
|
||||
这个 nginx 在虚拟机的外部 IP 地址上也被暴露到了 internet 上。
|
||||
|
||||
|
||||
|
||||
|
||||
因此,在 Google Compute Engine 或者 Google Kubernetes Engine 上开启防火墙端口时请
|
||||
小心。你可能无意间把其他服务也暴露给了 internet。
|
||||
|
||||
|
||||
这个问题会在 Kubernetes 后续版本中被修复。
|
||||
|
||||
|
||||
### 其他云服务商
|
||||
|
||||
|
||||
即将更新
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
---
|
||||
title: 使用 Service 把前端连接到后端
|
||||
content_template: templates/tutorial
|
||||
---
|
||||
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
|
||||
|
||||
本任务会描述如何创建前端微服务和后端微服务。后端微服务是一个 hello 欢迎程序。
|
||||
前端和后端的连接是通过 Kubernetes 服务对象(Service object)完成的。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture objectives %}}
|
||||
|
||||
|
||||
|
||||
|
||||
* 使用部署对象(Deployment object)创建并运行一个微服务
|
||||
* 从后端将流量路由到前端
|
||||
* 使用服务对象把前端应用连接到后端应用
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
|
||||
* 本任务使用 [外部负载均衡服务](/docs/tasks/access-application-cluster/create-external-load-balancer/),
|
||||
所以需要对应的可支持此功能的环境。如果你的环境不能支持,你可以使用
|
||||
[NodePort](/docs/user-guide/services/#type-nodeport) 类型的服务代替。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture lessoncontent %}}
|
||||
|
||||
|
||||
### 使用部署对象(Deployment)创建后端
|
||||
|
||||
|
||||
|
||||
后端是一个简单的 hello 欢迎微服务应用。这是后端应用的 Deployment 配置文件:
|
||||
|
||||
{{< code file="hello.yaml" >}}
|
||||
|
||||
|
||||
创建后端 Deployment:
|
||||
|
||||
```
|
||||
kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/hello.yaml
|
||||
```
|
||||
|
||||
|
||||
查看后端的 Deployment 信息:
|
||||
|
||||
```
|
||||
kubectl describe deployment hello
|
||||
```
|
||||
|
||||
|
||||
输出类似于:
|
||||
|
||||
```
|
||||
Name: hello
|
||||
Namespace: default
|
||||
CreationTimestamp: Mon, 24 Oct 2016 14:21:02 -0700
|
||||
Labels: app=hello
|
||||
tier=backend
|
||||
track=stable
|
||||
Selector: app=hello,tier=backend,track=stable
|
||||
Replicas: 7 updated | 7 total | 7 available | 0 unavailable
|
||||
StrategyType: RollingUpdate
|
||||
MinReadySeconds: 0
|
||||
RollingUpdateStrategy: 1 max unavailable, 1 max surge
|
||||
OldReplicaSets: <none>
|
||||
NewReplicaSet: hello-3621623197 (7/7 replicas created)
|
||||
Events:
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### 创建后端服务对象(Service object)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
前端连接到后端的关键是 Service。Service 创建一个固定 IP 和 DNS 解析名入口,
|
||||
使得后端微服务可达。Service 使用 selector 标签来寻找目标 Pod。
|
||||
|
||||
|
||||
首先,浏览 Service 的配置文件:
|
||||
|
||||
{{< code file="hello-service.yaml" >}}
|
||||
|
||||
|
||||
|
||||
配置文件中,你可以看到 Service 将流量路由到包含 `app: hello` 和 `tier: backend` 标签的 Pod。
|
||||
|
||||
|
||||
创建 `hello` Service:
|
||||
|
||||
```
|
||||
kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/hello-service.yaml
|
||||
```
|
||||
|
||||
|
||||
|
||||
此时,你已经有了一个在运行的后端 Deployment,你也有了一个 Service 用于路由网络流量。
|
||||
|
||||
|
||||
### 创建前端应用
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
既然你已经有了后端应用,你可以创建一个前端应用连接到后端。前端应用通过 DNS 名连接到后端的工作 Pods。
|
||||
DNS 名是 "hello",也就是 Service 配置文件中 `name` 字段的值。
|
||||
|
||||
|
||||
|
||||
前端 Deployment 中的 Pods 运行一个 nginx 镜像,这个已经配置好镜像去寻找后端的 hello Service。
|
||||
只是 nginx 的配置文件:
|
||||
|
||||
{{< code file="frontend/frontend.conf" >}}
|
||||
|
||||
|
||||
|
||||
|
||||
与后端类似,前端用包含一个 Deployment 和一个 Service。Service 的配置文件包含了 `type: LoadBalancer`,
|
||||
也就是说,Service 会使用你的云服务商的默认负载均衡设备。
|
||||
|
||||
{{< code file="frontend.yaml" >}}
|
||||
|
||||
|
||||
创建前端 Deployment 和 Service:
|
||||
|
||||
```
|
||||
kubectl create -f https://k8s.io/docs/tasks/access-application-cluster/frontend.yaml
|
||||
```
|
||||
|
||||
|
||||
通过输出确认两个资源都已经被创建:
|
||||
|
||||
```
|
||||
deployment "frontend" created
|
||||
service "frontend" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**注意**:这个 nginx 配置文件是被打包在 [容器镜像](/docs/tasks/access-application-cluster/frontend/Dockerfile) 里的。
|
||||
更好的方法是使用 [ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/),这样的话你可以更轻易地更改配置。
|
||||
|
||||
|
||||
### 与前端 Service 交互
|
||||
|
||||
|
||||
|
||||
一旦你创建了 LoadBalancer 类型的 Service,你可以使用这条命令查看外部 IP:
|
||||
|
||||
```
|
||||
kubectl get service frontend
|
||||
```
|
||||
|
||||
|
||||
|
||||
外部 IP 字段的生成可能需要一些时间。如果是这种情况,外部 IP 会显示为 `<pending>`。
|
||||
|
||||
```
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
frontend 10.51.252.116 <pending> 80/TCP 10s
|
||||
```
|
||||
|
||||
|
||||
使用相同的命令直到它显示外部 IP 地址:
|
||||
|
||||
```
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
frontend 10.51.252.116 XXX.XXX.XXX.XXX 80/TCP 1m
|
||||
```
|
||||
|
||||
|
||||
### 通过前端发送流量
|
||||
|
||||
|
||||
|
||||
前端和后端已经完成连接了。你可以使用 curl 命令通过你的前端 Service 的外部 IP 访问服务端点。
|
||||
|
||||
```
|
||||
curl http://<EXTERNAL-IP>
|
||||
```
|
||||
|
||||
|
||||
后端生成的消息输出如下:
|
||||
|
||||
```
|
||||
{"message":"Hello"}
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
|
||||
|
||||
* 了解更多 [Services](/docs/concepts/services-networking/service/)
|
||||
* 了解更多 [ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
selector:
|
||||
app: hello
|
||||
tier: frontend
|
||||
ports:
|
||||
- protocol: "TCP"
|
||||
port: 80
|
||||
targetPort: 80
|
||||
type: LoadBalancer
|
||||
---
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: frontend
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hello
|
||||
tier: frontend
|
||||
track: stable
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: "gcr.io/google-samples/hello-frontend:1.0"
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command: ["/usr/sbin/nginx","-s","quit"]
|
||||
@@ -0,0 +1,11 @@
|
||||
upstream hello {
|
||||
server hello;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
proxy_pass http://hello;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: hello
|
||||
spec:
|
||||
selector:
|
||||
app: hello
|
||||
tier: backend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: http
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: apps/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hello
|
||||
spec:
|
||||
replicas: 7
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: hello
|
||||
tier: backend
|
||||
track: stable
|
||||
spec:
|
||||
containers:
|
||||
- name: hello
|
||||
image: "gcr.io/google-samples/hello-go-gke:1.0"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis
|
||||
redis-sentinel: "true"
|
||||
role: master
|
||||
name: redis-master
|
||||
spec:
|
||||
containers:
|
||||
- name: master
|
||||
image: k8s.gcr.io/redis:v1
|
||||
env:
|
||||
- name: MASTER
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
resources:
|
||||
limits:
|
||||
cpu: "0.1"
|
||||
volumeMounts:
|
||||
- mountPath: /redis-master-data
|
||||
name: data
|
||||
- name: sentinel
|
||||
image: kubernetes/redis:v1
|
||||
env:
|
||||
- name: SENTINEL
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 26379
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: two-containers
|
||||
spec:
|
||||
|
||||
restartPolicy: Never
|
||||
|
||||
volumes:
|
||||
- name: shared-data
|
||||
emptyDir: {}
|
||||
|
||||
containers:
|
||||
|
||||
- name: nginx-container
|
||||
image: nginx
|
||||
volumeMounts:
|
||||
- name: shared-data
|
||||
mountPath: /usr/share/nginx/html
|
||||
|
||||
- name: debian-container
|
||||
image: debian
|
||||
volumeMounts:
|
||||
- name: shared-data
|
||||
mountPath: /pod-data
|
||||
command: ["/bin/sh"]
|
||||
args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
|
||||
title: 访问集群上运行的服务
|
||||
redirect_from:
|
||||
- "/docs/user-guide/accessing-the-cluster/"
|
||||
- "/docs/user-guide/accessing-the-cluster.html"
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本文展示了如何连接 Kubernetes 集群上运行的服务。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
{{% /capture %}}
|
||||
|
||||
{{% 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 的方式可能不能理解代理路径前缀。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
---
|
||||
approvers:
|
||||
- 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"
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
本示例展示了在一个 namespace 中控制资源用量的典型设置。
|
||||
|
||||
|
||||
本文展示了以下资源的使用: [Namespace](/docs/admin/namespaces), [ResourceQuota](/docs/concepts/policy/resource-quotas/) 和 [LimitRange](/docs/tasks/configure-pod-container/limit-range/)。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% 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 上的预期持久程度来为它们指定配额。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
## 总结
|
||||
|
||||
|
||||
消耗节点 cpu 和 memory 资源的动作受到 namespace 配额定义的硬性配额限制的管制。
|
||||
|
||||
|
||||
任意消耗那些资源的动作能够被调整,或者获得一个 namespace 级别的默认值以符合你最终的目标。
|
||||
|
||||
|
||||
可以基于服务质量或者在你集群中节点上的预期持久程度来分配配额。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
approvers:
|
||||
- caseydavenport
|
||||
title: 使用 Calico 来提供 NetworkPolicy
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
|
||||
{{% capture overview %}}
|
||||
本页展示怎么样使用 Calico 来提供 NetworkPolicy
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
* 为 Kubernetes 安装 Calico
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
## 使用 Calico 部署一个集群
|
||||
|
||||
|
||||
使用如下命令,您可以在默认的 [GCE 部署环境中](/docs/getting-started-guides/gce) 部署一个使用 Calico 来提供网络策略的集群:
|
||||
|
||||
```shell
|
||||
export NETWORK_POLICY_PROVIDER=calico
|
||||
export KUBE_NODE_OS_DISTRIBUTION=debian
|
||||
curl -sS https://get.k8s.io | bash
|
||||
```
|
||||
|
||||
|
||||
如果希望了解其它的部署选项,请您参考 [Calico 项目文档](http://docs.projectcalico.org/)
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
## 理解 Calico 组件
|
||||
|
||||
|
||||
部署使用 Calico 的集群其实是增加了支持 Kubernetes NetworkPolicy 的 Pods, 这些 Pods 运行在 `kube-system` 命名空间下。
|
||||
|
||||
|
||||
使用如下方式去查看这些运行的 Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods --namespace=kube-system
|
||||
```
|
||||
|
||||
|
||||
您可以看到类似下面这样的一个 Pods 列表:
|
||||
|
||||
```console
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
calico-node-kubernetes-minion-group-jck6 1/1 Running 0 46m
|
||||
calico-node-kubernetes-minion-group-k9jy 1/1 Running 0 46m
|
||||
calico-node-kubernetes-minion-group-szgr 1/1 Running 0 46m
|
||||
calico-policy-controller-65rw1 1/1 Running 0 46m
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
主要有两种组件
|
||||
|
||||
|
||||
- 在集群的每个节点上都会运行一个以 `calico-node` 开头命名的 Pod,用于配置 iptables 去实现那些机器上 Pods 的出/入网络策略
|
||||
|
||||
- 整个集群环境只有一个以 `calico-policy-controller` 开头命名的 Pod,用于从 Kubernetes API 中读取策略和标签信息,适当的对 Calico 进行配置
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
集群部署完成之后,您可以通过 [NetworkPolicy 入门指南](/docs/getting-started-guides/network-policy/walkthrough)去尝试使用 Kubernetes NetworkPolicy
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
|
||||
title: 改变默认 StorageClass
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本文展示了如何改变默认的 Storage Class,它用于为没有特殊需求的 PersistentVolumeClaims 配置 volumes。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% 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
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 了解更多关于 [StorageClasses](/docs/concepts/storage/persistent-volumes/)。
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: 更改 PersistentVolume 的回收策略
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
本文展示了如何更改 Kubernetes PersistentVolume 的回收策略。
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
|
||||
## 为什么要更改 PersistentVolume 的回收策略
|
||||
|
||||
|
||||
`PersistentVolumes` 可以有多种回收策略,包括 "Retain"、"Recycle" 和 "Delete"。对于动态配置的 `PersistentVolumes` 来说,默认回收策略为 "Delete"。这表示当用户删除对应的 `PersistentVolumeClaim` 时,动态配置的 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` 时,它不会被自动删除。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
* 了解更多关于 [PersistentVolumes](/docs/concepts/storage/persistent-volumes/)的信息。
|
||||
* 了解更多关于 [PersistentVolumeClaims](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 的信息。
|
||||
|
||||
|
||||
### 参考
|
||||
|
||||
* [PersistentVolume](/docs/api-reference/{{< param "version" >}}/#persistentvolume-v1-core)
|
||||
* [PersistentVolumeClaim](/docs/api-reference/{{< param "version" >}}/#persistentvolumeclaim-v1-core)
|
||||
|
||||
* 查阅 [PersistentVolumeSpec](/docs/api-reference/{{< param "version" >}}/#persistentvolumeclaim-v1-core) 的 `persistentVolumeReclaimPolicy` 字段。
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
approvers:
|
||||
- lavalamp
|
||||
- thockin
|
||||
title: 集群管理
|
||||
---
|
||||
|
||||
|
||||
{{< 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 Kubernetes Engine 集群
|
||||
|
||||
|
||||
Google Kubernetes Engine 自动升级 master 组件(例如 `kube-apiserver`、`kube-scheduler`)至最新版本。它还负责 master 运行的操作系统和其它组件。
|
||||
|
||||
|
||||
节点升级过程由用户初始化,[Google Kubernetes Engine 文档](https://cloud.google.com/kubernetes-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 或者 Google Kubernetes Engine,这将通过调整管理节点的实例组的大小完成。在 [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 或者 Google Kubernetes Engine,您可以配置您的集群,使其能够基于 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)或节点池(Google Kubernetes Engine)上配置。
|
||||
|
||||
|
||||
如果您使用 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
|
||||
```
|
||||
|
||||
|
||||
在 Google Kubernetes Engine 上,您可以在创建、更新集群或创建一个特别的节点池(您希望自动伸缩的)时,通过给对应的 `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) 命令用法。
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: constraints-cpu-demo-2
|
||||
spec:
|
||||
containers:
|
||||
- name: constraints-cpu-demo-2-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1.5"
|
||||
requests:
|
||||
cpu: "500m"
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: constraints-cpu-demo-4
|
||||
spec:
|
||||
containers:
|
||||
- name: constraints-cpu-demo-4-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: "800m"
|
||||
requests:
|
||||
cpu: "100m"
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: constraints-cpu-demo-4
|
||||
spec:
|
||||
containers:
|
||||
- name: constraints-cpu-demo-4-ctr
|
||||
image: vish/stress
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: constraints-cpu-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: constraints-cpu-demo-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: "800m"
|
||||
requests:
|
||||
cpu: "500m"
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: cpu-min-max-demo-lr
|
||||
spec:
|
||||
limits:
|
||||
- max:
|
||||
cpu: "800m"
|
||||
min:
|
||||
cpu: "200m"
|
||||
type: Container
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: default-cpu-demo-2
|
||||
spec:
|
||||
containers:
|
||||
- name: default-cpu-demo-2-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: default-cpu-demo-3
|
||||
spec:
|
||||
containers:
|
||||
- name: default-cpu-demo-3-ctr
|
||||
image: nginx
|
||||
resources:
|
||||
requests:
|
||||
cpu: "0.75"
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: default-cpu-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: default-cpu-demo-ctr
|
||||
image: nginx
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: cpu-limit-range
|
||||
spec:
|
||||
limits:
|
||||
- default:
|
||||
cpu: 1
|
||||
defaultRequest:
|
||||
cpu: 0.5
|
||||
type: Container
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
title: 控制节点上的CPU管理策略
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
按照设计,Kubernetes 对 pod 执行相关的很多方面进行了抽象,使得用户不必关心。然而,为了正常运行,有些工作负载要求在延迟和/或性能方面有更强的保证。 为此,kubelet 提供方法来实现更复杂的负载放置策略,同时保持抽象,避免显式的放置指令。
|
||||
|
||||
## CPU 管理策略
|
||||
|
||||
默认情况下,kubelet 使用 [CFS 配额](https://en.wikipedia.org/wiki/Completely_Fair_Scheduler) 来执行 pod 的 CPU 约束。当节点上运行了很多 CPU 密集的 pod 时,工作负载可能会迁移到不同的 CPU 核,这取决于调度时 pod 是否被扼制,以及哪些 CPU 核是可用的。许多工作负载对这种迁移不敏感,因此无需任何干预即可正常工作。
|
||||
|
||||
然而,有些工作负载的性能明显地受到 CPU 缓存亲和性以及调度延迟的影响,对此,kubelet 提供了可选的 CPU 管理策略,来确定节点上的一些分配偏好。
|
||||
|
||||
### 配置
|
||||
|
||||
CPU 管理器(CPU Manager)作为 alpha 特性引入 Kubernetes 1.8 版本。 必须在 kubelet 特性开关中显式启用:
|
||||
`--feature-gates=CPUManager=true`。
|
||||
|
||||
CPU 管理策略通过 kubelet 参数 `--cpu-manager-policy` 来指定,
|
||||
有两种支持策略:
|
||||
|
||||
* `none`:默认策略,表示现有的调度行为。
|
||||
* `static`:允许为节点上具有某些资源特征的 pod 赋予增强的 CPU 亲和性和独占性。
|
||||
|
||||
CPU管理器定期通过 CRI 写入资源更新,以保证内存中 CPU 分配与 cgroupfs 一致。同步频率通过新增的 Kubelet 配置参数
|
||||
`--cpu-manager-reconcile-period` 来设置。 如不指定,默认与 `--node-status-update-frequency` 的周期相同。
|
||||
|
||||
### None 策略
|
||||
|
||||
`none` 策略显式地启用现有的默认 CPU 亲和方案,不提供操作系统调度器默认行为之外的亲和性策略。 通过 CFS 配额来实现
|
||||
[Guaranteed pods](/docs/tasks/configure-pod-container/quality-service-pod/) 的 CPU 使用限制。
|
||||
|
||||
### Static 策略
|
||||
|
||||
`static` 策略针对具有整数型 CPU `requests` 的 pod ,它允许该类 pod 中的容器访问节点上的独占 CPU 资源。这种独占性是使用 [cpuset cgroup 控制器](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt) 来实现的。
|
||||
|
||||
{{< note >}}
|
||||
**注意:** 诸如容器运行时和 kubelet 本身的系统服务可以继续在这些独占 CPU 上运行。独占性仅针对其他 pod。
|
||||
{{< /note >}}
|
||||
|
||||
{{< note >}}
|
||||
**注意:** 该策略的 alpha 版本不保证 Kubelet 重启前后的静态独占性分配。
|
||||
{{< /note >}}
|
||||
|
||||
该策略管理一个共享 CPU 资源池,最初,该资源池包含节点上所有的 CPU 资源。可用的独占性 CPU 资源数量等于节点的 CPU 总量减去通过 `--kube-reserved` 或 `--system-reserved` 参数保留的 CPU 。通过这些参数预留的 CPU 是以整数方式,按物理内核 ID 升序从初始共享池获取的。 共享池是 `BestEffort` 和 `Burstable` pod 运行的 CPU 集合。`Guaranteed` pod 中的容器,如果声明了非整数值的 CPU `requests` ,也将运行在共享池的 CPU 上。只有 `Guaranteed` pod 中,指定了整数型 CPU `requests` 的容器,才会被分配独占 CPU 资源。
|
||||
|
||||
{{< note >}}
|
||||
**注意:** 当启用 static 策略时,要求使用 `--kube-reserved` 和/或 `--system-reserved` 来保证预留的 CPU 值大于零。 这是因为零预留 CPU 值可能使得共享池变空。
|
||||
{{< /note >}}
|
||||
|
||||
当 `Guaranteed` pod 调度到节点上时,如果其容器符合静态分配要求,相应的 CPU 会被从共享池中移除,并放置到容器的 cpuset 中。因为这些容器所使用的 CPU 受到调度域本身的限制,所以不需要使用 CFS 配额来进行 CPU 的绑定。换言之,容器 cpuset 中的 CPU 数量与 pod 规格中指定的整数型 CPU `limit` 相等。这种静态分配增强了 CPU 亲和性,减少了 CPU 密集的工作负载在节流时引起的上下文切换。
|
||||
|
||||
考虑以下 Pod 规格的容器:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
```
|
||||
|
||||
该 pod 属于 `BestEffort` 服务质量类型,因为其未指定 `requests` 或
|
||||
`limits` 值。 所以该容器运行在共享 CPU 池中。
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "200Mi"
|
||||
requests:
|
||||
memory: "100Mi"
|
||||
```
|
||||
|
||||
该 pod 属于 `Burstable` 服务质量类型,因为其资源 `requests` 不等于
|
||||
`limits`, 且未指定 `cpu` 数量。所以该容器运行在共享 CPU 池中。
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "200Mi"
|
||||
cpu: "2"
|
||||
requests:
|
||||
memory: "100Mi"
|
||||
cpu: "1"
|
||||
```
|
||||
|
||||
该 pod 属于 `Burstable` 服务质量类型,因为其资源 `requests` 不等于 `limits`。所以该容器运行在共享 CPU 池中。
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "200Mi"
|
||||
cpu: "2"
|
||||
requests:
|
||||
memory: "200Mi"
|
||||
cpu: "2"
|
||||
```
|
||||
|
||||
该 pod 属于 `Guaranteed` 服务质量类型,因为其 `requests` 值与 `limits`相等。
|
||||
同时,容器对 CPU 资源的限制值是一个大于或等于 1 的整数值。所以,该 `nginx` 容器被赋予 2 个独占 CPU。
|
||||
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "200Mi"
|
||||
cpu: "1.5"
|
||||
requests:
|
||||
memory: "200Mi"
|
||||
cpu: "1.5"
|
||||
```
|
||||
|
||||
该 pod 属于 `Guaranteed` 服务质量类型,因为其 `requests` 值与 `limits`相等。但是容器对 CPU 资源的限制值是一个小数。所以该容器运行在共享 CPU 池中。
|
||||
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx
|
||||
resources:
|
||||
limits:
|
||||
memory: "200Mi"
|
||||
cpu: "2"
|
||||
```
|
||||
|
||||
该 pod 属于 `Guaranteed` 服务质量类型,因其指定了 `limits` 值,
|
||||
同时当未显式指定时,`requests` 值被设置为与 `limits` 值相等。同时,容器对 CPU 资源的限制值是一个大于或等于 1 的整数值。所以,该 `nginx` 容器被赋予 2 个独占 CPU。
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
---
|
||||
approvers:
|
||||
- derekwaynecarr
|
||||
- janetkuo
|
||||
title: 设置 Pod CPU 和内存限制
|
||||
redirect_from:
|
||||
- "/docs/admin/limitrange/"
|
||||
- "/docs/admin/limitrange/index.html"
|
||||
- "/docs/tasks/configure-pod-container/limit-range/"
|
||||
- "/docs/tasks/configure-pod-container/limit-range.html"
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
|
||||
默认情况下,Pod 运行没有限制 CPU 使用量和内存使用量。
|
||||
这意味着当前系统中的任何 Pod 能够使用该 Pod 运行节点的所有 CPU 和内存资源。
|
||||
|
||||
|
||||
这个例子演示了如何限制 Kubernetes [Namespace](/docs/tasks/administer-cluster/namespaces-walkthrough/),以此来控制每个 Pod 的最小/最大资源限额。
|
||||
另外,这个例子演示了当终端用户没有为 Pod 设置资源限额时,如何使用默认的资源限额。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
* {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
|
||||
|
||||
## 创建 Namespace
|
||||
|
||||
这个例子将使用一个自定义的 Namespace 来演示相关的概念。
|
||||
|
||||
让我们创建一个名称为 limit-example 的 Namespace:
|
||||
|
||||
```shell
|
||||
$ kubectl create namespace limit-example
|
||||
namespace "limit-example" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
可以看到 `kubectl` 命令将打印出被创建或修改的资源的类型和名称,也会在后面的命令中使用到:
|
||||
|
||||
```shell
|
||||
$ kubectl get namespaces
|
||||
NAME STATUS AGE
|
||||
default Active 51s
|
||||
limit-example Active 45s
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 对 Namespace 应用限制
|
||||
|
||||
在我们的 Namespace 中创建一个简单的限制:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/limits.yaml --namespace=limit-example
|
||||
limitrange "mylimits" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
让我们查看一下在该 Namespace 中被强加的限制:
|
||||
|
||||
```shell
|
||||
$ kubectl describe limits mylimits --namespace=limit-example
|
||||
Name: mylimits
|
||||
Namespace: limit-example
|
||||
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
|
||||
---- -------- --- --- --------------- ------------- -----------------------
|
||||
Pod cpu 200m 2 - - -
|
||||
Pod memory 6Mi 1Gi - - -
|
||||
Container cpu 100m 2 200m 300m -
|
||||
Container memory 3Mi 1Gi 100Mi 200Mi -
|
||||
```
|
||||
|
||||
|
||||
|
||||
在这个场景下,指定了如下限制:
|
||||
|
||||
1. 如果一个资源被指定了最大约束(在该例子中为 2 CPU 和 1Gi 内存),则必须为跨所有容器的该资源指定限制(limits)。
|
||||
当尝试创建该 Pod 时,指定限额失败将导致一个验证错误。
|
||||
注意,一个默认的限额通过在 `limits.yaml` 文件中的 *default* 来设置(300m CPU 和 200Mi 内存)。
|
||||
2. 如果一个资源被指定了最小约束(在该例子中为 100m CPU 和 3Mi 内存),则必须跨所有容器的该资源指定请求(requests)。
|
||||
当尝试创建该 Pod 时,指定的请求失败将导致一个验证错误。
|
||||
注意,一个默认的请求的值通过在 `limits.yaml` 文件中的 *defaultRequest* 来设置(200m CPU 和 100Mi 内存)。
|
||||
3. 对任意 Pod,所有容器内存 requests 值之和必须 >= 6Mi,所有容器内存 limits 值之和必须 <= 1Gi;
|
||||
所有容器 CPU requests 值之和必须 >= 200m,所有容器 CPU limits 值之和必须 <= 2。
|
||||
|
||||
|
||||
|
||||
## 创建时强制设置限制
|
||||
|
||||
当集群中的 Pod 创建和更新时,在一个 Namespace 中列出的限额是强制设置的。
|
||||
如果将该限额修改成一个不同的值范围,它不会影响先前在该 Namespace 中创建的 Pod。
|
||||
|
||||
|
||||
|
||||
如果资源(CPU 或内存)被设置限额,用户将在创建时得到一个错误,并指出了错误的原因。
|
||||
|
||||
首先让我们启动一个 [Deployment](/docs/concepts/workloads/controllers/deployment/),它创建一个单容器 Pod,演示了如何将默认值应用到每个 Pod 上:
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image=nginx --replicas=1 --namespace=limit-example
|
||||
deployment "nginx" created
|
||||
```
|
||||
|
||||
|
||||
注意,在 >= v1.2 版本的 Kubernetes 集群中,`kubectl run` 创建了名称为 “nginx” 的 Deployment。如果在老版本的集群上运行,相反它会创建 ReplicationController。
|
||||
如果想要获取老版本的行为,使用 `--generator=run/v1` 选项来创建 ReplicationController。查看 [`kubectl run`](/docs/user-guide/kubectl/v1.6/#run) 获取更多详细信息。
|
||||
Deployment 管理单容器 Pod 的 1 个副本。让我们看一下它是如何管理 Pod 的。首先,查找到 Pod 的名称:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods --namespace=limit-example
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
nginx-2040093540-s8vzu 1/1 Running 0 11s
|
||||
```
|
||||
|
||||
|
||||
|
||||
以 yaml 输出格式来打印这个 Pod,然后 `grep` 其中的 `resources` 字段。注意,您自己的 Pod 的名称将不同于上面输出的:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods nginx-2040093540-s8vzu --namespace=limit-example -o yaml | grep resources -C 8
|
||||
resourceVersion: "57"
|
||||
selfLink: /api/v1/namespaces/limit-example/pods/nginx-2040093540-ivimu
|
||||
uid: 67b20741-f53b-11e5-b066-64510658e388
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx
|
||||
imagePullPolicy: Always
|
||||
name: nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 200Mi
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 100Mi
|
||||
terminationMessagePath: /dev/termination-log
|
||||
volumeMounts:
|
||||
```
|
||||
|
||||
|
||||
|
||||
注意,我们的 Nginx 容器已经使用了 Namespace 的默认 CPU 和内存资源的 *limits* 和 *requests*。
|
||||
|
||||
让我们创建一个 Pod,它具有一个请求 3 CPU 核心的容器,这超过了被允许的限额:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/invalid-pod.yaml --namespace=limit-example
|
||||
Error from server: error when creating "http://k8s.io/docs/tasks/configure-pod-container/invalid-pod.yaml": Pod "invalid-pod" is forbidden: [Maximum cpu usage per Pod is 2, but limit is 3., Maximum cpu usage per Container is 2, but limit is 3.]
|
||||
```
|
||||
|
||||
|
||||
|
||||
让我们创建一个 Pod,使它在允许的最大限额范围之内:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/valid-pod.yaml --namespace=limit-example
|
||||
pod "valid-pod" created
|
||||
```
|
||||
|
||||
|
||||
|
||||
现在查看该 Pod 的 resources 字段:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods valid-pod --namespace=limit-example -o yaml | grep -C 6 resources
|
||||
uid: 3b1bfd7a-f53c-11e5-b066-64510658e388
|
||||
spec:
|
||||
containers:
|
||||
- image: k8s.gcr.io/serve_hostname
|
||||
imagePullPolicy: Always
|
||||
name: kubernetes-serve-hostname
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 512Mi
|
||||
```
|
||||
|
||||
|
||||
|
||||
注意到这个 Pod 显式地指定了资源 *limits* 和 *requests*,所以它不会使用该 Namespace 的默认值。
|
||||
|
||||
注意:在物理节点上默认安装的 Kubernetes 集群中,CPU 资源的 *limits* 是被强制使用的,该 Kubernetes 集群运行容器,除非管理员在部署 kublet 时使用了如下标志:
|
||||
|
||||
```shell
|
||||
$ kubelet --help
|
||||
Usage of kubelet
|
||||
....
|
||||
--cpu-cfs-quota[=true]: Enable CPU CFS quota enforcement for containers that specify CPU limits
|
||||
$ kubelet --cpu-cfs-quota=false ...
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 清理
|
||||
|
||||
基于使用的该示例来清理资源,可以通过如下命令删除名称为 limit-example 的 Namespace:
|
||||
|
||||
```shell
|
||||
$ kubectl delete namespace limit-example
|
||||
namespace "limit-example" deleted
|
||||
$ kubectl get namespaces
|
||||
NAME STATUS AGE
|
||||
default Active 12m
|
||||
```
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture discussion %}}
|
||||
|
||||
|
||||
## 设置资限额制的动机
|
||||
|
||||
可能由于对资源使用的各种原因,用户希望对单个 Pod 的资源总量进行强制限制。
|
||||
|
||||
例如:
|
||||
|
||||
|
||||
|
||||
1. 集群中每个节点有 2GB 内存。集群操作员不想接受内存需求大于 2GB 的 Pod,因为集群中没有节点能支持这个要求。
|
||||
为了避免 Pod 永远无法被调度到集群中的节点上,操作员会选择去拒绝超过 2GB 内存作为许可控制的 Pod。
|
||||
2. 一个集群被一个组织内部的 2 个团体共享,分别作为生产和开发工作负载来运行。
|
||||
生产工作负载可能消耗多达 8GB 内存,而开发工作负载可能消耗 512MB 内存。
|
||||
集群操作员为每个工作负载创建了一个单独的 Namespace,为每个 Namespace 设置了限额。
|
||||
3. 用户会可能创建一个资源消耗低于机器容量的 Pod。剩余的空间可能太小但很有用,然而对于整个集群来说浪费的代价是足够大的。
|
||||
结果集群操作员会希望设置限额:为了统一调度和限制浪费,Pod 必须至少消耗它们平均节点大小 20% 的内存和 CPU。
|
||||
|
||||
|
||||
|
||||
## 总结
|
||||
|
||||
想要限制单个容器或 Pod 消耗资源总量的集群操作员,能够为每个 Kubernetes Namespace 定义可允许的范围。
|
||||
在没有任何明确指派的情况下,Kubernetes 系统能够使用默认的资源 *limits* 和 *requests*,如果需要的话,限制一个节点上的 Pod 的资源总量。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
|
||||
* 查看 [LimitRange 设计文档](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/resource-management/admission_control_limit_range.md) 获取更多信息。
|
||||
* 查看 [资源](/docs/concepts/configuration/manage-compute-resources-container/) 获取关于 Kubernetes 资源模型的详细描述。
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
approvers:
|
||||
- caseydavenport
|
||||
- danwinship
|
||||
title: 声明网络策略
|
||||
content_template: templates/task
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
|
||||
|
||||
本文可以帮助您开始使用 Kubernetes 的 [NetworkPolicy API](/docs/concepts/services-networking/network-policies/) 声明网络策略去管理 Pod 之间的通信
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture prerequisites %}}
|
||||
|
||||
|
||||
您首先需要有一个支持网络策略的 Kubernetes 集群。已经有许多支持 NetworkPolicy 的网络提供商,包括:
|
||||
|
||||
* [Calico](/docs/tasks/configure-pod-container/calico-network-policy/)
|
||||
* [Romana](/docs/tasks/configure-pod-container/romana-network-policy/)
|
||||
* [Weave 网络](/docs/tasks/configure-pod-container/weave-network-policy/)
|
||||
|
||||
|
||||
**注意**:以上列表是根据产品名称按字母顺序排序,而不是按推荐或偏好排序。下面示例对于使用了上面任何提供商的 Kubernetes 集群都是有效的
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture steps %}}
|
||||
|
||||
|
||||
## 创建一个`nginx` deployment 并且通过服务将其暴露
|
||||
|
||||
|
||||
为了查看 Kubernetes 网络策略是怎样工作的,可以从创建一个`nginx` deployment 并且通过服务将其暴露开始
|
||||
|
||||
```console
|
||||
$ kubectl run nginx --image=nginx --replicas=2
|
||||
deployment "nginx" created
|
||||
$ kubectl expose deployment nginx --port=80
|
||||
service "nginx" exposed
|
||||
```
|
||||
|
||||
|
||||
在 default 命名空间下运行了两个 `nginx` pod,而且通过一个名字为 `nginx` 的服务进行了暴露
|
||||
|
||||
```console
|
||||
$ kubectl get svc,pod
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
svc/kubernetes 10.100.0.1 <none> 443/TCP 46m
|
||||
svc/nginx 10.100.0.16 <none> 80/TCP 33s
|
||||
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
po/nginx-701339712-e0qfq 1/1 Running 0 35s
|
||||
po/nginx-701339712-o00ef 1/1 Running 0 35s
|
||||
```
|
||||
|
||||
|
||||
## 测试服务能够被其它的 pod 访问
|
||||
|
||||
|
||||
您应该可以从其它的 pod 访问这个新的 `nginx` 服务。为了验证它,从 default 命名空间下的其它 pod 来访问该服务。请您确保在该命名空间下没有执行孤立动作。
|
||||
|
||||
|
||||
启动一个 busybox 容器,然后在容器中使用 `wget` 命令去访问 `nginx` 服务:
|
||||
|
||||
```console
|
||||
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
|
||||
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
|
||||
|
||||
Hit enter for command prompt
|
||||
|
||||
/ # wget --spider --timeout=1 nginx
|
||||
Connecting to nginx (10.100.0.16:80)
|
||||
/ #
|
||||
```
|
||||
|
||||
|
||||
## 限制访问 `nginx` 服务
|
||||
|
||||
|
||||
如果说您想限制 `nginx` 服务,只让那些拥有标签 `access: true` 的 pod 访问它,那么您可以创建一个只允许从那些 pod 连接的 `NetworkPolicy`:
|
||||
|
||||
```yaml
|
||||
kind: NetworkPolicy
|
||||
apiVersion: networking.k8s.io/v1
|
||||
metadata:
|
||||
name: access-nginx
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
run: nginx
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
access: "true"
|
||||
```
|
||||
|
||||
|
||||
## 为服务指定策略
|
||||
|
||||
|
||||
使用 kubectl 工具根据上面的 nginx-policy.yaml 文件创建一个 NetworkPolicy:
|
||||
|
||||
```console
|
||||
$ kubectl create -f nginx-policy.yaml
|
||||
networkpolicy "access-nginx" created
|
||||
```
|
||||
|
||||
|
||||
## 当访问标签没有定义时测试访问服务
|
||||
|
||||
|
||||
如果您尝试从没有设定正确标签的 pod 中去访问 `nginx` 服务,请求将会超时:
|
||||
|
||||
```console
|
||||
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
|
||||
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
|
||||
|
||||
Hit enter for command prompt
|
||||
|
||||
/ # wget --spider --timeout=1 nginx
|
||||
Connecting to nginx (10.100.0.16:80)
|
||||
wget: download timed out
|
||||
/ #
|
||||
```
|
||||
|
||||
|
||||
## 定义访问标签后再次测试
|
||||
|
||||
|
||||
创建一个拥有正确标签的 pod,您将看到请求是被允许的:
|
||||
|
||||
```console
|
||||
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
|
||||
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
|
||||
|
||||
Hit enter for command prompt
|
||||
|
||||
/ # wget --spider --timeout=1 nginx
|
||||
Connecting to nginx (10.100.0.16:80)
|
||||
/ #
|
||||
```
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user