Day59-阿里云ACK实战:生产级K8s集群部署与运维

一、为什么不是自建 K8s,而是 ACK

前两篇文章我们用 kindminikube 在本地跑通了 K8s,也用 kubectl apply 部署了 Spring Boot 应用。但真正上生产,你面临一个选择:自建 K8s 还是用云厂商托管?

我先把结论放这儿:除非你有特殊合规要求或极端成本敏感,否则选托管。

维度 自建 K8s ACK 托管版
Master 节点 自己搭 3 台 etcd + kube-apiserver,挂了自己修 阿里云托管,SLA 99.95%
版本升级 自己 drain、升级、回滚,一个周末没了 控制台一键升级,自动兼容检查
证书轮换 手动生成 kubelet 证书,过期了集群直接挂 自动轮换,无感知
安全补丁 自己跟踪 CVE,手动打补丁 云安全中心自动告警+修复建议
运维人力 至少 2 个专职 SRE 1 个兼职 DevOps 搞定

自建 K8s 的隐藏成本极高。一个 3 Master 的集群,光是 etcd 备份策略、证书过期监控、apiserver 调优这些活儿,就能吃掉一个 SRE 大半精力。ACK 托管版把这些全包了,你只管 Worker 节点。

ACK 目前有三种形态:

  • ACK 托管版 (Pro/Pro 版):Master 免费托管,按 Worker 节点付费。绝大多数团队选这个。

  • ACK Serverless:连 Worker 都不用管,按 Pod 付费。适合突发流量场景,冷启动稍慢。

  • ACK 专有版:Master 也自己管,但用阿里云的 IaaS。极端合规需求才用。

下面以 ACK Pro 托管版为主线,讲生产级集群的落地流程。


二、集群创建:那些控制台不会告诉你的坑

2.1 网络规划------最容易被忽略的前置工作

创建集群前,先规划 VPC 和交换机。这是最容易被忽略的一步,但一旦搞错,后期迁移成本极高。

bash 复制代码
# 用 aliyun CLI 创建 VPC 和交换机(也可在控制台操作)
# 创建 VPC
aliyun vpc CreateVpc \
  --RegionId cn-hangzhou \
  --CidrBlock 10.0.0.0/8 \
  --VpcName k8s-prod-vpc
​
# 拿到 VpcId 后,创建两个交换机(跨可用区高可用)
aliyun vpc CreateVSwitch \
  --RegionId cn-hangzhou \
  --ZoneId cn-hangzhou-h \
  --CidrBlock 10.0.1.0/24 \
  --VpcId vpc-xxx \
  --VSwitchName k8s-prod-sw-h
​
aliyun vpc CreateVSwitch \
  --RegionId cn-hangzhou \
  --ZoneId cn-hangzhou-i \
  --CidrBlock 10.0.2.0/24 \
  --VpcId vpc-xxx \
  --VSwitchName k8s-prod-sw-i

三条铁律:

  1. Pod 网段和 Service 网段不能跟 VPC 网段重叠。ACK 默认 Pod 用 192.168.0.0/16,Service 用 172.21.0.0/20,如果跟你的 VPC 冲突,一定要改。

  2. 至少两个可用区的交换机。单可用区一旦机房故障,整个集群直接没了。

  3. 交换机网段留足余量。一个 /24 只有 254 个 IP,中型集群很快耗尽,建议 /20 起步。

2.2 集群参数配置

创建集群时,有几个参数必须按生产标准配:

bash 复制代码
# ACK 集群创建关键参数(控制台 / Terraform 均可配置)
# 这里用 Terraform 示例,方便版本化管理
resource "alicloud_cs_managed_kubernetes" "prod" {
  name                         = "k8s-prod"
  cluster_spec                 = "ack.pro.small"      # Pro 版,控制面规格
  worker_vswitch_ids          = ["vsw-h", "vsw-i"]    # 双可用区
  pod_cidr                    = "192.168.0.0/16"
  service_cidr                = "172.21.0.0/20"
  new_nat_gateway             = true                  # 自动创建 NAT 网关,拉镜像要用
  proxy_mode                  = "ipvs"                # 生产用 IPVS,不用 iptables
  delete_options              = ["delete-resourcegroups"]  # 删集群时清理关联资源
  kube_config_path            = "~/.kube/config-prod"
  
  # 安全组配置
  security_group_id           = alicloud_security_group.k8s_sg.id
  
  # 日志服务集成(SLS)
  log_config {
    type     = "SLS"
    project  = alicloud_log_project.k8s_log.name
  }
  
  # 监控插件
  addons {
    name    = "arms-prometheus"
    config  = jsonencode({ enable = true })
  }
}

