0

Kubernetes 笔记

 2 years ago
source link: https://yanhang.me/post/2017-08-18-kubernetes-note/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Kubernetes 笔记

2017-08-18 约 2208 字 预计阅读 5 分钟

声明式的 API

声明式: 结果是什么 命令式: 做什么

声明式的操作,相对于命令式操作,对于重复操作的效果是稳定的,这对于容易出现数据丢失或重复的分布式环境来说是很重要的。另外,声明式操作更容易被用户使用,可以使系统向用户隐藏实现的细节,隐藏实现的细节的同时,也就保留了系统未来持续优化的可能性

kubernetes 里的 API 都是声明式,我们描述好自己想要的 resource object,kubernetes 就会不断尝试去保证这个 resource object 按我们期望的方式存在.

API Response

一般包含三部分

  • metadata: 元数据
    • annotations: 一些元信息.给第工具用来存储和解析原信息用的.
    • labels: act as filter
    • namespace: resource 所处的 namespace
    • name: resource 名字
    • uuid: 唯一标识
    • creationTimestamp: 创建时间
    • deletionTimestamp: 计划删除的时间(graceful deletion)
    • resourceVersion: 每个 resource 的内部版本,可以用来确定是否发生了变化.也用于做并发控制
    • generation
  • spec: 具体描述,不同 resource 的属性不同。spec 里通过声明式的方式表明了期望的目标状态
  • status: resource 的当前状态

下面以展示一下 kubernetes node api 的 metadata 作为样例:

metadata:

metadata:
  annotations:
    flannel.alpha.coreos.com/backend-data: '{"VtepMAC":"9a:98:da:a1:b9:5d"}'
    flannel.alpha.coreos.com/backend-type: vxlan
    flannel.alpha.coreos.com/kube-subnet-manager: "true"
    flannel.alpha.coreos.com/public-ip: 172.18.0.4
    scheduler.alpha.kubernetes.io/taints: '[]'
    volumes.kubernetes.io/controller-managed-attach-detach: "true"
  creationTimestamp: 2017-07-13T09:45:11Z
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    ip: 172.18.0.4
    kubeadm.alpha.kubernetes.io/role: master
    kubernetes.io/hostname: 172.18.0.4
  name: 172.18.0.4
  resourceVersion: "3785002"
  selfLink: /api/v1/nodes172.18.0.4
  uid: f6fc3022-67af-11e7-b171-0017fa013946

可以看到 flannel 用它来存储了一些自己需要的信息.

这种区分几乎适用于 REST 架构中的大多数 resource.好处:

  • 比一整个大的 body 结构清晰
  • 模块化,每个部分的更新迭代不会影响整个 body 的结构
  • 展示及处理方便

kubernetes 的错误情况下的 response 也遵循上面相同的结构.示例如下:

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "pods \"grafana\" not found",
  "reason": "NotFound",
  "details": {
    "name": "grafana",
    "kind": "pods"
  },
  "code": 404
}

其特点是同时提供了机器可读(reason)以及人类可读(message)的消息. reason是对 http status code 的一种细化.

Resource Version

上面所说 metadata 中的resourceVersion字段被 Kubernets 用来做并发控制,在更新一个 object 前,会去检查它的 resourceVersion 的值与之前存的值是否匹配,如果不匹配,则会抛出一个StatusConflict(http 409).

Version

一般来说 REST API 都会要求有一个版本的概念,这样在架构迭代以及功能升级时可以用不同的版本来区分,保证语义及结构清晰.Kubernetes 做的更多,它也会用 version 来区分功能的成熟度(alpha,beta…)

  • alpha
    • 可能包含 bug,默认关闭,不保证兼容性,适合测试使用
  • beta
    • 大方向不会变,细节上可能会有修改.如果有不兼容的改动发生,会提供升级方式
  • stable
    • 可稳定使用

API Group

API 分组,一般 API 都会分为核心的对 Resource 进行操作的 API 以及其他零碎的 API.

一般 URL 格式为: GROUP/VERSION.GROUP 的名字建议的格式为 domin name 的格式,比如: widget.mycompany.com

Runtime config

kubernets 支持非常多的参数(已经有很多人在网上吐槽了..),结合上面的版本以及分组,kube-api 有很多参数可以用来调控这些.比如禁掉一些 Group,禁掉一些 Version 的 API.一个完全可插拔的 API Server.

REGEX

详细定义好各个 resource name 的REGEX要求,比如namespace,service中不能有点(.),只能小写(DNS 兼容).

像 date,timestamp 等这种字段要保证在所有 API 中使用用一种格式

PATCH 与 PUT

一般来说 PUT 应该发送 resource 的整个描述去 replace.PATCH 只发送需要更新的部分.但一般的场景中遵循此规则的应该不多,大多是只用一个 PUT,即用于整个更新也用于部分更新.

