Kubernetes_APIServer_APIServer简介

一、前言

api server 是 Kubernetes 集群的网关。它是 Kubernetes 集群中的所有用户、自动化和组件都可以访问的中心接触点。API
Server通过 HTTP 实现 RESTful API,执行所有 API 操作,并负责将 API 对象存储到持久存储后端。

APIServer组件两个核心知识点:
(1) APIServer 提供的所有接口、访问这些接口需要的所有证书、整个 k8s 内部组件访问架构
(2) 一个外部的 Request 请求到 k8s 集群,整个 APIServer 的处理流程

二、APIServer概要

尽管 Kubernetes API Server很复杂,但从管理的角度来看,实际上管理起来相对简单。因为 API Server的所有持久状态都存储在 API Server外部的数据库中,所以服务器本身是无状态的,可以复制以处理请求负载和容错。通常,在高可用集群中,API Server会被复制 3 次。

API Server输出的日志可能非常健谈。它为接收到的每个请求至少输出一行。因此,将某种形式的日志滚动添加到 API Server非常重要,这样它就不会消耗所有可用的磁盘空间。但是,由于 API Server日志对于理解 API Server的操作至关重要,我们强烈建议将日志从 API Server传送到日志聚合服务,以便后续自省和查询以调试用户或组件对 API 的请求。

apiserver是无状态的,不存储数据,存储数据的是etcd.,configmap 和 secret 都存储在 etcd 里面,然后 etcd 持久化到磁盘 /var/lib/etcd 目录下

操作 Kubernetes API Server涉及三个核心功能:

  • API management 服务器公开和管理 API 的过程 [即所有接口、所有证书、内部组件架构与交互]
  • Request processing 处理来自客户端的单个 API 请求的最大功能集 [即处理一个外部请求Request的完整流程]
  • Internal control loops 负责 API Server成功运行所需的后台操作的内部人员

三、APIServer中的接口

kube-apiserver 提供了 Kubernetes 的 REST API,实现了认证、授权、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

3.1 kubectl与APIServer之间是REST调用

官网 :https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-apiserver/

APIServer提供了K8S各类资源对象的操作,是集群内各个功能模块之间数据交互和通信的中心枢纽,是整个系统的数据总线和数据中心。通常我们通过kubectl与APIServer进行交互。

APIServer是通过kube-apiserver的进程提供服务,运行在master节点上。

kubectl与APIServer之间是REST调用

The Kubernetes API server validates and configures data for the api objects which include pods, services, replicationcontrollers, and others. The API Server services REST operations and provides the frontend to the cluster’s shared state through which all other components interact.

在这里插入图片描述

由上图,apisever提供其中类型的七类接口

/api/v1  核心API   常用的API资源
/apis  分组API    常用的API资源
/healthz 健康检查接口
/logs 获取日志
/ui  dashboard
/swaggerapi  OpenAPI
/metrics 性能度量

在这里插入图片描述

在这里插入图片描述

[root@m ~]# curl -k https://localhost:6443/ui
{
  "paths": [
    "/apis",
    "/apis/",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
    "/apis/apiextensions.k8s.io/v1beta1",
    
    "/healthz",
    "/healthz/etcd",
    "/healthz/log",
    "/healthz/ping",
    "/healthz/poststarthook/crd-informer-synced",
    "/healthz/poststarthook/generic-apiserver-start-informers",
    "/healthz/poststarthook/priority-and-fairness-config-consumer",
    "/healthz/poststarthook/priority-and-fairness-filter",
    "/healthz/poststarthook/start-apiextensions-controllers",
    "/healthz/poststarthook/start-apiextensions-informers",
    
    "/livez",
    "/livez/etcd",
    "/livez/log",
    "/livez/ping",
    "/livez/poststarthook/crd-informer-synced",
    "/livez/poststarthook/generic-apiserver-start-informers",
    "/livez/poststarthook/priority-and-fairness-config-consumer",
    "/livez/poststarthook/priority-and-fairness-filter",
    "/livez/poststarthook/start-apiextensions-controllers",
    "/livez/poststarthook/start-apiextensions-informers",
    
    "/metrics",
    
    "/openapi/v2",
    
    "/readyz",
    "/readyz/etcd",
    "/readyz/informer-sync",
    "/readyz/log",
    "/readyz/ping",
    "/readyz/poststarthook/crd-informer-synced",
    "/readyz/poststarthook/generic-apiserver-start-informers",
    "/readyz/poststarthook/priority-and-fairness-config-consumer",
    "/readyz/poststarthook/priority-and-fairness-filter",
    "/readyz/poststarthook/start-apiextensions-controllers",
    "/readyz/poststarthook/start-apiextensions-informers",
    "/readyz/shutdown",
    "/version"
  ]
}[root@m ~]# 

在这里插入图片描述

3.2 查看yaml文件中的apiVersion

grep -r "apiVersion" .

 ./pod_nginx.yaml:apiVersion: apps/v1 
 ./my-tomcat.yaml:apiVersion: apps/v1 
 ./my-tomcat.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: v1 
 ./mandatory.yaml:apiVersion: rbac.authorization.k8s.io/v1beta1 
 ./mandatory.yaml:apiVersion: rbac.authorization.k8s.io/v1beta1 
 ./mandatory.yaml:apiVersion: rbac.authorization.k8s.io/v1beta1 
 ...

