Kubernetes APIServer 最佳实践

Posted 乱舞春秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes APIServer 最佳实践相关的知识,希望对你有一定的参考价值。


1. kubernetes 整体架构

kubernetes 由 master 节点和工作节点组成。其中,master 节点的组件有 APIServer,scheduler 和 controller-manager。APIServer 是系统管理指令的统一入口,scheduler 负责调度 Pod 到合适的工作节点上,controller-manager 是一组资源控制器,负责控制管理对应的资源,如 replication 等。工作节点的组件有 kubelet 和 kube-proxy。kubelet 负责创建,管理,维护 pod,kube-proxy 负责将访问 service 的流量转发到对应的 endpoint 上。

kubernetes 的整体架构图如下所示:

了解了整体架构图,那么各个组件是如何协同工作的呢。这里以创建 pod 为例查看各组件的协作流程,流程图如下:

主要有如下几步:

  1. 用户调用 REST API 请求创建 pod,APIServer 响应 API 请求,并进行一系列验证操作,包括认证,授权和资源配置等,验证通过后,APIServer 调用 etcd 在后台数据库建立 Pod 资源对象。
  2. scheduler 定期调用 APIServer 的 kubernetes API 接口查看系统中可用的工作节点列表和待调度 Pod,使用调度策略为待调度 Pod 选择合适的工作节点,这个过程称为绑定(bind)。
  3. 绑定成功后,scheduler 调用 APIServer 在 etcd 中创建 binding 对象,该对象描述了工作节点上绑定运行的所有 pod 信息。

1.1 APIServer 概述

APIServer 作为统一接口,负责管理各组件的通信,是 kubernetes 集群的核心。对资源的增删改查操作都将通过 APIServer 传递到后台 etcd 数据库,使用 curl 工具可以很容易的获取到 APIServer 的 API 响应信息。

1.1.1 Kubernetes APIServer 组件

查看环境上运行的 APIServer:

[root@chunqiu ~ (Master)]# kubectl get pods -o wide -n kube-system | grep api
kube-apiserver-chunqiu-0            1/1     Running   1          70d    172.17.66.2     chunqiu-0   <none>           <none>
kube-apiserver-chunqiu-1            1/1     Running   1          70d    172.17.66.3     chunqiu-1   <none>           <none>
kube-apiserver-chunqiu-2            1/1     Running   1          70d    172.17.66.4     chunqiu-2   <none>           <none>

[root@chunqiu ~ (Master)]# kubectl get service -o wide
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes   ClusterIP   10.254.0.1   <none>        443/TCP   70d   <none>

[root@chunqiu ~ (Master)]# kubectl describe service kubernetes
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.254.0.1
Port:              https  443/TCP
TargetPort:        8443/TCP
Endpoints:         172.17.66.2:8443,172.17.66.3:8443,172.17.66.4:8443
Session Affinity:  None
Events:            <none>

当前环境为 master 和工作节点共用模式,可以看到每台节点上都以 pod 形式运行了 APIServer,并且它们与 kubernetes service 进行了绑定。

集群内的 APIServer 部署知道了,那 APIServer 的配置文件又是怎样的呢?查看组件的配置文件能更好的理解组件的整体结构:

[root@chunqiu ~ (Master)]# kubectl describe pods kube-apiserver-chunqiu-0 -n kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Status:               Running
IP:                   172.17.66.2
Containers:
  kube-apiserver:
    Image:         bcmt-registry:5000/k8s.gcr.io/kube-apiserver-amd64:v1.19.5
    Port:          8443/TCP
    Host Port:     8443/TCP
    Command:
      /usr/local/bin/kube-apiserver
      --default-not-ready-toleration-seconds=180
      --default-unreachable-toleration-seconds=180
      --bind-address=172.17.66.2
      --etcd-servers=https://172.17.66.2:2379
      --etcd-cafile=/etc/etcd/ssl/ca.pem
      --etcd-certfile=/etc/etcd/ssl/etcd-client.pem
      --etcd-keyfile=/etc/etcd/ssl/etcd-client-key.pem
      --allow-privileged=true
      --service-cluster-ip-range=10.254.0.0/16
      --secure-port=8443
      --insecure-port=0
      --anonymous-auth=false
      --authorization-mode=Node,RBAC
      --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount...
      --kubelet-certificate-authority=/etc/kubernetes/ssl/ca.pem
      --kubelet-client-certificate=/etc/kubernetes/ssl/cluster-admin.pem
      --kubelet-client-key=/etc/kubernetes/ssl/cluster-admin-key.pem
