云原生基础

2025-11-01T14:11:02+08:00 | 34分钟阅读 | 更新于 2025-11-01T14:11:02+08:00

@

学习目标

学完本章你应该能够:

  1. 讲清软件交付从「瀑布 → 精益 → 敏捷 → DevOps → SRE → AIOps」的演进脉络,以及每一阶段要解决的核心矛盾。
  2. 说清 AIOps 的严格定义、三阶段(监控 → 分析 → 自动化)、四大优势,以及它为什么必须与云原生结合。
  3. 讲明大模型给 AIOps 带来的两次机遇(数据建模 + 数据分析),并用「构建 AI 应用的五层理论」解释落地路径。
  4. 区分 LLM 与 AIOps 结合的核心技术栈:Prompt 工程、JSON Mode、Function Calling、RAG、微调,并理解各自解决什么问题。
  5. 画出一条真实 DevOps 流水线,分清 SLI / SLO / 错误预算,并能算月度错误预算消耗。
  6. 讲清 IaC 的三大特性(声明式、有状态、幂等)带来的优势,以及与 CLI/API「命令式」管理的本质区别。
  7. 跑通 terraform init / plan / apply / destroy 全流程,理解 state 文件、provider、registry、模块、workspace 与多环境管理。
  8. 借助 ArgoCD + Crossplane,理解并复现「YAML → 基础设施」的 PaaS 自建思路。

前置知识:用过 Git 和至少一种 CI 工具;知道 Docker / Kubernetes 基本概念;对 Prometheus 指标有耳闻即可。

本章你会动手做的事:

  • 用腾讯云 + Terraform 开通一台 CVM,跑通 plan → apply → destroy。
  • 把 Teraform 代码按 main/output/variable/version 标准布局拆分,并用模块 + 目录隔离 dev/test 多环境。
  • 用 Crossplane 的 YAML 创建一个 VPC + 子网 + 虚拟机,再交给 ArgoCD 体验「YAML to Infra」。
云原生基础演进脉络AI Ops 三阶段LLM×AIOpsIaC·TerraformPaaS·Crossplane瀑布→精益→敏捷DevOps→SRE→AIOps监控→分析→自动化数据层是核心基础五层理论·核心技术栈RAG·Agent·知识库HCL·provider·state模块·workspaceCrossplane·CRDArgoCD·GitOps 自建 PaaS

从精益、敏捷到 DevOps 的发展脉络

软件交付模式的演进,本质上是企业为了更快、更稳地响应市场变化而不断探索的过程。早期瀑布模型强调阶段清晰,但反馈周期长、变更成本高。随后精益(Lean)思想被引入软件开发,核心是消除浪费、持续流动;敏捷(Agile)则进一步强调小步快跑、拥抱变化,通过迭代和增量交付缩短反馈环。

复习提示:类比:瀑布模型像「盖楼前先画完整图纸、封顶才能入住」,改需求等于拆墙重建;敏捷像「先搭毛坯、每两周住进去体验一轮再改」,反馈快但得接受边住边装修。DevOps 则是把「盖楼的设计师」和「入住后的物业」合并成一个团队——你设计的楼,你自己负责它别塌。

DevOps 在敏捷基础上,将开发(Dev)与运维(Ops)之间的壁垒打通,倡导"you build it, you run it"的文化。它不只是工具链的整合,更是组织流程、度量和协作方式的变革。典型的 DevOps 流水线包含:需求管理、代码提交、持续集成(CI)、持续交付(CD)、部署发布、运行监控、反馈改进。

之所以把 AIOps 定义为「下一代的 DevOps」,是因为 AIOps 是在 DevOps 建立的数据、流程与组织基础之上,进一步用机器学习和大模型来加速分析与决策。

flowchart LR
    A[瀑布模型
阶段清晰/反馈慢] --> B[精益
消除浪费/持续流动] B --> C[敏捷
小步快跑/拥抱变化] C --> D[DevOps
打通 Dev 与 Ops] D --> E[SRE
用软件工程做运维] E --> F[AIOps
ML/LLM 智能决策]

一条真实流水线长啥样

下面这条是我自己搭过、踩过坑、能跑起来的典型 Web 服务流水线,每个阶段我都标了对应的工具:

[Plan 需求]      Jira / Linear / 飞书项目        ← 工程师拆卡,写 AC
    ↓
[Code 编码]      Git + GitHub/GitLab             ← feature 分支,commit message 关联 issue
    ↓
[Build 构建]     Docker buildx + BuildKit        ← 多阶段镜像构建,推 Harbor
    ↓
[Test 测试]      pytest / go test + SonarQube    ← 单测+覆盖率+静态扫描
    ↓
[Scan 安全]      Trivy + Grype                   ← 扫镜像 CVE,扫 IaC 配置
    ↓
[Deploy 部署]    ArgoCD GitOps                   ← 监听 manifest repo,自动 sync
    ↓
[Verify 验证]    Prometheus + Blackbox Exporter  ← 部署后 smoke test + SLO 检查
    ↓
[Monitor 监控]   Grafana + Loki + Tempo          ← 指标/日志/链路三件套
    ↓
[Feedback 反馈]  告警 → On-call → 复盘 → Jira    ← 失败案例回灌成新的需求

说实话我第一次看 DevOps 流水线图的时候觉得就那么回事儿,等真上手搭过几次才发现,流水线本身就是公司工程文化的镜子——你团队怎么协作,流水线就长什么样。

小团队 CI/CD 工具怎么选

工具定位优点我踩过的坑
Jenkins老牌 CI/CD 引擎插件多,啥都能干Jenkinsfile 一长就乱,master 节点一挂全员瘫痪
GitLab CIGitLab 内置 CI.gitlab-ci.yml 跟代码一起走shared runner 排队能等到天荒地老,得自己搭 runner
ArgoCDGitOps CD 控制器声明式、UI 直观、K8s 原生只管 CD 不管 CI;manifest repo 与代码 repo 解耦后维护成本上升

我个人觉得小团队 GitLab CI 一把梭就够了;规模上来或者要搞 GitOps 就上 ArgoCD,CI 保留 GitLab CI / GitHub Actions。Jenkins 现在基本不再主动选了,维护成本太高。

什么是 AIOps

AIOps 的定义非常明确:它是一种使用人工智能技术来简化运维工作流的技术方案,采用的技术包括机器学习与数据分析等。