grep -r “apiVersion” . # 在文件中查找指定字符串
该命令用于在当前目录及其子目录中搜索包含字符串 “apiVersion” 的文件,并将包含匹配字符串的行打印出来。其中,“-r” 表示递归搜索子目录,“.” 表示当前目录,grep 表示过滤/匹配,“apiVersion” 表示需要 过滤/匹配 的字符串。

效果如下:

在这里插入图片描述
在这里插入图片描述

3.3 APIServer 中的 Restful 风格接口

api官网 :https://kubernetes.io/docs/concepts/overview/kubernetes-api/

在官网上查看API文档,右上角可以更换版本和官网语言,其中 Version 可以告诉我们目前官网维护哪些版本的API

在这里插入图片描述

API文档链接如下(如上图只有 v1.23~1.27 的)
v1.27 :https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/

官网API文档:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#pod-v1-core,如下:

在这里插入图片描述

在这里插入图片描述

3.4 APIServer中的 API 路径

对 API Server的每个请求都遵循 RESTful API 模式,其中请求由请求的 HTTP 路径定义。所有 Kubernetes 请求都以前缀/api/(核心 API)或/apis/(按 API 组分组的 API)开头。这两组不同的路径主要是历史性的。API 组最初不存在于 Kubernetes API 中,因此原始或“核心”对象,如 Pod 和Services,在没有 API 组的情况下维护在’/api/'前缀下。后续 API 一般都添加在 API 组下,因此它们遵循’/apis/<api-group>/'路径。例如,该Job对象是batch API 组的一部分,因此可以在/apis/batch/v1/...下找到。

资源路径的另一个问题是资源是否已命名空间。Namespaces在 Kubernetes 中为对象添加了一层分组,命名空间资源只能在命名空间内创建,并且该命名空间的名称包含在命名空间资源的 HTTP 路径中。当然,有些资源并不存在于命名空间中(最明显的例子是NamespaceAPI 对象本身),在这种情况下,它们的 HTTP 路径中没有命名空间组件。

以下是命名空间资源类型的两种不同路径的组成部分:

/api/v1/namespaces/<namespace-name>/<resource-type-name>/<resource-name>
/apis/<api-group>/<api-version>/namespaces/<namespace-name>/<resource-type-name>/<resource-name>

以下是非命名空间资源类型的两种不同路径的组成部分:

/api/v1/<resource-type-name>/<resource-name>
/apis/<api-group>/<api-version>/<resource-type-name>/<resource-name>

k8s中,包含 /api 和 /apis 两种接口,如下:
在这里插入图片描述

3.5 kube-apiserver 的 insecure-port 端口

/etc/kubernetes/manifests/kube-apiserver.yaml 文件中包括两个属性,secure-port 和 insecure-port ,前者是安全端口,需要带 x509 证书认证才能访问,然后还需要 rbac 授权;后者是非安全端口,直接访问,这里看一下这个非安全端口的使用。

默认情况下,非安全端口为0,表示不打开,需要将其配置为一个具体的端口,这里配置为8080端口,把 8080 端口暴露出来,就可以用restful 接口操作了

# 默认8080端口是没有打开的
lsof -i tcp:8080 
vi /etc/kubernetes/manifests/kube-apiserver.yaml [kubeadm安装方式] 
# 查询insecure-port,并将修改端口为8080 
insecure-port=8080 
# kubect apply生效,需要等待一会 
kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml

效果如下:

默认是0,修改为8080
在这里插入图片描述

在这里插入图片描述

修改前后效果
在这里插入图片描述

查看端口以及访问测试,可以发现结果和kubectl使用一样

lsof -i tcp:8080 
curl localhost:8080 
curl localhost:8080/api 
curl localhost:8080/api/v1 
curl localhost:8080/api/v1/pods 
curl localhost:8080/api/v1/services

演示:
在这里插入图片描述

curl localhost:8080/api/v1/namespaces/wordpress/pods
curl 127.0.0.1:8080/api/v1/namespaces/wordpress/pods

在这里插入图片描述

3.6 操作 k8s 的开源工具

Github 上其实已经有开源的 kubernetes-client

在这里插入图片描述
https://github.com/kubernetes-client
Java :https://github.com/kubernetes-client/java
Go :https://github.com/kubernetes/client-go

还有图形化操作k8s的界面(rancher.com),如下:
在这里插入图片描述
在这里插入图片描述

3.7 APIServer资源查看

# kubectl查看资源与版本   
kubectl api-versions
kubectl api-resources
$ kubectl api-versions
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
apps/v1beta1
apps/v1beta2
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
metrics.k8s.io/v1beta1
networking.k8s.io/v1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

$ kubectl api-resources --api-group=storage.k8s.io
NAME                SHORTNAMES   APIGROUP         NAMESPACED   KIND
storageclasses      sc           storage.k8s.io   false        StorageClass
volumeattachments                storage.k8s.io   false        VolumeAttachment

尽管 API 的主要用途是为单个客户端请求提供服务,但在处理 API 请求之前,客户端必须知道如何发出 API 请求。最终,API Server是一个 HTTP 服务器——因此,每个 API 请求都是一个 HTTP 请求。但是必须描述这些 HTTP 请求的特征,以便客户端和服务器知道如何通信。出于探索的目的,让 API Server实际启动并运行非常好,这样您就可以对它进行探索。您可以使用您有权访问的现有 Kubernetes 集群,也可以将minikube 工具用于本地 Kubernetes 集群。

