一、前言
在微服务架构中,服务数量众多且状态各异,Kubernetes 自定义资源(Custom Resource)与自定义控制器(Controller)能够让我们扩展 Kubernetes API,将业务需求以原生对象形式管理,从而把复杂运维逻辑内置于集群之中。本文聚焦在 Red Hat Enterprise Linux 8(RHEL 8) 环境下,从零搭建 Kubernetes 自定义资源定义(CRD)与控制器实现,并评估在典型服务器硬件上运行的性能与可维护性。
本文适合具备基础 Kubernetes 与 Linux 使用经验的工程师,A5IDC希望实现业务级 CRD/Controller,将特定微服务生命周期和状态管理固化在 Kubernetes 生态中。
二、方案概览
目标是:
- 在 RHEL 8 上部署 Kubernetes(生产级或开发级均可)
- 使用 Operator SDK / controller-runtime 构建 CRD 与控制器
- 实现一个面向微服务的 CRD(例如 ServiceMeshPolicy)
- 使用 YAML 与 Go 代码示例完成完整生命周期管理
- 评估硬件、调度策略和扩展能力
架构图(逻辑关系简述):
[RHEL8 Nodes] --- kube-apiserver --- etcd --- controllers (Operator)
|
Custom Resource (CRD)
|
Microservices (Deployments / StatefulSets)
三、环境与硬件配置
3.1 香港服务器www.a5idc.com硬件建议
| 项 | 规格建议 | 说明 |
|---|---|---|
| CPU | 8 核(Intel Xeon / AMD EPYC) | Controller 与多个 Pods 负载稳定 |
| 内存 | 32 GB | 支撑 etcd、K8s 控制平面与服务 |
| 存储 | 1 TB NVMe | 高 IOPS 保证 etcd 性能 |
| 网络 | 10 Gbps | Nodes 之间低延迟网络 |
| 操作系统 | RHEL 8.8 | 支持 Podman / CRI-O / Docker |
3.2 Kubernetes 安装基础
本文采用 kubeadm 安装 Kubernetes v1.27(支持最新 API 特性)。
在每台节点上:
bash
# 关闭 Swap
swapoff -a
# 安装 kubeadm, kubelet, kubectl
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
yum install -y kubeadm-1.27.3 kubelet-1.27.3 kubectl-1.27.3
systemctl enable --now kubelet
初始化 Master 节点:
bash
kubeadm init --kubernetes-version=v1.27.3 \
--pod-network-cidr=10.244.0.0/16
网络插件选择 Canal 或 Calico 以支持 NetworkPolicy。以 Calico 为例:
bash
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
四、设计自定义资源(CRD)
4.1 需求分析
我们希望定义一个 CRD:ServiceMeshPolicy,用于对微服务侧车(Sidecar)部署、路由规则及限流策略管理。
目标字段:
-
serviceName: 微服务名
-
meshEnabled: 是否启用服务网格
-
trafficPolicy:
- retries
- timeout
- circuitBreaker
4.2 CRD YAML 示例
文件:servicemeshpolicy_crd.yaml
yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: servicemeshpolicies.example.com
spec:
group: example.com
versions:
- name: v1alpha1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
serviceName:
type: string
meshEnabled:
type: boolean
trafficPolicy:
type: object
properties:
retries:
type: integer
timeout:
type: string
circuitBreaker:
type: object
properties:
maxConnections:
type: integer
maxPendingRequests:
type: integer
subresources:
status: {}
scope: Namespaced
names:
plural: servicemeshpolicies
singular: servicemeshpolicy
kind: ServiceMeshPolicy
shortNames:
- smp
应用 CRD:
bash
kubectl apply -f servicemeshpolicy_crd.yaml
确认:
bash
kubectl get crd
五、编写控制器(Controller)
控制器负责监听 CR 对象变动,并对相应微服务对象(Deployment / ConfigMap / Sidecar 注入)执行自动调整。
5.1 使用 Operator SDK
安装 Operator SDK(v1.30+ 支持 Go Modules):
bash
go install github.com/operator-framework/operator-sdk@latest
创建项目:
bash
operator-sdk init --domain example.com --repo github.com/example/smp-controller
cd smp-controller
operator-sdk create api --group example --version v1alpha1 --kind ServiceMeshPolicy --resource --controller
5.2 核心 Reconcile 逻辑(Go 代码)
编辑 controllers/servicemeshpolicy_controller.go:
go
func (r *ServiceMeshPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := r.Log.WithValues("servicemeshpolicy", req.NamespacedName)
var smp examplev1alpha1.ServiceMeshPolicy
if err := r.Get(ctx, req.NamespacedName, &smp); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// 获取目标 Deployment
var deploy appsv1.Deployment
if err := r.Get(ctx, types.NamespacedName{Name: smp.Spec.ServiceName, Namespace: req.Namespace}, &deploy); err != nil {
log.Error(err, "Deployment not found")
return ctrl.Result{RequeueAfter: time.Minute}, nil
}
// 根据 CR Spec 更新 Deployment 注解
patch := client.MergeFrom(deploy.DeepCopy())
if smp.Spec.MeshEnabled {
if deploy.Spec.Template.ObjectMeta.Annotations == nil {
deploy.Spec.Template.ObjectMeta.Annotations = map[string]string{}
}
deploy.Spec.Template.ObjectMeta.Annotations["sidecar.istio.io/inject"] = "true"
} else {
delete(deploy.Spec.Template.ObjectMeta.Annotations, "sidecar.istio.io/inject")
}
if err := r.Patch(ctx, &deploy, patch); err != nil {
log.Error(err, "Failed to patch Deployment")
}
// 处理 TrafficPolicy ConfigMap
cmName := fmt.Sprintf("%s-traffic", smp.Name)
var cm corev1.ConfigMap
cmData := map[string]string{
"retries": strconv.Itoa(int(smp.Spec.TrafficPolicy.Retries)),
"timeout": smp.Spec.TrafficPolicy.Timeout,
}
cm = corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Name: cmName, Namespace: req.Namespace},
Data: cmData,
}
r.Client.Create(ctx, &cm)
return ctrl.Result{}, nil
}
注册 Controller:
go
func (r *ServiceMeshPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&examplev1alpha1.ServiceMeshPolicy{}).
Complete(r)
}
构建与部署:
bash
make docker-build docker-push IMG=registry.example.com/smp-controller:v0.1.0
kubectl apply -f config/manager/manager.yaml
六、示例 CR 对象与验证
6.1 示例 CR
yaml
apiVersion: example.com/v1alpha1
kind: ServiceMeshPolicy
metadata:
name: order-service-policy
spec:
serviceName: order-service
meshEnabled: true
trafficPolicy:
retries: 3
timeout: "5s"
circuitBreaker:
maxConnections: 100
maxPendingRequests: 50
应用 CR:
bash
kubectl apply -f example_smp.yaml
检查 Deployment 注解:
bash
kubectl describe deploy order-service | grep sidecar
检查 ConfigMap:
bash
kubectl get cm order-service-policy-traffic -o yaml
七、性能与行为评估
7.1 评估指标
| 指标 | 描述 | 理想值 |
|---|---|---|
| 控制器延迟 | 事件变更到执行时间 | < 500ms |
| CRD 查询负载 | API Server QPS | < 100 QPS |
| 资源稳定性 | Deployment 更新成功率 | 100% |
| 网络策略生效 | Sidecar 注入与路由更新 | 符合预期 |
7.2 压力测试方法
- 使用
kubectl apply -f批量创建 100 个 CR - 监控 Controller 日志和事件
- 使用 Prometheus 监控 API Server QPS/Latency
八、常见问题与优化建议
8.1 控制器重复执行
- 确保 Reconcile 处理幂等性
- 合理使用 Patch 而不是 Update
8.2 内存泄露
- 使用 context WithTimeout
- 避免长时间未关闭的子协程
8.3 资源命名规范
- 避免 Name 冲突
- 使用 Namespace 隔离
九、总结
通过本文步骤,你已经成功:
- 在 RHEL 8 环境搭建 Kubernetes
- 设计并应用 CRD(ServiceMeshPolicy)
- 使用 Operator SDK 编写 Controller
- 实现在微服务架构中对服务网格策略的集中化控制
这种方案适用于大型微服务团队,把业务策略从外部工具纳入 Kubernetes 控制闭环,提高一致性与自动化程度。A5数据认为未来还可以引入 Webhook 验证、状态回报机制以及更先进的策略引擎(如 Open Policy Agent)继续扩展。