几个关键点:

  • proxy_mode: ipvs:iptables 模式在节点 Pod 数超过 1000 后性能急剧下降。IPVS 用哈希表查找,O(1) 复杂度,生产集群必须切。

  • log_config:创建时就关联 SLS,后面再补配置很麻烦。

  • arms-prometheus:ARMS 监控插件在集群创建时就装好,省去后期手动安装的麻烦。

2.3 存储插件选择

ACK 默认安装 CSI 插件。如果你要用云盘做持久化存储,确保 StorageClass 配置正确:

bash 复制代码
# storageclass-disk.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: alicloud-disk-essd
provisioner: diskplugin.csi.alibabacloud.com
parameters:
  type: cloud_essd              # ESSD 云盘,性能最好
  performanceLevel: PL1         # PL1/PL2/PL3,按 IOPS 需求选
  fsType: ext4
reclaimPolicy: Retain           # 生产用 Retain,别用 Delete
volumeBindingMode: WaitForFirstConsumer  # 延迟绑定,等 Pod 调度到节点再建盘
allowVolumeExpansion: true      # 允许在线扩容

血泪经验reclaimPolicy 一定要设 Retain。默认是 Delete,PVC 删了云盘跟着删,数据直接蒸发。我见过好几个团队在这上面翻车。


三、节点池管理:弹性伸缩的正确姿势

3.1 节点池概念

节点池(NodePool)是 ACK 对一组相同配置的 Worker 节点的抽象。你可以按业务维度划分:

  • 系统节点池:跑 kube-system、日志 Agent、监控 Agent 等基础设施 Pod。用稳定机型,不弹。

  • 业务节点池:跑你的业务应用。用弹性伸缩,按需扩缩。

  • AI 节点池:带 GPU 的节点池,专门跑推理服务。贵,但可以按需弹。

bash 复制代码
# 节点池配置示例(通过 ACK 控制台或 OpenAPI 创建)
# 这里展示一个业务节点池的 Terraform 配置
resource "alicloud_cs_kubernetes_node_pool" "business" {
  cluster_id           = alicloud_cs_managed_kubernetes.prod.id
  name                 = "business-pool"
  vswitch_ids          = ["vsw-h", "vsw-i"]
  instance_types       = ["ecs.g7.xlarge"]    # 4C16G 通用型
  instance_charge_type = "PostPaid"           # 按量付费,弹性场景
  desired_size         = 3                     # 期望节点数
  min_size             = 2                     # 最小节点数
  max_size             = 10                    # 最大节点数
  
  # 弹性伸缩配置
  scaling_policy {
    type             = "proactive"            # 主动预测型伸缩
    proactive        {
      scale_down_debounce = 300                # 缩容冷却 5 分钟,防止抖动
    }
  }
  
  # 节点标签和污点
  labels = {
    "node-pool" = "business"
    "workload"  = "java-service"
  }
  taints {
    key    = "dedicated"
    value  = "business"
    effect = "NoSchedule"    # 只允许声明 toleration 的 Pod 调度上来
  }
  
  # 系统盘配置
  system_disk_category = "cloud_essd"
  system_disk_size     = 120
  
  # 登录密钥
  key_name = "k8s-prod-key"
}

3.2 弹性伸缩的核心原则

原则一:扩容快,缩容慢。

缩容太快会导致正在处理的请求被中断。scale_down_debounce 设 5~10 分钟,让系统有缓冲。扩容则要快------ACK 的弹性节点池从触发到节点 Ready 通常需要 1~2 分钟,对于突发流量这已经很慢了。应对方案是预留 Buffer:HPA 的目标 CPU 设 60% 而不是 80%,给扩容留反应时间。

原则二:别让系统 Pod 和业务 Pod 抢资源。

bash 复制代码
# 给系统 Pod 加亲和性,只调度到系统节点池
# nginx-ingress-controller 的 deployment 示例
spec:
  template:
    spec:
      nodeSelector:
        node-pool: system     # 只跑在系统节点池上
      tolerations:
      - key: "dedicated"
        value: "system"
        effect: "NoSchedule"
      containers:
      - name: ingress
        resources:
          requests:
            cpu: "1"
            memory: "2Gi"
          limits:
            cpu: "2"
            memory: "4Gi"

系统组件不设 resources limits 是另一个大坑。日志 Agent、监控 Agent 如果不限制资源,在流量高峰时会跟业务 Pod 抢 CPU,导致业务响应变慢。

原则三:GPU 节点池单独管。

AI 推理服务需要 GPU,而 GPU 实例贵得多(一台 ecs.gn7i-c8g1.2xlarge 带一张 A10,按量约 15 元/小时)。GPU 节点池建议:

  • min_size: 0,没任务时缩到 0 节省成本

  • cluster-autoscaler + 自定义扩容策略

  • GPU Pod 加 nvidia.com/gpu 资源请求,确保调度到 GPU 节点


