首页
/ Kubernetes sample-apiserver 实战:在 Minikube 上构建并部署一个扩展 API Server

Kubernetes sample-apiserver 实战:在 Minikube 上构建并部署一个扩展 API Server

2026-09-07 14:08:42作者:姚月梅Lane

本文以 Kubernetes 仓库中 staging/src/k8s.io/sample-apiserver 自带的官方指南 minikube-walkthrough.md 为主线,完整还原“从零开始把示例 API Server 跑起来”的全过程:构建二进制、制作并推送容器镜像、修改 Deployment、创建 RBAC 与 APIService 对象,最终用 kubectl 操作 Flunder 这一自定义资源。读完并动手之后,你将掌握 Kubernetes API 聚合(API Aggregation)模式下扩展 API Server 的完整部署链路,并能对照仓库源码理解每个部署对象存在的意义。

前置条件

指南列出的前置条件如下,全部满足后即可开始:

  • 已安装并配置好 Go(文档要求 Go 1.7.x 或更高版本,参考 Go 官方安装文档即可);
  • 拥有 Docker Hub 账号,用于推送构建出来的镜像;
  • 已安装 Minikube——一个运行在本地机器上的单节点 Kubernetes 集群,按其官方安装指南对号入座即可;
  • 已安装 kubectl(部署阶段会用到,参见 Kubernetes 官方工具安装文档)。

关于代码获取方式的补充:当前仓库就是 Kubernetes 单体仓库,sample-apiserver 的完整源码已经位于 staging/src/k8s.io/sample-apiserver。其 README.md 明确指出该目录是独立仓库 kubernetes/sample-apiserver 的 staging 同步源头——独立仓库由这里的代码自动发布,因此直接在本地仓库中操作即可,无需额外克隆。

这个 Demo 到底在演示什么

在动手前先用一句话界定范围:sample-apiserver 演示了如何使用 k8s.io/apiserver 库构建一个功能完整的 Kubernetes 风格 API Server,既可以作为 API 聚合(Aggregation)下的扩展 API Server 挂载到主 kube-apiserver,也可以独立运行。其 README.md 同时给出了选型建议:如果只是往集群里加一种资源,优先考虑 CRD(代码量和维护成本更低);只有确实需要自定义鉴权、准入、存储行为时才需要写扩展 API Server。

本 Demo 注册的 API 组是 wardle.example.com,版本为 v1alpha1,提供 Flunder(以及从生成的 clientset/informers 目录结构看,还有 Fischer)等资源类型。部署成功后,kubectl 就可以像操作内置资源一样操作 flunder

第 1 步:构建 sample-apiserver 二进制

要构建镜像,先得有二进制。在仓库根目录(即 main.go 所在目录,本仓库中为 staging/src/k8s.io/sample-apiserver)执行:

export GOOS=linux; go build .

如果一切顺利,当前目录下会出现一个名为 sample-apiserver 的二进制文件(Go 的模块名为 k8s.io/sample-apiserver,见 go.modgo build 默认以模块名作为输出二进制名)。

从源码看这个二进制的入口非常薄:main.go 仅做三件事——

ctx := genericapiserver.SetupSignalContext()
options := server.NewWardleServerOptions(os.Stdout, os.Stderr)
cmd := server.NewCommandStartWardleServer(ctx, options, false)
code := cli.Run(cmd)

它依赖 k8s.io/apiserver/pkg/server(generic apiserver 框架)创建信号上下文,然后由 pkg/cmd/server/start.go 构建 WardleServerOptions 与启动命令,真正的服务端装配逻辑位于 pkg/apiserver/apiserver.go。也就是说,一个“API Server”的核心就是:generic apiserver 框架 + 自己声明的 API 类型 + 存储/注册逻辑。

构建细节提示:README.md 给出的更严格的构建命令是 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o artifacts/simple-image/kube-sample-apiserver,直接产出 Dockerfile 所需的二进制。另外,如果你修改了 pkg/apis/.../types.go 中的类型定义,需要运行 hack/update-codegen.sh 重新生成代码。

第 2 步:构建并推送容器镜像

指南使用 artifacts/simple-image/Dockerfile 来打镜像。这个 Dockerfile 极其精简,只有三行有效指令:

FROM fedora
ADD kube-sample-apiserver /
ENTRYPOINT ["/kube-sample-apiserver"]

即以 fedora 为基底,把上一步构建的二进制重命名为 kube-sample-apiserver 放进镜像根目录并作为入口。因此构建镜像前需要先把二进制拷贝到位,然后从仓库根目录执行:

cp ./sample-apiserver ./artifacts/simple-image/kube-sample-apiserver
docker build -t <YOUR_DOCKERHUB_USER>/kube-sample-apiserver:latest ./artifacts/simple-image
docker push <YOUR_DOCKERHUB_USER>/kube-sample-apiserver

其中 <YOUR_DOCKERHUB_USER> 替换为你的 Docker Hub 用户名,镜像会被推送到你的个人仓库,供集群拉取。

替代方案:deployment.yaml 的注释中给出了现成测试镜像 registry.k8s.io/e2e-test-images/sample-apiserver:1.17.4,可以 docker pulldocker tagkube-sample-apiserver:latest,跳过自行构建的步骤(该方式依赖集群节点可访问该镜像仓库,Minikube 场景下配合 imagePullPolicy: Never 使用)。

第 3 步:修改 Deployment 的镜像与拉取策略

原文指南的这一步标题仍写作 “Modify the replication controller”,但当前仓库中 artifacts/example/deployment.yaml 实际是一个 apps/v1 的 Deployment(名为 wardle-server)。需要修改两处:

  1. imagePullPolicyNever 改为 AlwaysIfNotPresent
  2. imagekube-sample-apiserver:latest 改为你推送的 <YOUR_DOCKERHUB_USER>/kube-sample-apiserver:latest

修改后的关键片段:

...
      containers:
      - name: wardle-server
        image: <YOUR_DOCKERHUB_USER>/kube-sample-apiserver:latest
        imagePullPolicy: Always
...

理解这个 Pod 的完整结构有助于排障,deployment.yaml 中每个容器/参数都各司其职:

    spec:
      serviceAccountName: apiserver
      containers:
      - name: wardle-server
        image: kube-sample-apiserver:latest
        imagePullPolicy: Never
        args: [ "--etcd-servers=http://localhost:2379" ]
      - name: etcd
        image: registry.k8s.io/etcd:v3.7.0
  • serviceAccountName: apiserver:绑定后面创建的 ServiceAccount,用于委托鉴权;
  • --etcd-servers=http://localhost:2379:apiserver 的存储指向 localhost:2379,而 etcd 作为同 Pod 内的 sidecar 容器一起运行——这就是整个 Demo 不需要外部 etcd 集群的原因,也是它能在单节点 Minikube 上跑通的关键设计;
  • 注意 imagePullPolicy: Never 是仓库默认值(面向预加载镜像的 CI 场景),在 Minikube 上使用自建镜像时必须按上文修改。

第 4 步:部署到 Minikube

指南给出了一组完整的 kubectl 命令,这里完整保留,并逐条说明每个对象的用途(所有 YAML 均位于 artifacts/example/ 目录):

# create the namespace to run the apiserver in
kubectl create ns wardle

# create the service account used to run the server
kubectl create -f artifacts/example/sa.yaml -n wardle

# create the rolebindings that allow the service account user to delegate authz back to the kubernetes master for incoming requests to the apiserver
kubectl create -f artifacts/example/auth-delegator.yaml -n kube-system
kubectl create -f artifacts/example/auth-reader.yaml -n kube-system

# create rbac roles and clusterrolebinding that allow the service account user to use admission webhooks
kubectl create -f artifacts/example/rbac.yaml
kubectl create -f artifacts/example/rbac-bind.yaml

# create the service and replication controller
kubectl create -f artifacts/example/deployment.yaml -n wardle
kubectl create -f artifacts/example/service.yaml -n wardle

# create the apiservice object that tells kubernetes about your api extension and where in the cluster the server is located
kubectl create -f artifacts/example/apiservice.yaml

逐个对象拆解:

命名空间与 ServiceAccount

