K8S部署踩坑总结
这是一个前端 第一次涉及到集群 可能有很多不成熟的地方 也走了很多弯路 这篇就是现总结下目前成功部署需要注意的
本文的环境是使用阿里云ACK托管集群,项目结构是ecs中台管理器,ecs前端+mongodb数据库,集群中目前暂时一个节点服务器 后台服务集群
基本环境搭建:
中台连接集群,~/.kube/config 下面配置文件 单集群 (如果后期要多集群切换的话 --kubeConfig指定配置文件切换集群 或者其他方案 这个后续研究~)
安全组配置 :
集群的安全组入方向开启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 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。”
kube-proxy不是用于外部访问集群内部的 而是用于pod之间的访问 比如一个pod服务访问另一个pod上的服务 这个后期将mongodb迁移到集群内部的时候在进行详细分析
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 路由策略表问题
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的包 看流量端在哪一步
关于网络暴露模式于后期维护
网络暴露模式规定的是如何让外部访问节点的服务
cluster ip
流量路径:
客户端 → VPC 路由 → Worker 节点 (目标 IP 仍是 ClusterIP) → Pod
目前使用的是cluster ip 即流量转发到指定的一个worker 在VPC路由里设置 下一跳到worker ip 即使后期多个replicas 也可以通过这种方式 安全组也不用调整 因为是流量-----》worker ----->kube-proxy分发 pod节点 所以入方向还是前端的ecs mongodb入方向还是pod网段
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会话保持配置 反亲和性配置??
nodePort
nodeip直连 安全组也是所有worker ip 负载均衡需要手动配置 可以在nginx转发里配 或者openresty lua脚本配置 也就是说 nodePort是到worker的直连
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 网段 即上面提到的交换机所在的网段
关于滚动更新部署
当前项目的应用场景为,后端项目再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识别去除 运行时配置导出的配置文件格式正确
关于集群配置文件 pod service statefulSet 等,请见笔者另一篇文章k8s配置文件-CSDN博客
未完。。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)