Skip to content

Kubernetes MetalLB 实战教材

版本:v1.0
目标读者:Kubernetes 运维工程师、DevOps、云原生学习者
前置知识:Kubernetes 基础、Service 类型、网络基础(ARP/BGP)


目录

  1. 背景:为什么裸金属集群需要 MetalLB
  2. MetalLB 架构与组件
  3. Layer 2 模式:原理与配置
  4. BGP 模式:原理与配置
  5. IP 地址池与高级配置
  6. 生产环境最佳实践
  7. 故障排查与监控
  8. MetalLB vs 其他 VIP 方案对比
  9. 动手实验
  10. 附录与参考资料

第1章 背景:为什么裸金属集群需要 MetalLB

1.1 Service 类型回顾

Kubernetes 提供 4 种核心 Service 类型:

类型说明典型使用场景
ClusterIP仅集群内部访问微服务间调用
NodePort每个节点开放静态端口 30000-32767快速暴露、测试
LoadBalancer由云厂商或 MetalLB 分配外部 IP生产入口
ExternalNameDNS CNAME 映射外部服务代理

1.2 裸金属集群的困境

在 AWS、GCP、阿里云等公有云上,创建 LoadBalancer 类型的 Service 后,云控制器(Cloud Controller Manager)会自动:

  1. 调用云 API 创建负载均衡器
  2. 分配公网/私网 IP
  3. 配置后端指向 NodePort
  4. 写入 status.loadBalancer.ingress

在裸金属集群(自有服务器、私有云、虚拟机环境)中没有云控制器,Service 的 EXTERNAL-IP 会一直处于 <pending> 状态。

bash
$ kubectl get svc nginx
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
nginx   LoadBalancer   10.43.120.180   <pending>     80:30007/TCP   5m

1.3 传统解决方案的不足

NodePort

  • 端口必须在 30000-32767 范围内
  • 生产环境需要额外配置反向代理做端口映射
  • 管理大量端口困难

HostNetwork

  • Pod 直接使用宿主机网络命名空间
  • 端口冲突风险高
  • 无法利用 Kubernetes 的服务发现能力
  • 扩缩容复杂

手动部署 HAProxy + Keepalived

  • 需要额外维护一组负载均衡节点
  • 配置与 Kubernetes 解耦,无法自动感知 Pod 变化
  • 高可用依赖 VRRP,存在脑裂风险
  • 新增服务需要手动修改配置

1.4 MetalLB 的定位

MetalLB 将 Kubernetes 的 LoadBalancer 抽象延伸到裸金属环境:

  • 声明式:与 Kubernetes API 原生集成
  • 自动化:自动分配 IP、自动感知服务变化
  • 高可用:支持 L2 故障转移和 BGP ECMP
  • 标准化:让裸金属集群获得与公有云一致的体验

第2章 MetalLB 架构与组件

2.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                       │
│                                                             │
│   ┌─────────────────┐          ┌──────────────────────┐    │
│   │   Controller    │          │      Speaker         │    │
│   │   Deployment    │          │      DaemonSet       │    │
│   │   2 replicas    │          │   one per node       │    │
│   │                 │          │                      │    │
│   │  - 分配 IP      │          │  - ARP/NDP 宣告      │    │
│   │  - 管理池状态    │          │  - BGP 宣告          │    │
│   └─────────────────┘          └──────────────────────┘    │
│            │                              │                 │
│            │ Watch Service                │ Watch Service   │
│            ▼                              ▼                 │
│   ┌──────────────────────────────────────────────┐         │
│   │              Kubernetes API Server            │         │
│   └──────────────────────────────────────────────┘         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.2 Controller 详解

Controller 以 Deployment 形式运行,主要职责:

  1. 监听 Service 变化:通过 Kubernetes Informer 机制
  2. IP 地址分配:根据配置从 IPAddressPool 中选择可用 IP
  3. 状态更新:将分配的 IP 写入 Service 的 status.loadBalancer.ingress
  4. 冲突检测:防止 IP 重复分配

