ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

kubernetes/k8s 接合阿里云 LoadBalancer:一份可复制的 Service 配置与验证清单

kubernetes/k8s 接合阿里云 LoadBalancer:一份可复制的 Service 配置与验证清单 1. 为什么 k8s 服务暴露总卡在 LoadBalancer 这一步如果你在阿里云 ACK 或者自建集群里跑过带外部访问需求的服务大概率遇到过这个场景Service 的type写成LoadBalancerkubectl get svc一看EXTERNAL-IP永远是pending等了十分钟也没动静。或者更隐蔽一点SLB 实例确实创建出来了但后端服务器组是空的外部流量打进来直接 502。这个问题的本质是Kubernetes 本身并不知道阿里云 SLB 的 API 长什么样。它需要一个中间层把「我要一个 LoadBalancer」这个声明翻译成「去阿里云控制台创建一个公网 SLB 并挂载这些 ECS 节点」这个动作。这个中间层就是 Cloud Controller Manager简称 CCM。在 ACK 托管集群里CCM 是默认装好的你写个 Service 就能用。但在自建集群或者某些精简版环境里CCM 需要手动部署而且部署过程中涉及--cloud-providerexternal参数、AccessKey Secret、节点 providerID 等一系列配置。任何一环没对上LoadBalancer 就卡住。这篇内容聚焦一条完整链路从 Service 的注解写法到 CCM 组件的部署配置再到 SLB 实例生成后的验证动作。我会给出一份可以直接复制的 Service YAML 骨架以及用kubectl逐层排查的命令清单。适合正在 ACK 上打通外部访问、或者自建集群接阿里云 SLB 的同学。需要说明的是下面涉及 AccessKey 的部分建议用 RAM 子账号并只授予 SLB 和 ECS 相关权限不要用主账号 AK。这是生产环境的基本操作后面会具体说。2. 前置条件CCM 组件与权限准备在写 Service 之前得先确认你的集群里 CCM 是否在跑。ACK 托管集群一般不用管但如果你是自己用 kubeadm 搭的集群或者用的是阿里云 ECS 自建那 CCM 需要手动部署。2.1 确认集群是否已启用 external cloud providerCCM 正常工作的前提是 apiserver、controller-manager、kubelet 都带上--cloud-providerexternal参数。你可以通过下面这个命令快速判断kubectl get pods -n kube-system | grep cloud-controller如果输出里有cloud-controller-manager相关的 Pod 且状态是 Running说明 CCM 已经在运行。如果没有就需要手动部署。另一个判断方式是看节点有没有被打上node.cloudprovider.kubernetes.io/uninitialized这个 taint。CCM 启动后会负责去掉这个 taint如果 taint 还在说明 CCM 没正常工作kubectl describe node 你的节点名 | grep -i taint2.2 准备 AccessKey SecretCCM 调用阿里云 OpenAPI 创建 SLB需要 AccessKey。推荐在 RAM 控制台创建一个子账号只授予AliyunSLBFullAccess和AliyunECSReadOnlyAccess两个策略然后生成 AK。拿到 AccessKey ID 和 Secret 后用 base64 编码。注意echo要加-n否则会带上换行符导致解码失败echo -n 你的AccessKeyId | base64 echo -n 你的AccessKeySecret | base64把输出结果填到 Secret 的 YAML 里apiVersion: v1 kind: Secret metadata: name: alicloud-config namespace: kube-system data: access-key-id: 上面编码后的ID access-key-secret: 上面编码后的Secret应用它kubectl apply -f alicloud-secret.yaml注意base64 编码后的值不要带引号外的空格YAML 里用双引号包起来即可。如果编码时忘了-n解码后会多一个换行CCM 拿到的 AK 就是错的SLB 创建会直接报InvalidAccessKeyId。2.3 部署 CCM DeploymentCCM 的 Deployment 配置里有两个关键点一是要容忍node.cloudprovider.kubernetes.io/uninitialized这个 taint二是--master参数要指向你的 apiserver 地址。下面是一份精简后的配置骨架apiVersion: apps/v1 kind: Deployment metadata: name: cloud-controller-manager namespace: kube-system spec: replicas: 1 selector: matchLabels: app: cloud-controller-manager template: metadata: labels: app: cloud-controller-manager spec: dnsPolicy: Default tolerations: - key: node.cloudprovider.kubernetes.io/uninitialized value: true effect: NoSchedule containers: - name: cloud-controller-manager image: registry.cn-hangzhou.aliyuncs.com/acs/cloud-controller-manager:v1.9.3 command: - /cloud-controller-manager - --leader-electfalse - --allocate-node-cidrstrue - --cluster-cidr10.0.6.0/24 - --master你的apiserver地址:8080 env: - name: ACCESS_KEY_ID valueFrom: secretKeyRef: name: alicloud-config key: access-key-id - name: ACCESS_KEY_SECRET valueFrom: secretKeyRef: name: alicloud-config key: access-key-secret--cluster-cidr要和你 kube-controller-manager 里设置的一致否则 Pod CIDR 分配会出问题。--master如果集群启用了 TLS建议改用 kubeconfig 方式挂载这里为了简化先用 http 端点。应用后检查 Pod 状态kubectl apply -f ccm-deployment.yaml kubectl get pods -n kube-system -l appcloud-controller-managerRunning 之后CCM 就会开始监听 Service 事件了。3. 可复制的 Service YAML 骨架与注解说明CCM 跑起来之后暴露服务就简单了。核心就是一个type: LoadBalancer的 Service加上阿里云特有的注解来控制 SLB 的行为。3.1 最小可用 Service 配置下面这份 YAML 可以直接复制改一下name、namespace、selector和ports就能用apiVersion: v1 kind: Service metadata: name: my-tcp-service namespace: default annotations: service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet service.beta.kubernetes.io/alicloud-loadbalancer-slb-network-type: classic service.beta.kubernetes.io/alicloud-loadbalancer-health-check-flag: on service.beta.kubernetes.io/alicloud-loadbalancer-health-check-type: tcp service.beta.kubernetes.io/alicloud-loadbalancer-health-check-connect-port: 8080 service.beta.kubernetes.io/alicloud-loadbalancer-health-check-connect-timeout: 5 service.beta.kubernetes.io/alicloud-loadbalancer-health-check-interval: 2 service.beta.kubernetes.io/alicloud-loadbalancer-health-check-healthy-threshold: 3 service.beta.kubernetes.io/alicloud-loadbalancer-health-check-unhealthy-threshold: 3 spec: type: LoadBalancer ports: - name: tcp-8080 port: 8080 targetPort: 8080 protocol: TCP selector: app: my-app这份配置做了几件事创建一个公网类型的 SLB使用经典网络如果你的是 VPC 网络把slb-network-type改成vpc开启 TCP 健康检查检查后端 Pod 的 8080 端口。3.2 关键注解逐项说明阿里云 CCM 支持的注解很多下面这几个是最常用的建议对照表格理解注解作用常用值alicloud-loadbalancer-address-typeSLB 地址类型internet公网/intranet内网alicloud-loadbalancer-slb-network-type网络类型classic/vpcalicloud-loadbalancer-charge-type计费方式paybytraffic/paybybandwidthalicloud-loadbalancer-bandwidth带宽峰值如10单位 Mbpsalicloud-loadbalancer-health-check-flag健康检查开关on/offalicloud-loadbalancer-health-check-type健康检查协议tcp/httpalicloud-loadbalancer-health-check-connect-port检查端口如8080alicloud-loadbalancer-scheduler调度算法wrr/rr/wlc如果你要暴露的是 HTTP 服务健康检查类型可以改成http并加上alicloud-loadbalancer-health-check-uri指定检查路径比如/healthz。注意targetPort必须和 Pod 实际监听的端口一致。如果 Pod 里是 8080Service 的targetPort写成了 80健康检查会一直失败SLB 后端全部显示异常。3.3 复用已有 SLB 实例如果你已经有一个 SLB不想每次创建 Service 都新建一个可以用注解指定已有的 SLB 实例 IDannotations: service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-xxxxxxxxxxxx这样 CCM 就不会创建新 SLB而是把当前 Service 的端口映射挂到已有实例上。适合多个 Service 共享一个 SLB 的场景能省不少费用。4. 验证请求与成功结果确认YAML 应用之后不能只看kubectl get svc显示了个 IP 就完事。得逐层确认 SLB 实例、后端服务器组、健康检查状态都正常。4.1 确认 Service 拿到了 EXTERNAL-IPkubectl get svc my-tcp-service -o wide正常输出类似NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-tcp-service LoadBalancer 10.96.123.45 47.98.xx.xx 8080:31234/TCP 2mEXTERNAL-IP那一列显示的就是 SLB 的公网 IP。如果还是pending说明 CCM 没有成功创建 SLB跳到第 5 节排查。4.2 查看 Service 事件定位问题kubectl describe是最直接的排查入口kubectl describe svc my-tcp-service重点看Events部分。正常情况会看到类似Ensuring load balancer、Ensured load balancer的事件。如果出现Failed to create load balancer或AccessKey is invalid基本就是 AK 配置问题。4.3 确认 SLB 后端服务器组CCM 创建 SLB 后会自动把集群节点添加到后端服务器组。你可以在阿里云控制台的 SLB 详情页看到这些节点也可以用 API 查。更直接的方式是看 Service 的 Endpointskubectl get endpoints my-tcp-service输出应该列出所有匹配selector的 Pod IP 和端口NAME ENDPOINTS AGE my-tcp-service 10.0.6.12:8080,10.0.6.13:8080 3m如果ENDPOINTS是none说明selector没匹配到任何 Pod检查一下 Pod 的 label 是否和 Service 的selector一致。4.4 从外部实际请求验证最后一步从集群外的一台机器上请求 SLB 的公网 IPcurl -v http://47.98.xx.xx:8080/healthz如果返回 200 或者你服务定义的正常响应说明整条链路通了。如果是 TCP 服务可以用telnet或nc测试端口连通性nc -zv 47.98.xx.xx 8080连接成功会显示succeeded。如果连接被拒绝大概率是 SLB 后端健康检查没通过流量没有被转发到 Pod。5. 本篇常见报错排查清单下面这几个报错是我在实际环境里遇到频率最高的按出现概率排序。5.1 EXTERNAL-IP 一直 pending最常见的原因是 CCM 没有正常运行。先确认 Pod 状态kubectl get pods -n kube-system -l appcloud-controller-manager kubectl logs -n kube-system ccm-pod-name --tail100日志里如果出现cloud provider not initialized说明节点的providerID没设置。每个节点需要有providerID格式为cn-hangzhou.i-xxxxxxxx可以通过以下命令检查kubectl get nodes -o jsonpath{.items[*].spec.providerID}如果为空需要在 kubelet 启动参数里加--provider-idregionId.instanceId。regionId 和 instanceId 可以从 ECS 元数据接口获取curl -s http://100.100.100.200/latest/meta-data/region-id curl -s http://100.100.100.200/latest/meta-data/instance-id5.2 SLB 创建成功但后端为空这种情况通常是健康检查没通过。去阿里云控制台看 SLB 的后端服务器组如果显示「异常」检查两个点一是targetPort是否和 Pod 监听端口一致二是健康检查端口是否可达。可以在节点上直接 curl Pod IP 验证curl -v http://10.0.6.12:8080/healthz如果节点上能通但 SLB 显示异常检查安全组是否放行了健康检查的源 IP 段。阿里云 SLB 健康检查的源 IP 是100.64.0.0/10安全组入方向需要放行这个网段。5.3 报 InvalidAccessKeyId 或 ForbiddenAK 错误分两种一种是编码问题echo没加-n导致 base64 里多了换行另一种是 RAM 权限不够。先重新编码确认echo -n 你的AK | base64 | base64 -d解码后应该和原始 AK 完全一致没有多余字符。权限方面CCM 需要 SLB 的创建、修改、删除权限以及 ECS 的读取权限。RAM 策略里至少要包含AliyunSLBFullAccess和AliyunECSReadOnlyAccess。5.4 Service 删除后 SLB 没释放CCM 默认在 Service 删除时会一并删除它创建的 SLB。如果你发现 SLB 还在可能是用了alicloud-loadbalancer-id注解复用了已有实例这种情况下 CCM 不会删除 SLB需要手动去控制台释放。另外如果 CCM 在删除过程中挂了SLB 也可能残留。检查一下 CCM 日志里有没有Failed to delete load balancer的记录。6. 接入后的调试与长期维护建议链路打通之后日常维护还有几个点值得注意。如果你需要频繁调试模型服务或者验证 API 返回可以用 TaoToken 的模型对话功能快速对比不同模型的输出地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。对于需要长期跑编码任务或者 Agent 的场景Coding Plan 会更合适 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。回到 k8s 本身SLB 的计费方式建议根据流量模式选择。如果流量波动大用paybytraffic按流量计费如果流量稳定且带宽需求明确paybybandwidth包年包月更划算。带宽峰值不要设太小否则高峰期会被限速。另外生产环境建议给 SLB 配置多个可用区的后端节点避免单可用区故障导致服务不可用。CCM 会自动把节点挂到 SLB 的后端组但节点的分布取决于你的集群拓扑。如果所有节点都在同一个可用区SLB 的高可用能力就发挥不出来。最后AccessKey 的轮转也要纳入日常运维。建议每 90 天更换一次 AK更换时先更新 Secret再重启 CCM Pod观察日志确认新 AK 生效后再废弃旧的。这样能避免 AK 泄露带来的安全风险。
返回列表