[源码]spicedb: 源码阅读之第二篇(k8s 部署和运行)

spiceDB 的官网 doc 有教程说明如何在 k8s 上面部署 spiceDB 集群,对于 k8s 新手来说,寥寥无几的几个命令是完全弄不懂这个集群是如何部署的,因此本文主要描述k8s 是如何部署和管理集群的。

curl -v -XGET  -H "Accept: application/json" -H "User-Agent: kubectl/v1.25.2 (darwin/arm64) kubernetes/5835544" 'https://kubernetes.docker.internal:6443/apis/apiextensions.k8s.io/v1/customresourcedefinitions'

部署

Install the Operator with kubectl: kubectl apply –server-side -k github.com/authzed/spicedb-operator/config

两个重要参数:

  • –server-side:当我们使用命令 kubectl apply -f <xxx.yaml> --dry-run 验证yaml 文件是否写错时,这个 yaml 文件默认在本地运行而不将数据送至服务器,但是服务器可能会由于各种原因修改掉 yaml 文件,如果不能将这个对象送至服务器查看其最终的样子,那么用户可能就还是不清楚 apply yaml 文件的时候产生的实际效果是什么
  • -k: 实际上是 –kustomize 的缩写,表示要应用包含 kustomization 文件的目录中的资源,Kustomize 是一个用来定制 Kubernetes 配置的工具,详情参考官网

该命令实际上会使用kustomize工具加载 github 项目 github.com/authzed/spicedb-operator 下的 config 文件夹里的所有 yaml文件,然后拉取镜像运行(authzed/spicedb-operator),并使用 Deployment 来管理该镜像生成的容器。观察 config 文件夹里的目录:

config
├── crds
│   ├── authzed.com_spicedbclusters.yaml
│   └── kustomization.yaml
├── kustomization.yaml
├── operator.yaml
└── rbac
├── kustomization.yaml
├── role.yaml
├── spicedb-operator-edit.yaml
└── spicedb-operator-view.yaml

k8s本身提供的资源(Deployment, ServiceAccount等)就不在此赘述了,下面描述在普通的 k8s 教程里没见到过的Kustomization 和 CustomResourceDefinition

Kustomization

观察到 config 目录下有三个名字一致的文件(kustomization.yaml),这个文件其实是用来管理项目资源的。官网 描述了 Kustomzie 工具的作用,其中一个就是本项目的使用场景:

一种常见的做法是在项目中构造资源集合并将其放到同一个文件或目录中管理。 Kustomize 提供基于不同文件来组织资源并向其应用补丁或者其他定制的能力。Kustomize 支持组合不同的资源。kustomization.yaml 文件的 resources 字段定义配置中要包含的资源列表。 你可以将 resources 列表中的路径设置为资源配置文件的路径。

spiceDB 只是单纯通过 Kustomizie 工具来组织用到的各种 yaml 文件,看 config/kustomization.yaml 文件内容:

# 固定值
apiVersion: kustomize.config.k8s.io/v1beta1
# 固定值
kind: Kustomization
# 表示 k8s 资源的位置,这个可以是一个文件,也可以指向一个文件夹,读取的时候会按照顺序读取,路径可以是相对路径也可以是绝对路径,如果是相对路径那么就是相对于 kustomization.yml的路径
# 注意,resources下的资源文件顺序不管怎么放,kubectl apply -k -f config/ 的时候会自动处理资源依赖问题;如果不是用 kustomize 工具,那么直接 kubectl apply -f config/ 一个文件夹时会按照文件名顺序逐个加载,就可能出现先加载的文件找不到后加载文件的问题
resources:
- crds
- rbac
- operator.yaml
# Kustomize 还提供定制容器镜像或者将其他对象的字段值注入到容器中的能力,并且不需要创建补丁。 例如,可以通过在 kustomization.yaml 文件的 images 字段设置新的镜像来指定/更改容器中使用的镜像
# 此处用于指定 operatory.yaml 的 Deployment 里的 image 使用:ghcr.io/authzed/spicedb-operator:latest
images:
- name: ghcr.io/authzed/spicedb-operator
newTag: latest

使用命令查看将这些资源合并后最终生成的资源

# 查看包含 kustomization 文件的目录中的资源,可以看到生成的资源是按照特定顺序的,首先是 Namespace,然后是 CustomResourceDefiniton...,下面有源码解析
kubectl kustomize config

kubectl get -k config
kubectl describe -k config

# 然后再apply 进去k8s,就表示一次性将整个 config 目录下的所有 yaml 文件都加载到 k8s 里
kubectl apply -k config

# 删除
kubectl delete -k config

查看 kustomzie 的源码,可以看到资源构建的顺序[3]

var orderFirst = []string{
"Namespace",
"ResourceQuota",
"StorageClass",
"CustomResourceDefinition",
"ServiceAccount",
"PodSecurityPolicy",
"Role",
"ClusterRole",
"RoleBinding",
"ClusterRoleBinding",
"ConfigMap",
"Secret",
"Endpoints",
"Service",
"LimitRange",
"PriorityClass",
"PersistentVolume",
"PersistentVolumeClaim",
"Deployment",
"StatefulSet",
"CronJob",
"PodDisruptionBudget",
}
var orderLast = []string{
"MutatingWebhookConfiguration",
"ValidatingWebhookConfiguration",
}