...

省略了部分参数,主要配置参数及命令如下:

参数 描述
/usr/local/bin/kube-apiserver image 中包含的启动 apiserver 命令
bind-address apiserver 安全端口绑定的 ip 地址,用于接受安全连接
etcd-servers,etcd-cafile,etcd-certfile,etcd-keyfile 访问 etcd 需要的信息
allow-privileged 是否运行容器以特权模式运行
service-cluster-ip-range 绑定 service 的 ip 范围(kubernetes service 的 cluster ip 为 10.254.0.1)
secure-port 安全端口,通过安全 ip 加安全端口的方式可以访问到 apiserver
insecure-port 非安全端口,用于接受非安全连接,0 表示不启用非安全端口
enable-admission-plugins admission controller 的插件
kubelet-certificate-authority,kubelet-client-certificate,kubelet-client-key 访问 apiserver 的认证信息

介绍了 APIServer 配置信息,接下来使用 curl 调用 APIServer API 看看请求结果。

1.1.2 Kubernetes API

为了兼容旧版本的同时升级新版本 API,Kubernetes 提供了多版本 API 的支持,每个版本的 API 通过一个版本号路径前缀进行区分,如 /api/v1beta1 等。通过 kubectl api-version 命令可以查看当前 kubernetes 的版本信息:

[root@chunqiu ~ (Master)]# kubectl api-versions | grep v1
networking.k8s.io/v1
networking.k8s.io/v1beta1
...

可以看到资源 networking 包含不同的 APIVersion,其中 v1beta1 表示不建议使用(Deprecated)版本。关于版本发布及管理信息可看这里

kubernetes 使用 API Groups 对 API 进行标识,API Groups 分为两种:

  1. Core Groups(核心组)是 Kubernetes 最核心的 API,其特点是没有“组”的概念,例如 “v1” 即表示核心组 apiVersion: v1。
  2. 具有分组信息的 API,以 /api/$GROUP_NAME/$VERSION/ URL 路径进行标识,如 apiVersion: apps/v1。
    关于 API 详细信息可参考这里

以 pod 为例,查看 pod 的基本 API 接口:

资源类型 方法 说明 备注
PODS GET /api/v1/pods 获取 pod 列表
POST /api/v1/pods 创建 pod 列表
GET /api/v1/namespaces/{namespace}/pods 获取 Namespace 下的 pod 列表
POST /api/v1/namespaces/{namespace}/pods 在 Namespace 下创建 pod
DELETE /api/v1/namespaces/{namespace}/pods/{name} 删除 Namespace 下的 pod 对象
GET /api/v1/namespaces/{namespace}/pods/{name} 获取 Namespace 下的 pod 对象
PATCH /api/v1/namespaces/{namespace}/pods/{name} 部分更新某个 Namespace 下的 pod 对象
PUT /api/v1/namespaces/{namespace}/pods/{name} 替换某个 Namespace 下的 pod 对象

使用 curl 工具 curl pod 的 API:

[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/namespaces/ci/pods/ --cacert /etc/kubernetes/ssl/ca.pem \\ 
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/ci/pods/",
    "resourceVersion": "42384766"
  },
  "items": [
    {
      "metadata": {
        "name": "chunqiu-0",
        "generateName": "chunqiu-",
        "namespace": "ci",
        "selfLink": "/api/v1/namespaces/ci/pods/chunqiu-0",
        "uid": "36793f0c-9bf9-4bec-b46e-66f5945d3889",
        "resourceVersion": "42378305",
        "creationTimestamp": "2021-06-09T03:18:00Z",
...

curl 获取到 Namespace ci 下的 pod 列表。类似的,获取 apiVersion: apps/v1 的 statefulset 资源列表如下:

[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/apis/apps/v1/namespaces/ci/statefulsets/ --cacert /etc/kubernetes/ssl/ca.pem \\
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
  "kind": "StatefulSetList",
  "apiVersion": "apps/v1",
  "metadata": {
    "selfLink": "/apis/apps/v1/namespaces/ci/statefulsets/",
    "resourceVersion": "42392636"
  },
  "items": [
    {
      "metadata": {
        "name": "chunqiu",
        "namespace": "ci",
        "selfLink": "/apis/apps/v1/namespaces/ci/statefulsets/chunqiu",
        "uid": "0e00ffab-e504-43bf-bcd6-713359a2cfde",
        "resourceVersion": "42392038",
        "generation": 1,
        "creationTimestamp": "2021-06-09T03:40:55Z",
        "labels": {
          "app.kubernetes.io/managed-by": "Helm"
        },
...

对资源对象的操作除了增删改查外,Kubernetes 还提供另外一种资源操作类型 WATCH,WATCH 返回一连串 JSON 对象,该对象记录了某个给定资源对象的变化情况。如对 pod 的 WATCH 操作:

资源类型 类型 方法 URL Path 说明
PODS WATCH GET /api/v1/watch/pods 监听所有 pod 变化
POST /api/v1/watch/namespaces/{namespace}/pods 监听某个 Namespace 下所有 pod 的变化

调用 WATCH API 监听 pod 变化情况:

[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/pods/ --cacert /etc/kubernetes/ssl/ca.pem\\
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1"
...

# 删除 pod
{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"chunqiu-0","generateName":"chunqiu-...
...

可以看到 WATCH API 始终处于监控当前 pod 变化状态,使用 kubectl 删除某个 pod,WATCH API 监听到该 pod 的变化情况。

1.2 etcd 概述

那么 APIServer 介绍完了吗?并没有,离开 etcd 的 APIServer 是不完整的。介绍 etcd 之前,先看下 APIServer 的拓扑结构:

用户请求通过认证授权之后访问 APIServer,APIServer 会进一步调用 admission controller 对用户请求进行进一步资源审核,审核由多维度资源插件完成(APIServer 配置参数的 enable-admission-plugins 参数定义了所需资源审核插件),通过审核后 APIServer 会根据 REST API 调用在后台 etcd 进行实际的增删改查操作。

Kubernetes 的资源存储路径都以 /registry 开始的:

[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem \\
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/ --prefix --keys-only=true
/registry/apiextensions.k8s.io/customresourcedefinitions/brhooks.cbur.csf.chunqiu.com

/registry/apiextensions.k8s.io/customresourcedefinitions/brpolices.cbur.bcmt.local
...

构造场景使用 DELETE 方法删除 pod,查看 etcd 中该 pod 的资源变化情况:

  1. 默认 namespace 下创建 pod,查看 pod 在 etcd 存储情况。
[root@chunqiu ~ (Master)]# kubectl get pods
NAME         READY   STATUS             RESTARTS   AGE
etcdtester   0/1     ImagePullBackOff   0          100s

[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem \\
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/pods/default/etcdtester --prefix --keys-only=true
/registry/pods/default/etcdtester
  1. 开启 WATCH 监听默认 namespace 下 pod 变化情况。
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/namespaces/default/pods/ --cacert /etc/kubernetes/ssl/ca.pem \\
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...

  1. 调用 APIServer 的 DELETE 方法删除 pod,查看 etcd 中 pod 变化情况:
# DELETE pod
[root@chunqiu ~ (Master)]# curl -X DELETE https://172.17.66.2:8443/api/v1/namespaces/default/pods/etcdtester --cacert /etc/kubernetes/ssl/ca.pem \\
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "etcdtester",
    "namespace": "default",
    "selfLink": "/api/v1/namespaces/default/pods/etcdtester",
...

# WATCH 监听 pod
[root@chunqiu ~ (Master)]# curl https://172.17.66.2:8443/api/v1/watch/namespaces/default/pods/ --cacert /etc/kubernetes/ssl/ca.pem \\
--key /etc/kubernetes/ssl/cluster-admin-key.pem --cert /etc/kubernetes/ssl/cluster-admin.pem
{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...

{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"etcdtester"...

# etcd 查看 pod
[root@chunqiu ~ (Master)]# etcdctl --endpoints=https://172.17.66.2:2379 --cacert /etc/etcd/ssl/ca.pem \\
--key /etc/etcd/ssl/etcd-key.pem --cert /etc/etcd/ssl/etcd.pem get /registry/pods/default/etcdtester --prefix --keys-only=true

可以看到,删除 pod 后 WATCH 监听到 pod 变化,etcd 更新 pod 资源对象。

以上是关于Kubernetes APIServer 最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes_HPA实践使用

Kubernetes_HPA实践使用

Kubernetes组件_APIServer_静态Pod网关apiserver的audit审计日志

Kubernetes_16_静态Pod网关apiserver的audit审计日志

爬坑系列之解读kubernetes的认证原理&实践

Kubernetes_15_静态Pod网关apiserver底层的RBAC授权