从这个定义可以直接得出一个重要结论:无论是机器学习还是数据分析,数据对 AIOps 而言都是一个核心基础——没有高质量的数据,一切智能都是空中楼阁。

AIOps 的三个阶段

flowchart LR
    A[监控
数据来源
历史+实时] --> B[分析
归纳/分类/异常检测/性能/关联分析
→ 优化建议] --> C[自动化
按建议或任务自动执行流程]
  • 监控(数据来源):包含历史数据和实时数据,是整个 AIOps 的数据来源。
  • 分析:对历史数据和实时数据做归纳、分类、异常检测、性能分析、数据关联分析,并据此输出优化建议。
  • 自动化:根据优化建议或既定任务,自动执行运维自动化流程。

AIOps 的优势主要体现在分析与自动化这两个环节。

AIOps 的四大优势

结合上面的三阶段,AIOps 的核心价值可以归纳为四点:

  1. 持续观测海量数据流:人工难以持续盯住整个监控数据流或日志流,而 AIOps 擅长处理庞大的数据量,对数据的敏感度远超人工。
  2. 解决运维团队孤岛问题:业务团队之间相互孤立,运维团队理解的上下文有限。AIOps 通过业务指标 + 日志 + 追踪三种多模态数据做关联分析,随时发现问题。
  3. 预测问题并提前解决:借助机器学习对数据建模实现预测,而不是靠用户反馈或告警来被动响应。
  4. 根因分析:借助机器学习快速处理大量数据并建模,最终定位问题产生的根本原因。

实现 AIOps 的抽象层

从下到上大致是:

业务应用层   虚拟机 / 容器 / 分布式应用等不同形态
   ↓
数据接入层   日志 / 分布式追踪 / 指标 —— AIOps 的核心基础
   ↓
运维接口能力 重启 / 回滚 / 配置 / 调整参数 —— 智能化闭环的最后一环
  • 数据层是核心基础:这也是 OpenTelemetry 这类「一网打尽」技术备受关注的原因。
  • 运维接口能力:以前很难抽象化,但借助 K8s 的声明式能力,重启服务、回滚配置、调整参数、回滚发布版本都变得很容易实现。这是 AIOps 必须与云原生结合的重要原因之一。

容易忽略的元数据

在数据接入层,除了日志、监控、指标这些核心数据,还有一类实践上常被忽略、但实施 AIOps 平台时非常有用的数据——元数据,分为三类:

元数据类型内容用途
服务元数据编码语言、版本、SDK 核心版本让平台了解服务细节,辅助更深入的根因分析
部署元数据部署形式(容器/VM)、Pod、工作负载、所在节点/机房让平台了解部署层面的细节
业务元数据运维/开发元数据(所属团队、负责人等标识)产生告警时快速找到对应业务团队与负责人

AIOps 为什么之前发展不顺、现在又火了

AIOps 自 2016 年提出至今约 8 年,发展一直不算顺利,但最近又被重新提起来。很重要的一个原因就是:大模型给 AIOps 提供了一个全新的发展机会。国内大模型发展迅速,可选择的大模型也很多。

大模型与 AIOps 的结合

大模型与 AIOps 的关系主要体现在两点:数据建模与数据分析。

  • 数据分析:AIOps 环节中大量数据靠人工处理很困难,而大模型恰恰非常擅长处理文本数据(日志、告警),极大降低了数据分析的难度。
  • 数据建模:可借助大模型来编写数据建模的算法(时序预测、分类等),大模型就像一位拥有十几年运维经验的专家,帮我们快速迁移到 AIOps 平台。

传统根因分析的痛点 vs 大模型的新可能

传统运维在故障根因分析时的做法是:先把时间轴框出来,把不同指标和日志按固定时间轴对齐,然后纵向切分周期内的所有指标和日志,人工递归找上游/下游问题,直到递归到最上游或最下游。

这个方式的问题很明显:

  • 工作量极大、数据量大、指标维度多,几乎只有运维专家能胜任,且依赖专家经验。
  • 递归存在多个路线选择,人工选错路线会投入大量无效时间,效率非常低。

大模型出现后,多模态运维数据处理成为可能。所谓多模态数据即日志、指标、追踪等。可以借助大模型实现类似「混合专家」的模式:

  • 有一个 日志 Agent(Log 专家)、指标 Agent(指标专家)、分布式追踪专家,分别分析不同模态的数据。
  • 分析完后由大模型整合分析结果,输出故障可能产生的原因。

结合大模型,还能:

  • 对故障发生时刻引出的各种多模态数据做分析解释,甚至提出建议。
  • 结合内部运维专家知识库找到解决办法。

新的人机交互方式:自然语言

大模型与 AIOps 结合后,产生了一种以自然语言为核心的交互方式。以前查监控日志只能通过 UI/命令行/API,现在大模型能理解语义,并把语义里的内容转化为函数调用的参数:

  • 例如「查最近 7 天数据库层面的报错信息」,大模型能转换为调用 get_database_log 函数。
  • 能从语义中解析出时间范围周期、报错关键字、LEVEL 等参数,获取数据后返回结果。

构建 AI 应用的五层理论

要把大模型落地到 AIOps,需要跨越五层鸿沟:

flowchart TB
    L0[模型层
各大模型 API 接入] --> L1[Prompt 层
提示词工程 zero-shot / few-shot] L1 --> L2[思维链层
模型链式调用/多步思考] L2 --> L3[Agent 层
自主思考/决策/行动的智能体] L3 --> L4[多 Agent 协同层
任务拆分/协作分工]
  • 模型层:主要指各种大模型 API 的接入。
  • Prompt(提示语):提示词工程,比如常见的 zero-shot 和 few-shot。提示词的质量很大程度决定大模型输出的质量(是否给模型提供示例也是关键)。
  • 思维链:模型层面的链式调用,把一个模型输出作为下一次调用的输入,实现多步思考。
  • Agent:具备自主思考、决策、行动的智能体,是大模型与 AIOps 领域里非常垂直的研究方向(课程后续会带大家开发 Agent)。
  • 多 Agent 协同:单个 Agent 无法满足任务时,把任务拆分,让不同的 Agent 协作分工、相互调用。

核心技术栈:从上到下

除了五层理论,大模型落地 AIOps 的核心技术(底层都以 prompt 质量决定输出质量):

Prompt Engineering  提示词质量决定输出质量
   ↓
JSON Mode           稳定输出 JSON,作为 LLM 与程序之间的桥梁
   ↓