kubernetes 做的更多,在 PATCH 操作,它支持几种不同的操作语义

  • Json Patch: Content-Type: application/json-patch+json

    • 定义了需要做的操作,示例如下:
      • {"op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ]}
  • Merge Patch: Content-Type: application/merge-patch+jso

    • objects 类的是合并,lists 类的是 replace
  • Strategic Merge Patch: Content-Type: application/strategic-merge-patch+json

    • 支持各种自定义操作的 patch

Events

时间也是系统设计里非常重要的一环.发生了上面,什么时间,谁操作的,结果是什么,不仅可以用系统内部问题的排查,也可以作为产品提供给其他用户.

Kubernetes 对一些重复性的时间做了累积,原本需要重复显示 N 次的事件现在用一个计数器来代替.这样可以减少数据存储和系统负载.

Unix 有一个非常出名的设计哲学:“一切皆文件”,其优势在于,利用管道及其他工具,无数的小工具(find,grep,awk)等可以方便地协作以完成非常复杂的任务。各个工具均支持plain text作为输入以及输出。当然一切皆文件也有一个坏处,开源软件由不同的人写就,没有文本格式的约束,不同的工具均需要一定的文本格式的要求。工具越多,格式也越杂乱,需要人为记忆的东西也越多。例如很多 service 类工具的配置文件格式的差异,不同命令输出的差异等等

kubernetes 由很多组件构成,提供 API 的服务,命令行的访问工具(kubetctl)等等。类似于docker clidocker daemonkubectl也是从kube-api-server来读取信息展示给用户。我觉得 kubetcl 做的比较好的一点就是,它将数据的内部结构和展示二者分开了。示例如下:

获取节点的简单信息,不加任何参数:

[root@172 alauda]# kubectl get no
NAME         STATUS         AGE
172.18.0.4   Ready,master   38d
[root@172 alauda]#

指定输出 yaml 格式的详情

...
spec:
  externalID: 172.18.0.4
  podCIDR: 10.1.0.0/24
  providerID: azure:////2882C846-5C01-BE47-B19A-4C5DB5F26348
status:
  addresses:
  - address: 172.18.0.4
    type: LegacyHostIP
  - address: 172.18.0.4
    type: InternalIP
  - address: 172.18.0.4
    type: Hostname
  allocatable:
    alpha.kubernetes.io/nvidia-gpu: "0"
    cpu: "16"
    memory: 57710432Ki
    pods: "110"
...

指定输出 json 格式的详情

{
    "apiVersion": "v1",
    "kind": "Node",
    "metadata": {
        "annotations": {
            "flannel.alpha.coreos.com/backend-data": "{\"VtepMAC\":\"9a:98:da:a1:b9:5d\"}",
            "flannel.alpha.coreos.com/backend-type": "vxlan",
            "flannel.alpha.coreos.com/kube-subnet-manager": "true",
            "flannel.alpha.coreos.com/public-ip": "172.18.0.4",
            "scheduler.alpha.kubernetes.io/taints": "[]",
            "volumes.kubernetes.io/controller-managed-attach-detach": "true"
        },
        "creationTimestamp": "2017-07-13T09:45:11Z",
        "labels": {
            "beta.kubernetes.io/arch": "amd64",
            "beta.kubernetes.io/os": "linux",
            "ip": "172.18.0.4",
            "kubeadm.alpha.kubernetes.io/role": "master",
            "kubernetes.io/hostname": "172.18.0.4"
        },
        "name": "172.18.0.4",
        "resourceVersion": "3785243",
        "selfLink": "/api/v1/nodes172.18.0.4",
        "uid": "f6fc3022-67af-11e7-b171-0017fa013946"
    },
    "spec": {
        "externalID": "172.18.0.4",
        "podCIDR": "10.1.0.0/24",
        "providerID": "azure:////2882C846-5C01-BE47-B19A-4C5DB5F26348"
    },
    "....": "...."
}

默认的输出格式比较类似于 linux 上ls的默认输出。但也可以通过指定参数获取 json 或 yaml 格式的信息。前者适用于展示,后者适用于处理(管道).ls的输出目前既用于展示,也会用于输出。鉴于 json 目前的流行程度及简洁性,设想 plan9 上这些小工具均内置于对 json 或者 yaml 的支持,那么在利用管道及其他工具做数据处理的时候会大为简便,并且不易出错。

kubectl 支持从一个描述文件里创建一个 resource(yaml 或 json 格式).因为 API 结构的一致,kubernetes 里面几乎所有的资源都可以通过一个kubectl create -f来创建出来. 因为每种 resource 都有大体相同的结构: Kind,Version,Spec 等等


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK