This commit is contained in:
zhangqx2010
2017-09-21 12:02:55 +08:00
110 changed files with 3864 additions and 1269 deletions
@@ -0,0 +1,110 @@
---
title: 访问集群上运行的服务
redirect_from:
- "/docs/user-guide/accessing-the-cluster/"
- "/docs/user-guide/accessing-the-cluster.html"
---
{% capture overview %}
本文展示了如何连接 Kubernetes 集群上运行的服务。
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 访问集群上运行的服务
在 Kubernetes 里, [nodes](/docs/admin/node)、[pods](/docs/user-guide/pods) 和 [services](/docs/user-guide/services) 都有它们自己的 IP。许多情况下,集群上的 node IP、pod IP 和某些 service IP 路由不可达,所以不能从一个集群之外的节点访问它们,例如从你自己的台式机。
### 连接方式
你有多种从集群外连接 nodes、pods 和 services 的选项:
- 通过公共 IP 访问 services。
- 使用具有 `NodePort``LoadBalancer` 类型的 service,可以从外部访问它们。请查阅 [services](/docs/user-guide/services) 和 [kubectl expose](/docs/user-guide/kubectl/v1.6/#expose) 文档。
- 取决于你的集群环境,你可以仅把 service 暴露在你的企业网络环境中,也可以将其暴露在因特网上。需要考虑暴露的 service 是否安全,它是否有自己的用户认证?
- 将 pods 放置于 services 背后。如果要访问一个副本集合中特定的 pod,例如用于调试目的时,请给 pod 指定一个独特的标签并创建一个新 service 选择这个标签。
- 大部分情况下,都不需要应用开发者通过节点 IP 直接访问 nodes。
- 通过 Proxy Verb 访问 services、nodes 或者 pods。
- 在访问 Apiserver 远程服务之前是否经过认证和授权?如果你的服务暴露到因特网中不够安全,或者需要获取 node IP 之上的端口,又或者处于调试目的时,请使用这个特性。
- Proxies 可能给某些应用带来麻烦。
- 仅适用于 HTTP/HTTPS。
- 在[这里](#manually-constructing-apiserver-proxy-urls)描述
- 从集群中的 node 或者 pod 访问。
- 运行一个 pod,然后使用 [kubectl exec](/docs/user-guide/kubectl/v1.6/#exec) 连接到它的一个shell。从那个 shell 连接其他的 nodes、pods 和 services。
- 某些集群可能允许你 ssh 到集群中的节点。你可能可以从那儿访问集群服务。这是一个非标准的方式,可能在一些集群上能工作,但在另一些上却不能。浏览器和其他工具可能安装或可能不会安装。集群 DNS 可能不会正常工作。
### 发现内置服务
典型情况下,kube-system 会启动集群中的几个服务。使用 `kubectl cluster-info` 命令获取它们的列表:
```shell
$ kubectl cluster-info
Kubernetes master is running at https://104.197.5.247
elasticsearch-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy
kibana-logging is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kibana-logging/proxy
kube-dns is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns/proxy
grafana is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/monitoring-heapster/proxy
```
这显示了用于访问每个服务的 proxy-verb URL。例如,这个集群启用了(使用 Elasticsearch)集群层面的日志,如果提供合适的凭据可以通过 `https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/` 访问,或通过一个 kubectl 代理地址访问,如:`http://localhost:8080/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/`。(请查看 [上文](#accessing-the-cluster-api) 关于如何传递凭据或者使用 kubectl 代理的说明。)
#### 手动构建 apiserver 代理 URLs
如同上面所提到的,你可以使用 `kubectl cluster-info` 命令取得 service 的代理 URL。为了创建包含 service endpoints、suffixes 和 parameters 的代理 URLs,你可以简单的在 service 的代理 URL中 添加:
`http://`*`kubernetes_master_address`*`/api/v1/namespaces/`*`namespace_name`*`/services/`*`service_name[:port_name]`*`/proxy`
如果还没有为你的端口指定名称,你可以不用在 URL 中指定 *port_name*
##### 示例
* 你可以通过 `http://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_search?q=user:kimchy` 访问 Elasticsearch service endpoint `_search?q=user:kimchy`
* 你可以通过 `https://104.197.5.247/api/v1/namespaces/kube-system/services/elasticsearch-logging/proxy/_cluster/health?pretty=true` 访问 Elasticsearch 集群健康信息 endpoint `_cluster/health?pretty=true`
```json
{
"cluster_name" : "kubernetes_logging",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 5,
"active_shards" : 5,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 5
}
```
#### 通过 web 浏览器访问集群中运行的服务
你或许能够将 apiserver 代理的 url 放入浏览器的地址栏,然而:
- Web 服务器不总是能够传递令牌,所以你可能需要使用基本(密码)认证。 Apiserver 可以配置为接受基本认证,但你的集群可能并没有这样配置。
- 某些 web 应用可能不能工作,特别是那些使用客户端侧 javascript 的应用,它们构造 url 的方式可能不能理解代理路径前缀。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,411 @@
---
assignees:
- derekwaynecarr
- janetkuo
title: 应用资源配额和限额
redirect_from:
- "/docs/admin/resourcequota/walkthrough/"
- "/docs/admin/resourcequota/walkthrough.html"
- "/docs/tasks/configure-pod-container/apply-resource-quota-limit/"
- "/docs/tasks/configure-pod-container/apply-resource-quota-limit.html"
---
{% capture overview %}
本示例展示了在一个 namespace 中控制资源用量的典型设置。
本文展示了以下资源的使用: [Namespace](/docs/admin/namespaces), [ResourceQuota](/docs/concepts/policy/resource-quotas/) 和 [LimitRange](/docs/tasks/configure-pod-container/limit-range/)。
{% endcapture %}
{% capture prerequisites %}
* {% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 场景
集群管理员正在操作一个代表用户群体的集群,他希望控制一个特定 namespace 中可以被使用的资源总量,以达到促进对集群的公平共享及控制成本的目的。
集群管理员有以下目标:
* 限制运行中 pods 使用的计算资源数量
* 限制 persistent volume claims 数量以控制对存储的访问
* 限制 load balancers 数量以控制成本
* 防止使用 node ports 以保留稀缺资源
* 提供默认计算资源请求以实现更好的调度决策
## 创建 namespace
本示例将在一个自定义的 namespace 中运行,以展示相关概念。
让我们创建一个叫做 quota-example 的新 namespace
```shell
$ kubectl create namespace quota-example
namespace "quota-example" created
$ kubectl get namespaces
NAME STATUS AGE
default Active 2m
kube-system Active 2m
quota-example Active 39s
```
## 应用 object-count 配额到 namespace
集群管理员想要控制下列资源:
* persistent volume claims
* load balancers
* node ports
我们来创建一个简单的配额,用于控制这个 namespace 中那些资源类型的对象数量。
```shell
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-object-counts.yaml --namespace=quota-example
resourcequota "object-counts" created
```
配额系统将察觉到有一个配额被创建,并且会计算 namespace 中的资源消耗量作为响应。这应该会很快发生。
让我们显示一下配额来观察这个 namespace 中当前被消耗的资源:
```shell
$ kubectl describe quota object-counts --namespace=quota-example
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
```
配额系统现在将阻止用户创建比各个资源指定数量更多的资源。
## 应用计算资源配额到 namespace
为了限制这个 namespace 可以被使用的计算资源数量,让我们创建一个跟踪计算资源的配额。
```shell
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-compute-resources.yaml --namespace=quota-example
resourcequota "compute-resources" created
```
让我们显示一下配额来观察这个 namespace 中当前被消耗的资源:
```shell
$ kubectl describe quota compute-resources --namespace=quota-example
Name: compute-resources
Namespace: quota-example
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
```
配额系统现在会防止 namespace 拥有超过 4 个没有终止的 pods。此外它还将强制 pod 中的每个容器配置一个 `request` 并为 `cpu``memory` 定义 `limit`
## 应用默认资源请求和限制
Pod 的作者很少为它们的 pods 指定资源请求和限制。
既然我们对项目应用了配额,我们来看一下当终端用户通过创建一个没有 cpu 和 内存限制的 pod 时会发生什么。这通过在 pod 里创建一个 nginx 容器实现。
作为演示,让我们来创建一个运行 nginx 的 deployment
```shell
$ kubectl run nginx --image=nginx --replicas=1 --namespace=quota-example
deployment "nginx" created
```
现在我们来看一下创建的 pods。
```shell
$ kubectl get pods --namespace=quota-example
```
发生了什么?我一个 pods 都没有!让我们 describe 这个 deployment 来看看发生了什么。
```shell
$ kubectl describe deployment nginx --namespace=quota-example
Name: nginx
Namespace: quota-example
CreationTimestamp: Mon, 06 Jun 2016 16:11:37 -0400
Labels: run=nginx
Selector: run=nginx
Replicas: 0 updated | 1 total | 0 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
OldReplicaSets: <none>
NewReplicaSet: nginx-3137573019 (0/1 replicas created)
...
```
Deployment 创建了一个对应的 replica set 并尝试按照大小来创建一个 pod。
让我们看看 replica set 的更多细节。
```shell
$ kubectl describe rs nginx-3137573019 --namespace=quota-example
Name: nginx-3137573019
Namespace: quota-example
Image(s): nginx
Selector: pod-template-hash=3137573019,run=nginx
Labels: pod-template-hash=3137573019
run=nginx
Replicas: 0 current / 1 desired
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
No volumes.
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
4m 7s 11 {replicaset-controller } Warning FailedCreate Error creating: pods "nginx-3137573019-" is forbidden: Failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
```
Kubernetes API server 拒绝了 replica set 创建一个 pod 的请求,因为我们的 pods 没有为 `cpu``memory` 指定 `requests``limits`
因此,我们来为 pod 指定它可以使用的 `cpu``memory` 默认数量。
```shell
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-limits.yaml --namespace=quota-example
limitrange "limits" created
$ kubectl describe limits limits --namespace=quota-example
Name: limits
Namespace: quota-example
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container memory - - 256Mi 512Mi -
Container cpu - - 100m 200m -
```
如果 Kubernetes API server 发现一个 namespace 中有一个创建 pod 的请求,并且 pod 中的容器没有设置任何计算资源请求时,作为准入控制的一部分,一个默认的 request 和 limit 将会被应用。
在本例中,创建的每个 pod 都将拥有如下的计算资源限制:
```shell
$ kubectl run nginx \
--image=nginx \
--replicas=1 \
--requests=cpu=100m,memory=256Mi \
--limits=cpu=200m,memory=512Mi \
--namespace=quota-example
```
由于已经为我们的 namespace 申请了默认的计算资源,我们的 replica set 应该能够创建它的 pods 了。
```shell
$ kubectl get pods --namespace=quota-example
NAME READY STATUS RESTARTS AGE
nginx-3137573019-fvrig 1/1 Running 0 6m
```
而且如果打印出我们在这个 namespace 中的配额使用情况:
```shell
$ kubectl describe quota --namespace=quota-example
Name: compute-resources
Namespace: quota-example
Resource Used Hard
-------- ---- ----
limits.cpu 200m 2
limits.memory 512Mi 2Gi
pods 1 4
requests.cpu 100m 1
requests.memory 256Mi 1Gi
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
```
就像你看到的,创建的 pod 消耗了明确的计算资源量,并且正被 Kubernetes 正确的追踪着。
## 高级配额 scopes
让我们想象一下如果你不希望为你的 namespace 指定默认计算资源使用量。
作为替换,你希望用户在它们的 namespace 中运行指定数量的 `BestEffort` pods,以从宽松的计算资源中获得好处。然后要求用户为需要更高质量服务的 pods 配置一个显式的资源请求。
让我们新建一个拥有两个配额的 namespace 来演示这种行为:
```shell
$ kubectl create namespace quota-scopes
namespace "quota-scopes" created
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-best-effort.yaml --namespace=quota-scopes
resourcequota "best-effort" created
$ kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/rq-not-best-effort.yaml --namespace=quota-scopes
resourcequota "not-best-effort" created
$ kubectl describe quota --namespace=quota-scopes
Name: best-effort
Namespace: quota-scopes
Scopes: BestEffort
* Matches all pods that have best effort quality of service.
Resource Used Hard
-------- ---- ----
pods 0 10
Name: not-best-effort
Namespace: quota-scopes
Scopes: NotBestEffort
* Matches all pods that do not have best effort quality of service.
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
```
在这种场景下,一个没有配置计算资源请求的 pod 将会被 `best-effort` 配额跟踪。
而配置了计算资源请求的则会被 `not-best-effort` 配额追踪。
让我们创建两个 deployments 作为演示:
```shell
$ kubectl run best-effort-nginx --image=nginx --replicas=8 --namespace=quota-scopes
deployment "best-effort-nginx" created
$ kubectl run not-best-effort-nginx \
--image=nginx \
--replicas=2 \
--requests=cpu=100m,memory=256Mi \
--limits=cpu=200m,memory=512Mi \
--namespace=quota-scopes
deployment "not-best-effort-nginx" created
```
虽然没有指定默认的 limits`best-effort-nginx` deployment 还是会创建 8 个 pods。这是由于它被 `best-effort` 配额追踪,而 `not-best-effort` 配额将忽略它。`not-best-effort` 配额将追踪 `not-best-effort-nginx` deployment,因为它创建的 pods 具有 `Burstable` 服务质量。
让我们列出 namespace 中的 pods
```shell
$ kubectl get pods --namespace=quota-scopes
NAME READY STATUS RESTARTS AGE
best-effort-nginx-3488455095-2qb41 1/1 Running 0 51s
best-effort-nginx-3488455095-3go7n 1/1 Running 0 51s
best-effort-nginx-3488455095-9o2xg 1/1 Running 0 51s
best-effort-nginx-3488455095-eyg40 1/1 Running 0 51s
best-effort-nginx-3488455095-gcs3v 1/1 Running 0 51s
best-effort-nginx-3488455095-rq8p1 1/1 Running 0 51s
best-effort-nginx-3488455095-udhhd 1/1 Running 0 51s
best-effort-nginx-3488455095-zmk12 1/1 Running 0 51s
not-best-effort-nginx-2204666826-7sl61 1/1 Running 0 23s
not-best-effort-nginx-2204666826-ke746 1/1 Running 0 23s
```
如你看到的,所有 10 个 pods 都已经被准许创建。
让我们 describe 这个 namespace 当前的配额使用情况:
```shell
$ kubectl describe quota --namespace=quota-scopes
Name: best-effort
Namespace: quota-scopes
Scopes: BestEffort
* Matches all pods that have best effort quality of service.
Resource Used Hard
-------- ---- ----
pods 8 10
Name: not-best-effort
Namespace: quota-scopes
Scopes: NotBestEffort
* Matches all pods that do not have best effort quality of service.
Resource Used Hard
-------- ---- ----
limits.cpu 400m 2
limits.memory 1Gi 2Gi
pods 2 4
requests.cpu 200m 1
requests.memory 512Mi 1Gi
```
如你看到的,`best-effort` 配额追踪了我们在 `best-effort-nginx` deployment 中创建的 8 个 pods 的资源用量,而 `not-best-effort` 配额追踪了我们在 `not-best-effort-nginx` deployment 中创的两个 pods 的用量。
Scopes 提供了一种来对任何配额文档追踪的资源集合进行细分的机制,给操作人员部署和追踪资源消耗带来更大的灵活性。
`BestEffort``NotBestEffort` scopes 之外,还有用于限制长时间运行和有时限 pods 的scopes。`Terminating` scope 将匹配任何 `spec.activeDeadlineSeconds` 不为 `nil` 的 pod。`NotTerminating` scope 将匹配任何 `spec.activeDeadlineSeconds``nil` 的 pod。这些 scopes 允许你基于 pods 在你集群中 node 上的预期持久程度来为它们指定配额。
{% endcapture %}
{% capture discussion %}
## 总结
消耗节点 cpu 和 memory 资源的动作受到 namespace 配额定义的硬性配额限制的管制。
任意消耗那些资源的动作能够被调整,或者获得一个 namespace 级别的默认值以符合你最终的目标。
可以基于服务质量或者在你集群中节点上的预期持久程度来分配配额。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,94 @@
---
title: 改变默认 StorageClass
---
{% capture overview %}
本文展示了如何改变默认的 Storage Class,它用于为没有特殊需求的 PersistentVolumeClaims 配置 volumes。
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 为什么要改变默认 storage class
取决于安装模式,您的 Kubernetes 集群可能和一个被标记为默认的已有 StorageClass 一起部署。这个默认的 StorageClass 以后将被用于动态的为没有特定 storage class 需求的 PersistentVolumeClaims 配置存储。更多细节请查看 [PersistentVolumeClaim 文档](/docs/user-guide/persistent-volumes/#class-1)。
预先安装的默认 StorageClass 可能不能很好的适应您期望的工作负载;例如,它配置的存储可能太过昂贵。如果是这样的话,您可以改变默认 StorageClass,或者完全禁用它以防止动态配置存储。
简单的删除默认 StorageClass 可能行不通,因为它可能会被您集群中的扩展管理器自动重建。请查阅您的安装文档中关于扩展管理器的细节,以及如何禁用单个扩展。
## 改变默认 StorageClass
1. 列出您集群中的 StorageClasses
kubectl get storageclass
输出类似这样:
NAME TYPE
standard (default) kubernetes.io/gce-pd
gold kubernetes.io/gce-pd
默认 StorageClass 以 `(default)` 标记。
2. 标记默认 StorageClass 非默认:
默认 StorageClass 的注解 `storageclass.kubernetes.io/is-default-class` 设置为 `true`。注解的其它任意值或者缺省值将被解释为 `false`
要标记一个 StorageClass 为非默认的,您需要改变它的值为 `false`
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
这里的 `<your-class-name>` 是您选择的 StorageClass 的名字。
3. 标记一个 StorageClass 为默认的:
和前面的步骤类似,您需要添加/设置注解 `storageclass.kubernetes.io/is-default-class=true`
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
请注意,最多只能有一个 StorageClass 能够被标记为默认。如果它们中有两个或多个被标记为默认,Kubernetes 将忽略这个注解,也就是它将表现为没有默认 StorageClass。
4. 验证您选用的 StorageClass 为默认的:
kubectl get storageclass
输出类似这样:
NAME TYPE
standard kubernetes.io/gce-pd
gold (default) kubernetes.io/gce-pd
{% endcapture %}
{% capture whatsnext %}
* 了解更多关于 [StorageClasses](/docs/concepts/storage/persistent-volumes/)。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,80 @@
---
title: 更改 PersistentVolume 的回收策略
---
{% capture overview %}
本文展示了如何更改 Kubernetes PersistentVolume 的回收策略。
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 为什么要更改 PersistentVolume 的回收策略
`PersistentVolumes` 可以有多种回收策略,包括 "Retain"、"Recycle" 和 "Delete"。对于动态配置的 `PersistentVolumes` 来说,默认回收策略为 "Delete"。这表示当用户删除对应的 `PeristentVolumeClaim` 时,动态配置的 volume 将被自动删除。如果 volume 包含重要数据时,这种自动行为可能是不合适的。那种情况下,更适合使用 "Retain" 策略。使用 "Retain" 时,如果用户删除 `PersistentVolumeClaim`,对应的 `PersistentVolume` 不会被删除。相反,它将变为 `Released` 状态,表示所有的数据可以被手动恢复。
## 更改 PersistentVolume 的回收策略
1. 列出你集群中的 PersistentVolumes
kubectl get pv
输出类似于这样:
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 10s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 6s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim3 3s
这个列表同样包含了绑定到每个 volume 的 claims 名称,以便更容易的识别动态配置的 volumes。
2. 选择你的 PersistentVolumes 中的一个并更改它的回收策略:
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
这里的 `<your-pv-name>` 是你选择的 PersistentVolume 的名字。
3. 验证你选择的 PersistentVolume 拥有正确的策略:
kubectl get pv
输出类似于这样:
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pvc-b6efd8da-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim1 40s
pvc-b95650f8-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Delete Bound default/claim2 36s
pvc-bb3ca71d-b7b5-11e6-9d58-0ed433a7dd94 4Gi RWO Retain Bound default/claim3 33s
在前面的输出中,你可以看到绑定到 claim `default/claim3` 的 volume 拥有的回收策略为 `Retain`。当用户删除 claim `default/claim3` 时,它不会被自动删除。
{% endcapture %}
{% capture whatsnext %}
* 了解更多关于 [PersistentVolumes](/docs/concepts/storage/persistent-volumes/)的信息。
* 了解更多关于 [PersistentVolumeClaims](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 的信息。
### 参考
* [PersistentVolume](/docs/api-reference/{{page.version}}/#persistentvolume-v1-core)
* [PersistentVolumeClaim](/docs/api-reference/{{page.version}}/#persistentvolumeclaim-v1-core)
* 查阅 [PersistentVolumeSpec](/docs/api-reference/{{page.version}}/#persistentvolumeclaim-v1-core) 的 `persistentVolumeReclaimPolicy` 字段。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,227 @@
---
approvers:
- lavalamp
- thockin
title: 集群管理
---
* TOC
{:toc}
本文描述了和集群生命周期相关的几个主题:创建新集群、更新集群的 master 和 worker 节点、执行节点维护(例如升级内核)以及升级运行中集群的 Kubernetes API 版本。
## 创建和配置集群
要在一组机器上安装 Kubernetes, 请根据您的环境,查阅现有的 [入门指南](/docs/getting-started-guides/)
## 升级集群
集群升级当前是配套提供的,某些发布版本在升级时可能需要特殊处理。推荐管理员在升级他们的集群前,同时查阅 [发行说明](https://git.k8s.io/kubernetes/CHANGELOG.md) 和版本具体升级说明。
* [升级到 1.6](/docs/admin/upgrade-1-6)
### 升级 Google Compute Engine 集群
Google Compute Engine Open Source (GCE-OSS) 通过删除和重建 master 来支持 master 升级。通过维持相同的 Persistent Disk (PD) 以保证在升级过程中保留数据。
GCE 的 Node 升级采用 [管理实例组](https://cloud.google.com/compute/docs/instance-groups/),每个节点将被顺序的删除,然后使用新软件重建。任何运行在那个节点上的 Pod 需要用 Replication Controller 控制,或者在扩容之后手动重建。
开源 Google Compute Engine (GCE) 集群上的升级过程由 `cluster/gce/upgrade.sh` 脚本控制。
运行 `cluster/gce/upgrade.sh -h` 获取使用说明。
例如,只将 master 升级到一个指定的版本 (v1.0.2):
```shell
cluster/gce/upgrade.sh -M v1.0.2
```
或者,将整个集群升级到最新的稳定版本:
```shell
cluster/gce/upgrade.sh release/stable
```
### 升级 Google Container Engine (GKE) 集群
Google Container Engine 自动升级 master 组件(例如 `kube-apiserver``kube-scheduler`)至最新版本。它还负责 master 运行的操作系统和其它组件。
节点升级过程由用户初始化,[GKE 文档](https://cloud.google.com/container-engine/docs/clusters/upgrade) 里有相关描述。
### 在其他平台上升级集群
不同的供应商和工具管理升级的过程各不相同。建议您查阅它们有关升级的主要文档。
* [kops](https://github.com/kubernetes/kops)
* [kubespray](https://github.com/kubernetes-incubator/kubespray)
* [CoreOS Tectonic](https://coreos.com/tectonic/docs/latest/admin/upgrade.html)
* ...
## 调整集群大小
如果集群资源短缺,您可以轻松的添加更多的机器,如果集群正运行在[节点自注册模式](/docs/admin/node/#self-registration-of-nodes)下的话。如果正在使用的是 GCE 或者 GKE,这将通过调整管理节点的实例组的大小完成。在 [Google Cloud Console page](https://console.developers.google.com) 的 `Compute > Compute Engine > Instance groups > your group > Edit group` 下修改实例数量或使用 gcloud CLI 都可以完成这个任务。
```shell
gcloud compute instance-groups managed resize kubernetes-minion-group --size 42 --zone $ZONE
```
实例组将负责在新机器上放置恰当的镜像并启动它们。Kubelet 将向 API server 注册它的节点以使其可以用于调度。如果您对 instance group 进行缩容,系统将会随机选取节点来终止。
在其他环境上,您可能需要手动配置机器并告诉 Kubelet API server 在哪台机器上运行。
### 集群自动伸缩
如果正在使用 GCE 或者 GKE,您可以配置您的集群,使其能够基于 pod 需求自动重新调整大小。
如 [Compute Resource](/docs/concepts/configuration/manage-compute-resources-container/) 所述,用户可以控制预留多少 CPU 和内存来分配给 pod。这个信息被 Kubernetes scheduler 用来寻找一个运行 pod 的地方。如果没有一个节点有足够的空闲容量(或者不能满足其他 pod 的需求),这个 pod 就需要等待某些 pod 结束,或者一个新的节点被添加。
集群 autoscaler 查找不能被调度的 pod 并检查添加一个新节点(和集群中其它节点类似的)是否有帮助。如果是的话,它将调整集群的大小以容纳等待调度的 pod。
如果发现在一段延时时间内(默认10分钟,将来有可能改变)某些节点不再需要,集群 autoscaler 也会缩小集群。
集群 autoscaler 在每一个实例组(GCE)或节点池(GKE)上配置。
如果您使用 GCE,那么您可以在使用 kube-up.sh 脚本创建集群的时候启用它。要想配置集群 autoscaler,您需要设置三个环境变量:
* `KUBE_ENABLE_CLUSTER_AUTOSCALER` - 如果设置为 true 将启用集群 autoscaler。
* `KUBE_AUTOSCALER_MIN_NODES` - 集群的最小节点数量。
* `KUBE_AUTOSCALER_MAX_NODES` - 集群的最大节点数量。
示例:
```shell
KUBE_ENABLE_CLUSTER_AUTOSCALER=true KUBE_AUTOSCALER_MIN_NODES=3 KUBE_AUTOSCALER_MAX_NODES=10 NUM_NODES=5 ./cluster/kube-up.sh
```
在 GKE 上,您可以在创建、更新集群或创建一个特别的节点池(您希望自动伸缩的)时,通过给对应的 `gcloud` 命令传递 `--enable-autoscaling` `--min-nodes``--max-nodes` 来配置集群 autoscaler。
示例:
```shell
gcloud container clusters create mytestcluster --zone=us-central1-b --enable-autoscaling --min-nodes=3 --max-nodes=10 --num-nodes=5
```
```shell
gcloud container clusters update mytestcluster --enable-autoscaling --min-nodes=1 --max-nodes=15
```
**集群 autoscaler 期望节点未被手动修改过(例如通过 kubectl 添加标签),因为那些属性可能不能被传递到相同节点组中的新节点上。**
## 维护节点
如果需要重启节点(例如内核升级、libc 升级、硬件维修等),且停机时间很短时,当 Kubelet 重启后,它将尝试重启调度到节点上的 pod。如果重启花费较长时间(默认时间为 5 分钟,由 controller-manager 的 `--pod-eviction-timeout` 控制),节点控制器将会结束绑定到这个不可用节点上的 pod。如果存在对应的 replica set(或者 replication controller)时,则将在另一个节点上启动 pod 的新副本。所以,如果所有的 pod 都是复制而来,那么在不是所有节点都同时停机的前提下,升级可以在不需要特殊调整情况下完成。
如果您希望更多的控制升级过程,可以使用下面的工作流程:
使用 `kubectl drain` 优雅的结束节点上的所有 pod 并同时标记节点为不可调度:
```shell
kubectl drain $NODENAME
```
在您正试图使节点离线时,这将阻止新的 pod 落到它们上面。
对于有 replica set 的 pod 来说,它们将会被新的 pod 替换并且将被调度到一个新的节点。此外,如果 pod 是一个 service 的一部分,则客户端将被自动重定向到新的 pod。
对于没有 replica set 的 pod,您需要手动启动 pod 的新副本,并且如果它不是 service 的一部分,您需要手动将客户端重定向到这个 pod。
在节点上执行维护工作。
重新使节点可调度:
```shell
kubectl uncordon $NODENAME
```
如果删除了节点的虚拟机实例并重新创建,那么一个新的可调度节点资源将被自动创建(只在您使用支持节点发现的云服务提供商时;当前只有 Google Compute Engine,不包括在 Google Compute Engine 上使用 kube-register 的 CoreOS)。相关详细信息,请查阅 [节点](/docs/admin/node)。
## 高级主题
### 升级到不同的 API 版本
当新的 API 版本发布时,您可能需要升级集群支持新的 API 版本(例如当 'v2' 发布时从 'v1' 切换到 'v2')。
这不是一个经常性的事件,但需要谨慎的处理。这里有一系列升级到新 API 版本的步骤。
1. 开启新 API 版本。
2. 升级集群存储来使用新版本。
3. 升级所有配置文件。识别使用旧 API 版本 endpoint 的用户。
4. 运行 `cluster/update-storage-objects.sh` 升级存储中的现有对象为新版本。
5. 关闭旧 API 版本。
### 打开或关闭集群的 API 版本
可以在启动 API server 时传递 `--runtime-config=api/<version>` 标志来打开或关闭特定的 API 版本。例如:要关闭 v1 API,请传递 `--runtime-config=api/v1=false`。运行时配置还支持两个特殊键值:api/all 和 api/legacy,分别控制全部和遗留 API。例如要关闭除 v1 外全部 API 版本,请传递 `--runtime-config=api/all=false,api/v1=true`。对于这些标志来说,_legacy_ API 指那些被显式废弃的 API(例如 `v1beta3`)。
### 切换集群存储的 API 版本
存储于磁盘中,用于在集群内部代表 Kubernetes 活跃资源的对象使用特定的 API 版本书写。当支撑的 API 改变时,这些对象可能需要使用更新的 API 重写。重写失败将最终导致资源不再能够被 Kubernetes API server 解析或使用。
`kube-apiserver` 二进制文件的 `KUBE_API_VERSIONS` 环境变量控制了集群支持的 API 版本。列表中的第一个版本被用作集群的存储版本。因此,要设置特定的版本为存储版本,请将其放在 `KUBE_API_VERSIONS` 参数值版本列表的最前面。您需要重启 `kube-apiserver` 二进制以使这个变量的改动生效。
### 切换配置文件为新 API 版本
可以使用 `kubectl convert` 命令对不同 API 版本的配置文件进行转换。
```shell
kubectl convert -f pod.yaml --output-version v1
```
更多选项请参考 [kubectl convert](/docs/user-guide/kubectl/v1.6/#convert) 命令用法。
@@ -0,0 +1,134 @@
---
title: 配置命名空间下pod总数
---
{% capture overview %}
本文主要描述如何配置一个命名空间下可运行的pod总数。资源配额详细信息可查看:[资源配额](/docs/api-reference/v1.7/#resourcequota-v1-core)
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 创建一个命名空间
首先创建一个命名空间,这样可以将本次操作中创建的资源与集群其他资源隔离开来。
```shell
kubectl create namespace quota-pod-example
```
## 创建资源配额
下面是一个资源配额的配置文件:
{% include code.html language="yaml" file="quota-pod.yaml" ghlink="/docs/tasks/administer-cluster/quota-pod.yaml" %}
创建这个资源配额:
```shell
kubectl create -f https://k8s.io/docs/tasks/administer-cluster/quota-pod.yaml --namespace=quota-pod-example
```
查看资源配额的详细信息:
```shell
kubectl get resourcequota pod-demo --namespace=quota-pod-example --output=yaml
```
从输出的信息我们可以看到,该命名空间下pod的配额是2个,目前创建的pods数为0,配额使用率为0。
```yaml
spec:
hard:
pods: "2"
status:
hard:
pods: "2"
used:
pods: "0"
```
下面是一个Deployment的配置文件:
{% include code.html language="yaml" file="quota-pod-deployment.yaml" ghlink="/docs/tasks/administer-cluster/quota-pod-deployment.yaml" %}
在配置文件中, `replicas: 3` 告诉kubernetes尝试创建三个pods,且运行相同的应用。
创建这个Deployment
```shell
kubectl create -f https://k8s.io/docs/tasks/administer-cluster/quota-pod-deployment.yaml --namespace=quota-pod-example
```
查看Deployment的详细信息:
```shell
kubectl get deployment pod-quota-demo --namespace=quota-pod-example --output=yaml
```
从输出的信息我们可以看到,尽管尝试创建三个pod,但是由于配额的限制,只有两个pod能被成功创建。
```yaml
spec:
...
replicas: 3
...
status:
availableReplicas: 2
...
lastUpdateTime: 2017-07-07T20:57:05Z
message: 'unable to create pods: pods "pod-quota-demo-1650323038-" is forbidden:
exceeded quota: pod-demo, requested: pods=1, used: pods=2, limited: pods=2'
```
## 清理
删除命名空间:
```shell
kubectl delete namespace quota-pod-example
```
{% endcapture %}
{% capture whatsnext %}
### 对于集群管理
* [配置命名空间下,内存默认的request值和limit值](/docs/tasks/administer-cluster/memory-default-namespace/)
* [配置命名空间下,CPU默认的request值和limit值](/docs/tasks/administer-cluster/cpu-default-namespace/)
* [配置命名空间下,内存的最小值和最大值](/docs/tasks/administer-cluster/memory-constraint-namespace/)
* [配置命名空间下,CPU的最小值和最大值](/docs/tasks/administer-cluster/cpu-constraint-namespace/)
* [配置命名空间下,内存和CPU的配额](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/)
* [配置命名空间下,API对象的配额](/docs/tasks/administer-cluster/quota-api-object/)
### 对于应用开发
* [给容器和pod分配内存资源](/docs/tasks/configure-pod-container/assign-memory-resource/)
* [给容器和pod分配CPU资源](/docs/tasks/configure-pod-container/assign-cpu-resource/)
* [配置pod的QoS](/docs/tasks/configure-pod-container/quality-service-pod/)
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,137 @@
---
title: 给容器分配非透明整型资源
---
{% capture overview %}
本页展示了如何给容器分配非透明整型资源。
{% include feature-state-alpha.md %}
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
在做这个练习之前,请在[给节点配置非透明整型资源](/docs/tasks/administer-cluster/opaque-integer-resource-node/)文档中进行练习,
该文档介绍了在一个节点上配置dongle资源。
{% endcapture %}
{% capture steps %}
## 给Pod分配非透明整型资源
为了请求一个非透明整型资源,需要在容器配置文件中包含`resources:requests`字段。
非透明整型资源类型前缀是`pod.alpha.kubernetes.io/opaque-int-resource-`
下面是含有一个容器的Pod的配置文件:
{% include code.html language="yaml" file="oir-pod.yaml" ghlink="/cn/docs/tasks/configure-pod-container/oir-pod.yaml" %}
在配置文件中,可以看到容器请求了3个dongles资源。
创建Pod:
```shell
kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/oir-pod.yaml
```
验证Pod是否正在运行:
```shell
kubectl get pod oir-demo
```
查询Pod的状态:
```shell
kubectl describe pod oir-demo
```
输出显示了dongle请求:
```yaml
Requests:
pod.alpha.kubernetes.io/opaque-int-resource-dongle: 3
```
## 尝试创建第二个Pod
下面是含有一个容器的Pod的配置文件。该容器请求了两个dongles资源。
{% include code.html language="yaml" file="oir-pod-2.yaml" ghlink="/docs/tasks/configure-pod-container/oir-pod-2.yaml" %}
Kubernetes无法再满足两个dongles的请求,因为第一个Pod已经使用了四个可用dongles中的三个。
尝试创建Pod:
```shell
kubectl create -f https://k8s.io/docs/tasks/configure-pod-container/oir-pod-2.yaml
```
查询Pod的状态
```shell
kubectl describe pod oir-demo-2
```
输出显示该Pod无法被调度,因为没有节点有两个可用的dongles资源:
```
Conditions:
Type Status
PodScheduled False
...
Events:
...
... Warning FailedScheduling pod (oir-demo-2) failed to fit in any node
fit failure summary on nodes : Insufficient pod.alpha.kubernetes.io/opaque-int-resource-dongle (1)
```
查看Pod的状态:
```shell
kubectl get pod oir-demo-2
```
输出显示Pod已创建,但是没有被调度并运行在节点上。
它的状态为Pending:
```yaml
NAME READY STATUS RESTARTS AGE
oir-demo-2 0/1 Pending 0 6m
```
## 删除
删除本练习中创建的Pod:
```shell
kubectl delete pod oir-demo
```
{% endcapture %}
{% capture whatsnext %}
### 对于应用开发者
* [分配内存资源](/docs/tasks/configure-pod-container/assign-memory-resource/)
* [分配CPU资源](/docs/tasks/configure-pod-container/assign-cpu-resource/)
### 对于集群管理员
* [给节点配置非透明整型资源](/docs/tasks/administer-cluster/opaque-integer-resource-node/)
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,87 @@
---
title: 调试Pods和Replication Controllers
---
* TOC
{:toc}
## 调试Pods
调试一个pod的第一步是观察它。使用下面的命令检查这个pod的当前状态和最近事件:
$ kubectl describe pods ${POD_NAME}
看看pod中的容器的状态。他们都是`Running`吗?有最近重启了吗?
根据pod的状态继续调试。
### 我的Pod保持Pending
如果一个pod被卡在`Pending`中,就意味着它不能调度在某个节点上。一般来说,这是因为某种类型的资源不足
阻止调度。 看看上面的命令`kubectl describe ...`的输出。调度器的消息中应该会包含无法调度Pod的原因。
理由包括:
#### 资源不足
您可能已经耗尽了集群中供应的CPU或内存。在这个情况下你可以尝试几件事情:
* [添加更多节点](/docs/admin/cluster-management/#resizing-a-cluster) 到集群。
* [终止不需要的pod](/docs/user-guide/pods/single-container/#deleting_a_pod)
为pending中的pods提供空间。
* 检查该pod是否不大于您的节点。例如,如果全部节点具有`cpu:1`容量,那么具有`cpu: 1.1`请求的pod永远不会被调度。
您可以使用`kubectl get nodes -o <format>`命令来检查节点容量。
下面是一些能够提取必要信息的命令示例:
kubectl get nodes -o yaml | grep '\sname\|cpu\|memory'
kubectl get nodes -o json | jq '.items[] | {name: .metadata.name, cap: .status.capacity}'
可以考虑配置[资源配额](/docs/concepts/policy/resource-quotas/)来限制可耗用的资源总量。如果与命名空间一起使用,它可以防止一个团队吞噬所有的资源。
#### 使用hostPort
当你将一个pod绑定到一个`hostPort`时,这个pod能被调度的位置数量有限。
在大多数情况下,`hostPort`是不必要的; 尝试使用服务对象来暴露您的pod。
如果你需要`hostPort`,那么你可以调度的Pod数量不能超过集群的节点个数。
### 我的Pod一直在Waiting
如果一个pod被卡在`Waiting`状态,那么它已被调度在某个工作节点,但它不能在该机器上运行。
再次,来自`kubectl describe ...`的内容应该是可以提供信息的。
最常见的原因`Waiting`的pod是无法拉取镜像。有三件事要检查:
* 确保您的镜像的名称正确。
* 您是否将镜像推送到存储库?
* 在您的机器上手动运行`docker pull <image>`,看看是否可以拉取镜像。
### 我的Pod一直Crashing或者有别的不健康状态
首先,查看当前容器的日志:
$ kubectl logs ${POD_NAME} ${CONTAINER_NAME}
如果您的容器先前已崩溃,则可以访问上一个容器的崩溃日志:
$ kubectl logs --previous ${POD_NAME} ${CONTAINER_NAME}
或者,您可以使用`exec`在该容器内运行命令:
$ kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
请注意,`-c ${CONTAINER_NAME}`是可选的,对于pod只包含一个容器可以省略。
例如,要查看正在运行的Cassandra pod的日志,可以运行:
$ kubectl exec cassandra -- cat /var/log/cassandra/system.log
如果这些方法都不起作用,您可以找到该运行pod所在的主机并SSH到该主机。
## 调试Replication Controllers
Replication Controllers相当简单。他们能或不能创建pod。如果他们无法创建pod,那么请参考
[上面的说明](#debugging_pods)来调试你的pod。
您也可以使用`kubectl describe rc ${CONTROLLER_NAME}`来检查和Replication Controllers有关的事件。
@@ -0,0 +1,77 @@
---
title: 调试StatefulSet
---
{% capture overview %}
此任务展示如何调试StatefulSet。
{% endcapture %}
{% capture prerequisites %}
* 你需要有一个Kubernetes集群,通过必要的配置使kubectl命令行工具与您的集群进行通信。
* 你应该有一个运行中的StatefulSet,以便用于调试。
{% endcapture %}
{% capture steps %}
## 调试StatefulSet
由于StatefulSet在创建时设置了`app=myapp`标签,列出仅属于该StatefulSet的所有pod时,可以使用以下命令:
```shell
kubectl get pods -l app=myapp
```
如果您发现列出的任何Pods长时间处于`Unknown``Terminating`状态,关于如何处理它们的说明任务,请参阅[删除 StatefulSet Pods](/docs/tasks/manage-stateful-set/delete-pods/)。您可以参考[调试 Pods](/docs/user-guide/debugging-pods-and-replication-controllers/#debugging-pods)指南来调试StatefulSet中的各个Pod。
StatefulSets提供调试机制,可以使用注解来暂停所有控制器在Pod上的操作。在任何StatefulSet Pod上设置`pod.alpha.kubernetes.io/initialized`注解为`"false"`将*暂停* StatefulSet的所有操作。暂停时,StatefulSet将不执行任何伸缩操作。一旦调试钩子设置完成后,就可以在StatefulSet pod的容器内执行命令,而不会造成伸缩操作的干扰。您可以通过执行以下命令将注解设置为`"false"`
```shell
kubectl annotate pods <pod-name> pod.alpha.kubernetes.io/initialized="false" --overwrite
```
当注解设置为`"false"`时,StatefulSet在其Pods变得不健康或不可用时将不会响应。StatefulSet不会创建副本Pod直到每个Pod上删除注解或将注解设置为`"true"`
### 逐步初始化
创建StatefulSet之前,您可以通过使用和上文相同的注解,即将yaml文件中`.spec.template.metadata.annotations`里的`pod.alpha.kubernetes.io/initialized`字段设置为`"false"`,对竞态条件的StatefulSet进行调试。
```yaml
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: my-app
spec:
serviceName: "my-app"
replicas: 3
template:
metadata:
labels:
app: my-app
annotations:
pod.alpha.kubernetes.io/initialized: "false"
...
...
...
```
设置注解后,如果创建了StatefulSet,您可以等待每个Pod来验证它是否正确初始化。StatefulSet将不会创建任何后续的Pods,直到在已经创建的每个Pod上将调试注解设置为`"true"` (或删除)。 您可以通过执行以下命令将注解设置为`"true"`
```shell
kubectl annotate pods <pod-name> pod.alpha.kubernetes.io/initialized="true" --overwrite
```
{% endcapture %}
{% capture whatsnext %}
点击链接[调试init-container](/docs/tasks/troubleshoot/debug-init-containers/),了解更多信息。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,12 @@
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"]
@@ -0,0 +1,128 @@
---
title: 为容器设置启动时要执行的命令及其入参
---
{% capture overview %}
本页将展示如何为Kubernetes Pod下的容器设置启动时要执行的命令及其入参。
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 创建Pod时为其下的容器设置启动时要执行的命令及其入参
创建Pod时,可以为其下的容器设置启动时要执行的命令及其入参。如果要设置命令,就
填写在配置文件的`command`字段下,如果要设置命令的入参,就填写在配置文件的`args
`字段下。一旦Pod创建完成,该命令及其入参就无法再进行更改了。
如果在配置文件中设置了容器启动时要执行的命令及其入参,那么容器镜像中自带的命令
与入参将会被覆盖而不再执行。如果配置文件中只是设置了入参,却没有设置其对应的命
令,那么容器镜像中自带的命令会使用该新入参作为其执行时的入参。
本示例中,将创建一个只包含单个容器的Pod。在Pod配置文件中设置了一个命令与两个入参:
{% include code.html language="yaml" file="commands.yaml" ghlink="/cn/docs/tasks/inject-data-application/commands.yaml" %}
1. 基于YAML文件创建一个Pod
kubectl create -f https://k8s.io/docs/tasks/inject-data-application/commands.yaml
1. 获取一下当前正在运行的Pods信息:
kubectl get pods
查询结果显示在command-demo这个Pod下运行的容器已经启动完成
1. 如果要获取容器启动时执行命令的输出结果,可以通过Pod的日志进行查看
kubectl logs command-demo
日志中显示了HOSTNAME 与KUBERNETES_PORT 这两个环境变量的值:
command-demo
tcp://10.3.240.1:443
## 使用环境变量来设置入参
在上面的示例中,我们直接将一串字符作为命令的入参。除此之外,我们还可以
将环境变量作为命令的入参。
env:
- name: MESSAGE
value: "hello world"
command: ["/bin/echo"]
args: ["$(MESSAGE)"]
这样一来,我们就可以将那些用来设置环境变量的方法应用于设置命令的入参,其
中包括了[ConfigMaps](/docs/tasks/configure-pod-container/configmap/)
[Secrets](/docs/concepts/configuration/secret/).
**注意:** 环境变量需要加上括号,类似于`"$(VAR)"`。这是在`command`
`args`字段使用变量的格式要求。
{: .note}
## 通过shell来执行命令
有时候,需要通过shell来执行命令。 例如,命令可能由多个命令组合而成,抑或包含
在一个shell脚本中。这时,就可以通过如下方式在shell中执行命令:
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
## 注意
下表给出了Docker 与 Kubernetes中对应的字段名称。
| Description | Docker field name | Kubernetes field name |
|----------------------------------------|------------------------|-----------------------|
| The command run by the container | Entrypoint | command |
| The arguments passed to the command | Cmd | args |
如果要覆盖默认的Entrypoint 与 Cmd,需要遵循如下规则:
* 如果在容器配置中没有设置`command` 或者 `args`,那么将使用Docker镜像自带的命
令及其入参。
* 如果在容器配置中只设置了`command`但是没有设置`args`,那么容器启动时只会执行该
命令,Docker镜像中自带的命令及其入参会被忽略。
* 如果在容器配置中只设置了`args`,那么Docker镜像中自带的命令会使用该新入参作为
其执行时的入参。
* 如果在容器配置中同时设置了`command``args`,那么Docker镜像中自带的命令及
其入参会被忽略。容器启动时只会执行配置中设置的命令,并使用配置中设置的入参作为
命令的入参。
下表涵盖了各类设置场景:
| Image Entrypoint | Image Cmd | Container command | Container args | Command run |
|--------------------|------------------|---------------------|--------------------|------------------|
| `[/ep-1]` | `[foo bar]` | &lt;not set&gt; | &lt;not set&gt; | `[ep-1 foo bar]` |
| `[/ep-1]` | `[foo bar]` | `[/ep-2]` | &lt;not set&gt; | `[ep-2]` |
| `[/ep-1]` | `[foo bar]` | &lt;not set&gt; | `[zoo boo]` | `[ep-1 zoo boo]` |
| `[/ep-1]` | `[foo bar]` | `[/ep-2]` | `[zoo boo]` | `[ep-2 zoo boo]` |
{% endcapture %}
{% capture whatsnext %}
* 获取更多资讯可参考 [containers and commands](/docs/user-guide/containers/).
* 获取更多资讯可参考 [configuring pods and containers](/docs/tasks/).
* 获取更多资讯可参考 [running commands in a container](/docs/tasks/debug-application-cluster/get-shell-running-container/).
* 参考 [Container](/docs/api-reference/{{page.version}}/#container-v1-core).
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,72 @@
---
title: 为容器设置环境变量
---
{% capture overview %}
本页将展示如何为kubernetes Pod下的容器设置环境变量。
{% endcapture %}
{% capture prerequisites %}
{% include task-tutorial-prereqs.md %}
{% endcapture %}
{% capture steps %}
## 为容器设置一个环境变量
创建Pod时,可以为其下的容器设置环境变量。通过配置文件的`env`或者`envFrom` 字段来设置环境变量。
本示例中,将创建一个只包含单个容器的Pod。Pod的配置文件中设置环境变量的名称为`DEMO_GREETING`
其值为`"Hello from the environment"`。下面是Pod的配置文件内容:
{% include code.html language="yaml" file="envars.yaml" ghlink="/docs/tasks/inject-data-application/envars.yaml" %}
1. 基于YAML文件创建一个Pod:
kubectl create -f https://k8s.io/docs/tasks/inject-data-application/envars.yaml
1. 获取一下当前正在运行的Pods信息:
kubectl get pods -l purpose=demonstrate-envars
查询结果应为:
NAME READY STATUS RESTARTS AGE
envar-demo 1/1 Running 0 9s
1. 进入该Pod下的容器并打开一个命令终端:
kubectl exec -it envar-demo -- /bin/bash
1. 在命令终端中通过执行`printenv`打印出环境变量。
root@envar-demo:/# printenv
打印结果应为:
NODE_VERSION=4.4.2
EXAMPLE_SERVICE_PORT_8080_TCP_ADDR=10.3.245.237
HOSTNAME=envar-demo
...
DEMO_GREETING=Hello from the environment
1. 通过键入`exit`退出命令终端。
{% endcapture %}
{% capture whatsnext %}
* 有关环境变量的更多信息,请参阅[这里](/docs/tasks/configure-pod-container/environment-variable-expose-pod-information/)。
* 有关如何通过环境变量来使用Secret,请参阅[这里](/docs/user-guide/secrets/#using-secrets-as-environment-variables)。
* 关于[EnvVarSource](/docs/api-reference/{{page.version}}/#envvarsource-v1-core)资源的信息。
{% endcapture %}
{% include templates/task.md %}
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Pod
metadata:
name: envar-demo
labels:
purpose: demonstrate-envars
spec:
containers:
- name: envar-demo-container
image: gcr.io/google-samples/node-hello:1.0
env:
- name: DEMO_GREETING
value: "Hello from the environment"
@@ -0,0 +1,225 @@
---
approvers:
- janetkuo
title: 基于Replication Controller执行滚动升级
---
* TOC
{:toc}
## 概述
**注**: 创建副本应用的首选方法是使用[Deployment](/docs/api-reference/{{page.version}}/#deployment-v1beta1-apps)Deployment使用[ReplicaSet](/docs/api-reference/{{page.version}}/#replicaset-v1beta1-extensions)来进行副本控制。
更多信息, 查看[使用Deployment运行一个无状态应用](/docs/tasks/run-application/run-stateless-application-deployment/)。
为了在更新服务的同时不中断业务, `kubectl` 支持['滚动更新'](/docs/user-guide/kubectl/v1.6/#rolling-update),它一次更新一个pod,而不是同时停止整个服务。 有关更多信息,请参阅 [滚动更新设计文档](https://git.k8s.io/community/contributors/design-proposals/simple-rolling-update.md) 和 [滚动更新示例](/docs/tasks/run-application/rolling-update-replication-controller/)。
请注意, `kubectl rolling-update` 仅支持Replication Controllers。 但是,如果使用Replication Controllers部署应用,请考虑将其切换到[Deployments](/docs/concepts/workloads/controllers/deployment/). Deployment是一种被推荐使用的更高级别的控制器,它可以对应用进行声明性的自动滚动更新。 如果您仍然希望保留您的Replication Controllers并使用 `kubectl rolling-update`进行滚动更新, 请继续往下阅读:
滚动更新可以对replication controller所管理的Pod的配置进行变更,变更可以通过一个新的配置文件来进行,或者,如果只更新镜像,则可以直接指定新的容器镜像。
滚动更新的工作流程:
1. 通过新的配置创建一个replication controller
2. 在新的控制器上增加副本数,在旧的上面减少副本数,直到副本数达到期望值
3. 删除之前的replication controller
使用`kubectl rolling-update`命令来进行滚动更新:
$ kubectl rolling-update NAME \
([NEW_NAME] --image=IMAGE | -f FILE)
## 通过配置文件更新
通过配置文件来进行滚动更新,需要在`kubectl rolling-update`命令后面带上新的配置文件:
$ kubectl rolling-update NAME -f FILE
这个配置文件必须满足以下条件:
* 指定不同的`metadata.name`
* 至少要修改`spec.selector`中的一个标签值
* `metadata.namespace`字段必须相同
Replication Controllers的配置文件详细介绍见[创建Replication Controllers](/docs/tutorials/stateless-application/run-stateless-ap-replication-controller/).
### 示例
// 通过新的配置文件frontend-v2.json来更新frontend-v1的pods
$ kubectl rolling-update frontend-v1 -f frontend-v2.json
// 将frontend-v2.json数据传到标准输入来更新frontend-v1的pods
$ cat frontend-v2.json | kubectl rolling-update frontend-v1 -f -
## 更新容器镜像
仅更新容器镜像的话,可通过如下命令,该命令可以指定一个新的控制器名称(可选),通过`--image`参数来指定新的镜像名称和标签。
$ kubectl rolling-update NAME [NEW_NAME] --image=IMAGE:TAG
`--image`参数仅支持单容器pod,多容器pod使用`--image`参数会返回错误。
如果没有指定 `NEW_NAME` ,新的replication controller创建后会使用一个临时名称,当更新完成,旧的controller被删除后,新的controller名称会被更新成旧的controller名称。
如果`IMAGE:TAG` 和当前值相同,更新就会失败。 因此,我们建议使用版本号来作为标签,而不是使用 `:latest`。从一个 `image:latest`镜像升级到一个新的 `image:latest` 镜像将会失败,即使这两个镜像不是相同的。
所以,我们不建议使用 `:latest` 来作为标签,详细信息见[最佳配置实践](/docs/concepts/configuration/overview/#container-images) 。
### 示例
// 更新frontend-v1的pod到frontend-v2
$ kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2
// 更新frontend的pods,不更改replication controller的名称
$ kubectl rolling-update frontend --image=image:v2
## 必选和可选字段
必选字段:
* `NAME`: 需要进行滚动更新的replication controller名称
下面两个字段选其一:
* `-f FILE`: 新的replication controller的配置文件,JSON或者YAML格式均可。配置文件必须指定一个新的顶层`id`值,且至少包含一个现有`spec.selector`中的键值对。
详细信息见[通过Replication Controller运行无状态应用](/docs/tutorials/stateless-application/run-stateless-ap-replication-controller/#replication-controller-configuration-file)。
<br>
<br>
或者:
<br>
<br>
* `--image IMAGE:TAG`: 更新后的镜像的名称和标签。必须和当前的image:tag不同。
可选字段包括:
* `NEW_NAME`: 只和 `--image` 一起使用,不和 `-f FILE` 一起使用。标识新的replication controller的名称。
* `--poll-interval DURATION`: 在更新后轮询控制器状态的间隔时间。有效单位有 `ns` (纳秒),`us``µs`(微秒),`ms`(毫秒),`s`(秒),`m`(分钟)或 `h`(小时)。 单位可以自由组合(例如 `1m30s`)。 默认值为 `3s`
* `--timeout DURATION`: 退出更新之前,等待控制器更新一个pod的最大时间。默认是`5m0s`。有效单位如`--poll-interval`所述。
* `--update-period DURATION`: 更新两个pod之间等待的时间,默认值是`1m0s`。有效单位如`--poll-interval`所述。
有关`kubectl rolling-update`命令的更多信息见[`kubectl`参考](/docs/user-guide/kubectl/v1.6/#rolling-update).
## 实践
现在你运行了一个1.7.9版本的nginx应用:
```yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: my-nginx
spec:
replicas: 5
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
```
要更新到1.9.1版本,你可以使用[`kubectl rolling-update --image`](https://git.k8s.io/community/contributors/design-proposals/simple-rolling-update.md)来指定一个新的镜像:
```shell
$ kubectl rolling-update my-nginx --image=nginx:1.9.1
Created my-nginx-ccba8fbd8cc8160970f63f9a2696fc46
```
在终端上打开另一个窗口 ,你可以看到`kubectl` 给每个pod都增加了一个值为配置文件哈希值的 `deployment` 标签,用来区分新旧pod
```shell
$ kubectl get pods -l app=nginx -L deployment
NAME READY STATUS RESTARTS AGE DEPLOYMENT
my-nginx-ccba8fbd8cc8160970f63f9a2696fc46-k156z 1/1 Running 0 1m ccba8fbd8cc8160970f63f9a2696fc46
my-nginx-ccba8fbd8cc8160970f63f9a2696fc46-v95yh 1/1 Running 0 35s ccba8fbd8cc8160970f63f9a2696fc46
my-nginx-divi2 1/1 Running 0 2h 2d1d7a8f682934a254002b56404b813e
my-nginx-o0ef1 1/1 Running 0 2h 2d1d7a8f682934a254002b56404b813e
my-nginx-q6all 1/1 Running 0 8m 2d1d7a8f682934a254002b56404b813e
```
使用`kubectl rolling-update`可以实时看到更新的进度:
```
Scaling up my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 from 0 to 3, scaling down my-nginx from 3 to 0 (keep 3 pods available, don't exceed 4 pods)
Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 1
Scaling my-nginx down to 2
Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 2
Scaling my-nginx down to 1
Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 up to 3
Scaling my-nginx down to 0
Update succeeded. Deleting old controller: my-nginx
Renaming my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 to my-nginx
replicationcontroller "my-nginx" rolling updated
```
如果遇到问题,你可以中途停止滚动更新,并且使用 `--rollback` 来回滚到以前的版本:
```shell
$ kubectl rolling-update my-nginx --rollback
Setting "my-nginx" replicas to 1
Continuing update with existing controller my-nginx.
Scaling up nginx from 1 to 1, scaling down my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 from 1 to 0 (keep 1 pods available, don't exceed 2 pods)
Scaling my-nginx-ccba8fbd8cc8160970f63f9a2696fc46 down to 0
Update succeeded. Deleting my-nginx-ccba8fbd8cc8160970f63f9a2696fc46
replicationcontroller "my-nginx" rolling updated
```
这个例子说明容器的不变性是个巨大的优点。
如果你不仅仅是需要更新镜像,(例如,更新命令参数,环境变量等),你可以创建一个新的replication controller配置文件,包含一个新的名称和不同的标签值,例如:
```yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: my-nginx-v4
spec:
replicas: 5
selector:
app: nginx
deployment: v4
template:
metadata:
labels:
app: nginx
deployment: v4
spec:
containers:
- name: nginx
image: nginx:1.9.2
args: ["nginx", "-T"]
ports:
- containerPort: 80
```
然后使用它来进行更新:
```shell
$ kubectl rolling-update my-nginx -f ./nginx-rc.yaml
Created my-nginx-v4
Scaling up my-nginx-v4 from 0 to 5, scaling down my-nginx from 4 to 0 (keep 4 pods available, don't exceed 5 pods)
Scaling my-nginx-v4 up to 1
Scaling my-nginx down to 3
Scaling my-nginx-v4 up to 2
Scaling my-nginx down to 2
Scaling my-nginx-v4 up to 3
Scaling my-nginx down to 1
Scaling my-nginx-v4 up to 4
Scaling my-nginx down to 0
Scaling my-nginx-v4 up to 5
Update succeeded. Deleting old controller: my-nginx
replicationcontroller "my-nginx-v4" rolling updated
```
## 故障分析
如果更新过程中,达到超时时长`timeout`后还没更新完成,则更新会失败。这时,一些pod会属于新的replication controller,一些会属于旧的。
如果更新失败,可以尝试使用同样的命令来继续更新过程。
在尝试更新之前如果需要回滚到之前的状态,可在之前的命令后面添加`--rollback=true`参数,这将回退所有的更改。
@@ -0,0 +1,226 @@
---
title: 运行一个单实例有状态应用
---
{% capture overview %}
本文介绍在Kubernetes中使用PersistentVolume和Deployment如何运行一个单实例有状态应用. 该应用是MySQL.
{% endcapture %}
{% capture objectives %}
* 在环境中通过磁盘创建一个PersistentVolume.
* 创建一个MySQL Deployment.
* 在集群内以一个已知的DNS名将MySQL暴露给其他pods.
{% endcapture %}
{% capture prerequisites %}
* {% include task-tutorial-prereqs.md %}
* 为了数据持久性我们将在环境上通过磁盘创建一个持久卷. 环境支持的类型见这里[here](/docs/user-guide/persistent-volumes/#types-of-persistent-volumes). 本篇文档将介绍 `GCEPersistentDisk` . `GCEPersistentDisk`卷只能工作在Google Compute Engine平台上.
{% endcapture %}
{% capture lessoncontent %}
## 在环境中设置一个磁盘
你可以为有状态的应用使用任何类型的持久卷. 有关支持环境的磁盘列表,请参考持久卷类型[Types of Persistent Volumes](/docs/user-guide/persistent-volumes/#types-of-persistent-volumes). 对于Google Compute Engine, 请运行:
```
gcloud compute disks create --size=20GB mysql-disk
```
接下来创建一个指向刚创建的 `mysql-disk`磁盘的PersistentVolume. 下面是一个PersistentVolume的配置文件,它指向上面创建的Compute Engine磁盘:
{% include code.html language="yaml" file="gce-volume.yaml" ghlink="/docs/tasks/run-application/gce-volume.yaml" %}
注意`pdName: mysql-disk` 这行与Compute Engine环境中的磁盘名称相匹配. 有关为其
他环境编写PersistentVolume配置文件的详细信息,请参见持久卷[Persistent Volumes](/docs/concepts/storage/persistent-volumes/).
创建持久卷:
```
kubectl create -f https://k8s.io/docs/tasks/run-application/gce-volume.yaml
```
## 部署MySQL
通过创建Kubernetes Deployment并使用PersistentVolumeClaim将其连接到现已存在的PersistentVolume上来运行一个有状态的应用. 例如, 下面这个YAML文件描述了一个运行MySQL
并引用PersistentVolumeClaim的Deployment. 该文件定义了一个volume其挂载目录为/var/lib/mysql, 然后创建一个内存为20G的卷的PersistentVolumeClaim. 此申领可以通过任
何符合需求的卷来满足, 在本例中满足上面创建的卷.
注意: 在配置的yaml文件中定义密码的做法是不安全的. 具体安全解决方案请参考
[Kubernetes Secrets](/docs/concepts/configuration/secret/).
{% include code.html language="yaml" file="mysql-deployment.yaml" ghlink="/docs/tasks/run-application/mysql-deployment.yaml" %}
1. 部署YAML文件中定义的内容:
kubectl create -f https://k8s.io/docs/tasks/run-application/mysql-deployment.yaml
1. 展示Deployment相关信息:
kubectl describe deployment mysql
Name: mysql
Namespace: default
CreationTimestamp: Tue, 01 Nov 2016 11:18:45 -0700
Labels: app=mysql
Annotations: deployment.kubernetes.io/revision=1
Selector: app=mysql
Replicas: 1 desired | 1 updated | 1 total | 0 available | 1 unavailable
StrategyType: Recreate
MinReadySeconds: 0
Pod Template:
Labels: app=mysql
Containers:
mysql:
Image: mysql:5.6
Port: 3306/TCP
Environment:
MYSQL_ROOT_PASSWORD: password
Mounts:
/var/lib/mysql from mysql-persistent-storage (rw)
Volumes:
mysql-persistent-storage:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: mysql-pv-claim
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: mysql-63082529 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set mysql-63082529 to 1
1. 列举出Deployment创建的pods:
kubectl get pods -l app=mysql
NAME READY STATUS RESTARTS AGE
mysql-63082529-2z3ki 1/1 Running 0 3m
1. 查看持久卷:
kubectl describe pv mysql-pv
Name: mysql-pv
Labels: <none>
Status: Bound
Claim: default/mysql-pv-claim
Reclaim Policy: Retain
Access Modes: RWO
Capacity: 20Gi
Message:
Source:
Type: GCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)
PDName: mysql-disk
FSType: ext4
Partition: 0
ReadOnly: false
No events.
1. 查看PersistentVolumeClaim:
kubectl describe pvc mysql-pv-claim
Name: mysql-pv-claim
Namespace: default
Status: Bound
Volume: mysql-pv
Labels: <none>
Capacity: 20Gi
Access Modes: RWO
No events.
## 访问MySQL实例
前面YAML文件中创建了一个允许集群内其他pods访问数据库的服务. 该服务中选项
`clusterIP: None` 让服务DNS名称直接解析为Pod的IP地址. 当在一个服务下只有一个pod
并且不打算增加pods的数量这是最好的.
运行MySQL客户端以连接到服务器:
```
kubectl run -it --rm --image=mysql:5.6 mysql-client -- mysql -h <pod-ip> -p <password>
```
此命令在集群内创建一个新的Pod并运行MySQL客户端,并通过服务将其连接到服务器.如果连接成功,你就知道有状态的MySQL database正处于运行状态.
```
Waiting for pod default/mysql-client-274442439-zyp6i to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
mysql>
```
## 更新
Deployment中镜像或其他部分同往常一样可以通过 `kubectl apply` 命令更新. 以下是
特定于有状态应用的一些注意事项:
* 不要弹性伸缩. 弹性伸缩仅适用于单实例应用. 下层的PersistentVolume仅只能挂载一个pod. 对于集群级有状态应用, 请参考StatefulSet文档
[StatefulSet documentation](/docs/concepts/workloads/controllers/statefulset/).
* 在Deployment的YAML文件中使用 `strategy:` `type: Recreate` . 该选项指示Kubernetes不使用滚动升级. 滚动升级将无法工作, 由于一次不能运行多个pod. 在更新配置文件
创建一个新的pod前 `Recreate`策略将先停止第一个pod.
## 删除deployment
通过名称删除部署的对象:
```
kubectl delete deployment,svc mysql
kubectl delete pvc mysql-pv-claim
kubectl delete pv mysql-pv
```
如果使用Compute Engine磁盘,也可以使用如下命令:
```
gcloud compute disks delete mysql-disk
```
{% endcapture %}
{% capture whatsnext %}
* 了解更多Deployment对象请参考 [Deployment objects](/docs/concepts/workloads/controllers/deployment/).
* 了解更多Deployment应用请参考 [Deploying applications](/docs/user-guide/deploying-applications/)
* kubectl run文档请参考[kubectl run documentation](/docs/user-guide/kubectl/v1.6/#run)
* 卷和持久卷请参考[Volumes](/docs/concepts/storage/volumes/) and [Persistent Volumes](/docs/concepts/storage/persistent-volumes/)
{% endcapture %}
{% include templates/tutorial.md %}
@@ -0,0 +1,89 @@
---
approvers:
- bprashanth
- enisoc
- erictune
- foxish
- janetkuo
- kow3ns
- smarterclayton
title: 弹缩StatefulSet
---
{% capture overview %}
本文介绍如何弹缩StatefulSet.
{% endcapture %}
{% capture prerequisites %}
* StatefulSets仅适用于Kubernetes1.5及以上版本.
* **不是所有Stateful应用都适合弹缩.** 在弹缩前您的应用前. 您必须充分了解您的应用, 不适当的弹缩StatefulSet或许会造成应用自身功能的不稳定.
* 仅当您确定该Stateful应用的集群是完全健康才可执行弹缩操作.
{% endcapture %}
{% capture steps %}
## 使用 `kubectl` 弹缩StatefulSets
弹缩请确认 `kubectl` 已经升级到Kubernetes1.5及以上版本. 如果不确定, 执行 `kubectl version` 命令并检查使用的 `Client Version`.
### `kubectl 弹缩`
首先, 找到您想要弹缩的StatefulSet. 记住, 您需先清楚是否能弹缩该应用.
```shell
kubectl get statefulsets <stateful-set-name>
```
改变StatefulSet副本数量:
```shell
kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
```
### 可使用其他命令: `kubectl apply` / `kubectl edit` / `kubectl patch`
另外, 您可以 [in-place updates](/docs/concepts/cluster-administration/manage-deployment/#in-place-updates-of-resources) StatefulSets.
如果您的StatefulSet开始由 `kubectl apply``kubectl create --save-config` 创建,更新StatefulSet manifests中的 `.spec.replicas`, 然后执行命令 `kubectl apply`:
```shell
kubectl apply -f <stateful-set-file-updated>
```
除此之外, 可以通过命令 `kubectl edit` 编辑该字段:
```shell
kubectl edit statefulsets <stateful-set-name>
```
或使用 `kubectl patch`:
```shell
kubectl patch statefulsets <stateful-set-name> -p '{"spec":{"replicas":<new-replicas>}}'
```
## 排查故障
### 缩容工作不正常
当Stateful管理下的任何一个Pod不健康时您不能缩容该StatefulSet. 仅当Stateful下的所有Pods都处于运行和ready状态后才可缩容.
当一个StatefulSet的size > 1, 如果有一个Pod不健康, 没有办法让Kubernetes知道是否是由于永久性故障还是瞬态(升级/维护/节点重启)导致. 如果该Pod不健康是由于永久性
故障导致, 则在不纠正该故障的情况下进行缩容可能会导致一种状态, 即StatefulSet下的Pod数量低于应正常运行的副本数. 这也许会导致StatefulSet不可用.
如果由于瞬态故障而导致Pod不健康,并且Pod可能再次可用,那么瞬态错误可能会干扰您对
StatefulSet的扩容/缩容操作. 一些分布式数据库在节点加入和同时离开时存在问题. 在
这些情况下,最好是在应用级别进行弹缩操作, 并且只有在您确保Stateful应用的集群是完全健康时才执行弹缩.
{% endcapture %}
{% capture whatsnext %}
了解更多 [deleting a StatefulSet](/docs/tasks/manage-stateful-set/deleting-a-statefulset/).
{% endcapture %}
{% include templates/task.md %}