Function Calling    把方法封装成函数调用,实现链式调用、意图识别
   ↓
RAG                 检索增强生成,用个人/运维专家知识库解决幻觉与不懂业务
   ↓
微调                 现阶段 GPT-4 等不能微调、实践上用得少,建议先用现成大模型
复习提示:我的建议:现阶段大模型自身能力已经不错,微调并没有那么重要——直接用现成的大模型就好。微调目前比如只有 GPT-3.5 级别可以微调,实践上一般较少使用。真正决定落地产出的是 Prompt 工程、JSON Mode、Function Calling 与 RAG 的组合。

实施 AIOps 的五大挑战

虽然挑战都比较大,但换个层面讲也要保持耐心与信心,因为每个挑战目前都有对应解决方案:

挑战说明应对思路
运维场景严肃性对错误容忍度极低用 RAG 技术极大缓解大模型的幻觉问题
数据隐私/安全/合规数据安全性限制多把开源大模型私有化部署(量化、裁剪等低成本方式)
高质量运维数据标注缺失语料和知识库普遍不足逐步积累、先聚焦聚类+人工标注核心场景
大模型难处理海量实时数据token 限制 + 成本,不能逐条分析先用机器学习对日志聚类,只把异常日志交给大模型
如何结合存量 DevOps 工具让大模型调用现有运维工具通过 Function Calling / Agent 把大模型与工具连接

大模型应用自身的可观测性

开发大模型应用时,自身也需要可观测性,例如:

  • Agent 里继承各种工具:要看调用链、调用结果、不同调用链的调用关系。
  • 调试不同的提示语(prompt 里面的 system)。
  • 在线调试:不同提示语立即修改、立即查看,而不是重新运行一遍程序。
  • 统计 token 消耗与费用。

这些需求可以借助大模型工程平台(如 Dify、Langfuse)实现。Langfuse 是开源的、价格也比较便宜;Dify 是很好的开源替代方案。

AIOps 与云原生:数据接入与运维接口

除了大模型,云原生架构也极大加速了 AIOps 发展,解决的是数据接入层和运维接口能力两大痛点:

  1. 运维接口能力(声明式):没有统一平台时,单独实现重启、配置变更、配置回滚这些接口能力很不容易。但业务整体采用云原生架构后,借助声明式通过 YAML 文件就能实现调整配置、回滚版本等。AIOps 平台调用运维接口时就拥有统一的方式。
  2. 数据接入层(OpenTelemetry / eBPF):最近两年很火的 OpenTelemetry 能统一日志、指标、追踪,是一个「All-in-One」的整体解决方案,一次性集成解决三种数据的采集问题。借助 eBPF 技术还能实现零侵入的指标收集与监控(如 Cilium、Falco)。

分布式追踪系统原理

用 OpenTelemetry 构建分布式追踪系统很简单:

  • 每个业务被抽象为一个 Span。
  • 请求被发起时的入口服务称为 Root Span(根节点),如图中的服务 A。
  • 服务 A 调用服务 B、服务 C,B/C 又调用下游服务,整个调用链就是一次分布式追踪。
  • Span 之间的边界反映父子关系:Span C 是 Span A 的子节点。
  • 右侧的调用时序图直观展示不同服务在时间线上的调用情况,也能倒推出 Span 之间的父子关系。
flowchart LR
    A[服务A
Root Span] --> B[服务B] A --> C[服务C] B --> D[服务D] C --> E[服务E]
复习提示:采样:分布式追踪数据量一般特别大(每次请求一条链路,QPS 高时数据量极大),实践中常用采样方式,比如 1:100 的采样比例来采集分布式追踪数据。

AIOps 常用算法与应用案例

在广件应用场景里,可以通过机器学习简化运维工作流程,例如故障预警、持续预测、故障分类、异常检测。按算法类别可分为:统计分析、持续分析与预测、机器学习分类、异常检测。

场景常用算法
故障预警LSTM(长短期记忆网络)、XGBoost 等
异常检测Z-score、滑动窗口 + 聚类等
流量预测预测波峰波谷的时间序列算法
日志聚类日志提取 → 分词 → 词向量 → 降维 → 聚类(如 DBSCAN)

日志聚类的核心流程:日志提取、分词、把分词转化为词向量、降维,最后用聚类算法实现聚类。最核心的步骤是借助**词频 + 逆文本频率指数(TF-IDF)**得到日志的特征向量,之后做降维,最后用 DBSCAN 等聚类算法把海量日志聚类为正常日志、错误日志、WARN 级别等。

运维知识库与数字分身

大模型结合 Agent 的一个典型场景是构建个人运维知识库 / 数字分身:

  • 流业务方通过询问 Agent 解决常见运维问答,而不是询问运维本人,例如「监控面板怎么看?」「memory_overcommit 指标是什么意思?」「分配给我的账号密码」「如何申请更高指标权限」「自动填写工单」等。
  • 同理,可以构建公司级的业务运维专家知识库:把运维专家的知识和经验通过 RAG 提供给大模型,相当于「克隆运维专家」——不仅能解决技术问题,还能解决专家知识的存储、快速检索、在不同专家之间的流动与汇总问题。

历史故障驱动的根因推断

运维知识库还有一个很不错的用法:用历史故障 + 专家经验(向量数据库)来推断新故障的原因。例如当出现「支付接口失败率 > 50%、持续 5 分钟」这类故障时:

  1. 借助 Agent 从向量数据库找出 Top-N 个历史类似故障及专家解决方案。
  2. 结合历史故障推断本次故障的原因和解决方向。
  3. 交给大模型处理,过程中让大模型做反思(Self-Reflection)来提高 RAG 准确率。
  4. 最终把本次故障加入向量数据库,实现知识库的实时更新,相当于拥有了「不断学习新知识的内部 AI 运维专家」。

一个完整的智能化运维流程

最终目标是构建一个智能化的运维闭环:

flowchart TB
    A[指标报警] --> B[异常检测机制
分析指标异常原因] B --> C[Agent 结合日志+追踪数据做根因分析] C --> D[向量数据库匹配专家知识库] D --> E[把 prompt+日志+追踪+专家知识
+历史类似故障交给大模型判断] E --> F{能否自动修复?} F -->|能| G[调用其他 Agent 多Agent协同主动修复] F -->|不能| H[调用人类帮助 Agent
与人类交互]

课程后续的训练营会带大家探索并实践这个简单的智能化运维流程。

基础设施即代码(IaC)概述

