当前位置: 首页 > news >正文

Kubernetes服务注册到consul流程实践


文章目录

  • 前言
  • 架构图示意
  • 一、环境准备
  • 二、consul部署
    • 1.yaml示例
    • 2.consul部署验证
  • 三、consulctl工具实现
    • 1.核心功能
    • 2.注册到consul的标签及元数据
    • 3.consulctl工具使用示例
  • 四、通过Dockerfile构建consulctl工具镜像
  • 五、Kubernetes集成方案
  • 六、 结果验证
    • 1.注册验证
    • 2.销毁验证
  • 总结
    • 物来顺应,未来不迎,当时不杂,既过不恋


前言

在云原生架构中,服务注册与发现是微服务架构的核心组件之一。随着Kubernetes成为容器编排的事实标准,如何将传统服务注册中心与Kubernetes原生服务发现机制相结合,成为企业级应用面临的重要课题。本文详细介绍如何利用HashiCorp Consul实现Kubernetes服务的自动注册与发现,通过开发定制化工具解决实际生产环境中的服务治理难题,并结合Prometheus实现监控


目的: 通过开发一个轻量级的 consulctl 工具,配合Kubernetes的生命周期钩子preStop函数+sidecar边车容器实现pod启动时自动注册到consul、pod销毁时自动从consul剔除

架构图示意

在这里插入图片描述

一、环境准备

名称作用
k8s1.28集群用于部署consul及测试pod
docker镜像构建
harbor镜像存储

二、consul部署

以NFS为底层存储,通过storageclass实现consul的动态pv

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: consul-storage #要与statefulset文件中的名称一致
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:archiveOnDelete: "true"
reclaimPolicy: Retai

1.yaml示例

如下(示例):consul开启ACL token,避免后续未授权登录漏洞

生成一个64位字符串用做于consul的master token

[root@k8s-master consul]# uuidgen
9bfbe81f-2648-4673-af14-d13e0a170050

准备consul的配置文件,开启acl、配置token,生成configmap