小结:kubectl api-versions 列出所有支持的 API 版本,而 kubectl api-resources 列出所有可用的 API 资源类型。[一个列出版本,一个列出资源]
kubectl proxy 不带端口,默认打开 8001 端口;不带 & 后缀,默认是前端启动,xshell会话关闭或者 ctrl + c 关闭,就停止了

四、APIServer中的接口属性

4.1 APIServer 中的API版本(Alpha/Beta/GA)

在这里插入图片描述

Alpha API: 在 Kubernetes 中,API 最初是一个 alpha API(例如,v1alpha1)。alpha 名称表示 API 不稳定且不适合生产用例。采用 alpha API 的用户应该预料到 API 表面区域可能会在 Kubernetes 版本之间发生变化,并且 API 本身的实现可能会不稳定,甚至可能会破坏整个 Kubernetes 集群的稳定性。因此,在生产 Kubernetes 集群中禁用了 Alpha API。

beta API: 一旦 API 成熟,它就会成为 beta API(例如,v1beta1)。Beta 指定表明 API 通常是稳定的,但可能存在错误或最终的 API 表面改进。通常,假设 Kubernetes 版本之间的 beta API 是稳定的,并且向后兼容是一个目标。但是,在特殊情况下,Beta API 可能仍然在 Kubernetes 版本之间不兼容。同样,beta API 旨在保持稳定,但可能仍然存在错误。Beta API 通常在生产 Kubernetes 集群中启用,但应谨慎使用。

GA API: 最后,API 变得普遍可用(例如,v1)。通用可用性 (GA) 表明 API 是稳定的。这些 API 带有向后兼容性保证和弃用保证。在 API 被标记为计划删除后,Kubernetes 会将该 API 保留至少三个版本或一年,以先到者为准。弃用也不太可能。只有在开发出更好的替代方案后,API 才会被弃用。同样,GA API 是稳定的,适用于所有生产用途。

Kubernetes 的特定版本可以支持多个版本(alpha、beta 和 GA)。

为了实现这一点,API Server始终具有三种不同的 API 表示:

  • 外部表示,即通过 API 请求进入的表示;
  • 内部表示,它是在 API Server中用于处理的对象的内存表示;
  • 存储表示,它被记录到存储层以持久化 API 对象。

API Server中的代码知道如何在所有这些表示之间执行各种转换。API 对象可以作为v1alpha1版本提交,作为v1对象存储,然后作为v1beta1对象或任何其他任意支持的版本检索。

4.2 APIServer请求格式(JSON编码/YAML编码/协议缓冲区编码)

API Server 一共支持三种请求格式

JSON编码:请求的编码由请求上的 Content-Type HTTP 标头指示。如果缺少此标头,则假定内容为application/json,表示 JSON 编码。

YAML编码:由application/yamlContent Type 指示。YAML 是一种基于文本的格式,通常被认为比 JSON 更易于阅读。几乎没有理由使用 YAML 进行编码以与服务器通信,但在某些情况下它可能很方便(例如,通过 手动将文件发送到服务器curl)。

协议缓冲区编码: 由application/vnd.kubernetes.protobufContent-Type 标头指示。Protocol Buffers 是一个相当有效的二进制对象协议, 使用协议缓冲区可以为 API Server带来更高效和更高吞吐量的请求。事实上,许多 Kubernetes 内部工具都使用协议缓冲区作为它们的传输。Protocol Buffers 的主要问题是,由于它们的二进制性质,它们在有线格式中更难可视化/调试。此外,目前并非所有客户端库都支持 Protocol Buffers 请求或响应。

4.3 APIServer常见响应代码

APIServer 管理着 Kubernetes 集群所有接口,因为 API Server是作为 RESTful 服务器实现的,所以来自服务器的所有响应都与 HTTP 响应代码保持一致。除了典型的 200 表示 OK 响应和 500 表示内部服务器错误之外,以下是一些常见的响应代码及其含义:

202 公认。已收到创建或删除对象的异步请求。结果以状态对象响应,直到异步请求完成,此时将返回实际对象。
400 错误的请求。服务器无法解析或理解该请求。
401 未经授权。在没有已知身份验证方案的情况下接收到请求,对应到 APIServer 里面就是 x509客户端证书 认证失败。
403 禁止。已收到并理解请求,但禁止访问,对应到 APIServer 里面就是 RBAC 授权失败。
409 冲突。已收到请求,但它是更新旧版本对象的请求。
422 无法处理的实体。请求已正确解析,但未通过某种验证.

五、管理 Request

Kubernetes 中 API Server的主要用途是接收和处理 HTTP 请求形式的 API 调用。这些请求要么来自 Kubernetes 系统中的其他组件,要么是最终用户请求。无论哪种情况,它们都由 Kubernetes API Server以相同的方式处理。

5.1 Requests 四种请求类型

GET:最简单的请求是GET对特定资源的请求。这些请求检索与特定资源关联的数据。例如,对路径/api/v1/namespaces/default/pods/foo 的 HTTP请求检索名为foo的 Pod 的数据。

LIST:一个稍微复杂但仍然相当简单的请求是 acollection GET或LIST。这些是列出许多不同请求的请求。例如,对路径/api/v1/namespaces/default/pods. GET的 HTTP请求检索命名空间中所有 Pod 的集合。requests 还可以选择指定标签查询,在这种情况下,仅返回与该标签查询匹配的资源。