在进入容器和 Kubernetes 之前,需要先掌握基础设施即代码(IaC),因为后续模块会用到这一技术。

从创建云资源的三种方式说起

创建云资源一般有三种途径:

  1. UI 控制台:通过界面开通产品、做配置。体验好、无门槛,但缺点明显:
    • 除你之外没人知道在界面上到底操作了什么(不可审计、不可复现)。
    • 需要开通管理员级权限或子账户授权,管理上不够安全。
    • 体验取决于云厂商控制台能力(有的创建一台 VM 需要 VPC、子网、安全组、镜像、登录方式、密码、带宽、计费等一大堆东西)。
  2. API / CLI 命令行工具:每家用厂商都提供 API 或命令行工具(腾讯云 CLI、阿里云 CLI、AWS CLI),背后都调用自家 API。可以在 CI 流水线中创建云资源、拉起整套开发环境,也能用 SDK 集成做自动化。门槛更高,需要编程或 CLI 经验。CLI/API 本质上都是「命令式」的基础设施管理方式。
  3. IaC(Infrastructure as Code):以代码的方式把基础设施定义出来,用代码实现对基础设施的增删改查。因为只需要用 IaC 代码描述最终想达成的状态,它是一种「声明式」的基础设施管理方式——不必关注命令执行流程,只关注最终结果。

IaC 的三大特性

  1. 声明式:基础设施定义代码可方便地存储在 Git 仓库,并实现版本控制。
  2. 有状态:能够把 IaC 定义与真实云资源状态进行对比,并自动应用差异部分(新增/删除/修改)。
  3. 幂等:每次执行 IaC 代码都产生相同结果,不会因执行顺序或次数不同而改变。

IaC 带来的优势

  • 代码定义的就是基础设施最终状态,运行结果人人一致、可复现。
  • 借助 Git 版本控制,知道任何人、何时、对基础设施做了何种变更;故障时可回滚 IaC 代码。
  • 结合 Git 实现 CI 层面的质量门禁(合并前的 review、变更检查)。
  • 变更前 IaC 工具会输出清晰的影响范围:创建了什么、删除/更新了什么,而不是靠人写文档描述过程。
  • 一条命令、几分钟就能拉起一整套复杂基础设施——对有私有部署/私有交付团队尤其重要,离开 IaC 交付很难。

六大应用场景

  1. 用代码(声明式)定义和创建基础设施。
  2. 把既有的云资源统一导入,做统一管理。
  3. 更安全地变更:执行前列出影响范围,人工确认后再变更。
  4. 与 CI/CD 工具整合,形成基础设施管理的工作流。
  5. 提供可复用的模块,供其他团队复用。
  6. 团队实现标准化的基础设施管理流程(不再依赖某个人在控制台点点点)。

主流 IaC 工具

  • Terraform:本节课重点,最著名的 IaC 工具。
  • Crossplane:运行在 Kubernetes 平台上,能让你以 Kubernetes 声明式的思想、通过 CRD 来管理基础设施。

两者都支持主流云厂商(国内:腾讯、阿里、华为;国外:AWS、Azure、GCP)。

Terraform 核心概念与架构

Terraform 是 IaC 的代表工具,使用自创的 HCL(HashiCorp Configuration Language)语言定义基础设施。

为什么用 HCL 而不是 YAML / JSON

HCL 是一种DSL(领域特定语言)。配置语言在复杂场景下,模块复用能力和编程能力很关键,而这正是 YAML/JSON 支持较差的地方,导致它们在大规模配置场景下比较尴尬。HCL 设计时希望同时保留 YAML/JSON 的可读性优势,同时增加动态编程特性——写起来很像编程,但它是面向配置的编程语言。

例如生成一段 JSON 配置,用 HCL 往往只需三行就能表达 JSON 需要写多行的内容。细节:HCL 是给人编写、给 Terraform 读取的;真正调用云厂商 API 时,大部分情况还是用 JSON(这是 Terraform 内部做的接口层转换)。

常见使用范式

  • Terraform + Ansible:Terraform 管理基础设施,Ansible 做服务器配置(二者可一起用)。
  • Terraform 管 K8s 集群:用 Terraform 开通云厂商集群;测试场景就安装 K3s,快速得到测试集群;生产级可直接管理托管集群(腾讯 TKE、阿里 ACK/EKS、AWS EKS)。
  • 最简易测试流程:有测试需求时,用 Terraform + IaC 代码,一条命令拉出一套带公网访问能力的测试 K8s 集群。

总体架构

┌──────────────────────────────────────────────────────┐
│      HCL 配置代码(期望状态)  →  Terraform Core       │
│                           ↘                          │
│               Terraform 来读取 state 文件(当前状态)   │
│                           ↙                          │
│              对比差异 → 调用  provider → 云厂商 API    │
└──────────────────────────────────────────────────────┘
  • Terraform Core:核心编排引擎。加载 HCL 配置(期望状态)与 state 文件(当前状态),做差异对比,并把差异转化为调用云平台 API 的行为。
  • Provider:Terraform Core 本身不具备与云厂商直接交互的能力,靠 Provider(类似 Terraform 的插件、与核心引擎解耦)实现。Provider 将 HCL 配置映射到云厂商具体的 API 请求参数;一个 Terraform 文件里可用多个 Provider。
  • Registry:存储主流云厂商 Provider 的地方。每个 Provider 文档会告诉你如何安装、如何配置密钥、创建各种资源的示例代码。不需要死记硬背,知道怎么查怎么用即可。
复习提示:版本固定:引入 Provider 时强烈建议固定版本,防止上游更新导致 IaC 代码异常或参数废弃。常用的版本匹配符是 ~>(悲观约束符)——同时约束最旧和最新版本,允许小版本号更新、限制大版本号更新。

Terraform 核心命令

Terraform 最常见的四类命令:init / plan / apply / destroy。

命令作用说明
terraform init初始化依赖拉取 Provider 并下载到项目根目录 .terraform/;引入新依赖或拿到别人代码后先执行
terraform plan预览变更在 apply 之前确认本次变更的影响是否符合预期
terraform apply应用变更有交互式确认;CI 中可用 -auto-approve 跳过二次确认
terraform destroy销毁资源只删除由 Terraform 创建并记录在 state 文件里的资源,不会误删其它资源

init 的细节:目录结构

