K8S部署踩坑总结
这是一个前端 第一次涉及到集群 可能有很多不成熟的地方 也走了很多弯路 这篇就是现总结下目前成功部署需要注意的
本文的环境是使用阿里云ACK托管集群,项目结构是ecs中台管理器,ecs前端+mongodb数据库,集群中目前暂时一个节点服务器 后台服务集群
基本环境搭建:
中台连接集群,~/.kube/config 下面配置文件 单集群 (如果后期要多集群切换的话 --kubeConfig指定配置文件切换集群 或者其他方案 这个后续研究~)
kubectl config get-contexts
kubectl config use-context 切换指定集群
安全组配置 :
集群的安全组入方向开启VPC内网 6443 和 中台管理器内网IP 6443
前置条件:
中台服务器 集群 集群节点需要在同一个VPC下面 集群节点添加到集群中 需要在被添加的节点服务器上 运行云厂商命令 成功后 使用kubelet 查看
基本上查看当前集群 服务器节点运行 和 节点服务器是否正常
kubectl get nodes -o wide 查看集群下所有服务器节点的状态 kubectl get pods -n kube-system -o wide 查看集群下核心组件的状态 核心组件一般都在kube-system 下面 terway网络插件的状态 kubectl get pods -n kube-system -l app=terway-eniip 查看 Terway DaemonSet 状态 kubectl get ds -n kube-system terway-eniip
部署结构 :
1. 后端sh自动化脚本打包镜像 推送ACR镜像服务地址 需要在ACR里提前建好命名空间和镜像仓库 并注意推送的时候写好版本号 可以在sh中使用变量${version} 每次执行时 动态传入变量 sh xxx.sh 版本号
后续更新部署的时候 sh更新版本号 ACR控制台看到新版本镜像
中台管理器运行 滚动部署
kubectl set image deployment/你的部署名 你的容器名=新镜像地址:新版本 -n 你的命名空间
kubectl rollout status deployment/你的部署名 -n 你的命名空间 查看当前滚动更新的状态
2. 后端集群部署的deploy +svc 里 连接 ACR地址 要注意 个人版的ACR 拉取镜像 最好配置VPC内网地址
业务连通:
1. 集群需要访问外部服务 mongodb
实际链路:流量走向 pod ------->节点 -----------> VPC------------>目标ecs
mongodb安全组入方向
1)放行集群pod 交换机网段
2)VPC内网网段
并且要在worker节点上配置好 addroute mongodb 内网ip via VPC子网默认网关
安全组是为了开启mongodb接受访问的入口
addroute增加路由表 是因为pod访问外部服务terway 网络 将worker配置eni 走策略路由 但是外部的内网ip不在路由表里 需要在pod-->worker对应的路由表下
kubectl get pods -o wide -n 查看pod-ip
ip rule show 查看每个流量对应的路由表 (根据当前的pod ip找到对应路由表)
ip route show table [] 查看指定的路由表
同时也要增加安全组配置 mongod服务器 入方向 允许 terway默认子网网关的访问 pod虚拟交换机的ipv4网段 如果有多个虚拟交换机需要配置多条
因为再terway的网络模式下 流量时从eni出去的 对于外部的服务来说 看到的源ip 是 podip 而不是pod所在的worker节点的ecs ip 并且这个与当前服务的类型无关
# 查看 Terway ConfigMap
kubectl describe cm -n kube-system eni-config 可以查看下面的vswitches字段 交换机id 根据交换机id 查看pod网段
后期就算replicas设置成多个 pod ip依然会在网段内
策略路由时为了告诉pod 流量从哪块网卡发出
放行mongodb的接受通路
2. 外部ecs服务器访问pod内部服务
请求的链路:
前端-》默认网关-》VPC网络-》worker节点-》kube-proxy--》pod节点
外部到cluster ip 关键节点
VPC路由表里是否有 集群 service CIDR 下一跳 worker ecs节点的路由 (因为集群cluster ip在 service CIDR网段里 外部访问cluster ip -------------->worker ) 将访问集群的流量直接转发worker通路 是为了打通实际流量走的通路 明确访问集群的走worker ( 为什么pod访问外部不需要 因为pod访问外部的ecs ecs ip是具体存在的ip terway知道通路在哪 外部访问集群 cluster ip事是虚拟ip地址 再service CIDR网关范围内 所以需要通过路由表指定流量走向 请求到目标为service CIDR的 就直接请求到worker ecs ip 并且目前使用的cluster ip模式 这样处理是正确的 关于网络暴露模式请见下文 )
排查外部访问集群内部pod 走不通 可以根据下面几个方向:
1. 排查集群内部的网络是否正常
kube-proxy组件是否正常运行 服务分发 将cluster-ip 转为pod-ip 到达pod内部
iptables-save -t nat | grep 【pod-ip】 如果返回为空 说明流量规则没有走到pod kube-proxy运行不正常 则重启kube-proxy组件
pod-ip是 kubectl get pods -o wide -n [命名空间] 查看
打通前端出方向--》集群 cluster ip cluster ip只要不重启service 就不变
查看worker节点到pod的通路
ip route show table 1004 | grep service 网段 查看 是否有service网段到默认网关的规则 一般是Terway CNI 组件自动生成的
“去往 192.168.0.0/16(Service 网段,Pod IP 属于此范围)的流量,从 eth0 网卡发出,下一跳发给网关 172.23.239.253。”
上面的配置是用于pod跨node节点通信 流量配置的
kube-proxy不是用于外部访问集群内部的 而是用于pod之间的访问 比如一个pod服务访问另一个pod上的服务 clusterip-->podip的转化,但是具体到podip的流量通路还是通过 node节点内部的路由表 和eni ,如果eni组件健康运作 ,比如我的terway模式是terway-eniip,那么会自动在node的main表上添加veth对路由策略
而 上面的网段路由和 veth的精确路由 的运作机制 是基于路由规则是优先匹配精确,其次到默认模糊匹配的,等于如果他有精确的veth对路由策略 就走路由策略 所以是本地的podip通路 剩下匹配不上的会直接匹配到默认的路由策略 即 eni自动添加的这条 而这条的目的就是为了能正确将流量引出当前的node 发往 VPC 然后通过VPC 根据podip 找到对应的node节点 ( 即跨节点流量策略 )
2.集群入方向《--------前端 内网ip
排查方向:抓包工具tcpdump的妙用
前端访问集群
可以在前端执行telnet请求 前端进行 抓包 如果有包 说明前端出方向正常
sudo tcpdump -i eth0 host cluster ip and port 3300 -n在worker节点抓包
抓service ip的包 看请求是否到达了worker节点
抓pod ip的包 看请求是否kube-proxy转发正常
集群访问前端
pod 内部 nc -zt 请求
worker节点 tcpdump -i eth0 抓包
结果排查:1.没输出则服务没到worker VPC路由下一跳设置 或者 集群出方向安全组
2.只有SYN包 mongodb服务问题 没启动或者安全组入方向拦截
3. route unreachable 路由策略表问题
通过在集群中 nslookup 资源地址 类似于 nlb-xxxx 或者 svc.cluster.local 可以查看解析是否正常 排查地址拼写错误
3.pod之前的相互访问
不能在策略路由里设置pod ip via 默认网关 需要 pod ip 直连
ip neigh show查看ARP表是否正常 即 pod解析为mac地址是否正常
pod之间的访问主要通过veth 对于terway网络模式 如果pod之间访问不通 查看 pod内部的ip route 表 访问podip 是否通过指定的veth地址 而不是 eth0的默认网卡 而且得注意不能配置pod网段 via eth0导致访问的流量会批量错误处理 目前的方案是通过 configMap+daemonSet daemonSet会在worker节点启动的时候执行 定时任务自动刷新configMap
daemonSet里配置指定configmap
volumes:
- name: pod-info
configMap:
name: backend-pod-info
自动读取后端pod 获取pod 对应的veth 将 podip via veth 写入路由表
ip route replace $POD_IP dev $veth table 1003 2>/dev/null
ip route replace $POD_IP dev $veth table 1004 2>/dev/null
ip neight show获取veth
目前 我mongodb部署的是headless + statefulSet(有状态应用)返回的是podIp 可以直接通过podIp访问或者是 podName?.[serviceName].[spaceName].svc.cluster.local 访问 如果后期想要以多副本 则会变成 mongodb-0 mongodb-1... 具体配置文件和前端,后端访问方法请见我另一篇文章 clusterIp 与 statefulSet+headless-CSDN博客
排查pod与pod间的通信问题也可以通过抓包工具tcpdump 抓请求podip的包 抓被请求的目标podip的包 看流量端在哪一步
原理:
pod间的访问是通过veth相互访问 因为每一个pod都有自己单独的命名空间 podip是在pod的eth0网卡上面,另一端是在worker节点上的veth (veth对的两端)pod与worker之间的通路就是通过veth对进行连接的,即使podip已经在某一个worker节点上面,如果多个eni场景下调试过程中因为某些原因不能自动加入,则需要手动修改,或者使用策略路由1003 1004时,有可能某些原因没有自动添加到策略路由,
完整的获取veth的流程:
ping podip 先手动ping一下 让他加进arp表中
arp -a |grep podip 获取mac表的值
ip link show |grep 对应的mac值获取veth
或者使用 ip neigh show podip | awk '{print $3}'
最后直接设置 ip route replace podIp via veth
7.18更新--
但是K8S正常情况不应该直接通过pod访问 即使是单节点 也应该通过副本集进行访问,k8S自动会通过kube-proxy 转发 自动服务发现 ARP广播和缓存 上面则是强制的简易处理了这个过程,正确步骤应该是配置为 svc.cluster.local 并且一定要写replicaSet=rs0 这个是和statefulSet 配置对应 containers.args.["--replSet", "rs0"] k8s会处理成副本集 然后自动处理流量转发 服务发现 arp表缓存 广播 而且配置后如果之前有手动处理的逻辑切记删除
外部不应该直接访问podip clusterip这些都是对于集群内部的 ,外部只能 nodePort loadBalanacer ingress
关于 statefulSet (有状态)和 deployment (无状态的区别)
statefulSet下的每一个pod 会有自己独立的存储 ,所以如果想实现持久化存储 直接配合 PVC PV volumeClaimTemplate 连接远程云盘存储 不要使用hostPath本地存储 hostPath是再每一个pod所在的node节点上创建存储 一旦pod重启后不在原来的node上很有可能数据丢失 并且不能共享存储
deployment是下面所有的pod共用一个存储盘,如果使用的hostPath,在重启pod的时候有可能分布在多个node上面,导致只有第一个podn能挂载成功,要么如果单节点或者 hostPath,如果真的想实现数据持久化 只能使用nfs
关于网络暴露模式于后期维护
网络暴露模式规定的是如何让外部访问节点的服务
cluster ip
流量路径:
客户端 → VPC 路由 → Worker 节点 (目标 IP 仍是 ClusterIP) → Pod
目前使用的是cluster ip 即流量转发到指定的一个worker 在VPC路由里设置 下一跳到worker ip 即使后期多个replicas 也可以通过这种方式 安全组也不用调整 因为是流量-----》worker ----->kube-proxy分发 pod节点 所以入方向还是前端的ecs mongodb入方向还是pod网段
但是上面这种 仅限于单节点的情况可以走通 而且k8s里clusterIp原本只是面向集群内部的 外部访问还是需要通过nodePort或则loadBalancer 上面只是因为强行指定了下一跳,转发了路由走向
loadBalancer
流量路径
客户端 负载均衡 worker节点 pod
客户端 → 负载均衡器 → Worker 节点 (目标 IP 已是节点 IP) → Pod
所以不需要像cluster ip模式一样在 VPC路由里面配置service cidr下一跳指定worker节点 因为负载均衡已经自动分发到worker节点了
使用于多个worker节点 在集群入方向的安全组设置 原本设置的前端ecs 必须改为worker节点的ip 因为是通过外部负载均衡转发到worker 安全组校验的worker是否可以接受指定的外部流量 可以是worker 节点每个具体ip 或者整个VPC网段 因为loadBalancer安全组校验的是目标ip 当然从外部到worker worker到kube-proxy分配pod 有可能会分配到一个pod 配置 podAntiAffinity 防止挤在一个pod sessionAffinity: ClientIP会话保持配置 反亲和性配置??
loadBalacer 相当于外部负载均衡+ nodePort
如果使用云厂商的lb
流量走向就是 外部-->云厂商LB--> worker节点 --> ingress controller --> 后端service
所以对于worker节点入方向安全组 开启 云厂商LB网段的访问
如果改到lb的 pod直连模式
loadBalancer的基础上 加annotations
service.beta.kubernetes.io/backend-type: "eni"
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-server-group-type: "Ip"流量走向 云厂商LB--> ingress controller ENNIP -->ingress controller-->后端service -->pod
重点在于pod直连模式不会走kube-proxy 进行 到podip的解析 所以需要在pod 即 弹性网卡的安全组放行 nlb网段 如果nlb和 service pod都在同一个VPC下 则开启VPC网段就行
不论时nlb 到 node节点还是 podip 都有可能出现落在 与nlb不同可用区的情况 这个时候就走了节点转发的流量逻辑 主表 (podip 弹性网卡网段 via eth0 )或者 1003 1004策略表 (service CIDR via VPC网段 )
通过直接再控制台查看nlb 模式时四层还是七层反向代理 (监听 服务协议 如果时 tcp/ucp 则为四层 http/https则为七层 )
如果 直接使用nodePort 流量走向就是
外部-->nodePort -->worker节点 --> ingress controller --> 后端service
外部直接访问worker节点 worker安全组设置 入方向 外部ip 端口范围 nodePort端口范围
访问则是 前端 -->node节点+ nodePort +/api -->匹配到ingress controller 对应的后端service
当安装了云厂商LB后 默认是 对于该集群下面的所有 ingress规则的访问都生效 ,外部访问时,是根据 path访问路径对应转发到service
nodePort
nodeip直连 安全组也是所有worker ip 负载均衡需要手动配置 可以在nginx转发里配 或者openresty lua脚本配置 也就是说 nodePort是到worker的直连 他会将targetPort port映射一个外部访问的port 通过kubectl get svc -n 可以查看具体分配的端口 nginx里面配置 worker节点ip +port可以使用upstream负载均衡
安全组配置 前端服务器 出方向 服务端口 VPC网络 ipv4 网段+端口
后端集群 前端ECS地址+端口
loadBalancer VS nodePort
loadBalancer 对外会统一暴露一个ip 内部自动处理负载均衡 和业务宕机处理 但是nodePort相当于每一个worker节点上一个相同端口 需要自己手动处理 节点宕机健康处理 前端也需要手动的配置upstream负载均衡 如果为了节省成本可以使用nodePort+upstream nginx配置 如果费用充裕还是建议直接 loadBalancer由K8S内部自动处理 SLB和节点的健康转发节点调度
loadBalancer ingress 通过负载均衡到随机的node节点上方面 然后node节点 通过kube-proxy找到podip 有可能在当前节点也有可能跨节点 跨节点则通过策略路由流量出node 或者直接在当前的node节点下 跨节点的话会造成流量性能损耗 (虽然很小)所以可以通过节点亲和性配置 优先调度到有pod运行的node节点
cluster ip service CIDR pod Ip 概念使用场景区分
cluster ip 是每次在apply service时 在 service CIDR范围内生成的IP 用于 集群外部 访问 集群 的地址 比如 前端访问后端集群 nginx配置的地址就是 cluster ip的地址
service CIDR是所有 cluster ip的段 所以用于在VPC路由里面设置下一跳 对流量走向进行统一约束
pod ip是每一个pod节点的ip 在pod 访问外部服务的时候 设置安全组使用 但是pod ip 每次随机生成的 不能直接设置pod ip 需要拓宽到pod 网段 即上面提到的交换机所在的网段
| 概念 | 定义 | 谁分配的 | 是否真实存在 |
|---|---|---|---|
| Service CIDR | 分配给 Service 的虚拟 IP 段,所有 ClusterIP 从这里分配 | 创建集群时指定 | ❌ 虚拟 IP,不绑定任何网卡 |
| Terway ENIIP 网段 | Pod 使用的辅助 IP 地址段,从 vSwitch 分配,绑定在 ENI 上 | Terway 从 vSwitch 分配 | ✅ 真实 IP,绑定在 ENI 上 |
| Terway VPC 网段 | VPC 本身的地址空间,包含所有 vSwitch 和节点 IP | 创建 VPC 时指定 | ✅ 真实 IP,VPC 网络的基础 |
| Pod CIDR(补充) | 传统 CNI 模式下分配给 Pod 的网段 | CNI 插件分配 | ✅ 真实 IP,在 Terway 下通常不独立存在 |
| 场景 | 涉及哪个网段 | 配置要点 |
|---|---|---|
| Pod 之间跨节点通信 | Terway ENIIP 网段(Pod IP) | 依赖 VPC 路由表,节点主路由表的默认路由指向 VPC 网关 |
| Pod 访问 Service(ClusterIP) | Service CIDR | kube-proxy 维护 iptables/IPVS 规则,Terway 在路由表中添加去往 Service CIDR 的路由 |
| 外部访问 Service(NodePort/LoadBalancer) | Service CIDR + Terway ENIIP 网段 | NodePort 在节点上开放端口,LoadBalancer 通过云 LB 转发到 NodePort 或直接到 Pod ENI |
| 外部直接访问 Pod IP | Terway ENIIP 网段 | 需要 VPC 路由表 + 安全组放行 Pod ENI |
| Pod 访问外部服务 | Terway ENIIP 网段 | Pod 流量从 ENI 出去,源 IP 是 Pod IP,安全组放行出方向 |
podip直连走main 路由表 + eniip 网卡 via eth0(跨节点出方向链路)
访问clusterip 等 service 通过kube-proxy解析为podip 如果是需要跨节点 策略路由 1003 1004上面 service CIDR via VPC 网关网段 到了目标node节点 不论直连还是 访问service 因为解析成了podip 并且 为 terway ennip模式 则 veth对的策略链路就是在main路由主表上面设置
目前的最佳应用实践 ingress+nodePort +nginx (如果预算较小)
后端服务通过ingress controller 通过转发 匹配多个端口服务 nodePort 在多个worker节点上暴露相同端口 前端nginx unpstream 负载均衡配置连接 ingress 的 nodePort service 通过具体的llocation匹配到 ingress的具体路由 这也是后期高科维护的方向 主要优点事避免端口直接暴露 方便同一管理 统一配置相应 限流等操作
注意: ingress controller也是对匹配路径做转发处理 和nginx相似 也存在location路径的拼接问题,从前端nginx匹配地址,转发到ingress对应前缀,在跳转后端对应服务端口,如果需要在实际请求路径中不携带请求前置路径,ingress配置里 pathType ImplementationSpecific path 匹配替换
http:
paths:
- pathType: ImplementationSpecific
path: "/api(/|$)(.*)"
backend:
service:
name: vue3-office-server-svc
port:
number: 3300
如果后端集群和前端服务器再同一个VPC和可用区,可以直接通过nlb指定可用区的内网ip 访问,这个能减少延迟,跨可用区的流量耗费
具体实现:
nlb + ingress + loadBalancer
通过外部访问 nlb 通过ingress规则 到worker 节点 到 pod节点
关于流量走向的总结:(什么时候走eni 什么时候走kube-proxy)
pod访问外部ecs pod访问pod (podip 直连 ) 走eni 即对于访问目标来说 源ip 都是podip
pod访问clusterip 等另一个service通过服务域名 外部 nodePort ——> pod 走 kube-proxy
对于同一个VPC内的相互访问出方向的策略是默认放行的
口诀:如果是服务器访问直连 则放行的都是 ecs ip 如果有中间件 那如果是同一个VPC则是VPC网段 如果是源ip是podip则为pod网段 即 eni交换机网段
关于滚动更新部署
当前项目的应用场景为,后端项目再ecs服务器上,需要每次推送到远程镜像库,并再另一个中台服务器上面部署集群,之前我们通过sh自动化脚本部署,现在再自动化脚本基础上,不是直接run运行镜像,而是再 tag push推送远程镜像结束后 ssh登录远程的中台服务器,set image 更新集群镜像,rollout等待更新部署完成,并根据当前运行的最新的pod导出纯净 (不包含运行时参数的配置文件 保证集群镜像版本和配置文件的镜像版本同步 )导出文件直接覆盖原有的配置文件 即 apply -f的配置文件
配置文件更新的生效验证
1.通过 grep image获取最新的镜像版本
kubectl get deployment vue3-office-server-deploy -n backend-space -o yaml | grep image2.确认本地配置文件的镜像版本
grep image back-deploy.yaml
具体导出代码如下:
kubectl get deployment vue3-office-server-deploy -n backend-space -o yaml | \
yq eval 'del(.metadata.annotations."kubectl.kubernetes.io/last-applied-configuration")' - | \
yq eval 'del(.metadata.creationTimestamp)' - | \
yq eval 'del(.metadata.generation)' - | \
yq eval 'del(.metadata.resourceVersion)' - | \
yq eval 'del(.metadata.uid)' - | \
yq eval 'del(.status)' - > backend-deploy-clean.yaml
经过实践,通过yq识别去除 运行时配置导出的配置文件格式正确
关于滚动部署的最佳实践是:
kubectl apply -f + rollout history type name 直接应用配置文件 并且获取历史版本记录
--revision= 查看更新的指定版本号更新的具体内容
更新注释信息 kubectl annotate type name kubernetes.io/change-cause= --overwrite 覆盖更新注释信息 对应 rollout history 查看到的change-cause列
yaml文件里的annotations 注释信息字段可以
关于数据卷挂载的几个场景和配置总结:
手动声明挂载
配置文件引用 secret configMap
secret使用secretName configMap使用name 声明引用,都是用items指明配置项key,和存储项path
volumes:
- name: redis-config
secret:
secretName: redis-secret
defaultMode: 0400 #仅root权限可读
configMap:
name: redis-config
items:
# key 是redis configMap中声明的data定义配置项的key path是存储再容器中的文件名
# 上面的volumesMounts 中定义的redis-config 是配置文件再容器中的存储位置
- key: master.conf
path: redis.conf
引用 最终实际挂载地址为容器内 mountPath+path
containers:
volumeMounts:
- name: redis-config
# redis-server服务默认是使用该路径下的redis.conf配置文件启动的
# 所以直接将配置文件挂载到容器内的指定路径即可
mountPath: /etc/redis
readOnly: true
- name: redis-data
mountPath: /data
使用远程云盘
自动创建PV PVC
声明 直接再pod配置文件内 使用阿里云默认分配的云盘 metadata.name则已经再内部声明了redis-data 所以不需要再volumes内在声明 注意:volumeClaimTemplate只适用于 statefulSet 因为是给每一个pod创建一个独立的PV
spec:
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: alicloud-disk-topology-alltype
resources:
requests:
storage: 20Gi # ← 阿里云云盘最小 20Gi
使用用和之前写法一样
containers:
volumeMounts:
- name: redis-config
# redis-server服务默认是使用该路径下的redis.conf配置文件启动的
# 所以直接将配置文件挂载到容器内的指定路径即可
mountPath: /etc/redis
readOnly: true
- name: redis-data
mountPath: /data
手动创建PV PVC
阿里云控制台创建云盘
创建PV persistentVolume PVC persistentVolumeClaim 注意:适用于deployment 因为所有pod副本要是用同一个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: mongodb-pv-0
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClass:'' #声明storageClass
csi:
driver: diskplugin.csi.alibabacloud.com
volumeHandle: "d-xxx" # 填入你的云盘 ID
fsType: "ext4"
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc-0
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: "" #匹配persistentVolume声明的storageClass
pod内使用 其他的声明和 引用写法和上面的相同 需要注意一点 声明时需要使用 persistentClaim 即上面创建的 persistentClaim名称 metadata.name
volumes:
- name: redis-config
persistentClaim: ''
secret:
secretName: redis-secret
defaultMode: 0400 #仅root权限可读
configMap:
name: redis-config
items:
# key 是redis configMap中声明的data定义配置项的key path是存储再容器中的文件名
# 上面的volumesMounts 中定义的redis-config 是配置文件再容器中的存储位置
- key: master.conf
path: redis.conf
总结:PVC和 PV 通过 storageClass关联匹配 pod 和 PVC通过 persistentClaim 关联匹配
关于集群配置文件 pod service statefulSet 等,请见笔者另一篇文章k8s配置文件-CSDN博客
关于集群 的secret 环境变量引用 变量声明关系对映 实战请见笔者 redis集群部署与连接-CSDN博客
未完。。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)