跳转到主要内容

热门内容

今日:


总体:


最近浏览:


Chinese, Simplified

category

欢迎来到Kubernetes深潜博客系列。我们,也就是Stefan Schimanski(Engineering)和Michael Hausenblas(Advocy),将深入研究Kubernetes的特定方面以及它们在OpenShift中的使用方式。如果你对Kubernetes的内部工作原理以及如何调试它感兴趣,这个博客系列就是为你准备的。此外,如果你想扩展Kubernetes或开始为项目做出贡献,你可能会从中受益。熟悉Go是一个优势,但不是一个很难遵循的要求。

在本期文章中,我们将从Kubernetes API服务器的一般介绍开始,提供一些术语并解释API请求流。未来的文章将涉及存储相关主题和API服务器的可扩展性要点。

介绍API服务器


在概念层面上,Kubernetes是由一堆具有不同角色的节点组成的。主节点上的控制平面由API服务器、控制器管理器和调度程序组成。API服务器是中央管理实体,也是唯一与分布式存储组件etcd直接对话的组件。它提供以下核心功能:

  • 服务于Kubernetes API,在内部由工作节点集群使用,在外部由kubectl集群使用
  • 代理集群组件,如Kubernetes UI
  • 允许操作对象的状态,例如pod和服务
  • 将对象的状态保持在分布式存储(etcd)中

Kubernetes API是一个以JSON为主要序列化模式的HTTP API,但它也支持协议缓冲区,主要用于集群内部通信。出于可扩展性的原因,Kubernetes在不同的API路径上支持多个API版本,例如/API/v1或/apis/extensions/v1beta1。不同的API版本意味着不同级别的稳定性和支持:

  • Alpha级别,例如v1alpha1在默认情况下是禁用的,对某个功能的支持可能会在没有通知的情况下随时删除,并且只能在短时间的测试集群中使用。
  • Beta级别,例如v2beta3,默认情况下是启用的,这意味着代码经过了良好的测试,但在后续的Beta或稳定版本中,对象的语义可能会以不兼容的方式发生变化。
  • 稳定级别,例如,v1将出现在许多后续版本的已发布软件中。


现在让我们看看HTTP API空间是如何构建的。在顶层,我们区分核心组(/api/v1以下的所有内容,出于历史原因,在此路径下,而不是/api/core/v1下)、命名组(位于路径/api/$NAME/$VERSION)和系统范围的实体(如/metrics)。

HTTP API空间的一部分(基于v1.5)如下所示:

接下来,我们将关注一个具体的例子:批处理操作。在Kubernetes 1.5中,存在两个版本的批处理操作:/apis/batch/v1和/apis/patch/v2alpha1,公开了可以查询和操作的不同实体集。

现在,我们将注意力转向与API的示例性交互(我们在这里使用Minishift和代理命令oc-proxy--port=8080来直接访问API):

$ curl http://127.0.0.1:8080/apis/batch/v1
{
 "kind": "APIResourceList",
 "apiVersion": "v1",
 "groupVersion": "batch/v1",
 "resources": [
   {
     "name": "jobs",
     "namespaced": true,
     "kind": "Job"
   },
   {
     "name": "jobs/status",
     "namespaced": true,
     "kind": "Job"
   }
 ]
}

此外,使用新的alpha版本:

$ curl http://127.0.0.1:8080/apis/batch/v2alpha1
{
 "kind": "APIResourceList",
 "apiVersion": "v1",
 "groupVersion": "batch/v2alpha1",
 "resources": [
   {
     "name": "cronjobs",
     "namespaced": true,
     "kind": "CronJob"
   },
   {
     "name": "cronjobs/status",
     "namespaced": true,
     "kind": "CronJob"
   },
   {
     "name": "jobs",
     "namespaced": true,
     "kind": "Job"
   },
   {
     "name": "jobs/status",
     "namespaced": true,
     "kind": "Job"
   },
   {
     "name": "scheduledjobs",
     "namespaced": true,
     "kind": "ScheduledJob"
   },
   {
     "name": "scheduledjobs/status",
     "namespaced": true,
     "kind": "ScheduledJob"
   }
 ]
}

通常,Kubernetes API支持通过标准HTTP谓词POST、PUT、delete和GET在给定路径上创建、更新、删除和检索操作,JSON作为默认负载。

大多数API对象在对象的期望状态的指定和对象在当前时间的状态之间进行区分。规范是对所需状态的完整描述,并保持在稳定的存储中。

术语


在对API服务器和HTTP API空间及其属性进行简要概述之后,我们现在更正式地定义本文中使用的术语。pod、服务、端点、部署等基本元素构成了Kubernetes类型宇宙的对象。我们使用以下术语:

Kind是实体的类型。每个对象都有一个字段Kind,它告诉一个客户端,比如kubectl或oc-它代表的是一个pod:

apiVersion: v1
kind: Pod
metadata:
 name: webserver
spec:
 containers:
 - name: nginx
   image: nginx:1.9
   ports:
   - containerPort: 80
 

种类有三类:

  • 对象表示系统中的持久实体。一个对象可能具有多个资源,客户端可以使用这些资源来执行特定操作。示例:Pod和Namespace。
  • 列表是一种或多种实体的资源集合。列表具有一组有限的通用元数据。示例:PodLists和NodeLists。
    例如,特殊用途类型用于对象上的特定操作和非持久性实体,如/binding或/status,发现使用APIGroup和APIResource,错误结果使用status等。
  • API组是逻辑相关的种类的集合。例如,所有批处理对象(如Job或ScheduledJob)都在批处理API组中。

版本每个API组可以存在于多个版本中。例如,一个组首先出现为v1alpha1,然后升级为v1beta1,最后升级为v1。在一个版本(例如v1beta1)中创建的对象可以在每个支持的版本(例如v1)中检索。API服务器进行无损转换以返回请求版本中的对象。

资源是通过HTTP以JSON形式发送或检索的系统实体的表示;可以作为单个资源(如…/namespaces/default)或资源集合(如…/jobs)公开。

API组、版本和资源(GVR)唯一地定义HTTP路径:

 

更准确地说,作业的实际路径是/api/batch/v1/namespaces/$NAMESPACE/jobs,因为与例如节点资源相比,作业不是集群范围的资源。为了简洁起见,我们在整个帖子中省略了路径的$NAMESPACE段。

请注意,Kinds不仅可以存在于不同的版本中,还可以同时存在于不同API组中。例如,部署最初是扩展组中的alpha Kind,最终在其自己的组apps.k8s.io中升级为GA版本。因此,要唯一识别Kinds,需要API组、版本和种类名称(GVK)。

请求流程和处理


现在我们已经回顾了Kubernetes API中使用的术语,接下来我们将讨论如何处理API请求。API位于k8s.io/pkg/API中,处理来自集群内以及集群外客户端的请求。

那么,当HTTP请求到达Kubernetes API时,实际会发生什么呢?在高层次上,会发生以下互动:

  1. HTTP请求由在DefaultBuildHandlerChain()中注册的筛选器链(请参阅config.go)处理,该筛选器链对其应用操作(有关筛选器的更多详细信息,请参阅下文)。过滤器通过并将相应的信息附加到ctx。RequestInfo,例如经过身份验证的用户或返回适当的HTTP响应代码。
  2. 接下来,复用器(请参阅container.go)根据HTTP路径将HTTP请求路由到相应的处理程序。
  3. 路由(如路由/*中所定义)将处理程序与HTTP路径连接起来。
  4. 按API组注册的处理程序(请参阅groupversion.go和installer.go)获取HTTP请求和上下文(如用户、权限等),并从存储中传递请求的对象。


整个流程如下所示:

再次注意,为了简洁起见,我们省略了上图中HTTP路径的$NAMESPACE段。

现在让我们仔细看看config.go中DefaultBuildHandlerChain()设置的过滤器:

  • requestinfo.go中定义的WithRequestInfo()将requestinfo附加到上下文
  • maxinflight.go中定义的WithMaxInFlightLimit()限制飞行中请求的数量
  • timeout.go中定义的WithTimeoutForNonLongRunningRequests()会超时非长时间运行的请求(如大多数GET、PUT、POST、DELETE请求),而不是长时间运行请求(如监视和代理请求)
  • wrap.go中定义的WithPanicRecovery()包装处理程序以恢复和记录恐慌
  • cors.go中定义的WithCORS()提供了一个cors实现;CORS代表跨来源资源共享,是一种允许嵌入HTML页面的JavaScript向不同于JavaScript来源的域发出XMLHttpRequest的机制。
  • authentication.go中定义的WithAuthentication()尝试将给定请求作为用户进行身份验证,并将用户信息存储在提供的上下文中。成功后,授权HTTP标头将从请求中删除。
  • audit.go中定义的WithAudit()用所有传入请求的审计日志信息装饰处理程序。审计日志条目包含信息,如请求的源IP、调用操作的用户和请求的命名空间。
    在模拟中定义的WithImpersonation()。go通过检查试图更改用户的请求来处理用户模拟(类似于sudo)。
  • authorization.go中定义的WithAuthorization()将所有授权请求传递给多路复用器,多路复用器将请求分派给正确的处理程序,否则返回禁止的错误。
     

至此,我们将结束API服务器深入研究的第一部分。下一次,我们将更深入地了解资源的序列化是如何发生的,以及对象是如何在分布式存储中持久化的。

本文地址
最后修改
星期三, June 5, 2024 - 17:37
Article