执行 terraform init 后:

  • Provider 存放在项目根目录的 .terraform/ 下,下载到的是一个二进制可执行文件,而且二进制是与平台相关的(不同平台的依赖不能复用)。
  • 会生成 .terraform.lock.hcl 文件,类似 Go/NodeJS 的依赖锁定文件,用来锁定依赖版本。
  • 若项目依赖了某个 Module,也会一并下载(Module 是为了实现代码复用而引入的概念,稍后介绍)。

plan 的对比逻辑

运行 terraform plan 时,Terraform 把**期望状态(HCL 代码 / .tf 文件)与当前状态(state 文件)**做对比。例如期望状态定义两台虚拟机 + 一台数据库,而当前状态只记录了一台虚拟机 + 一台数据库,plan 就会提示你需要新增一台虚拟机。

关键细节:期望状态和真实状态里的每个资源都有一一对应的内部唯一 ID 来标识。

state 文件

terraform apply 会在项目目录下生成 terraform.tfstate 文件,以 JSON 格式记录基础设置的真实状态。要点:

  • 文件中可能包含敏感信息(如虚拟机密码),保管要非常小心。
  • 单机使用可安全放本地或 Git 私有仓库;团队协作时放远端(对象存储 / Terraform Cloud),而不是放进 Git。
  • 执行 destroy 后该文件会随之清空。
复习提示:敏感信息警告:state 文件里可能存有密码、secret 等敏感信息,绝不能提交到公开 Git 仓库。团队协作时用远端后端存储,见下文「remote backend」。

import:导入既有资源

如果资源是在用 Terraform 之前通过控制台创建的,state 文件里没有记录,需要用 terraform import 导入:

terraform import tencentcloud_instance.web <资源ID>
  • 参数中的资源名必须与 resource 块中写的对象名称一一对应。
  • 运行后 Terraform 会从云厂商拉取该 ID 的所有信息,重新生成 state 文件,把它变成由 Terraform 管理。
  • 注意:并不是所有资源都支持导入。

apply 的四种状态组合

用「配置(IaC 代码)/ state 文件 / 真实状态」三者的组合,判断 apply 时的行为:

配置 (IaC)state 文件真实环境apply 行为说明
有无无创建全新资源
有有无创建state 记载有误,以 IaC 代码为准(会先调云厂商接口核真实环境)
有有有什么都不做三者一致
无有有删除从代码里删掉了该资源
无无有什么都不做该资源非 Terraform 管理,不会删除
无有无更新 state 文件真实已不存在
flowchart LR
    C{配置存在?} -->|是| S1{state有?} -->|无| CREATE[创建]
    S1 -->|有| R1{真实有?} -->|无| CREATE
    R1 -->|有| NOP1[什么都不做]
    C -->|否| S2{state有?} --- R2{真实有?}

state 的两种存储方式与 remote backend

  • 本地存储(local):一开始了解、使用 Terraform 时很方便。但文件在本地,不利于协作——两人 state 不同又先后变更会产生不一致。
  • 远端存储(remote backend):中心化存储 place,多人变更时都从中心拉取最新 state,不需要担心一致性问题。

远端存储方式包括:Terraform Cloud、对象存储(AWS S3 / 腾讯 COS / 阿里 OSS) 等。

Terraform Cloud

5 人以下免费,超过 5 人收费。在 Terraform Cloud 里创建组织和 workspace,代码里直接指定用 Terraform Cloud 作为后端存储。

terraform {
  backend "remote" {
    organization = "your-org"
    workspaces {
      name = "default-project"
    }
  }
}

用 COS / S3 做 backend

除了 Terraform Cloud,可用 AWS S3、腾讯 COS、阿里 OSS 存储 state:

  • S3 可指定加解密存储,还要配 DynamoDB 实现原子性操作(阻止两人同时变更)。
  • 腾讯 COS 做 backend 时,需要 region、bucket、app_id、prefix 等参数。
复习提示:先有鸡还是先有蛋:如果一上来就想用 Terraform 创建一个对象存储、又依赖这个对象存储存 state,会变成死循环。Terraform 已经解决了这个问题——可以在本地 state 时先创建好 COS,再修改 backend 配置把 state 迁移过去。

COS 迁移实操要点:先用本地 state 创建 COS 桶(私有 + SSE256 加密),配置好 backend 参数(region / bucket / app_id / prefix)后,执行 terraform init,它会识别 backend 变更并提示执行迁移;输入 yes 后本地 terraform.tfstate 会被清空,state 成功迁移到 COS。

state 相关命令

terraform refresh     # 本地 state 与远端不一致时,从远端更新 state(如你在控制台改过资源)
terraform state list # 列出 state 记录的所有资源
terraform state rm    # 删除 state 里保存的某条状态(destroy 失败时可尝试删异常状态后重跑)
terraform state pull # 从远端 backend 拉取 state
terraform state push # 将本地 state 推送到远端 backend

Terraform 项目布局(Layout)与变量

把所有 IaC 写在一个 .tf 文件里可读性和维护性都很差。官方推荐的良好布局是把一个文件拆成四个文件:

文件职责
main.tf主要业务逻辑;逻辑多可拆成多个子文件(如 cvm.tf / cos.tf),放同一目录下 Terraform 统一加载
output.tf定义运行结束输出的内容(如公网 IP、登录密码等);值可以是硬编码,也可引用资源对象;可标记为敏感数据避免打印
variables.tf定义输入参数并在 main 里引用(如 secret_id/key、region 等);支持校验函数(如长度 > 3)、敏感标记
versions.tf定义 Provider 版本,固定依赖版本,避免上游更新导致代码不可用
# variables.tf —— 声明输入参数
variable "region" {
  description = "基础设施地域"
  type        = string
  default     = "ap-hongkong"
}

variable "ssh_password" {
  type        = string
  sensitive   = true   # 敏感数据,plan 时不显示
  validation {
    condition     = length(var.ssh_password) > 3
    error_message = "密码长度必须大于3"
  }
}

变量的 5 种设置方式与优先级

设置 variable 一共 5 种方式,优先级从高到低覆盖:

  1. 命令行:terraform apply -var="foo=bar"。
  2. 配置文件:terraform.tfvars 文件(所有参数集中配置)。
  3. 环境变量:前缀 TF_VAR_(如 TF_VAR_region、TF_VAR_secret_id)——推荐方式,尤其配合不把密钥写进代码。
  4. 默认值:在 variables.tf 里定义 default(提供基础值)。
  5. 交互式输入:以上方式都取不到时,apply 会以交互式方式让你输入。