POST:要创建资源,需要使用POST请求。请求的主体是应该创建的新资源。在POST请求的情况下,路径是资源类型(例如,/api/v1/namespaces/default/pods)。要更新现有资源,需要PUT向特定资源路径(例如/api/v1/namespaces/default/pods/foo)发出请求。

DELETE:当需要删除请求时,将使用DELETE对资源路径(例如/api/v1/namespaces/default/pods/foo)的 HTTP 请求。请务必注意,此更改是永久性的——在发出 HTTP 请求后,资源将被删除。

所有这些请求的内容类型通常是基于文本的 JSON ( application/json),但最近发布的 Kubernetes 也支持 Protocol Buffers 二进制编码。一般来说,JSON 更适合客户端和服务器之间网络上的人类可读和可调试流量,但解析起来更加冗长和昂贵。常用工具 curl,可以提高 API 请求的性能和吞吐量。

除了这些标准请求之外,许多请求还使用 WebSocket 协议来启用客户端和服务器之间的流式会话。此类协议的示例类似attach命令。

5.2 Request 生命周期(认证 授权 准入控制 验证)

为了更好地理解 API Server对每个不同的请求做了什么,我们将拆开并描述对 API Server的单个请求的处理。

官网 :https://v1-26.docs.kubernetes.io/docs/reference/access-authn-authz/controlling-access/

当一个外部 Request 请求访问 k8s 集群的时候,就必须访问 apiserver,因为所有的接口在 apiserver 里面,但是访问 apiserver ,需要认证、授权、准入控制三步骤。

在这里插入图片描述

其实是五个步骤(第一步和第五步太简单, 可略去):
传输安全 Transport Security
认证 Authentication
授权 Authorization
准入控制 Admission Control
IP和端口 API Server Ports and IPs

5.2.1 Authentication(认证)

请求处理的第一阶段是身份验证,它建立与请求关联的身份。API Server支持多种不同的身份建立模式,包括客户端证书、承载令牌和 HTTP 基本身份验证。一般来说,应该使用客户端证书或不记名令牌进行身份验证;不鼓励使用 HTTP 基本身份验证。

除了这些建立身份的本地方法之外,身份验证是可插入的,并且有几个使用远程身份提供者的插件实现。其中包括对 OpenID Connect (OIDC) 协议以及 Azure Active Directory 的支持。这些身份验证插件被编译到 API Server和客户端库中。这意味着您可能需要确保命令行工具和 API Server的版本大致相同或支持相同的身份验证方法。

API Server还支持基于远程 webhook 的身份验证配置,其中身份验证决策通过不记名令牌转发委托给外部服务器。外部服务器验证来自最终用户的不记名令牌,并将身份验证信息返回给 API Server

官网:https://v1-26.docs.kubernetes.io/docs/reference/access-authn-authz/controlling-access/#authentication

说白了,就是如何来识别客户端的身份,K8s集群提供了3种识别客户端身份的方式
HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式
HTTP Token认证:通过一个Token来识别合法用户
HTTP Base认证:通过用户名+密码的方式认证

中文社区(中文写的,界面跳转快):http://docs.kubernetes.org.cn/27.html

传输安全 - 认证 - 授权 - 准入控制 - Port和Ip的操作
传输安全:客户端和服务端之间安全通道,实现数据的加密传输
认证:就是要识别客户端的身份,认证分为两个维度。认证分为两类(即两个维度)
(1) 认证的第一个维度:外部客户端(系统外部组件)要想和apiServer的认证,通过三种方式有其一就可以了:HTTPS证书认证、token、用户名和密码
(2) 认证的第二个维度:系统内部组件要想和apiServer的认证,通过serviceAccount实现

认证的第一个维度(三种方式有其一就可以了):HTTPS证书认证、token、用户名和密码

HTTPS证书认证就是ca认证

对称加密和非对称加密
对称加密:发送方加密和接收方解密使用同一个密钥,简单高效,但是容易被篡改,不安全
非对称加密:公钥加密私钥加密,安全但是复杂度高,所以将 ca 公钥放到值得信赖的政府或企业,就是ca证书。
在这里插入图片描述

对于master节点的 /etc/kubernetes/pki 目录下的一系列证书,就是如下图:

在这里插入图片描述
且可以通过 ps -ef|grep apiserver 查看使用的就是 /etc/kubernetes/pki 目录下的 ca.crt 证书,如下:

在这里插入图片描述

认证的第二个维度:serviceAccount简称为sa,主节点上默认就有一个serviceAccount,使用 kubectl get sa 查看,使用 kubectl describe sa 查看详细信息;每一个pod也会有serviceAccount,进入pod里面的容器,存放在 /run/secrets/kubernetes.io/serviceaccount 目录下。

在这里插入图片描述

系统内部组件 serviceAccount 默认有一个serviceAccount,可以直接使用默认的 serviceAccount,也可以用户自己新建 serviceAccount ,授予权限。

每个组件也有serviceAccount,就放在 /run/secrets/kubernetes.io/serviceaccount 目录下,如下图:
在这里插入图片描述

在这里插入图片描述

5.2.2 RBAC(授权)

在 API Server确定请求的身份后,它会继续对其进行授权。对 Kubernetes 的每个请求都遵循传统的 RBAC 模型。要访问请求,身份必须具有与请求关联的适当角色。Kubernetes RBAC 是一个丰富而复杂的话题,因此,我们用一整章的时间来详细介绍RBAC它的运作方式。就本 API Server摘要而言,在处理请求时,API Server会确定与请求关联的身份是否可以访问请求中的动词和 HTTP 路径的组合。如果请求的身份具有适当的角色,则允许继续。否则,返回 HTTP 403 响应。

