既然您已经了解了如何安装、交互和使用 Kubernetes 来部署和管理应用,我们将在本章重点介绍如何根据您的需求调整 Kubernetes 以及修复 Kubernetes 中的错误。为此,您需要安装 Go 并访问 GitHub 上托管的 Kubernetes 源代码。我们展示了如何编译 Kubernetes(作为一个整体),也展示了如何编译像客户端kubectl
这样的特定组件。我们还演示了如何使用 Python 与 Kubernetes API 服务器对话,并展示了如何使用自定义资源定义来扩展 Kubernetes。
您希望从源代码中打包自己的 Kubernetes 二进制文件,而不是下载官方发布的二进制文件(参见食谱 2.4 )或第三方工件。
克隆 Kubernetes Git 存储库并从源代码构建。
如果您在 Docker 主机上,您可以使用根 Makefile 的quick-release
目标,如下所示:
$ git clone https://github.com/kubernetes/kubernetes
$ cd kubernetes
$ make quick-release
这种基于 Docker 的构建需要至少 4 GB 的内存才能完成。确保您的 Docker 守护程序可以访问那么多内存。在 macOS 上,访问 Docker 获取 Mac 首选项并增加分配的内存。
二进制文件将位于输出/发布阶段目录中,完整的包将位于输出/发布阶段目录中。
或者,如果您已经正确设置了 Golang 环境,请使用根 Makefile : 的release
目标
$ git clone https://github.com/kubernetes/Kubernetes
$ cd kubernetes
$ make
二进制文件将位于 _output/bin 目录中。
- 详细的 Kubernetes 开发者指南
您希望从源代码中构建 Kubernetes 的特定组件,而不是所有组件——例如,您只希望构建客户端kubectl
。
不用make quick-release
或者简单的make
,如食谱 13.1 所示,做make kubectl
。
根 Makefile 中有构建单个组件的目标。例如要编译kubectl
、kubeadm
、hyperkube
,请执行以下操作:
$ make kubectl
$ make kubeadm
$ make hyperkube
二进制文件将位于 _output/bin 目录中。
你想用 Python 来编写使用 Kubernetes API 的脚本。
安装 Python kubernetes
模块。该模块目前正在 Kubernetes孵化器中开发。您可以从源代码或从 Python 包索引(PyPi)网站安装该模块:
$ pip install kubernetes
使用默认的kubectl
上下文可以到达一个 Kubernetes 集群,现在可以使用这个 Python 模块与 Kubernetes API 进行对话了。例如,下面的 Python 脚本列出了所有的 pod 并打印了它们的名称:
from kubernetes import client, config
config.load_kube_config()
v1 = client.CoreV1Api()
res = v1.list_pod_for_all_namespaces(watch=False)
for pod in res.items:
print(pod.metadata.name)
该脚本中的config.load_kube_config()
调用将从您的kubectl
配置文件中加载您的 Kubernetes 凭证和端点。默认情况下,它将加载当前上下文的集群端点和凭据。
Python 客户端是使用 Kubernetes 应用编程接口的 OpenAPI 规范构建的。它是最新的并且是自动生成的。所有的 API 都可以通过这个客户端获得。
每个 API 组对应一个特定的类,因此要调用属于/api/v1
API 组的 API 对象上的方法,需要实例化CoreV1Api
类。要使用部署,您需要实例化extensionsV1beta1Api
类。所有方法和对应的 API 组实例可以在自动生成的 自述文件 中找到。
您有一个自定义工作负载,而现有资源(如Deployment
、一个Job
或一个StatefulSet
)都不适合。因此,您希望用代表您的工作负载的新资源来扩展 Kubernetes API,同时继续以通常的方式使用kubectl
。
如[此处]所述,使用 CustomResourceDefinition
(CRD) 。
假设您想要定义一种自定义资源Function
。这代表了一种类似短期运行的资源,类似于 AWS Lambda 所提供的,那就是功能即服务(FaaS,或者有时被误称为“无服务器”)。
有关在 Kubernetes 上运行的生产就绪型 FaaS 解决方案,请参见配方 14.7 。
首先,在名为函数-crd.yaml 的清单文件中定义 CRD:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: function.example.com
spec:
group: example.com
version: v1
names:
kind: Function
plural: functions
scope: Namespaced
然后让 API 服务器知道您的新 CRD(注册可能需要几分钟时间):
$ kubectl create -f functions-crd.yaml
customresourcedefinition "functions.example.com" created
既然您已经定义了自定义资源Function
,并且应用编程接口服务器知道它,您可以使用名为 myfaas.yaml 的清单来实例化它,其内容如下:
apiVersion: example.com/v1
kind: Function
metadata:
name: myfaas
spec:
code: "http://src.example.com/myfaas.js"
ram: 100Mi
并像往常一样创建类Function
的myfaas
资源:
$ kubectl create -f myfaas.yaml
function "myfaas" created
$ kubectl get crd functions.example.com -o yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
creationTimestamp: 2017-08-13T10:11:50Z
name: functions.example.com
resourceVersion: "458065"
selfLink: /apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions
/functions.example.com
uid: 278016fe-81a2-11e7-b58a-080027390640
spec:
group: example.com
names:
kind: Function
listKind: FunctionList
plural: functions
singular: function
scope: Namespaced
version: v1
status:
acceptedNames:
kind: Function
listKind: FunctionList
plural: functions
singular: function
conditions:
- lastTransitionTime: null
message: no conflicts found
reason: NoConflicts
status: "True"
type: NamesAccepted
- lastTransitionTime: 2017-08-13T10:11:50Z
message: the initial names have been accepted
reason: InitialNamesAccepted
status: "True"
type: Established
$ kubectl describe functions.example.com/myfaas
Name: myfaas
Namespace: default
Labels: <none>
Annotations: <none>
API Version: example.com/v1
Kind: Function
Metadata:
Cluster Name:
Creation Timestamp: 2017-08-13T10:12:07Z
Deletion Grace Period Seconds: <nil>
Deletion Timestamp: <nil>
Resource Version: 458086
Self Link: /apis/example.com/v1/namespaces/default
/functions/myfaas
UID: 316f3e99-81a2-11e7-b58a-080027390640
Spec:
Code: http://src.example.com/myfaas.js
Ram: 100Mi
Events: <none>
要发现 CRD,只需访问 API 服务器。例如,使用kubectl proxy
,可以在本地访问 API 服务器并查询键空间(在我们的例子中为example.com/v1
):
$ curl 127.0.0.1:8001/apis/example.com/v1/ | jq .
{
"kind": "APIResourceList",
"apiVersion": "v1",
"groupVersion": "example.com/v1",
"resources": [
{
"name": "functions",
"singularName": "function",
"namespaced": true,
"kind": "Function",
"verbs": [
"delete",
"deletecollection",
"get",
"list",
"patch",
"create",
"update",
"watch"
]
}
]
}
在这里,您可以看到资源以及允许的动词。
当您想要删除您的自定义资源实例myfaas
时,只需将其删除即可:
$ kubectl delete functions.example.com/myfaas
function "myfaas" deleted
如您所见,创建 CRD 很简单。从最终用户的角度来看,CRD 提供了一个一致的 API,并且或多或少与本机资源(如 pod 或 jobs)无法区分。所有常用的命令,如kubectl get
和kubectl delete
,都如预期的那样工作。
然而,创建一个 CRD 实际上还不到完全扩展 Kubernetes 应用编程接口所需工作的一半。CRDs 本身只允许您通过 etcd 中的 API 服务器存储和检索自定义数据。您还需要编写一个自定义控制器,解释表达用户意图的自定义数据,并建立一个控制循环,将当前状态与声明的状态进行比较,并尝试协调两者。
直到 1.7 版本,现在所谓的 CRDs 被称为第三方资源(TPR)。如果你刚好有一个 TPR,强烈考虑现在就把它迁移到。
CRDs 的主要限制(以及在某些情况下您可能希望使用用户应用编程接口服务器的原因)是:
-
每个 CRD 只支持一个版本,尽管每个 API 组可能有多个版本(这意味着您不能在您的 CRD 的不同表示之间转换)。
-
CRDS 不支持在 v1.7 或更早版本中为字段分配默认值。
-
只有从 1.8 版开始,才能验证 CRD 规范中定义的字段
-
无法定义子资源,如
status
资源。
-
Stefan Schimanski 和 Michael Hausenblas 的博文“Kubernetes Deep Dive:API Server–第 3a 部分”
-
Aaron Levy,“编写自定义控制器:扩展集群的功能”,KubeCon 2017
-
Yaron Haviv 的文章“用定制资源扩展 Kubernetes 1.7”