2.3 Speaker 详解

Speaker 以 DaemonSet 形式运行,每个节点一个 Pod,主要职责:

  1. 监听 Service 变化:感知哪些 Service 获得了外部 IP
  2. 路由宣告
    • L2 模式:通过 ARP/NDP 宣告 MAC 地址
    • BGP 模式:通过 BGP 会话宣告 /32/128 路由
  3. Leader 选举:L2 模式下通过 memberlist 选举哪个节点响应 ARP
  4. 健康检查:确保只有健康的节点参与流量转发

2.4 数据流总览

外部客户端


LoadBalancer Service IP (VIP)

    ├─ L2 模式: ARP/NDP 解析到某个节点的 MAC
    └─ BGP 模式: ECMP 路由到多个节点


Node 网卡


kube-proxy (iptables / IPVS)


Pod Endpoint

MetalLB 只负责把流量引入集群,进入节点后的转发由 kube-proxy 完成。


第3章 Layer 2 模式:原理与配置

3.1 工作原理

Layer 2 模式使用 ARP(Address Resolution Protocol,IPv4)或 NDP(Neighbor Discovery Protocol,IPv6)将 VIP 解析为某个节点的 MAC 地址。

ARP 工作流程

客户端: "Who has 192.168.1.100? Tell 192.168.1.10"


Speaker Leader 节点: "192.168.1.100 is at 00:11:22:33:44:55"


客户端将 192.168.1.100 的 MAC 缓存为 Leader 节点的 MAC


流量到达 Leader 节点后,由 kube-proxy 转发到后端 Pod

3.2 流量路径