官网:https://v1-26.docs.kubernetes.io/docs/reference/access-authn-authz/controlling-access/#authorization

授权分为三种,如下:

(1) ABAC授权模式(已过时,略):基于属性的访问控制
(2) Webhook授权模式(已过时,略)
(3) RBRC授权模式(推荐使用, 需认真学习):基于角色的访问控制

常见的资源是Role、ClusterRole、RoleBinding和ClusterRoleBinding,用户可以使用kubectl或者API调用等方式操作这些资源对象,如下图:

在这里插入图片描述

Role与ClusterRole的区别(RoleBinding与ClusterRoleBinding的区别)
没有Cluster,Role和RoleBinding,表示某个局部的权限
有Cluster,ClusterRole和ClusterRoleBinding,表示整个集群的权限

(1) 定义一个ServiceAccount
(2) 定义一个Role,角色关联的权限
(3) 最后定义RoleBinding,直接把 ServiceAccount 和 Role 都绑定起来

在这里插入图片描述

5.2.3 Admission control(准入控制)

在请求经过身份验证和授权后,它会进入准入控制。身份验证和 RBAC 确定是否允许发生请求,这基于请求的 HTTP 属性(标头、方法和路径)。准入控制确定请求是否格式正确,并可能在处理请求之前对其进行修改。准入控制定义了一个可插拔的接口:

apply(request): (transformedRequest, error)
如果任何准入控制器发现错误,则拒绝该请求。如果请求被接受,则使用转换后的请求而不是初始请求。准入控制器被串行调用,每个接收前一个的输出。

因为准入控制是一种通用的、可插入的机制,所以它被用于 API Server中的各种不同功能。例如,它用于向对象添加默认值。它还可以用于强制执行策略(例如,要求所有对象都具有特定标签)。此外,它还可以用来做一些事情,比如向每个 Pod 注入一个额外的容器。服务网格 Istio 使用这种方法透明地注入其 sidecar 容器。

准入控制器非常通用,可以通过基于 webhook 的准入控制动态添加到 API Server。

官网 :https://v1-12.docs.kubernetes.io/docs/reference/access-authn-authz/controlling-access/#admission-control

准入控制有三种类型,Pod具体使用那种类型,可以在yaml里面配置,三种类型如下:

Always:允许所有请求
AlwaysPullImages:在启动容器之前总是尝试重新下载镜像
AlwaysDeny:禁止所有请求

Admission Control 是准入控制,类似于 filter 拦截器,可以修改或拒绝请求(modify or reject requests),准入控制通俗易懂的来说就是 一组强大的拦截器给你拦着,只要有一个拦截器你没有通过,整个请求就失败了。

5.2.4 Validation(验证)

请求验证发生在准入控制之后,尽管它也可以作为准入控制的一部分来实现,尤其是对于基于 Webhook 的外部验证。此外,仅对单个对象执行验证。如果它需要更广泛的集群状态知识,则必须将其实现为准入控制器。

请求验证确保请求中包含的特定资源有效。例如,它确保Service对象的名称符合 DNS 名称的规则,因为最终 a 的名称Service将被编程到 KubernetesService发现 DNS 服务器中。通常,验证是作为按资源类型定义的自定义代码来实现的。

5.3 特殊 requests(/proxy, /exec, /attach, /logs)

除了标准的 RESTful 请求之外,API Server还有许多专门的请求模式,为客户端提供扩展功能:

/proxy, /exec, /attach, /logs

流式数据: 第一类重要的操作是与 API Server的开放的、长时间运行的连接。这些请求提供流数据而不是立即响应。

该logs操作是我们描述的第一个流式请求,因为它最容易理解。事实上,默认情况下,logs根本不是流式传输请求。/logs客户端通过附加到特定 Pod 的路径末尾(例如 /api/v1/namespaces/default/pods/some-pod/logs)然后指定容器名称来请求获取 Pod 的日志作为 HTTP 查询参数和 HTTP GET请求。给定一个默认请求,API Server会以纯文本形式返回截至当前时间的所有日志,然后关闭 HTTP 请求。但是,如果客户端请求跟踪日志(通过指定follow查询参数),HTTP 响应由 API Server保持打开状态,并且在通过 API Server从 kubelet 接收新日志时将新日志写入 HTTP 响应。这种连接如下图:

在这里插入图片描述

logs是最容易理解的流式传输请求,因为它只是让请求保持打开状态并流入更多数据。其余操作利用 WebSocket 协议进行双向流数据。它们实际上还对这些流中的数据进行了多路复用,以通过 HTTP 启用任意数量的双向流。如果这一切听起来有点复杂,它确实是,但它也是 API Server表面区域的一个有价值的部分。

API Server实际上支持两种不同的流协议。它支持 SPDY 协议,以及 HTTP2/WebSocket。SPDY 正在被 HTTP2/WebSocket 取代,因此我们将注意力集中在 WebSocket 协议上。

完整的 WebSocket 协议超出了本书的范围,但它在许多其他地方都有记录。为了理解 API Server,您可以简单地将 WebSocket 视为一种将 HTTP 转换为双向字节流协议的协议。