优先级:命令行 > 配置文件 > 环境变量 > 默认值。例如你在 variables.tf 里定义了默认值,但又用环境变量设置了同名参数,则以环境变量为准。

Terraform 实战:VM + K3s + ArgoCD

用一个综合例子走一遍「标准布局 + 模块化 + 多环境」:开通虚拟机 → 安装 K3s → 安装 ArgoCD,全部通过 IaC 管理。

目录拆分为多文件

在这个例子里,不用单个 main.tf,而是拆成:

.
├── main.tf          # (这里不需要,因为拆成下面三个业务文件)
├── cvm.tf           # 开通虚拟机
├── k3s.tf           # 在虚拟机上安装 K3s
├── argocd.tf        # 安装 ArgoCD
├── variables.tf     # 入参:secret_id / secret_key / region / ssh_password
├── output.tf        # 输出:public_ip、kube_config、ssh_password
└── versions.tf      # provider 版本固定(腾讯云 + helm)

所有参数值都从 variables 里取(var.secret_id 等),不再重复定义。安装 K3s 用一个 K3s 模块,安装 ArgoCD 用官方 Helm 模块。

depends_on:显式依赖

安装 Helm 前必须先有 K3s 集群,所以 Helm 处用了 depends_on 显式指定依赖 K3s 模块:

# argocd.tf
resource "helm_release" "argocd" {
  name       = "argocd"
  repository = "https://argoproj.github.io/argo-helm"
  chart      = "argo-cd"
  namespace  = "argocd"
  create_namespace = true

  depends_on = [module.k3s]   # 等 K3s 模块跑完才装 ArgoCD
}
复习提示:

依赖有两种:

  • 隐式依赖:一个模块的输出作为另一个模块的输入(如 K3s 引用虚拟机的 IP 和密码),Terraform 自动识别。
  • 显式依赖:模块之间没有相互引用时,只能通过 depends_on 指定执行顺序。 Terraform 的 plan 会依据依赖关系形成有向无环图(DAG),再按 DAG 顺序执行各模块。可用 terraform graph 生成该图。

运行与 graph

terraform init
TF_VAR_secret_id=<id> TF_VAR_secret_key=<key> terraform apply -auto-approve
terraform graph | dot -Tsvg > graph.svg   # 可视化依赖关系

用 terraform graph 生成的 SVG 就是 Terraform 构建的 DAG:所有资源的执行依赖和步骤都记录在这张图里。

HCL 进阶:表达式、函数与元参数

相较 YAML/JSON,HCL 因具备编程特性,能生成复杂结构。

表达式与函数

  • 表达式:引用模板变量、运算符、条件表达式做流程控制;for 表达式可以把生成的块当作程序一样,生成 N 个资源块。
  • 函数:字符串处理、集合操作等方法都能找到。常用 templatefile 函数——定义自己的 shell 脚本模板文件,用 Terraform 内置变量替换模板里变量值重新生成文件,对处理复杂情况很有帮助。

四个元参数

元参数的作用域主要是 resource 和 module,用来控制资源的创建和销毁过程:

元参数作用
depends_on显式声明资源依赖关系,生成 DAG 保证执行顺序
count创建 N 个完全一致的资源,web[0]、web[1]… 带索引访问
for_each类似 count,但更好控制,适合每台配置不同的场景(如不同子网);先声明集合再循环使用
lifecycle控制创建/删除行为:before/阻止删除/忽略差异/引用变化时替换资源;常用「先建后删」实现零停机
复习提示:count 与 for_each 区别:count 创建的资源完全一致;当要创建两台属于不同子网的虚拟机时,for_each 能更好地控制。

Provisioner

Provisioner 用于在本地或远端虚拟机中执行一组动作,三个最常用的:

类型作用注意点
file把本地文件拷贝到远端虚拟机(类似 scp)传配置文件、shell 脚本时好用
local-exec执行本地命令有平台差异:Linux 能跑的命令放 Windows 可能跑不了
remote-exec在远端虚拟机执行命令可用 inline 写多行命令,也可指定远端 shell 脚本(通常先 file 传脚本再 remote-exec 运行)

多环境管理

怎么为同一套基础设施创建多环境(dev / test / prod)?有三种方案:

方案一:目录隔离(缺点明显)

Terraform 把状态记录在 state 文件,最直接的方式就是区分 state 文件。把 IaC 代码复制到不同目录(目录名即环境名),各自拥有专属 state 文件。

缺点:修改 IaC 代码需同时修改多个环境目录下的相同文件,时间久了环境差异会越来越大、越来越难维护。

方案二:Workspace(需维护上下文)

terraform workspace 本质上也是对 state 文件做区分,但它是一种内置功能:在同一份 Terraform 代码下创建子目录放不同 state 文件,实现不同环境/workspace 的区分。

terraform workspace list           # 默认只有 default
terraform workspace new dev        # 创建并切换到 dev workspace
terraform workspace new testing    # 创建 testing
terraform workspace select dev     # 切换回 dev

只需维护一份代码即可创建 N 个环境。但它额外增加了上下文负担——执行任何命令都必须清楚自己所在 workspace,一不小心就会在错误的 workspace 执行错误的命令。

复习提示:我的建议:实际场景里尽量不用 workspace 方案做环境隔离,上下文切换出错代价很大。

方案三:模块 + 目录隔离(推荐)

兼顾目录与 workspace 二者优点的方案是用模块(Module)+ 目录隔离。

模块概念很像程序里的 class,目的是复用 Terraform 代码,让代码组织更具结构与灵活。分两类:

  • 根模块:包含所有工作目录下的 .tf 文件——你创建的任意 demo 目录都是根模块。
  • 子模块:通过引用方式使用外部模块(本地模块、Registry 模块、其他来源)。K3s 那个模块就是 Registry 里的模块。

重构为模块的思路:

demo/
├── modules/
│   ├── cvm/            # 虚拟机模块:main.tf + variables.tf + outputs.tf + versions.tf
│   └── k3s/            # K3s 模块:main.tf + variables.tf + outputs.tf
├── dev/                # dev 环境目录
│   ├── main.tf         # 只引用模块,几乎无业务逻辑
│   └── variables.tf
└── testing/            # testing 环境目录(结构同 dev)
  • 每个模块独立工作,输出通过 outputs 暴露。
  • 环境目录下的 main.tf 逻辑极简,只引用 cvm 模块 + k3s 模块并传参。
  • 用 module 输出(public_ip)作为下一个模块输入,形成隐式依赖,Terraform 自动先建 cvm 再建 k3s。