四、日志采集:SLS 让 Pod 日志自动汇聚

4.1 SLS 日志服务集成

ACK 集群创建时如果关联了 SLS,会自动在每个节点安装 Logtail Agent。Logtail 以 DaemonSet 形式运行,采集节点上所有 Pod 的 stdout/stderr 日志,发到 SLS。

但默认配置只是「能用」,离「好用」还有几步。

4.2 为 Spring Boot 应用配置结构化日志

第一步,让应用输出 JSON 格式日志。Logback 配置:

java 复制代码
<!-- logback-spring.xml -->
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <customFields>
                {"app":"ai-service","env":"prod","version":"${project.version}"}</customFields>
            <fieldNames>
                <timestamp>@timestamp</timestamp>
                <version>[ignore]</version>
                <levelValue>[ignore]</levelValue>
            </fieldNames>
        </encoder>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

用 JSON 日志的好处:SLS 可以直接做字段索引,查询时不用写正则提取。例如查所有 ERROR 级别且包含特定 traceId 的日志,直接 level: ERROR AND traceId: abc123

第二步,在 SLS 侧创建 Logstore 和采集配置:

java 复制代码
// SLS 采集配置(通过 API 或控制台配置)
{
  "configName": "ai-service-stdout",
  "inputType": "container_stdout",
  "inputDetail": {
    "Stdout": {
      "IncludeLabel": {
        "app": "ai-service"        // 只采集带这个 label 的 Pod
      },
      "ExcludeLabel": {}
    }
  },
  "outputType": "LogService",
  "outputDetail": {
    "logstoreName": "ai-service-log"
  }
}

4.3 日志查询与告警

日志进 SLS 后,可以配告警规则。比如「5 分钟内 ERROR 日志超过 50 条就告警」:

sql 复制代码
-- SLS 告警 SQL
* and level: ERROR | 
SELECT 
  count(*) as error_count,
  max(@timestamp) as last_error_time
FROM ai-service-log
WHERE __time__ > to_unixtime(now() - 300)
GROUP BY app
HAVING error_count > 50

配告警通知到钉钉机器人:

java 复制代码
// 告警通知配置
{
  "actionName": "钉钉告警",
  "type": "dingding",
  "service": {
    "webhook": "https://oapi.dingtalk.com/robot/send?access_token=xxx",
    "content": "告警:${results[0].app} ERROR 日志 ${results[0].error_count} 条,请检查"
  }
}

五、监控告警:ARMS 实现 JVM 级别可观测

5.1 ARMS 是什么

ARMS(Application Real-Time Monitoring Service)是阿里云的应用监控服务。跟 Prometheus + Grafana 自己搭相比,ARMS 的优势是零侵入------你不用改代码,不用加 JMX exporter,ACK 会自动给 Java 应用注入探针。

在 ACK 控制台给命名空间开启 ARMS 监控后,所有新启动的 Java Pod 会自动被注入 ARMS Agent(通过 init-container + JVM -javaagent 参数实现)。

5.2 关键监控指标

ARMS 采集到的 JVM 级别指标包括:

指标 含义 告警阈值建议
jvm_thread_count JVM 线程数 > 500 告警
jvm_heap_used 堆内存使用量 > 85% 持续 3 分钟告警
jvm_gc_count GC 次数 Full GC > 5 次/分钟告警
jvm_gc_time GC 耗时 单次 GC > 500ms 告警
http_request_count HTTP 请求量 按业务基线配
http_response_time HTTP 响应时间 P99 > 2s 告警
http_error_count HTTP 5xx > 10 次/分钟告警

5.3 配置自定义业务指标

ARMS 支持通过 @ArmsMethod 注解或 Micrometer 上报自定义指标。如果你的 Spring Boot 已经用了 Micrometer,直接配 ARMS 的 Prometheus Remote Write:

java 复制代码
# application.yml --- Micrometer 对接 ARMS
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus,metrics
  metrics:
    tags:
      application: ai-service
      env: prod
    export:
      prometheus:
        enabled: true
  # ARMS 会自动抓取 /actuator/prometheus 端点

自定义业务指标示例------统计 AI 调用的 Token 消耗:

java 复制代码
// AI 调用 Token 计量器
@Component
public class AiUsageMetrics {
    
    private final MeterRegistry meterRegistry;
    private final Counter inputTokenCounter;
    private final Counter outputTokenCounter;
    private final Counter requestCounter;
    