然而,在这些流之上,Kubernetes API Server实际上引入了一个额外的多路复用流协议。这样做的原因是,对于许多用例,API Server能够为多个独立的字节流提供服务是非常有用的。例如,考虑在容器中执行命令。在这种情况下,实际上需要维护三个流(stdin、stderr和stdout)。

此流的基本协议如下:为每个流分配一个从 0 到 255 的数字。该流编号用于输入和输出,它在概念上模拟单个双向字节流。

对于通过 WebSocket 协议发送的每一帧,第一个字节是流号(例如,0),帧的其余部分是在该流上传输的数据如下图:

图:Kubernetes WebSocket 多通道框架的示例

使用此协议和 WebSockets,API Server可以在单个 WebSocket 会话中同时多路复用 256 字节流。

此基本协议用于会话exec,attach具有以下通道:

  • stdin用于写入进程的流。不会从此流中读取数据。
  • 用于从进程stdout读取的输出流。stdout不应将数据写入此流。
  • 用于从进程stderr读取的输出流。stderr不应将数据写入此流。

endpoint用于在/proxy客户端与集群内运行的容器和服务之间转发网络流量,而这些endpoint不会暴露在外部。为了流式传输这些 TCP 会话,协议稍微复杂一些。除了多路复用各种流之外,流的前两个字节(在流号之后,所以实际上是 WebSockets 帧中的第二和第三个字节)是正在转发的端口号,因此单个 WebSockets 帧用于/proxy查找如下图:

在这里插入图片描述

5.4 APIServer高级操作: Watch operations

除了流式数据,API Server还支持 watch API。

watch监视更改的路径,采用的方式不是在某个时间间隔轮询可能的更新,这会引入额外的负载(由于快速轮询)或额外的延迟(由于慢速轮询),而是使用watch使用户能够通过单个连接获得低延迟更新。

当用户通过向?watch=true某个 API Server请求添加查询参数来建立到 API Server的监视连接时,API Server切换到监视模式,并保持客户端和服务器之间的连接打开。同样,API Server返回的数据不再只是 API 对象,而是返回一个Watch包含更改类型(创建、更新、删除)和 API 对象本身的对象。通过这种方式,客户端可以观察和观察对该对象或对象集的所有更改。

5.5 APIServer高级操作: 乐观并发更新

API Server支持的另一个高级操作是能够乐观地执行 Kubernetes API 的并发更新。乐观并发背后的想法是能够在不使用锁的情况下执行大多数操作(悲观并发),并检测何时发生并发写入,拒绝两个并发写入中的后者。被拒绝的写入不会重试(由客户端检测冲突并自己重试写入)。

要理解为什么需要这种乐观并发和冲突检测,了解读/更新/写竞争条件的结构很重要。许多 API Server客户端的操作涉及三个步骤:

  1. 从 API Server读取一些数据。
  2. 更新内存中的数据。
  3. 将其写回 API Server。

现在想象一下当这两种读/更新/写模式同时发生时会发生什么。

  1. 服务器 A 读取对象 O。
  2. 服务器 B 读取对象 O。
  3. 服务器 A 更新客户端内存中的对象 O。
  4. 服务器 B 更新客户端内存中的对象 O。
  5. 服务器 A 写入对象 O。
  6. 服务器 B 写入对象 O。

最后,服务器 A 所做的更改将丢失,因为它们被服务器 B 的更新覆盖。

解决这场比赛有两种选择。第一个是悲观锁(pessimistic lock),它可以防止在服务器 A 对对象进行操作时发生其他读取。这样做的问题是它会序列化所有操作,这会导致性能和吞吐量问题。

Kubernetes API Server实现的另一个选项是乐观并发(optimistic concurrency),它假设一切都会顺利进行,并且仅在尝试写入冲突时才检测到问题。为此,对象的每个实例都返回其数据和资源版本。此资源版本指示对象的当前迭代。发生写入时,如果设置了对象的资源版本,则只有当前版本与对象的版本匹配,才能写入成功。如果没有,则返回 HTTP 错误 409(冲突)并且客户端发霉重试。要了解这如何解决刚刚描述的读/更新/写竞争,让我们再次看一下操作:

  1. 服务器 A 读取版本为 v1 的对象 O。
  2. 服务器 B 读取版本为 v1 的对象 O。
  3. 服务器 A 在客户端的内存中更新版本为 v1 的对象 O。
  4. 服务器 B 更新客户端内存中版本 v1 的对象 O。
  5. 服务器 A 以版本 v1 写入对象 O;这是成功的。
  6. 服务器B在v1版本写入对象O,但对象在v2;返回 409 冲突。

小结:乐观锁并法更新属于APIServer底层设计,与开发者操作K8S集群关系不大,了解即可。

六、访问 API Server 的多种方式

有多种方式可以访问 Kubernetes 提供的 REST API:

kubectl 命令行工具
SDK,支持多种语言
Go
Java KubernetesClient框架

6.1 kubectl 命令行工具

kubectl get --raw /api/v1/namespaces
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods

在这里插入图片描述

在这里插入图片描述

6.2 kubectl proxy

首先,为了简化事情,我们使用kubectl命令行工具的内置proxy来为我们的集群提供身份验证

kubectl在proxy使用以下命令在 localhost:8001 上公开未经身份验证的 API Server的模式:

为了便于使用该curl工具来探索 API Server,请

$ kubectl proxy --port=8080 &
$ curl http://localhost:8080/api/
{
  "versions": [
    "v1"
  ]
}
或者
kubectl proxy