# dev/main.tf —— 引用模块
module "cvm" {
  source   = "../modules/cvm"
  secret_id = var.secret_id
  secret_key = var.secret_key
  password  = var.ssh_password
}

module "k3s" {
  source      = "../modules/k3s"
  public_ip   = module.cvm.public_ip
  private_ip  = module.cvm.private_ip
}

output "kube_config" {
  value = module.k3s.kube_config
}

好处:修改 IaC 只需改 module,环境代码几乎不变,不会导致各环境在维护中产生差异。

设计模块的原则

  • 以产品功能为维度拆分模块。
  • 为模块设置必要入参和逻辑条件判断,让同一模块在不同参数下更灵活(如根据环境名判断 dev 用按量付费、生产用包年包月)。
  • 入参提供有用的默认值,降低使用难度、减少必须传参数量。
  • 一定要设置 output,它是把不同模块串联起来的必要条件。

Crossplane:把云资源变成 Kubernetes CRD

Crossplane 是一个 Kubernetes 控制器(Operator),能让你以 CRD 的方式定义基础设施:

  • 用声明式方式管理基础设施,支持多云与混合云。
  • 甚至可以在 Kubernetes 里运行 Terraform,实现「YAML → Infra」——把一段代码部署到集群就能自动开通基础设施。
  • 尤其适合自研 PaaS 平台:提供 UI 表单让开发同学填单,后端把表单生成 YAML 部署到集群,就能自动创建基础设施。

工作原理

Crossplane 由 CRD(描述 Crossplane 资源对象,如虚拟机、VPC、COS 对象存储) 和 Controller(控制循环,不断 watch CRD 变化,变化时自动执行基础设施变更) 组成。它与 Terraform 设计相近:有核心、有 Provider,核心能力由 Provider 提供;提供商市场(如 Boundless)里能找到大量第三方 Provider。

注意:国内云厂商对 Crossplane Provider 的投入更新频率比 Terraform Provider 低,但不影响使用。

用 Crossplane 创建腾讯云 CVM

在安装好 Crossplane 的 K3s 集群里,通过 YAML 创建 VPC + 子网 + CVM:

  1. Install Provider:Provider.yaml,把腾讯云 Provider 安装进去。
  2. ProviderConfig:通过文件把 secret_id / secret_key 传进去(引用一个 Secret)。
  3. Secret:在 crossplane-system 命名空间存放 credential 信息。
  4. VPC:只需一个 CIDR block。
  5. Subnet:可用区 + CIDR + spec.forProvider.vpcIdRef(引用上面创建的 VPC)。
  6. CVM:实例名、可用区、计费类型、镜像 ID、实例类型、磁盘类型 + 引用 VPC/子网 ID。
kubectl apply -f vpc.yaml
kubectl apply -f subnet.yaml
kubectl apply -f cvm.yaml
kubectl get vpcs,subnets,cvms   # 查看状态,READY 从 false → true
复习提示:实操坑:CVM 创建状态卡在 false 时,优先检查三件事——① 子网和 VPC 的 reference 是否命名正确;② secret_id/key 是否有效(无效时换一组并重新 apply ProviderConfig/Secret);③ 可用区、命名空间是否写对(如 crossplane-system 与 crossplane 混淆)。Kubernetes 会等 Crossplane 控制器完成后状态才变 true。

ArgoCD + Crossplane 自建 PaaS(YAML to Infra)

把 Crossplane 的 YAML(基础设施代码)放进 Git 仓库,用 ArgoCD 同步到集群,实现「提交 YAML → 自动建/删基础设施」:

  1. 安装 ArgoCD:加 chart 仓库并安装,取出 admin 密码,端口转发访问 8080。
  2. 添加仓库(Repository):在 settings → repositories 里添加 Git 仓库(需要 personal access token)。
  3. 创建应用:填写仓库、路径(如 module2/tencent/cvm)、目标 namespace,设为自动同步。
  4. 变更即上线:修改仓库里的 VPC YAML(如新增 VPC2 + 改 CIDR),ArgoCD 按轮询拉变更并同步到集群,Crossplane 监听到新 CRD 后调用腾讯 API 创建;ArgoCD UI 里点 Refresh 可跳过同步间隔手动触发。删除时把 YAML 从仓库删掉同步,资源也会被删除。