ns.yaml 定义 wardle 命名空间(上面用 kubectl create ns 等价创建);sa.yaml 在其中创建名为 apiserver 的 ServiceAccount,Deployment 通过 serviceAccountName: apiserver 引用它。

委托鉴权(Delegated Authn/Authz)

扩展 API Server 并不自己做用户身份识别,而是把请求“委托”回主 kube-apiserver。这由两个绑定文件实现:

  • auth-delegator.yaml:把内置的 system:auth-delegator ClusterRole 绑定给 wardle/apiserver SA,允许它调用主 API Server 的 TokenReview/SubjectAccessReview 机制完成委托鉴权与鉴权;
  • auth-reader.yaml:在 kube-system 命名空间把 extension-apiserver-authentication-reader Role 绑定给该 SA,允许其读取 extension-apiserver-authentication ConfigMap(包含主 API Server 的 requestheader CA 等委托所需配置)。

这正是指南中“allow the service account user to delegate authz back to the kubernetes master for incoming requests”的含义。

聚合 API Server 自身需要的 RBAC

  • rbac.yaml 定义 ClusterRole aggregated-apiserver-clusterrole,授予三类权限:对核心组 namespacesget/watch/list、对 admissionregistration.k8s.io 下 mutating/validating webhook 配置及 ValidatingAdmissionPolicy 的 get/watch/list、对 flowcontrol.apiserver.k8s.ioprioritylevelconfigurationsflowschemaslist/watch
  • rbac-bind.yaml 通过 ClusterRoleBinding sample-apiserver-clusterrolebinding 将该角色授予 wardle/apiserver SA。

这些权限是 generic apiserver 框架在运行期拉取 admission webhook 配置、APF 流控配置和 namespace 信息所必需的(见指南注释 “allow the service account user to use admission webhooks”)。

Service 与 APIService——聚合接入的最后一块拼图

  • service.yaml:创建名为 api 的 Service(wardle 命名空间,443 端口,selector 为 apiserver: "true",与 Deployment 的标签对应),作为集群内访问扩展 API Server 的入口;
  • apiservice.yaml:创建 apiregistration.k8s.io/v1 的 APIService 对象,告诉主 API Server “wardle.example.comv1alpha1 版本的路由转发到 wardle/api 这个 Service”:
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1alpha1.wardle.example.com
spec:
  insecureSkipTLSVerify: true
  group: wardle.example.com
  groupPriorityMinimum: 1000
  versionPriority: 15
  service:
    name: api
    namespace: wardle
  version: v1alpha1

其中 groupPriorityMinimum/versionPriority 用于多版本共存时的优先级仲裁,insecureSkipTLSVerify: true 是因为 Demo 使用自签证书。

批量部署的等价写法:README.md 的 “Deploy into a Kubernetes Cluster” 一节给出了更省事的方式——修改好 deployment.yaml 的镜像后直接 kubectl apply -f artifacts/example,一次性应用整个目录下的示例对象。

第 5 步:验证部署

APIService 就绪后,主 API Server 就会把 /apis/wardle.example.com/v1alpha1/... 下的请求转发到你的 wardle-server Pod。按指南验证——创建资源:

kubectl create -f artifacts/flunders/01-flunder.yaml
# outputs flunder "my-first-flunder" created

01-flunder.yaml 的内容:

apiVersion: wardle.example.com/v1alpha1
kind: Flunder
metadata:
  name: my-first-flunder
  labels:
    sample-label: "true"

然后查询它:

kubectl get flunder my-first-flunder

#outputs
# NAME               KIND
# my-first-flunder   Flunder.v1alpha1.wardle.example.com

如果能看到 my-first-flunderFlunder.v1alpha1.wardle.example.com,说明从 kubectl → kube-apiserver(发现 APIService)→ Service wardle/apiwardle-server 容器 → 同 Pod etcd 存储的整条链路已经打通。此时 kubectl get 的 KIND 列也直观体现了版本化的 API 命名规则:<Kind>.<version>.<group>

延伸阅读:仓库内可以继续深挖的位置

minikube-walkthrough.md 的五个步骤顺序执行,配合上述源码路径逐层对照,即可完整理解 Kubernetes 扩展 API Server 从构建到聚合接入的每个环节。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389