在这里插入图片描述

小结: kubectl proxy 也是一种跳过认证的方式,但是只能使用localhost/127.0.0.1, 无法用 网卡IP/EIP 访问

这将创建一个在本地计算机上的端口 8001 上运行的简单服务器。

我们可以使用这个服务器来启动 API 发现的过程。我们首先检查/api前缀:

$ curl localhost:8001/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.0.1:6443"
    }
  ]
}

在这里插入图片描述

但是 kubectl proxy 有一个局限,就是无法使用网卡ip访问,就无法从外部用 Postman 访问了

在这里插入图片描述

您可以看到服务器返回了一个类型为 的 API 对象APIVersions。这个对象为我们提供了一个versions字段,列出了可用的版本。

在这种情况下,只有一个,但对于/apis前缀,有很多。返回的对象包含/api/v1/路径下暴露的资源列表。

描述 API(元 API 对象)的 OpenAPI/Swagger JSON 规范除了资源类型之外还包含各种有趣的信息。考虑Pod对象的 OpenAPI 规范:

{
      "name": "pods",
      "singularName": "",
      "namespaced": true,
      "kind": "Pod",
      "verbs": [
        "create",
        "delete",
        "deletecollection",
        "get",
        "list",
        "patch",
        "proxy",
        "update",
        "watch"
      ],
      "shortNames": [
        "po"
      ],
      "categories": [
        "all"
      ]
},
{
      "name": "pods/attach",
      "singularName": "",
      "namespaced": true,
      "kind": "Pod",
      "verbs": []
}

查看此对象,该name字段提供此资源的名称。它还指示这些资源的子路径。由于推断英语单词的复数形式具有挑战性,因此 API 资源还包含一个singularName字段,该字段指示应用于该资源的单个实例的名称。我们之前讨论过命名空间。对象描述中的namespaced字段指示对象是否被命名空间。该kind字段提供了存在于 API 对象的 JSON 表示中的字符串,以指示它是什么类型的对象。该verbs字段是 API 对象中最重要的字段之一,因为它指示可以对该对象执行哪些类型的操作。这pods宾语包含所有可能的动词。动词的大部分效果从它们的名字就很明显了。需要更多解释的两个是watch和proxy。watch表示可以为资源建立监视。监视是一个长时间运行的操作,它提供有关对象更改的通知。proxy是一种专门的操作,它通过 API Server与网络端口建立代理网络连接。目前只有两种资源(Pod 和Services)支持proxy.

除了可以对对象执行的操作(描述为动词)之外,还有其他操作被建模为资源类型的子资源。例如,attach命令被建模为子资源:

{
  "name": "pods/attach",
  "singularName": "",
  "namespaced": true,
  "kind": "Pod",
  "verbs": []
}

6.3 curl 请求访问

$ TOKEN=$(cat /run/secrets/kubernetes.io/serviceaccount/token)
$ CACERT=/run/secrets/kubernetes.io/serviceaccount/ca.crt
$ curl --cacert $CACERT --header "Authorization: Bearer $TOKEN"  https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}
$ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ")
$ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token'| cut -f2 -d':'| tr -d '\t')
$ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "10.0.1.149:443"
    }
  ]
}

七、调试 APIServer

通常情况下,您真正​​需要的是能够调试 API Server(以及调用 API 的客户端)的实际情况服务器)。实现这一点的主要方式是通过 API Server写入的日志。API Server导出两个日志流:basicLogs + audioLogs,它们试图捕获发出请求的原因和方式以及更改的 API Server状态。此外,可以打开更详细的日志记录来调试特定问题。

7.1 Basic Logs

默认情况下,Pod运行的API Server,Container容器会记录发送到 API Server的每个请求。此日志包括客户端的 IP 地址、请求的路径以及服务器返回的代码。如果意外错误导致服务器崩溃,服务器也会捕捉到这种恐慌,返回 500,并记录该错误。

I0803 19:59:19.929302       1 trace.go:76] Trace[1449222206]: "Create /api/v1/namespaces/default/events" 
(started: 2018-08-03 19:59:19.001777279 +0000 UTC m=+25.386403121) (total time: 927.484579ms):
Trace[1449222206]: [927.401927ms] [927.279642ms] Object stored in database

I0803 19:59:20.402215       1 controller.go:537] quota admission added evaluator for: { namespaces}

在此日志中,您可以看到它以I0803 19:59:…发出日志行时的时间戳开始,然后是发出它的行号,trace.go:76最后是日志消息本身。

7.2 Audit Logs

审计日志(Audit Logs)旨在使服务器管理员能够取证恢复服务器的状态以及导致 Kubernetes API 中数据当前状态的一系列客户端交互。例如,它使用户能够回答诸如“为什么要ReplicaSet扩大到 100 个?”、“谁删除了那个 Pod?”等问题。

审计日志有一个可插入的后端,用于记录它们的写入位置。通常,审计日志会写入文件,但也可以将它们写入 webhook。在任何一种情况下,记录的数据都是API 组中类型event的结构化 JSON 对象audit.k8s.io。

审计本身可以通过同一 API 组中的策略对象进行配置。此策略允许您指定将审计事件发送到审计日志的规则。

7.3 激活附加日志

Kubernetes 使用 leveled logging github.com/golang/glog 包进行日志记录。使用 API Server上的标志–v,您可以调整日志记录的详细程度。一般来说,Kubernetes 项目已将日志详细级别 2 ( --v=2) 设置为记录相关但不太垃圾邮件的合理默认值。

