admin-task-docs-pr-2017-09-08
This commit is contained in:
parent
15b57839b8
commit
dce409f734
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
assignees:
|
||||
- erictune
|
||||
- lavalamp
|
||||
- deads2k
|
||||
- liggitt
|
||||
title: Webhook Mode
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
{% capture overview %}
|
||||
WebHook 是一个 HTTP 回调:当某些事情发生时的一个 HTTP POST 请求;通过 HTTP POST 发送的一个简单事件通知。一个继续 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL 。
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
|
||||
|
||||
{% 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 文件必须有上下文. 需要提供一个给 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 对象对于 [versioning compatibility rules](/docs/api/) 和其他 Kuberntes 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).
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/concept.md %}
|
|
@ -0,0 +1,221 @@
|
|||
---
|
||||
assignees:
|
||||
- jbeda
|
||||
|
||||
title: Webhook 模式
|
||||
---
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## 概述
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
启动引导令牌是一种简单的 bearer token ,这种令牌是在新建集群或者在现有集群中添加新加新节点时使用的。
|
||||
它被设计成能支持 [`kubeadm`](/docs/admin/kubeadm/),但是也可以被用在其他上下文中以便用户在
|
||||
不使用 `kubeadm` 的情况下启动cluster。它也被设计成可以通过 RBAC 策略,结合[Kubelet TLS
|
||||
Bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 系统进行工作。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
启动引导令牌被定义成一个特定类型的secrets (`bootstrap.kubernetes.io/token`),并存在于
|
||||
`kube-system` 命名空间中。然后这些 secrets 会被 API 服务器上的启动引导的认证器读取。
|
||||
过期的令牌与令牌清除控制器会被控制管理器一起清除。令牌也会被用于创建签名,签名用于
|
||||
启动引导签名控制器在 "discovery" 进程中特定的 configmap 。
|
||||
|
||||
|
||||
|
||||
|
||||
目前,启动引导令牌处于 **alpha** 阶段,但是预期也不会有大的突破性的变化。
|
||||
|
||||
|
||||
## 令牌格式
|
||||
|
||||
|
||||
|
||||
启动引导令牌使用 `abcdef.0123456789abcdef` 的形式。
|
||||
更加规范地说,它们必须符合正则表达式 `[a-z0-9]{6}\.[a-z0-9]{16}`。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
令牌的第一部分是 "Token ID" ,它是公共信息。它被用于引用一个 token 用于认证而不会泄漏保密部分。
|
||||
第二部分是 "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 是包含在数据字典中的。
|
||||
|
||||
The `usage-bootstrap-*` members indicate what this secret is intended to be used
|
||||
for. A value must be set to `true` to be enabled.
|
||||
`usage-bootstrap-*` 成员代表了这个 secret 被用于什么。启用时,值必须设置为 `true`。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
`usage-bootstrap-authentication` 表示令牌可以用于 API 服务器的认证。认证器会以
|
||||
`system:bootstrap:<Token ID>` 认证。它被包含在 `system:bootstrappers` 组中。
|
||||
命名和组是故意受限制的,以阻碍用户在启动引导后再使用这些令牌。
|
||||
|
||||
|
||||
|
||||
`usage-bootstrap-signing` 表示令牌应该被用于 `cluster-info` ConfigMap 的签名,就像下面描述的那样。
|
||||
|
||||
|
||||
|
||||
|
||||
`expiration` 数据成员列举了令牌在失效后的时间。这是通过 RFC3339 进行编码的 UTC 时间。
|
||||
令牌清理控制器会删除过期的令牌。
|
||||
|
||||
|
||||
## 使用 `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 是 `kube-public` 命名空间中的 `cluster-info`。
|
||||
典型的工作流中,客户端读取这个 ConfigMap 而不管认证和 TLS 报错。
|
||||
它会通过 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,160 @@
|
|||
---
|
||||
assignees:
|
||||
- davidopp
|
||||
- lavalamp
|
||||
|
||||
title:搭建大型集群
|
||||
---
|
||||
|
||||
|
||||
## 支持
|
||||
|
||||
|
||||
在 {{page.version}} 版本中,Kubernetes 支持集群节点数可达1000个。更具体地说,我们配置能够支持*所有*如下条件:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
* 不超过2000个
|
||||
* 不超过总共6000个 pods
|
||||
* 不超过总共12000个节点容器
|
||||
* 单节点不超过100个 pods
|
||||
|
||||
<br>
|
||||
|
||||
* TOC
|
||||
{:toc}
|
||||
|
||||
|
||||
## 安装
|
||||
|
||||
|
||||
集群是一组运行着 Kubernetes 代理的节点(物理或者虚机),被 "主服务器" (集群层面的控制台)所管理。
|
||||
|
||||
|
||||
通常来说,集群中的节点数是通过平台相关的 `config-default.sh` 文件(例子参考[GCE's `config-default.sh`](http://releases.k8s.io/{{page.githubbranch}}/cluster/gce/config-default.sh)中的 `NUM_NODES` 值控制的。
|
||||
|
||||
|
||||
然而,单单把这个值更改到很大会导致脚本在许多云服务商平台上运行失败。例如 GCE 部署,会有配额问题导致集群启动失败。
|
||||
|
||||
|
||||
当需要建立大规模 Kubernetes 集群时,必须考虑下列问题:
|
||||
|
||||
|
||||
### 配额问题
|
||||
|
||||
|
||||
为了避免云服务商的配额导致问题,当创建一个许多节点的集群是,要考虑:
|
||||
|
||||
|
||||
* 增加这些资源的配额,比如 CPU ,IP 地址等等。
|
||||
* 在 [GCE 中,举个例子](https://cloud.google.com/compute/docs/resource-quotas) 你会需要增加:
|
||||
* CPU
|
||||
* 虚拟机实例
|
||||
* 总共保留的永久磁盘
|
||||
* 在使用的 IP 地址
|
||||
* 防火墙规则
|
||||
* 转发规则
|
||||
* 路由
|
||||
* 目标池
|
||||
* 调整好安装脚本,让它能够在创建虚拟机节点的批处理间能有等待时间,因为很多云服务商对于虚拟机有创建频率的限制。
|
||||
|
||||
|
||||
### Etcd 存储
|
||||
|
||||
|
||||
为了提高大规模集群的性能,我们将 events 存储在一个独立的特定的etcd实例中。
|
||||
|
||||
|
||||
当创建一个集群时,现有的 salt 脚本会:
|
||||
|
||||
|
||||
|
||||
* 启动并配置额外的 etcd 实例
|
||||
* 配置 api-server 使用它来储存 events
|
||||
|
||||
|
||||
### 主服务器和主服务器组件的规格
|
||||
|
||||
|
||||
在 GCE/GKE 和 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
|
||||
|
||||
|
||||
注意这些主服务器节点规格只能在集群启动是设置,如果后续对于集群扩容或者缩容(比如,手工或者使用集群自动扩展器删除或增加节点),规格是不会调整的。
|
||||
|
||||
|
||||
### Addon (插件)资源
|
||||
|
||||
|
||||
为了防止[集群 addons](https://releases.k8s.io/{{page.githubbranch}}/cluster/addons) 内存泄漏或者其他资源问题导致消耗完节点的所有资源,Kubernetes 对 addon 容器设定了资源限制,以限制他们使用 CPU 和内存资源。(参见 PR [#10653](http://pr.k8s.io/10653/files) 和 [#10778](http://pr.k8s.io/10778/files))
|
||||
|
||||
|
||||
举例:
|
||||
|
||||
```yaml
|
||||
containers:
|
||||
- name: fluentd-cloud-logging
|
||||
image: gcr.io/google_containers/fluentd-gcp:1.16
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 200Mi
|
||||
```
|
||||
|
||||
|
||||
除了 Heapster,这些限制是固定的,并且是基于我们对于 addon 运行在4节点集群的采样数据(见 [#10335](http://issue.k8s.io/10335#issuecomment-117861225))。运行在大规模集群上时,addon 会消耗更多的资源(见 [#5880](http://issue.k8s.io/5880#issuecomment-113984085))。所以,如果大规模集群没有调整这些参数时,addon 可能会被持续杀死,因为他们总是达到限制。
|
||||
|
||||
|
||||
为了避免集群的 addon 资源问题出现,当创建一个许多节点的集群是,考虑如下问题:
|
||||
|
||||
|
||||
* 为以下每个 addon 调整内存和 CPU 限制,使用时,随着你的集群扩容 (每个 addon 有一个 replica 来处理整个集群,所以 CPU/内存 使用量会随着集群的 规模/负载 按比例增加):
|
||||
* [InfluxDB and Grafana](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/cluster-monitoring/influxdb/influxdb-grafana-controller.yaml)
|
||||
* [kubedns, dnsmasq, and sidecar](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/kubedns-controller.yaml.in)
|
||||
* [Kibana](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/kibana-controller.yaml)
|
||||
* 为以下这些 addon 调整 replicas 数量, 使用时, 随着集群规模数量一起调整 (每个 addon 会有多个 replicas, 所以增加 replicas 应该能帮助处理增加的负载,但是,由于每个 replica 的负载也稍稍增加, 同时需要考虑增加 CPU/内存 限制):
|
||||
* [elasticsearch](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/es-controller.yaml)
|
||||
* 为以下这些 addon 稍稍增加 memory 和 CPU 使用限制, 使用时, 随着集群规模数量一起调整 (每个节点有一个 replica,但是 CPU/内存 使用量与集群的 负载/规模 会稍稍增加):
|
||||
* [FluentD with ElasticSearch Plugin](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-elasticsearch/fluentd-es-ds.yaml)
|
||||
* [FluentD with GCP Plugin](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/fluentd-gcp/fluentd-gcp-ds.yaml)
|
||||
|
||||
|
||||
Heapseter 的资源限制是基于集群的初始规模动态配置的 (见 [#16185](http://issue.k8s.io/16185) 和 [#22940](http://issue.k8s.io/22940))。
|
||||
如果你发现 Hepaster 的资源不够,你应该调整 heapster 对于内存的请求公式 (详见这些 PRs)。
|
||||
|
||||
|
||||
对于如何检查 addon 容器是否达到了资源使用限制,参考 [Troubleshooting section of Compute Resources](/docs/concepts/configuration/manage-compute-resources-container/#troubleshooting)。
|
||||
|
||||
|
||||
在[未来](http://issue.k8s.io/13048),我们预期会基于集群规模来设置所有集群 addon 的资源限制,并且会在你的集群扩容或缩容时进行动态调整。
|
||||
我们欢迎实现这些功能的 PR 。
|
||||
|
||||
|
||||
### 允许少数节点在启动时失败
|
||||
|
||||
|
||||
由于各种原因 (详细信息见 [#18969](https://github.com/kubernetes/kubernetes/issues/18969)),运行 `kube-up.sh` 建立非常大
|
||||
的 `NUM_NODES` 集群会由于个别的节点启动失败而失败。目前你有两个选择:重启集群 (再次运行 `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,111 @@
|
|||
---
|
||||
assignees:
|
||||
- bprashanth
|
||||
- davidopp
|
||||
- lavalamp
|
||||
- liggitt
|
||||
title: Managing Service Accounts
|
||||
---
|
||||
|
||||
*本文是 service accounts 管理员手册。需要[Service Accounts 用户手册](/docs/user-guide/service-accounts)的知识背景。*
|
||||
|
||||
*对于 authorization 和 user accounts 支持已经在计划中,但是还未完成。为了更好地解释 service
|
||||
accounts,有时会提到一些未完成的功能特性。*
|
||||
|
||||
|
||||
## 用户账号 vs 服务账号
|
||||
|
||||
|
||||
Kubernetes 将 user account 和 service account 的概念区分开,主要基于以下几个原因:
|
||||
|
||||
- user account 是给人使用的。servcice account是给 pod 中运行的进程使用的。
|
||||
- user account 为全局设计。命名必须在一个集群的所有命名空间中唯一,未来的用户资源不会被设计到命名空间中。
|
||||
service account 是按命名空间的。
|
||||
- 典型场景中,一个集群的 user account 是来自于企业数据库的,在数据库中新建用户一般需要特殊权限,并且账号是与复杂都业务流程关联的。
|
||||
service account的创建往往更轻量,允许集群用户为特定的任务创建service account(即,权限最小化原则)。
|
||||
- 对于人和服务的账号,审计要求会是不同的。
|
||||
- 对于复杂系统而言,配置包可以包含该系统各类组件的 service account 定义,
|
||||
因为 service account 可以有临时的创建需求和自己的命名空间,这类配置是便携式的。
|
||||
|
||||
|
||||
## 服务账号自动化
|
||||
|
||||
|
||||
service accounts 的自动化由三个独立的组建共同配合实现:
|
||||
|
||||
- A Service account admission controller (service account 准入控制器)
|
||||
- A Token controller (令牌控制器)
|
||||
- A Service account controller (service account 控制器)
|
||||
|
||||
|
||||
### 服务账号准入控制器
|
||||
|
||||
|
||||
对于 pods 的操作是通过一个叫做 [准入控制器](/docs/admin/admission-controllers) 的插件实现的。它是 apiserver 的一部分。
|
||||
当准入控制器被创建或更新时,他会对 pod 同步进行操作。当这个插件时活动状态时(大部分版本默认是活动状态),并在 pod 被创建或者更改时,
|
||||
它会做如下操作:
|
||||
|
||||
1. 如果 pod 没有配置 `ServiceAccount`,它会将 `ServiceAccount` 设置为 `default`。
|
||||
2. 它会确保被 pod 关联的 `ServiceAccount` 是存在的,否则就拒绝请求。
|
||||
|
||||
4. 如果 pod 没有包含任何的 `ImagePullSecrets`,那么 `ServiceAccount` 的 `ImagePullSecrets` 就会被添加到 pod。
|
||||
5. 它会把一个 `volume` 添加给 pod, 该 pod 包含有一个用于 API 访问的 token。
|
||||
6. 它会把一个 `volumeSource` 添加到 pod 的每个 container,并挂载到 `/var/run/secrets/kubernetes.io/serviceaccount`。
|
||||
|
||||
|
||||
### 令牌控制器
|
||||
|
||||
|
||||
令牌控制器(TokenController)作为 controller-manager 的一部分运行。它异步运行。它会:
|
||||
|
||||
- 监听对于 serviceAccount 的创建动作,并创建对应的 Secret 以允许 API 访问。
|
||||
- 监听对于 serviceAccount 的删除动作,并删除所有对应的 ServiceAccountToken Secrets。
|
||||
- 监听对于 secret 的添加动作,确保相关联的 ServiceAccount 是存在的,并在根据需要为 secret 添加一个 token。
|
||||
- 监听对于 secret 的删除动作,并根据需要删除对应 ServiceAccount 的关联。
|
||||
|
||||
你必须给令牌控制器(token controller)传递一个 service account 的私钥(private key),可以通过 `--service-account-private-key-file` 参数完成。
|
||||
传递的私钥将被用来对 service account tokens 进行签名。类似的,你必须给 kube-apiserver 传递一个公钥(public key),通过 `--service-account-key-file`
|
||||
参数完成。传递的公钥会被用来验证认证过程中的令牌(token)。
|
||||
|
||||
|
||||
#### 创建额外的 API 令牌
|
||||
|
||||
|
||||
控制器的循环运行会确保对于每个 service account 都存在一个带有 API token(API 令牌)的secret。
|
||||
如需要为一个 service account 创建一个额外的 API 令牌(API token),可以创建一个 `ServiceAccountToken`
|
||||
类型的 secret,并添加与 service account 对应的 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
|
||||
```
|
||||
|
||||
|
||||
#### 删除/作废服务账号令牌
|
||||
|
||||
```shell
|
||||
kubectl delete secret mysecretname
|
||||
```
|
||||
|
||||
|
||||
### 服务账号控制器
|
||||
|
||||
|
||||
Service Account Controller 在 namespaces 内管理 ServiceAccount,需要保证名为 "default" 的
|
||||
ServiceAccount在每个命名空间中存在。
|
|
@ -0,0 +1,185 @@
|
|||
---
|
||||
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"
|
||||
---
|
||||
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
|
||||
|
||||
本文旨在说明如何使用一个卷(Volume)让一个 Pod 内的两个容器进行通信
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
{% include task-tutorial-prereqs.md %}
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture steps %}
|
||||
|
||||
|
||||
## 创建一个两个容器的 Pod
|
||||
|
||||
|
||||
|
||||
|
||||
在这个练习中,你会创建一个包含两个容器的 Pod。两个容器共享一个卷用于他们之间的通信。
|
||||
Pod 的配置文件如下:
|
||||
|
||||
{% include code.html language="yaml" file="two-container-pod.yaml" ghlink="/docs/tasks/access-application-cluster/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
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture discussion %}
|
||||
|
||||
|
||||
## 讨论
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Pod 能有多个容器的主要原因是为了支持协助主应用的辅助应用。辅助应用的典型例子是数据抽取,数据推送和代理。
|
||||
辅助应用和主应用经常需要相互通信。通常这是通过共享文件系统完成的,就如这个练习所示,或者通过回环网络接口
|
||||
localhost 完成。网络接口的例子是 web 服务器带有一个协助程序用于拉取 Git 仓库的更新。
|
||||
|
||||
|
||||
|
||||
|
||||
在本练习中的卷为 Pod 生命周期中的容器相互通信提供了一种方法。如果 Pod 被删除或者重建了,
|
||||
任何共享卷中的数据都会丢失。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% 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/v1.6/#volume-v1-core)。
|
||||
|
||||
|
||||
* 参见 [Pod](/docs/api-reference/v1.6/#pod-v1-core).
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% include templates/task.md %}
|
|
@ -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 Container 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 Container Engine 上开启防火墙端口时请
|
||||
小心。你可能无意间把其他服务也暴露给了 internet。
|
||||
|
||||
|
||||
这个问题会在 Kubernetes 后续版本中被修复。
|
||||
|
||||
|
||||
### 其他云服务商
|
||||
|
||||
|
||||
即将更新
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
---
|
||||
title: 使用 Service 把前端连接到后端
|
||||
---
|
||||
|
||||
|
||||
{% capture overview %}
|
||||
|
||||
|
||||
|
||||
|
||||
这项任务会描述如何创建一个前端和一个后端的微服务。后端微服务是一个 hello 欢迎程序。
|
||||
前端和后端的连接是通过 Kubernetes Service 对象完成的。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture objectives %}
|
||||
|
||||
|
||||
|
||||
|
||||
* 使用 Deployment 对象创建并运行一个微服务
|
||||
* 从后端将流量路由到前端
|
||||
* 使用 Service 对象把前端应用连接到后端应用
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture prerequisites %}
|
||||
|
||||
* {% include task-tutorial-prereqs.md %}
|
||||
|
||||
|
||||
* 本项任务使用[外部负载均衡服务](/docs/tasks/access-application-cluster/create-external-load-balancer/),
|
||||
所以需要对应的可支持此功能的环境。如果你的环境不能支持,你可以使用[NodePort](/docs/user-guide/services/#type-nodeport)
|
||||
的类型 Service 来代替。
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture lessoncontent %}
|
||||
|
||||
|
||||
### 使用 Deployment 创建后端
|
||||
|
||||
|
||||
|
||||
后端是一个简单的 hello 欢迎微服务应用。这是后端应用的 Deployment 配置文件:
|
||||
|
||||
{% include code.html language="yaml" file="hello.yaml" ghlink="/docs/tasks/access-application-cluster/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 对象
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
前端连接到后端的关键是 Service。Service 创建一个固定 IP 和 DNS 解析名入口,
|
||||
使得后端微服务可达。Service 使用 selector 标签来寻找目的地 Pods。
|
||||
|
||||
|
||||
首先,浏览 Service 的配置文件:
|
||||
|
||||
{% include code.html language="yaml" file="hello-service.yaml" ghlink="/docs/tasks/access-application-cluster/hello-service.yaml" %}
|
||||
|
||||
|
||||
|
||||
配置文件中,你可以看到 Service 将流量路由到包含 `app: hello` 和 `tier: backend` 标签的 Pods。
|
||||
|
||||
|
||||
创建 `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 的配置文件:
|
||||
|
||||
{% include code.html file="frontend/frontend.conf" ghlink="/docs/tasks/access-application-cluster/frontend/frontend.conf" %}
|
||||
|
||||
|
||||
|
||||
|
||||
与后端类似,前端用包含一个 Deployment 和一个 Service。Service 的配置文件包含了 `type: LoadBalancer`,
|
||||
也就是说,Service 会使用你的云服务商的默认负载均衡设备。
|
||||
|
||||
{% include code.html language="yaml" file="frontend.yaml" ghlink="/docs/tasks/access-application-cluster/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/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"}
|
||||
```
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
|
||||
{% capture whatsnext %}
|
||||
|
||||
|
||||
|
||||
* 了解更多 [Services](/docs/concepts/services-networking/service/)
|
||||
* 了解更多 [ConfigMaps](/docs/tasks/configure-pod-container/configmap/)
|
||||
|
||||
{% endcapture %}
|
||||
|
||||
{% include templates/tutorial.md %}
|
Loading…
Reference in New Issue