flowchart LR
    REPO[(Git 仓库
跨plane YAML)] -->|ArgoCD 同步| K8S["K8s 集群
CRD: VPC/子网/CVM"] K8S -->|watch 变更| XP[Crossplane Provider] XP -->|调用 API| CLOUD[腾讯云资源]

至此你就实现了一个「ArgoCD + Crossplane 自建 PaaS」的最小闭环:Infra 作为代码存入 Git,增删改都走 GitOps,无需人工介入。

总结

云原生基础不仅是容器和 Kubernetes,更是一套围绕 DevOps、SRE、AIOps 的现代化工程体系。本章核心脉络:

  • 演进脉络:瀑布 → 精益 → 敏捷 → DevOps → SRE → AIOps,后者不是替代前者,而是在协作、可靠性、智能三层叠加能力。
  • AIOps 三阶段:监控(数据来源)→ 分析 → 自动化;数据层是核心基础,运维接口能力借助 K8s 声明式得以抽象化,因此 AIOps 必须与云原生结合。
  • 大模型两大机遇:数据建模 + 数据分析;用「五层理论」(模型 → Prompt → 思维链 → Agent → 多 Agent 协同)落地,核心技术栈含 JSON Mode、Function Calling、RAG。
  • 五大挑战:场景严肃性、数据隐私合规、数据标注缺失、海量实时数据、结合存量工具——每个都有应对方案。
  • IaC:声明式、有状态、幂等三大特性;Terraform 用 HCL,核心是 init/plan/apply/destroy + state + provider + registry。
  • 多环境:目录 / workspace / 模块+目录三种方案,推荐模块 + 目录隔离并遵守标准布局。
  • PaaS:ArgoCD + Crossplane 实现「YAML → Infra」的 GitOps 自建 PaaS。

说真的这一章全是概念,看着最枯燥,但真到后面写 Operator、调 LLM、做流量预测的时候,回头再看会发现每一步都对得上。DevOps 给你流水线,SRE 给你 SLO,AIOps 在这俩基础上才能落地。


自测题与动手练习

面试官
AIOps 的严格定义是什么?它的三个基本阶段分别是什么?为什么说「数据」是 AIOps 的核心基础?
候选人
定义:AIOps 是使用人工智能技术(机器学习、数据分析等)来简化运维工作流的技术方案。
三阶段:① 监控(数据来源,含历史/实时数据)→ ② 分析(归纳/分类/异常检测/关联分析)→ ③ 自动化(按建议或任务自动执行)。
因为无论是机器学习还是数据分析,处理对象都是数据——没有高质量数据,一切的智能分析都无从谈起。
面试官
为什么 AIOps 一定要与云原生结合?OpenTelemetry 和 eBPF 分别解决了数据接入层的什么问题?
候选人
① AIOps 最上层需要运维接口能力,早期很难抽象;借助 K8s 的声明式能力,重启/回滚/调整参数都容易实现,所以必须与云原生结合。
② OpenTelemetry 统一日志/指标/追踪,是 All-in-One 方案,一次集成解决三种数据采集;eBPF 实现零侵入的指标收集与监控(如 Cilium、Falco)。
面试官
用「五层理论」说明大模型落地 AIOps 需要跨越哪五层鸿沟?核心技术栈从上到下依次是什么?
候选人
五层:模型层(API 接入)→ Prompt 层(提示词工程)→ 思维链(链式/多步调用)→ Agent 层(自主决策行动)→ 多 Agent 协同(任务拆分协作)。
核心技术栈(都以 Prompt 质量为基础):Prompt Engineering → JSON Mode(稳定输出,作为 LLM 与程序桥梁)→ Function Calling(封装函数调用、链式、意图识别)→ RAG(用知识库解决幻觉/不懂业务)→ 微调(现阶段实践用得少,建议先用现成大模型)。
面试官
AIOps 的五大实施挑战分别是什么?每个挑战对应的应对思路是什么?
候选人
① 运维场景严肃性 → 用 RAG 缓解幻觉;② 数据隐私/合规 → 开源大模型私有化部署(量化/裁剪);③ 高质量数据标注缺失 → 逐步积累、聚类+人工标注核心场景;④ 大模型难处理海量实时数据 → 先用机器学习聚类,只把异常日志给大模型;⑤ 如何结合存量 DevOps 工具 → 用 Function Calling / Agent 连接工具。
面试官
IaC 相对 CLI/API 的「命令式」管理,核心优势是什么?它的三大特性是什么?
候选人
优势:可版本控制与回滚、人人一致可复现、变更影响范围可预览、一条命令拉起整套复杂基础设施。
三大特性:声明式(只描述最终状态)、有状态(对比差异并自动应用)、幂等(每次执行结果都相同)。
面试官
Terraform 的 plan、apply、destroy 都基于什么做判断?state 文件为什么重要、团队协作时应存到哪里?
候选人
plan/apply/destroy 都基于 state 文件(当前状态)与 HCL 配置(期望状态)的对比,每个资源有内部唯一 ID 一一对应。
state 文件以 JSON 记录真实状态,可能含敏感信息(如密码);单机可放本地/私有 Git,团队协作时放远端(COS/S3/Terraform Cloud),destroy 后清空。
面试官
多环境管理有哪三种方案?为什么推荐「模块 + 目录隔离」?
候选人
三种:① 目录隔离(复制代码到不同目录,维护性差);② Workspace(一份代码多环境,但要维护「当前 workspace」上下文,易执行错命令);③ 模块 + 目录隔离(推荐)。
模块化让修改只发生在 module,环境目录只引用模块、几乎不变,不会让各环境差异越来越大,同时通过模块输出(public_ip)串联隐性依赖。
面试官
Crossplane 与 Terraform 的根本区别是什么?如何用 ArgoCD + Crossplane 实现「YAML → Infra」?
候选人
Terraform 用 HCL 走 write→plan→apply;Crossplane 是 K8s 控制器,用 CRD/YAML 声明式管理基础设施,Controller 持续 watch CRD 变化并调用云厂商 API。
YAML → Infra 流程:把 Crossplane 的 YAML 存入 Git → ArgoCD 同步到集群 → Crossplane 监听到 CRD 变更 → 调腾讯 API 创建/删除资源。增删改全走 GitOps,无需人工介入,适合自研 PaaS。

动手练习(建议真做一遍):

  1. 用腾讯云 + Terraform 开通一台 CVM,体验 plan 看变更 → apply → destroy 全流程;再把密钥改用 TF_VAR_ 环境变量方式传(而不是写进代码)。
  2. 把 IaC 按 main/output/variables/versions 拆分,再用 Crossplane 的 YAML(VPC + 子网 + CVM)创建资源,最后接入 ArgoCD 体验一次「改 Git → 自动建资源」。
  3. 把 Teraform 代码重构为「模块 + dev/testing 目录」结构,改一次 module 让两个环境同时生效,体会模块化多环境的收益。

本章小结

复习提示:
  • 软件交付从瀑布→精益→敏捷→DevOps→SRE→AIOps 持续演进,后者不是替代前者,而是在协作、可靠性、智能三层叠加能力。
  • AIOps = 使用 AI(ML/LLM)简化运维工作流;三阶段是监控→分析→自动化,数据是核心基础,运维接口能力靠 K8s 声明式抽象 —— 所以 AIOps 必须与云原生结合。
  • 大模型给 AIOps 带来数据建模 + 数据分析两次机遇;用「五层理论」落地,核心技术栈为 Prompt/JSON Node/Function Calling/RAG/微调,落地有五大挑战但都有对策。
  • 传统根因分析靠「人工纵向切周期 + 递归上下游」,效率低易选错路线;大模型实现多模态数据 + 混合专家处理,还催生自然语言交互与 Agent 协作。
  • IaC 三大特性(声明式/有状态/幂等)带来可审计、可复现、可回滚的收益;Terraform 用 HCL,version 固定用 ~>,state 绝不能提交公开 Git。
  • 多环境推荐模块 + 目录隔离并遵守标准四文件布局;Paas 自建可走 ArgoCD + Crossplane 的 YAML→Infra 闭环。
  • 下一章进入容器和 Kubernetes,届时会用到本章的 IaC 能力搭建测试集群。
About Me

没什么想介绍的,一个很大众的码农…

喜欢代码,车,马,真的是 🐎

讨厌别人让我给自己的代码写注释 最厌烦别人的程序没有写注释

目标

学AI,加油!加油!