[root@k8s-master consul]# cat consul-config.json 
{"datacenter":"dc8","primary_datacenter":"dc8","acl":{"enabled":true, #开启ACL"default_policy":"deny","enable_token_persistence":true,"enable_key_list_policy":true,"tokens":{"master":"9bfbe81f-2648-4673-af14-d13e0a170050" #上述生成}}
}[root@k8s-master consul]# kubectl create configmap global-config -n middleware --from-file ./consul-config.json

statefulset文件

apiVersion: apps/v1
kind: StatefulSet
metadata:name: consulnamespace: middleware
spec:serviceName: consul-serverreplicas: 1selector:  # 新增selector部分matchLabels:component: consul  # 必须与template.metadata.labels中的标签匹配template:metadata:labels:component: consul  # 这里已经正确设置spec:tolerations:  # 新增污点容忍- key: "node-role.kubernetes.io/control-plane"operator: "Exists"effect: "NoSchedule"affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:  # 改为软性要求- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: componentoperator: Invalues:- consultopologyKey: kubernetes.io/hostnamecontainers:- name: consulimage: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/hashicorp/consul:latestargs:- "agent"- "-server"- "-bootstrap-expect=1" #此处的数量要与副本数相同- "-ui"- "-data-dir=/etc/consul/data"- "-config-file=/etc/consul/config/consul-config.json"- "-bind=0.0.0.0"- "-client=0.0.0.0"- "-advertise=$(PODIP)"- "-retry-join=consul-server.$(NAMESPACE).svc.cluster.local" - "-domain=cluster.local"- "-disable-host-node-id"livenessProbe:httpGet:path: /v1/status/leaderport: 8500initialDelaySeconds: 20  # Consul启动较慢需要更长的初始延迟periodSeconds: 20failureThreshold: 3readinessProbe:httpGet:path: /v1/status/peersport: 8500initialDelaySeconds: 15periodSeconds: 5successThreshold: 1failureThreshold: 2resources:requests:memory: "256Mi"cpu: "100m"limits:memory: "512Mi"cpu: "500m"volumeMounts:- name: datamountPath: /etc/consul/data- name: configmountPath: /etc/consul/config- name: timemountPath: /etc/localtimeenv:- name: PODIPvalueFrom:fieldRef:fieldPath: status.podIP- name: NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespaceports:- containerPort: 8500name: ui-port- containerPort: 8400name: alt-port- containerPort: 53name: udp-port- containerPort: 8443name: https-port- containerPort: 8080name: http-port- containerPort: 8301name: serflan- containerPort: 8302name: serfwan- containerPort: 8600name: consuldns- containerPort: 8300name: servervolumes:- name: configconfigMap:name: consul- name: timehostPath:path: /usr/share/zoneinfo/Asia/Shanghai#- name: data#emptyDir: {}volumeClaimTemplates:  # 持久化存储声明模板- metadata:name: dataspec:accessModes: [ "ReadWriteOnce" ]storageClassName: "consul-storage"  # 根据实际存储类调整resources:requests:storage: 1Gi #自行调整

无头service文件和nodeport类型的svc文件

apiVersion: v1
kind: Service
metadata:name: consul-server  # 必须与 StatefulSet 的 serviceName 一致namespace: middleware
spec:clusterIP: None  # Headless Service 特征ports:- port: 8300name: server-rpcselector:component: consul  # 匹配 Pod 标签
---
apiVersion: v1
kind: Service
metadata:name: consul-uinamespace: middlewarelabels:component: consul
spec:type: NodePortports:- name: httpport: 8500targetPort: 8500nodePort: 30850  # 自定义端口范围 30000-32767selector:component: consul  # 必须匹配 StatefulSet 的 Pod 标签

2.consul部署验证

代码如下(示例):

[root@k8s-master consul]# kubectl get pod,svc -n middleware 
NAME           READY   STATUS    RESTARTS   AGE
pod/consul-0   1/1     Running   0          11mNAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/consul-server   ClusterIP   None           <none>        8300/TCP         46h
service/consul-ui       NodePort    10.96.23.206   <none>        8500:30850/TCP   46h

访问验证
在这里插入图片描述

三、consulctl工具实现

1.核心功能

使用golang 调用consul包"github.com/hashicorp/consul/api" 实现pod的注册和销毁
注册逻辑包含以下关键步骤:1. 解析Pod环境变量(名称、IP、命名空间)2. 构造service名称 (采用pod所在的名称空间)3. 构造服务ID(采用 <pod-name>-<port> 格式)4. 添加丰富的元数据(监控类型、所属项目等)5. 调用Consul API完成注册
采用双重注销机制确保可靠性:1. 当执行delete pod或者delete -f xxx.yaml时 优先通过Agent接口注销2. 失败后尝试Catalog接口注销3. 收集所有错误信息统一处理
//核心功能定义
type ServiceManager struct {client *api.Client
}func NewServiceManager(consulAddr, token string) (*ServiceManager, error) {config := api.DefaultConfig()config.Address = strings.TrimSpace(consulAddr)config.Token = strings.TrimSpace(token)config.Transport.TLSHandshakeTimeout = defaultTimeoutclient, err := api.NewClient(config)if err != nil {return nil, fmt.Errorf("consul client init failed: %w", err)}return &ServiceManager{client: client}, nil
}func (sm *ServiceManager) Register(service *api.AgentServiceRegistration) error {return sm.client.Agent().ServiceRegister(service)
}func (sm *ServiceManager) Deregister(serviceID string) error {return sm.client.Agent().ServiceDeregister(serviceID)
}

2.注册到consul的标签及元数据

pod注册到consul中后tag是container和对应的pod名称,元数据标签包含pod名称、podIP、端口、所在节点名称、监控类型、标题

Tags: []string{"container",podName,},
Meta: map[string]string{"podName":     podName,"podIP":       podIP,"podPort":     port,"hostNode":    hostNode,"monitorType": monitorType,"project":     project,
}

3.consulctl工具使用示例

注册

[root@k8s-master consul]# ./consulctl register "http://consulIP:consulPort" "consul的ACL TOKEN" "微服务的容器端口" "monitorType(自行命名)" "project(自行命名)"

销毁

[root@k8s-master consul]# ./consulctl deregister "http://consulIP:consulPort" "consul的ACL TOKEN" "微服务的容器端口" "consul的节点名称(理解为conusl的pod名称)"

四、通过Dockerfile构建consulctl工具镜像

结合golang多阶段构建

FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/golang:1.23.7 AS builder
WORKDIR /app
COPY go.mod go.sum ./
COPY vendor  ./
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -mod=vendor -o /usr/local/bin/consulctlFROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/alpine:3.18.6
WORKDIR /usr/local/bin/
COPY --from=builder /usr/local/bin/consulctl /usr/local/bin/
ENTRYPOINT ["consulctl"]

通过docker构建并保存为tar文件

[root@k8s-master consul]# docker build -t pod_registry:v1.0 .
[root@k8s-master consul]# docker save -o pod_registry_v1.tar.gz pod_registry:v1.0

通过containerd的ctr命令将其导入到harbor中

#导入
[root@k8s-master consul]# ctr image import pod_registry_v1.tar.gz#替换标签
[root@k8s-master consul]# ctr image tag docker.io/library/pod_registry:v1 harbor.ops.local/registry/pod_registry:v1.0#推送到harbor仓库
[root@k8s-master consul]# ctr image push harbor.ops.local/registry/pod_registry:v1.0 --user admin:"xxxx" -k

五、Kubernetes集成方案

以k8s部署minio为例,修改对应的yaml文件,实现minio pod启动时将其注册到consul

文件如下所示 :只演示关键部分添加

global-config名称的configamap准备

apiVersion: v1
kind: ConfigMap
metadata:name: global-confignamespace: middleware  # 与微服务同命名空间
data:CONSUL_IP: "consul-server.middleware.svc.cluster.local:8500"  # Consul服务DNS名称

acl-token secretyaml准备

apiVersion: v1
kind: Secret
metadata:name: acl-tokennamespace: middleware
type: Opaque
data:ACL_TOKEN: OWJmYmU4MWYtMjY0OC00NjczLWFmMTQtZDEzZTBhMTcwMDUwCg==  #上述64位字符串进行base64加密

共享卷使用--使initContainer中的consulctl命令能在container中使用

关键设计点:1. 使用initContainer完成注册2. 通过共享卷将工具拷贝到业务容器3. 支持Consul节点参数动态配置和动态获取Consul服务地址和ACL令牌
      initContainers:- name: service-registrarimage: harbor.ops.local/registry/pod_registry:v1.0 #consulctl工具镜像env:- name: POD_NAME #获取pod名称,用于注册到consul中显示valueFrom:fieldRef:fieldPath: metadata.name- name: POD_NAMESPACE  #用于将注册到consul的pod以自身的名称空间为目录valueFrom:fieldRef:fieldPath: metadata.namespace- name: POD_IP #用于consul中meta元数据展示valueFrom:fieldRef:fieldPath: status.podIP- name: CONSUL_IP #用于注册时连接consulvalueFrom:configMapKeyRef:name: global-config #与上述configmap名称一致key: CONSUL_IP- name: ACL_TOKEN #用于注册时登录consulvalueFrom:secretKeyRef:name: acl-token #与上述secret名称一致key: ACL_TOKEN - name: NODE_NAME  #用于consul中meta元数据展示valueFrom: fieldRef:fieldPath: spec.nodeNamevolumeMounts:- mountPath: /shared-bin  # 共享卷 /shared-bin目录 挂载到 Container,使其也能使用这个工具,不用再次封装minio镜像name: shared-bincommand: ["sh", "-c"]args:- |cp /usr/local/bin/consulctl /shared-bin/ &&/usr/local/bin/consulctl register \"$CONSUL_IP" \"$ACL_TOKEN" \"9000" \    #微服务pod端口"容器监控" \ #自定义"k8s"       #自定义

preStop钩子函数

通过preStop钩子确保:1. 服务注销先于Pod终止2. 设置terminationGracePeriodSeconds为60秒3. 支持Consul节点参数动态配置和动态获取Consul服务地址和ACL令牌
.....containers:- env:- name: CONSUL_IP  # 必须显式声明valueFrom:configMapKeyRef:name: global-configkey: CONSUL_IP- name: ACL_TOKEN  # 必须显式声明valueFrom:secretKeyRef:name: acl-tokenkey: ACL_TOKEN- name: CONSUL_NODE_NAME #根据自己的consul名称替换value: "consul-0"- name: POD_NAMEvalueFrom:fieldRef:fieldPath: metadata.nameimage: harbor.jdicity.local/registry/minio:latestlifecycle:preStop:exec:command: ["sh", "-c", "/usr/local/bin/consulctl deregister $CONSUL_IP $ACL_TOKEN 9000(根据实际微服务端口进行替换) $CONSUL_NODE_NAME"]volumeMounts:- mountPath: /usr/local/bin/consulctl  # 挂载到 minio 容器的 PATH 目录name: shared-binsubPath: consulctlvolumes:- name: shared-bin  # 共享卷emptyDir: {}

六、 结果验证

1.注册验证

在这里插入图片描述

创建minio,查看conusl ui中是否已经按要求注册到minio pod

[root@k8s-master consul]# kubectl apply -f sts_minio.yaml[root@k8s-master consul]# kubectl get pod -n middleware  -owide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE                       NOMINATED NODE   READINESS GATES
minio-0    1/1     Running   0          52s   10.244.1.63    k8s-node.ops.local     <none>           <none>
minio-1    1/1     Running   0          52s   10.244.0.113   k8s-master.ops.local   <none>           <none>#查看sidecar边车容器日志 提示注册成功
[root@k8s-master consul]# kubectl logs -f -n middleware minio-0 service-registrar 
/usr/local/bin/consulctl
register
consul-server.middleware.svc.cluster.local:8500
9bfbe81f-2648-4673-af14-d13e0a1700509000
容器监控
k8s
Service registered successfully

在这里插入图片描述
在这里插入图片描述

2.销毁验证

现在模拟删除一个minio-0 pod,看新pod是否会注册

[root@k8s-master consul]# kubectl delete pod -n middleware  minio-0
pod "minio-0" deleted
[root@k8s-master consul]# kubectl get pod -n middleware  -owide
NAME       READY   STATUS    RESTARTS   AGE     IP             NODE                  NOMINATED NODE   READINESS GATES
minio-0    1/1     Running   0          18s     10.244.1.64    k8s-node.ops.local     <none>           <none>
minio-1    1/1     Running   0          8m44s   10.244.0.113   k8s-master.ops.local   <none>           <none>

在这里插入图片描述
在这里插入图片描述
现在模拟删除一个minio的statefulset yml文件,看pod是否会被剔除

[root@k8s-master consul]# kubectl delete -f sts_minio.yml 
service "minio-svc" deleted
secret "minio-secret" deleted
statefulset.apps "minio" deleted

在这里插入图片描述

至此pod在consul中的注册/销毁功能已全部演示完成,目前已接入维护的项目中,需要工具留言即可


总结

物来顺应,未来不迎,当时不杂,既过不恋

曾国藩的这十六字箴言意思是,凡事要顺其自然,坦然面对,活在当下,不过度担忧未来还未发生的事,要心无杂念地做好眼前的事,不要去留恋和纠结发生过的事。这些处世原则可以帮助我们更好地应对生活的挑战,也让我们拥有更为丰富、充实和幸福的人生。希望各位亦是如此!!!


http://www.mrgr.cn/news/98266.html

相关文章:

  • ArkTS语言入门之接口、泛型、空安全、特殊运算符等
  • vulkanscenegraph显示倾斜模型(5.9)-vsg中vulkan资源的编译
  • 基于PySide6与pycatia的CATIA绘图比例智能调节工具开发全解析
  • 入门到精通,C语言十大经典程序
  • 从0到1使用C++操作MSXML
  • C语言十大经典数学应用
  • 考研单词笔记 2025.04.13
  • 【甲子光年】DeepSeek开启AI算法变革元年
  • Go:方法
  • 【随身wifi】青龙面板保姆级教程
  • C语言的发展史
  • cursor+高德MCP:制作一份旅游攻略
  • 2025蓝桥杯C++ A组省赛 题解
  • 【嵌入式人工智能产品开发实战】(十九)—— 政安晨:小智AI嵌入式终端代码解读:【A】应用入口
  • 【深度学习与大模型基础】第10章-期望、方差和协方差
  • 【NLP】18. Encoder 和 Decoder
  • vue项目使用html2canvas和jspdf将页面导出成PDF文件
  • Restful风格接口开发
  • C语言斐波那契数列的多样实现
  • OpenHarmony5.0.2 USB摄像头适配