另外提一下,kustomize 还能用于打布丁,管理不同运行环境的配置文件等重要用途。

CustomResourceDefinition

对于文件 config/crds/authzed.com_spicedbclusters.yaml,明显能看到 kind 并不是我们熟知的 k8s 内置资源(Pod,Deployment,ReplicaSet 等),这是因为 spiceDB 使用了 k8s 的自定义资源(CRM, CustomResourceDefinitions)来扩展 k8s 的功能,使用 CRD 可以在不修改 k8s源码的基础上扩展 k8s的功能。

文件路径:https://github.com/authzed/spicedb-operator/tree/main/pkg/crds/authzed.com_spicedbclusters.yaml

挑出 CustomResourceDefinitions 中关键的字段如下:

# CRD本身也是资源,大于1.7.0版本的集群可以使用​​apiextensions.k8s.io/v1beta1API​​访问CRD,大于1.16.0版本则可以使用​​apiextensions.k8s.io/v1API​​
apiVersion: apiextensions.k8s.io/v1
# kind 的值是固定的
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.2
creationTimestamp: null
# 名称必须符合如下格式:<plural>.<group>
name: spicedbclusters.authzed.com
spec:
# 组名称,用于 REST API: /apis/<组>/<版本>
group: authzed.com
names:
categories:
- authzed
# kind 通常是单数形式的驼峰命名(CamelCased)形式。你的资源清单会使用这一形式。
kind: SpiceDBCluster
listKind: SpiceDBClusterList
# 名称的复数形式,用于 URL:/apis/<组>/<版本>/<名称的复数形式>
plural: spicedbclusters
shortNames:
- spicedbs
# 名称的单数形式,作为命令行使用时和显示时的别名
singular: spicedbcluster
scope: Namespaced
versions:
# kubectl get 命令要显示的列有哪些
- additionalPrinterColumns:
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
# 此 CustomResourceDefinition 所支持的版本
name: v1alpha1
schema:
# openAPIV3Schema 是验证自定义对象的模式。
openAPIV3Schema:
description: SpiceDBCluster defines all options for a full SpiceDB cluster
# 定义创建容器的 yaml 文件的全部字段
properties:
apiVersion:
description: '...'
type: string
kind:
description: '...'
type: string
metadata:
type: object
spec:
description: ClusterSpec holds the desired state of the cluster.
properties:
# 重点:spec.config 用来保存 spiceDB 启动时的各种参数
config:
description: Config values to be passed to the cluster
type: object
# 阻止无法识别的字段
x-kubernetes-preserve-unknown-fields: true
# spec.secretName 的值必须是 string 类型
secretName:
description: SecretName points to a secret (in the same namespace)
that holds secret config for the cluster like passwords, credentials,
etc. If the secret is omitted, one will be generated
type: string
type: object
status:
description: ClusterStatus communicates the observed state of the cluster.
properties:
//...
type: object
type: object
# 开启/关闭该API
served: true
# 有且只能有一个版本要将storage设置为true
storage: true
subresources:
status: {}

将该文件 apply 之后,就可以看到该 CRD

kubectl apply -f authzed.com_spicedbclusters.yaml

kubectl get crd
# NAME CREATED AT
# spicedbclusters.authzed.com 2023-07-10T07:08:48Z

将该 CRD apply 之后,这样一个新的受名字空间约束的 RESTful API 端点会被创建在:/apis/authzed.com/v1alpha1/namespaces/*/spicedbclusters/… 今后如果发起对类型为 SpiceDBCluster 的对象的处理,k8s 的 apiserver 就能识别到该对象类型并对此路径发起 restful 请求,转发给对应的CRD controller(需要写一个 controller,即 spicedb-operator)。

接下来继续看官网 doc 是如何创建 SpiceDBCluster 对象的:

kubectl apply --server-side -f - <<EOF
apiVersion: authzed.com/v1alpha1
kind: SpiceDBCluster
metadata:
name: dev
spec:
config:
datastoreEngine: memory
secretName: dev-spicedb-config
---
apiVersion: v1
kind: Secret
metadata:
name: dev-spicedb-config
stringData:
preshared_key: "averysecretpresharedkey"
EOF

执行该命令之后,就能成功创建 SpiceDBCluster 对象并生成容器运行。

从上面创建 SpiceDBCluster 容器的命令来看,甚至没有指明使用哪个镜像,那么容器是怎么被创建出来的呢?其实CRD 只是定义了 SpiceDBCluster 类型,要想真正使用这个类型来创建和管理容器,还需要跟自定义控制器(Controller)结合起来才能真正管理资源。自定义的控制器是通过镜像 spicedb-operator 实现的,详情查看另一篇博文。

引用

[1] Kubernetes 的 Server-Side Apply
[2] kustomize 简明教程
[3] Kubernetes学习(当使用kubectl apply -f 多个资源时,资源创建的顺序是怎么样的)
[4] 使用 CustomResourceDefinition 扩展 Kubernetes API

文章作者: kylinlin
文章链接: https://kylinlingh.github.io/2023/07/19/%E6%BA%90%E7%A0%81-spicedb-%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E4%B9%8B%E7%AC%AC%E4%BA%8C%E7%AF%87-k8s-%E9%83%A8%E7%BD%B2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Water&Melon's Blog