如果您正在调查特定问题,您可以提高日志记录级别以查看更多(可能是垃圾邮件)消息。
由于过多的日志记录会影响性能,我们建议不要在生产中使用详细的日志级别运行。
如果您正在寻找更有针对性的日志记录,该–vmodule标志可以提高单个源文件的日志级别。这对于仅限于一小部分文件的非常有针对性的详细日志记录非常有用。

7.4 调试 kubectl 请求

除了通过日志调试 API Server外,还可以通过kubectl命令行工具调试与 API Server的交互。与 API Server一样,kubectl命令行工具通过github.com/golang/glog包记录并支持–v详细度标志。将详细程度设置为级别 10 ( --v=10) 会启用最大程度详细记录。在此模式下,kubectl记录它向服务器发出的所有请求,以及尝试打印curl可用于复制这些请求的命令。请注意,这些curl命令有时不完整。

此外,如果您想直接戳 API Server,我们之前用于探索 API 发现的方法效果很好。Running kubectl proxy在 localhost 上创建一个代理服务器,它会根据本地$HOME/.kube/config文件自动提供您的身份验证和授权凭据。运行代理后,使用该curl命令查看各种 API 请求相当简单。

尾声

API Server的所有持久状态都存储在 API Server外部的数据库中,所以服务器本身是无状态的,可以复制以处理请求负载和容错。通常,在高可用集群中,API Server会被复制 3 次。

无状态:不存储数据 (因为不存储数据,所以不记录上一次请求/无法记住上一次请求)

kube-apiserver 提供了 Kubernetes 的 REST API,实现了认证Authentication、授权Authorization、准入控制等安全校验功能,同时也负责集群状态的存储操作(通过 etcd)。

当访问APIServer接口的时候,需要经过 认证(人使用userAccount,pod使用serviceAccount)-授权(统一使用rbac)-准入控制

解释:
认证Authentication:即userAccount(x509证书/静态文件/匿名)、ServiceAccount(一种方式,即 bearerToken)
授权Authorization:即 rbac 授权方式,涉及资源包括 Role、ClusterRole、RoleBinding、ClusterRoleBinding
准入控制AdmissionController:略

参考:kubernetes API Server 看这篇试试

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 错误:没有提供配置,请尝试设置kubernetes_master环境变量。 这个错误通常是由于缺少Kubernetes的配置信息导致的。解决方法是设置kubernetes_master环境变量,指定Kubernetes的主节点地址。具体操作可以参考Kubernetes的官方文档或者相关教程。 ### 回答2: “no configuration has been provided, try setting kubernetes_master environment variable”这个错误信息通常出现在使用Kubernetes命令行工具(kubectl)时,因为在执行kubectl命令的时候,kubectl需要获取集群的相关配置信息,如API Server地址、Token等等。如果这些配置信息未被正确设置,kubectl就会出现“error: no configuration has been provided”这个错误提示。 解决这个问题可以尝试以下几种方法: 1. 设置Kubernetes master环境变量 通过设置环境变量来告诉kubectl如何连接到Kubernetes集群。Kubernetes master环境变量指定了Kubernetes API服务器的地址,你可以将其设置为Kubernetes Master节点的IP地址或域名。在命令行中执行如下命令: ``` export KUBECONFIG=/path/to/kubeconfig.yaml export KUBERNETES_MASTER=http://your-kubernetes-master:8080 ``` 2. 在命令中指定kubeconfig文件 使用--kubeconfig选项可以让kubectl从指定文件中获取集群的配置信息。例如: ``` kubectl --kubeconfig=/path/to/kubeconfig.yaml get pods ``` 3. 检查kubeconfig文件中的配置信息 如果配置信息正确,那么可以打开kubeconfig文件来检查其中是否包含正确的集群信息,例如apiServer地址、证书、token等。 以上是一些解决“error: no configuration has been provided, try setting kubernetes_master environment variable”错误的方法,如果以上解决方法仍然无法解决问题,那么也可以考虑咨询相关专业人员。 ### 回答3: 这个错误提示意味着在运行Kubernetes命令时没有配置正确的环境变量。Kubernetes是一个开源的容器编排系统,它可以让开发者快速、自动化地部署、扩展和管理容器化应用程序。 在使用Kubernetes时,需要正确设置相关的环境变量以便Kubernetes能够访问和管理集群。这些环境变量包括Kubernetes Master的地址、证书和凭证等信息。 解决该错误的步骤如下: 1. 设置Kubernetes Master环境变量。可以通过以下命令来设置: ``` export KUBECONFIG=path/to/kubeconfig.yaml ``` 其中path/to/kubeconfig.yaml是指向Kubernetes Master的配置文件路径。该配置文件包含了Kubernetes API Server的地址、证书以及其他凭证信息。 2. 检查Kubernetes Master的地址是否正确。在设置Kubernetes Master环境变量时,需要确保指定的地址是正确的。可以通过命令行或者其他工具来验证Kubernetes Master是否正常运行。 3. 检查证书和凭证是否正确。在访问Kubernetes Master时,需要使用正确的证书和凭证。如果证书或凭证不正确,可能会导致连接失败。 在解决该错误之后,可以通过Kubernetes命令来管理容器化应用程序,并通过Kubernetes Dashboard等工具来监控和调试Kubernetes集群的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祖母绿宝石

打赏一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值