    public AiUsageMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.inputTokenCounter = Counter.builder("ai_tokens_total")
            .tag("type", "input")
            .tag("model", "qwen-turbo")
            .description("AI input tokens consumed")
            .register(meterRegistry);
        this.outputTokenCounter = Counter.builder("ai_tokens_total")
            .tag("type", "output")
            .tag("model", "qwen-turbo")
            .description("AI output tokens consumed")
            .register(meterRegistry);
        this.requestCounter = Counter.builder("ai_requests_total")
            .tag("model", "qwen-turbo")
            .description("Total AI API requests")
            .register(meterRegistry);
    }
    
    public void recordUsage(int inputTokens, int outputTokens) {
        // Counter 只增不减,适合累计统计
        inputTokenCounter.increment(inputTokens);
        outputTokenCounter.increment(outputTokens);
        requestCounter.increment();
    }
}

这段代码执行后,ARMS 的 Prometheus 端点会暴露三个时序指标:ai_tokens_total{type="input",model="qwen-turbo"}ai_tokens_total{type="output",model="qwen-turbo"}ai_requests_total{model="qwen-turbo"}。在 ARMS 控制台可以直接用 PromQL 查询并配告警。

5.4 告警最佳实践

生产环境的告警要遵循「少而准」原则。我见过太多团队配了上百条告警,结果每天收到几十条通知,最后全部静音------告警失去了意义。

建议只配三类告警:

  1. 可用性告警:Pod 重启次数 > 3 次/5分钟、HPA 扩到上限、节点 NotReady

  2. 性能告警:HTTP P99 > 2s、Full GC 频繁、堆内存 > 85%

  3. 业务告警:AI 调用 5xx 率 > 5%、Token 消耗异常飙升(可能被刷)

每条告警必须配可执行的 Runbook------告警里带上排查链接,告诉值班人第一步干什么、第二步干什么。没 Runbook 的告警等于没告警。


六、三条建议

1. 集群创建用 Terraform 管理,别在控制台点。

控制台创建的集群没有版本记录,出问题时无法回溯配置。把 VPC、交换机、ACK 集群、节点池、SLS、ARMS 全部写成 Terraform 代码,放 Git 仓库。改配置走 PR Review,有审计有回滚。

2. 日志和监控在集群创建时就配好,别等上线后补。

见过太多团队先上线业务、后补日志和监控,结果第一周出问题完全是裸奔状态。log_configarms-prometheus 在创建集群时就带上,应用一部署日志就在 SLS 里了,监控大盘自动生成。

3. GPU 节点池的 min_size 设为 0,用模型预热池解决冷启动。

AI 推理服务用 GPU 节点池,空闲时缩到 0 是省钱利器。但冷启动 1~2 分钟的延迟可能让用户体验很差。解法是:部署一个轻量的「预热 Pod」始终占用 1 个 GPU(用 Deployment replicas=1),真正的推理 Pod 按需弹。预热 Pod 只加载模型到显存,不接流量,等新节点起来后推理 Pod 能快速调度上去。

自建 K8s 是技术能力的体现,但生产环境从不为「炫技」买单------稳定、可观测、可回滚,才是运维的唯一标准。

下篇预告

Day 60:Serverless 开发入门------函数计算改写传统 Spring Boot。 K8s 是当前主流,但 Serverless 正在蚕食低流量场景。下一篇我们看阿里云函数计算(FC)怎么跑 Spring Boot,冷启动到底有多慢,以及什么场景该上 Serverless。

相关推荐
云边云科技_云网融合2 小时前
生态共建 · 专业交付 | 我们与阿里云共建的 Landing Zone 标杆实践
阿里云·云计算
码视野2 小时前
基于 Vue3 + Element Plus 的【智慧新能源汽车充电桩运维调度与分时共享租赁系统】设计与实现(附完整源码与PRD)
运维·人工智能·汽车·vue3
qq_426003963 小时前
【UI自动化测试】UI自动化报错解决方案
运维·ui·自动化
网安蟹佬霸3 小时前
WAF绕过技术实战:从规则检测到编码绕过全指南(2026最新版,附Payload集与自动化脚本)
运维·安全·网络安全·架构·自动化·网安
小杨不想秃头3 小时前
信息安全工程师教程第二章密码学
运维·服务器·密码学
I'mChloe3 小时前
WGCLOUD怎么监控多台服务器?从Server、Agent 部署到监控面板实战
运维·服务器
养海绵宝宝的小蜗3 小时前
Pod 管理总结
k8s
Android系统攻城狮3 小时前
Linux PipeWire深度解析之pw_init调用流程与实战(八十三)
linux·运维·服务器·音频进阶·pipewire音频进阶
国科安芯4 小时前
轨道供电韧性:ASP4644四通道降压架构在低轨卫星平台电源管理中的适用性分析
运维·网络·数据库·嵌入式硬件·架构·状态模式·低轨卫星星座