假设:

  • VIP:192.168.1.100
  • Leader 节点:node-1(MAC: aa:bb:cc:dd:ee:01
  • 后端 Pod 分布在 node-1node-2node-3
外部客户端请求 192.168.1.80:80


ARP 解析: 192.168.1.100 -> aa:bb:cc:dd:ee:01 (node-1)


流量到达 node-1 的网卡


iptables/IPVS 规则将 DNAT 到 Pod IP


Pod 处理请求,响应通过 node-1 返回(因为 DNAT 会修改连接状态)

注意:在 L2 模式下,入站流量全部经过一个节点,但该节点上的 Pod 可以直接本地处理;如果目标 Pod 在其他节点,会通过 CNI 网络转发。

3.3 故障转移

当 Leader 节点故障时:

  1. Kubernetes 检测到 Speaker Pod 失效
  2. 其他 Speaker 节点重新选举 Leader
  3. 新 Leader 发送 GARP(Gratuitous ARP)广播
  4. 网络设备更新 ARP 缓存
  5. 流量切换到新节点

故障转移时间取决于:

  • Speaker 检测时间
  • Kubernetes Pod 终止时间
  • 客户端 ARP 缓存刷新时间(通常几秒)

3.4 配置示例

前置条件

启用 kube-proxy 的 strictARP:

bash
kubectl get configmap kube-proxy -n kube-system -o yaml | \
  sed -e "s/strictARP: false/strictARP: true/" | \
  kubectl apply -f - -n kube-system

安装 MetalLB

bash
METALLB_VERSION="v0.14.5"
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/${METALLB_VERSION}/config/manifests/metallb-native.yaml

配置 IPAddressPool 和 L2Advertisement

yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: l2-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.1.240-192.168.1.250
  autoAssign: true
  avoidBuggyIPs: true
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - l2-pool
  nodeSelectors:
    - matchLabels:
        metallb/l2: "true"

创建 LoadBalancer Service

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-lb
  annotations:
    metallb.universe.tf/loadBalancerIPs: "192.168.1.240"
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: nginx

3.5 适用场景

  • 中小型集群
  • 测试/开发环境
  • 没有 BGP 支持的物理网络
  • 流量不大、对单点瓶颈不敏感的场景

第4章 BGP 模式:原理与配置

4.1 BGP 基础

BGP(Border Gateway Protocol,边界网关协议)是一种路径向量协议,广泛用于互联网路由。在数据中心内部,iBGP(internal BGP)常用于:

  • 宣告服务 IP
  • 实现 ECMP(Equal-Cost Multi-Path)负载均衡
  • 提供快速故障收敛

4.2 BGP 模式工作原理

每个 Speaker 与上游交换机/路由器建立 BGP peer 关系,将 VIP 作为 /32(IPv4)或 /128(IPv6)主机路由宣告出去。

          ┌─────────────────┐
          │   核心交换机      │
          │   ASN: 64501    │
          └────────┬────────┘
                   │ BGP Peering
      ┌────────────┼────────────┐
      │            │            │
      ▼            ▼            ▼
┌─────────┐  ┌─────────┐  ┌─────────┐
│ Speaker │  │ Speaker │  │ Speaker │
│ node-1  │  │ node-2  │  │ node-3  │
│ ASN:64500│  │ ASN:64500│  │ ASN:64500│
│ VIP/32  │  │ VIP/32  │  │ VIP/32  │
└─────────┘  └─────────┘  └─────────┘

交换机学习到 3 条等价路由后,通过 ECMP 将流量分发到多个节点。

4.3 ECMP 负载均衡

ECMP 根据数据包的五元组或三元组进行哈希:

  • 源 IP
  • 目的 IP
  • 源端口
  • 目的端口
  • 协议

优点:

  • 真正的多活负载均衡
  • 无单点瓶颈
  • 横向扩展能力强

缺点:

  • 某个节点故障时,哈希到该节点的连接会中断
  • 长连接业务需要注意重连机制

4.4 BGP 配置示例

yaml
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: bgp-pool
  namespace: metallb-system
spec:
  addresses:
    - 10.0.10.0/24
  autoAssign: true
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
  name: bgp-adv
  namespace: metallb-system
spec:
  ipAddressPools:
    - bgp-pool
  aggregationLength: 32
  localPref: 100
  communities:
    - no-advertise
---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
  name: leaf-switch-1
  namespace: metallb-system
spec:
  myASN: 64500
  peerASN: 64501
  peerAddress: 10.0.0.1
  peerPort: 179
  password: "xxx"
  holdTime: 90s
  keepaliveTime: 30s
  sourceAddress: 10.0.0.11
  nodeSelectors:
    - matchLabels:
        topology.kubernetes.io/zone: zone-a
---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
  name: leaf-switch-2
  namespace: metallb-system
spec:
  myASN: 64500
  peerASN: 64501
  peerAddress: 10.0.0.2
  password: "xxx"
  nodeSelectors:
    - matchLabels:
        topology.kubernetes.io/zone: zone-b

4.5 BGP 故障切换

当某个 Speaker 节点故障:

  1. BGP hold timer 超时
  2. 交换机撤销该节点宣告的 /32 路由
  3. 流量自动切换到其他可用路径
  4. 收敛时间由 BGP timer 决定

4.6 适用场景

  • 大规模生产集群
  • 高流量入口
  • 有 BGP 支持的网络环境
  • 需要真正多活负载均衡的场景

第5章 IP 地址池与高级配置

5.1 IPAddressPool 核心字段

yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: production-pool
  namespace: metallb-system
spec:
  addresses:
    - 192.168.1.100-192.168.1.199
    - 192.168.2.0/24
  autoAssign: true
  avoidBuggyIPs: true
  serviceAllocation:
    priority: 100
    namespaces:
      - production
      - staging
    namespaceSelectors:
      - matchLabels:
          env: production
    serviceSelectors:
      - matchExpressions:
          - key: app
            operator: In
            values: ["nginx", "api"]
字段说明
addressesIP 范围或 CIDR,可配置多个
autoAssign是否自动分配,false 则只允许显式指定
avoidBuggyIPs跳过范围中的第一个和最后一个 IP
serviceAllocation按命名空间或服务标签限制池的使用

5.2 多池分配策略

MetalLB 按以下优先级选择 IP 池:

  1. Service 注解 metallb.universe.tf/loadBalancerIPs
  2. 匹配 serviceAllocation 的池
  3. autoAssign: true 的池

5.3 共享 IP

多个 Service 可以共享同一个 IP,通过不同端口区分:

yaml
apiVersion: v1
kind: Service
metadata:
  name: http-service
  annotations:
    metallb.universe.tf/allow-shared-ip: "shared-vip"
spec:
  type: LoadBalancer
  ports:
    - port: 80
  selector:
    app: http
---
apiVersion: v1
kind: Service
metadata:
  name: https-service
  annotations:
    metallb.universe.tf/allow-shared-ip: "shared-vip"
spec:
  type: LoadBalancer
  ports:
    - port: 443
  selector:
    app: https

注意:共享 IP 时,两个 Service 必须指定相同的 loadBalancerIP 或从同一个池中自动分配。

5.4 指定 Speaker 节点

通过 nodeSelectors 控制哪些节点参与宣告:

yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: l2-adv
  namespace: metallb-system
spec:
  nodeSelectors:
    - matchLabels:
        metallb.io/l2: "true"

第6章 生产环境最佳实践

6.1 网络规划

IP 池规划原则

集群节点网络: 192.168.1.0/24
MetalLB L2 池: 192.168.1.240/28  (240-254)
MetalLB BGP 池: 10.10.10.0/24
  • L2 池建议与节点同网段,避免跨网段路由问题
  • BGP 池可独立网段,通过路由宣告
  • 预留足够 IP,考虑未来扩容
  • 避免与 DHCP 范围重叠

交换机侧配置(BGP)

cisco
! Cisco IOS 示例
router bgp 64501
 neighbor 10.0.0.11 remote-as 64500
 neighbor 10.0.0.12 remote-as 64500
 neighbor 10.0.0.13 remote-as 64500
 maximum-paths 16

6.2 高可用配置

Controller

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: controller
  namespace: metallb-system
spec:
  replicas: 2
  strategy:
    type: RollingUpdate

Speaker

  • 默认 DaemonSet 全节点部署
  • 关键业务节点可配置反亲和性避免集中在少量节点

6.3 安全配置

  • BGP 使用 MD5 密码认证
  • 限制 MetalLB Namespace 的 RBAC 权限
  • 防火墙限制 VIP 访问范围
  • 使用 NetworkPolicy 隔离 Speaker 和 Controller

6.4 监控指标

MetalLB 暴露 Prometheus 指标:

metallb_speaker_announced       # 当前宣告的 Service 数量
metallb_allocator_addresses_total # 池中的总 IP 数
metallb_allocator_addresses_in_use # 已使用的 IP 数
metallb_bgp_session_up          # BGP 会话状态
metallb_layer2_gratuitous_sent  # 发送的 GARP 数量

告警规则示例:

yaml
groups:
  - name: metallb
    rules:
      - alert: MetalLBBGPSessionDown
        expr: metallb_bgp_session_up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "MetalLB BGP session is down"

6.5 升级策略

  1. 先升级 Controller
  2. 再滚动升级 Speaker
  3. 升级期间 VIP 可能短暂漂移,建议在低峰期进行
  4. 升级前备份 CRD 配置

第7章 故障排查与监控

7.1 Service 一直 Pending

排查步骤:

bash
# 1. 查看 Service 事件
kubectl describe svc <service-name>

# 2. 检查 Controller 日志
kubectl logs -n metallb-system deployment/controller

# 3. 检查 IPAddressPool
kubectl get ipaddresspool -n metallb-system -o yaml

# 4. 检查地址是否耗尽
kubectl get l2advertisement,bgpadvertisement -n metallb-system

常见原因:

  • IP 池耗尽
  • 没有匹配的 Advertisement
  • Service 的 selector 没有匹配到 Pod
  • autoAssign: false 但没有指定 IP

7.2 L2 模式外部无法访问

bash
# 在客户端执行 ARP 检查
arp -a | grep <VIP>

# 在节点上查看 Speaker 日志
kubectl logs -n metallb-system -l app=metallb,component=speaker

# 抓包看 ARP 响应
tcpdump -i eth0 arp host <VIP>

常见问题:

  • 客户端与 VIP 不在同一网段,且没有正确路由
  • 交换机/防火墙拦截了 ARP
  • Speaker 没有运行或没有选举 Leader

7.3 BGP 模式外部无法访问

bash
# 检查 BGP 会话
kubectl logs -n metallb-system -l app=metallb,component=speaker | grep -i bgp

# 在交换机上查看路由
show ip bgp summary
show ip route <VIP>

常见问题:

  • BGP peer 配置错误(ASN、密码、地址)
  • 交换机未启用 ECMP
  • 防火墙拦截 TCP 179

7.4 性能问题

现象可能原因解决方案
单节点流量高L2 模式单点瓶颈切换到 BGP
连接中断节点故障/ECMP 重哈希业务层实现重连
延迟高流量跨节点转发优化 Pod 调度

第8章 MetalLB vs 其他 VIP 方案对比

8.1 方案总览

方案类型工作层次复杂度负载均衡能力
MetalLB L2Kubernetes 原生L2 (ARP/NDP)Failover
MetalLB BGPKubernetes 原生L3 (BGP/ECMP)多活 ECMP
kube-vipKubernetes 原生L2 (ARP) / BGPFailover / ECMP
HAProxy + Keepalived外部独立L4 + VRRP主动-备援
Nginx + Keepalived外部独立L4/L7 + VRRP主动-备援
Calico BGPCNI 集成L3 (BGP)ECMP
PorterLBKubernetes 原生L2 / BGPFailover / ECMP
SeesawGoogle 开源L4ECMP

8.2 MetalLB L2 vs kube-vip (L2)

维度MetalLB L2kube-vip L2
部署方式Controller + Speaker DaemonSet单 DaemonSet,可选 Control Plane VIP
配置方式CRD (IPAddressPool, L2Advertisement)ConfigMap 或 CRD
控制平面 VIP不支持支持(可作为 API Server 入口)
ARP 实现成熟稳定轻量
社区生态大,CNCF Sandbox较小但活跃
使用场景Service LoadBalancer控制平面 + Service VIP
资源占用略高(两个组件)较低

选择建议

  • 只需要 Service LoadBalancer → MetalLB
  • 还需要为 Kubernetes API Server 提供 VIP → kube-vip

8.3 MetalLB BGP vs HAProxy + Keepalived

维度MetalLB BGPHAProxy + Keepalived
与 Kubernetes 集成原生集成,自动感知服务变化独立组件,需手动配置
高可用机制BGP ECMP 多活VRRP 主备
负载均衡能力ECMP 分布式HAProxy 单点(主节点)
七层能力无(需配合 Ingress)HAProxy 原生支持
运维复杂度中(需要 BGP)
扩展性强,新增服务自动宣告弱,新增服务需改配置
适用规模大规模集群中小规模

选择建议

  • 大规模、云原生、需要自动化 → MetalLB BGP
  • 已有 HAProxy 经验、需要七层代理 → HAProxy + Keepalived

8.4 MetalLB vs Calico BGP

维度MetalLBCalico BGP
主要功能Service VIP 宣告Pod CNI 路由 + Service 路由
BGP ASN 配置独立配置与 Calico 网络一体化
使用条件任何 CNI必须使用 Calico
灵活性高,专注 LoadBalancer中,与网络强绑定
组合使用可与 Calico 共存可替代 MetalLB BGP

选择建议

  • 使用 Calico 且网络团队熟悉 BGP → 可用 Calico 原生 Service IP 宣告
  • 使用其他 CNI 或需要独立管理 → MetalLB

8.5 MetalLB vs PorterLB

维度MetalLBPorterLB
项目归属开源社区,CNCF SandboxKubeSphere 生态
中文支持依赖社区较好
功能覆盖L2 / BGPL2 / BGP / EIP
企业支持社区青云科技
学习曲线标准略低(中文文档)

选择建议

  • 国际化项目、社区生态 → MetalLB
  • 国内环境、需要中文支持 → PorterLB

8.6 方案选择决策树

是否需要 Kubernetes 原生集成?
    ├── 否 → HAProxy + Keepalived / Nginx + Keepalived
    └── 是 → 网络是否支持 BGP?
              ├── 否 → MetalLB L2 或 kube-vip L2
              │         ├── 需要 API Server VIP? → kube-vip
              │         └── 只需要 Service VIP? → MetalLB L2
              └── 是 → 是否需要真正多活负载均衡?
                        ├── 否 → MetalLB L2
                        └── 是 → MetalLB BGP / kube-vip BGP / Calico BGP

第9章 动手实验

实验1:在 kind/minikube 中部署 MetalLB L2

bash
# 1. 创建 kind 集群
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
EOF

# 2. 安装 MetalLB
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml

# 3. 等待启动
kubectl wait --namespace metallb-system \
  --for=condition=ready pod \
  --selector=app=metallb \
  --timeout=90s

# 4. 配置 IP 池(根据 kind 网络调整)
kubectl apply -f - <<EOF
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: kind-pool
  namespace: metallb-system
spec:
  addresses:
    - 172.18.255.200-172.18.255.250
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: kind-l2
  namespace: metallb-system
EOF

# 5. 部署测试应用
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=LoadBalancer

# 6. 查看分配的 IP
kubectl get svc nginx

实验2:验证 L2 ARP 宣告

bash
# 进入 kind 工作节点容器
docker exec -it kind-worker bash

# 安装 arping
apt-get update && apt-get install -y iputils-arping

# 查看 Service 的 EXTERNAL-IP
VIP=$(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

# ARP 探测
arping -c 4 $VIP

实验3:BGP 多活验证(需要 BGP 交换机或软件路由器)

使用 BIRD 或 FRR 作为软件 BGP peer:

bash
# 安装 FRR
docker run -d --name frr --privileged quay.io/frrouting/frr:stable_8.4

# 配置 BGP peer
docker exec -it frr vtysh
configure terminal
router bgp 64501
 neighbor 10.0.0.11 remote-as 64500
 neighbor 10.0.0.12 remote-as 64500
 neighbor 10.0.0.13 remote-as 64500
 maximum-paths 8
exit

第10章 附录与参考资料

10.1 核心 CRD 速查

CRD用途
IPAddressPool定义 IP 地址池
L2Advertisement配置 L2 宣告
BGPAdvertisement配置 BGP 宣告
BGPPeer配置 BGP 邻居
Community定义 BGP community
BFDProfile配置 BFD 快速检测

10.2 常用命令

bash
# 查看 MetalLB 组件
kubectl get pods -n metallb-system

# 查看 IP 池
kubectl get ipaddresspool -n metallb-system

# 查看宣告状态
kubectl get l2advertisement,bgpadvertisement -n metallb-system

# 查看 BGP 会话
kubectl logs -n metallb-system -l component=speaker | grep -i bgp

10.3 参考资料


结语

MetalLB 是裸金属 Kubernetes 集群实现 LoadBalancer 类型 Service 的标准方案。理解其 L2 和 BGP 两种模式的原理、适用场景和最佳实践,对于构建高可用、可扩展的本地 Kubernetes 基础设施至关重要。

在选择 VIP 方案时,应综合考虑:

  • 现有网络能力(是否支持 BGP)
  • 集群规模与流量需求
  • 团队技术栈与运维能力
  • 是否需要与 Kubernetes 原生集成

本教材由 Kimi Code CLI 生成,供学习参考使用。