使用 OwnerReference 管理资源父子关系 代码在: https://github.com/tangx/kubebuilder-zero-to-one https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/ 在上一章的代码可以通过如下命令创建一个 redis 实例, 并随即创建一个 Pod 1 ka -f deploy/ 但是在使用如下命令删除 redis 实例时, 虽然命令行界面提示删除成功, 但是创建的 Pod 依旧存在。 1 krm -f deploy/ 其原因是 redis 实例 与 Pod 之间 没有 建立关联关系。 那要如何创建关联关系呢? 可以参考阅读官方博客,……
阅读全文
使用 finalizers 防止资源被删除 代码在: https://github.com/tangx/kubebuilder-zero-to-one 上一章使用了 OwnerReference 关联 redis instance 和所创建的 Pod, 这里的删除是通过 k8s 内置的关系处理器处理的。 https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/ 根据官方博客文档中的阐述, 当一个资源的额 finalizers 没有被清空时, 这个资源将无法被删除。 因此, 本章通过 finalizers 来建立 redis instance 和所创建 pod 的关系, 以及处理删除逻辑 1. 创建 redis instance 与 pod 的关系 在 /controllers/helper/redis_helper.go 通过……
阅读全文
Pod 扩容与缩容 代码在: https://github.com/tangx/kubebuilder-zero-to-one 代码分支越来越多 增/删/改 都有了, 于是选择拆分为 3 个分支。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 扩容 func (r *RedisReconciler) increaseReconcile(ctx context.Context, redis *myappv1.Redis) (ctrl.Result, error) { // ... } // 缩容 func (r *RedisReconciler) decreaseReconcile(ctx context.Context, redis *myappv1.Redis) (ctrl.Result, error) { // ... } // 删除 func (r *RedisReconciler) deleteReconcile(ctx context.Context, redis *myappv1.Redis) (ctrl.Result, error) { // ... } 所谓 扩容/缩容, 在通过 finalizers 管理的时候就是 redis.spec.replicas 与 len(redis.finalizers) 的大小比较。 1 2 3 4 // 缩容 if len(redis.Finalizers) >……
阅读全文
监听 k8s 事件 代码在: https://github.com/tangx/kubebuilder-zero-to-one 之前的代码遗留了一个问题, 当手动通过命令删除 pod 时候, 不会出发 redis.Finalizers 的更新, 也不会重建被删除的 Pod, 实现效果并不好 1 kubectl delete pod pod_name 1. 监听事件 在 /controllers/redis_controller.go 中生成了对象和方法监听 k8s 的事件。 ctrl 创建的 Builder 可以通过 链式 调用方式, 监听多个 k8s 对象的事件。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // SetupWithManager sets up the……
阅读全文
重建被删除的 Pod 代码在: https://github.com/tangx/kubebuilder-zero-to-one 之前遗留了一个问题, 直接用命令行删除的 Pod 不能被重建。 这次就来解决它。 首先来整理之前遗留的问题故障点在哪里? 使用命令 kubectl delete 直接删除 pod 的时候, redis.Finalizers 不会变更, 依旧包含被删除的 pod.Name。 在创建 Pod 的时候, 判断 Pod 是否存在使用的是 redis.Finalizers 提供信息, 而 没有判断 k8s 中真实的情况……
阅读全文
使用 controllerutil 优化代码 代码在: https://github.com/tangx/kubebuilder-zero-to-one 在之前的代码中, 对于 OwnerReference 和 Finalizers 操作我们自己实现了一些方法。 其实这些操作官方已经封好成包了, 开箱即用。 复制 /controllers/helper 保存为 /controllers/helper2。 前者保存手工代码, 后者保存优化代码。 https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil Finalizers 操作 之前 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29……
阅读全文
增加 event 事件支持 代码在: https://github.com/tangx/kubebuilder-zero-to-one k8s 官方 controller 都实现了 Events 消息信息, 如下 1 2 3 4 5 6 7 kubectl describe deployment k8s-operator-demo-controller-manager Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 15m deployment-controller Scaled up replica set k8s-operator-demo-controller-manager-75cc59d8ff to 1 Normal ScalingReplicaSet 14m deployment-controller Scaled down replica set k8s-operator-demo-controller-manager-b9d9f7886 to 0 我们自定义的 Operator 同样可以实现。 operator 支持 event 在 /controllers/redis_controller.go 中定义 RedisReconcile 的时候, 添加 EventRecord 字段。 1 2 3 4 5 6 7 8 // RedisReconciler reconciles a Redis object type RedisReconciler struct { client.Client Scheme *runtime.Scheme // 添加事件 EventRecord record.EventRecorder } 在 /main.go 中, 创……
阅读全文
添加 CRD 对象 Status 状态字段 代码在: https://github.com/tangx/kubebuilder-zero-to-one 添加 kd 状态字段 在 /api/v1/redis_types.go 的 RedisStatus 中添加需要展示的字段。 这里添加一个副本数量。 1 2 3 4 5 type RedisStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file Replicas int `json:"replicas"` } 偷懒, 没有在创建或删除 pod 时进行精细控制。 而是使用 defer 在 Reconcile 退出的时候进行一次最终的赋值管理。 1 2 3 4 5 6 7 8 9 10 11 12 13……
阅读全文
支持 kubectl scale 和 kubectl autoscale 命令 代码在: https://github.com/tangx/kubebuilder-zero-to-one 在 k8s 自定义资源中有关于 scale 和 hpa 的 subresources 字段, 只有这些字段被定义的时候才能支持 scale 和 autoscale 命令 官方定义如下 https://kubernetes.io/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource 在 kubebuilde 中, 使用 //+kubebuilder:subresource:scale 增加注解, 生成对应的配置。 注意, 未知需要在 //+kubebuilder:subresource:status 下方 1 2 3 //+kubebuilder:object:root=true //+kubebuilder:subresource:status //+kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector 三个关键字段: specpath: specReplicasPath 指定定制资源内与 scale.spec.replicas 对应的 JSON 路径。 此字段为 必需值 。 只可以使用 .spec 下的 JSON……
阅读全文
Golang 库: 为什么 Golang slog 库不支持 slog.Fatal API 原文链接: https://tangx.in/posts/2023/01/06/why-dont-golang-slog-support-fatal-api/ 使用 slog 默认不支持 Fatal 如果直接把 slog 当成 log 使用, 会有一点点头疼 1 2 3 4 5 6 7 8 9 10 11 func main() { slog.Debug("debug") slog.Info("info") slog.Warn("warn") slog.Error("err", fmt.Errorf("game over")) // slog.Fatal("don't support") } // 2023/01/06 07:41:50 INFO info // 2023/01/06 07:41:50 WARN warn // 2023/01/06 07:41:50 ERROR err err="game over" slog 默认日志级别 是 info, 无法输出 DEBUG 日志。 需要自定义 handler 实现日志级别判断。 参考 Golang 库: 怎么使用 golang slog 设置日志……
阅读全文