课程目录

第 3 周 · 初阶

第3周:云计算与云原生

从传统架构走向云原生

周目标:理解云服务模型、华为云生态、云原生架构思想

课程成果:CO1 CO8

已学习 0 / 7 天

本周 7 个学习日

Day 15

云计算基础

建议时长:60 分钟

本日 CO:CO1 CO8

本日概要

用 NIST 的五个基本特征、IaaS/PaaS/SaaS 三种服务模型与公有云、私有云、社区云、混合云四种部署模型建立统一语言;从责任边界、弹性、可计量、数据位置、合规、可移植性与退出路径评估服务,而不是把“上云”当作单一产品选择。练习不比较易变价格,只记录计费单位、成本驱动因素与必须在实际选区重新核验的变量。

听书与视频

本日听书

5 分钟 · MP3 · 双主持人讲解

B 站讲解

1.1 云计算基础知识

idontcare11 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能用五个基本特征判断一项能力是否符合 NIST 云计算定义
  • 能区分 IaaS、PaaS、SaaS 的控制权与运维责任,不把服务模型等同部署位置
  • 能比较公有云、私有云、社区云、混合云的访问范围与连接关系
  • 能用需求、风险、可运维性和成本驱动因素形成可复核选型假设

核心讲解

两组正交分类:买到什么与部署给谁

NIST 把云计算描述为按需网络访问共享可配置资源池,并列出按需自助、广泛网络访问、资源池化、快速弹性和可计量服务五个特征。IaaS 提供计算、存储和网络等基础能力,使用方仍管理操作系统与应用;PaaS 提供应用运行平台,使用方聚焦代码和数据;SaaS 直接交付可使用的软件。它们表达的是能力与责任边界,不是“机器在谁的机房”。

部署模型回答访问和治理范围:公有云面向公众使用,私有云由单一组织专用,社区云服务具有共同关注点的组织群体,混合云把两个或更多仍保持独立的云以技术连接,使数据或应用可移植。混合云不是任意两套系统并排,也不自动带来容灾;身份、网络、数据一致性和故障切换仍需明确设计与验证。

从产品清单转向责任、风险与成本驱动

选择服务时先写工作负载:请求模式、数据敏感度、恢复目标、延迟、团队能力、锁定风险和退出方式,再判断哪些层愿意自行管理。IaaS 控制更细但补丁、容量和备份责任更多;托管平台减少日常操作,却可能限制运行时、网络或迁移路径;SaaS 上手快,但配置、身份、导出和供应商边界仍由采购者核验。所谓“托管”不等于责任消失。

成本意识不等于抄一张价格表。更稳定的做法是记录实例时长、存储容量与请求、网络出站、备份保留、日志与追踪量、支持等级等计费单位,建立低/中/高负载情景,并注明区域、币种、税费、折扣和核验日期均为运行前变量。没有授权账号和预算时只做架构与计算器草案,不创建会计费的资源。

实践任务

为同一个小型 Web API 分别设计 IaaS、PaaS、SaaS 组合,画出用户与提供方责任边界,并说明公有云、私有云和混合云部署条件。

  • 平台:浏览器与本地表格;权限:只读访问 NIST 和云厂商官方文档,不登录或创建资源。列出小型 API 的用户、数据、峰值、恢复、合规和团队约束。
  • 建立“服务模型—使用方管理—提供方管理—可替换接口—失败影响”矩阵,分别给出 IaaS/PaaS/SaaS 方案;将事实、推断和建议分列。
  • 为公有云、私有云、社区云、混合云画访问者和资源边界,指出混合连接、身份、数据同步与退出验证点。
  • 安全:不录入账号、密钥或真实业务数据;成本只写计费单位与情景假设,不复制会变化的单价。清理:关闭浏览器中的未提交计算器草案,删除本人临时表格前确认路径与文件名。

自测与答案

第 1 题

IaaS 与私有云是否属于同一分类维度?

尚未检查本题。

查看答案与评价要点

参考答案:不是。IaaS 是服务模型,描述交付能力和责任边界;私有云是部署模型,描述专用访问和治理范围,两者可以组合。

评价要点:明确服务模型与部署模型是两个维度;说明 IaaS 与私有云可以组合

第 2 题

为什么仅比较月度总价不足以完成云服务选型?

尚未检查本题。

查看答案与评价要点

参考答案:总价依赖区域、用量、网络出站、备份、可观测性和折扣等假设;还必须同时评价责任、风险、性能、迁移与退出证据。

评价要点:列出至少三个价格或用量假设;同时考虑责任、风险与退出证据

尚未完成自测。

今日完成标准

  • 完成三种服务模型与四种部署模型的正交矩阵,至少标出六项责任或风险
  • 提交一个不含易变单价的三情景成本驱动表,并给出官方来源与实际核验日期

常见错误与纠正提示

  • 把 PaaS 直接写成公有云,混淆服务模型和部署模型
  • 把资源创建快等同于可用、合规或可恢复,没有定义验证证据
  • 复制某地区即时价格后写成长期普遍结论

分层任务

基础任务

使用给定需求卡完成分类与责任边界填空。

标准任务

独立提出三种服务模型方案并用风险和成本驱动因素比较。

挑战任务

增加混合云退出演练,说明身份、网络与数据可移植性的可验证条件。

关联知识点

延伸阅读

学习状态:未学习

Day 16

华为云生态

建议时长:65 分钟

本日 CO:CO1 CO8

本日概要

以华为云 ECS、EVS、VPC、OBS、RDS 为例进行云服务选型:先按计算、块存储、对象存储、网络和托管数据库区分职责,再用数据路径、故障域、权限、备份恢复和计费单位验证组合。课堂默认只读查文档与画方案;真实控制台创建必须使用授权沙箱、预算和清理单,不把拥有账号误当作拥有业务变更权限。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

2.3.1 华为云生态&快速入门

idontcare11 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能解释 ECS、EVS、VPC、OBS、RDS 的核心职责和连接关系
  • 能根据块访问、对象访问、事务数据库和网络隔离需求排除不适合的服务
  • 能为一套方案标注最小权限、数据保护、恢复与成本核验点
  • 能区分官方产品事实、自己的架构推断和仍需沙箱验证的假设

核心讲解

从服务名称还原资源与数据路径

ECS 是包含 vCPU、内存、操作系统和 EVS 磁盘等要素的计算单元;EVS 面向可挂载的块存储;VPC 为云服务器、容器和数据库提供逻辑隔离网络,并通过子网、安全组、路由等组织连接;OBS 以对象接口保存非结构化数据;RDS 承担受托管的关系数据库能力。架构图应写清客户端经何处进入、应用访问哪类数据,以及控制操作由谁发起。

不能因为服务在同一品牌下就假设网络天然可达或数据天然备份。ECS 到 RDS 的连通仍取决于 VPC、子网、路由、安全组和数据库授权;EVS 与 OBS 的访问语义不同,前者像块设备,后者通过对象 API;RDS 的托管会减少部分数据库运维,但应用账号、数据分类、查询设计和恢复验收仍有用户责任。

创建前评审比控制台点击更重要

一个可评审方案至少包含区域与可用区假设、CIDR、入站和出站、身份角色、加密与密钥责任、备份保留、恢复演练、监控、标签和所有资源的退出动作。先用数据分类决定能否放入示例环境,再用最小权限矩阵决定谁可以查看、创建、修改和删除;没有变更单或教师沙箱时,学习产物应停在架构图与创建前检查表。

成本表不保存当日单价,而保存驱动项:ECS 运行时长和规格、EVS 容量与性能类别、OBS 容量/请求/网络流量、RDS 实例和备份、弹性公网带宽、日志量以及闲置资源。每个驱动项写使用假设、预算阈值、告警责任人和实际查询入口;若以后实施,按资源 ID 与课程标签逐项核验后清理,绝不用全局批量删除。

实践任务

为静态资源加小型事务 API 选择 ECS/EVS/VPC/OBS/RDS 组合,提交控制面、数据面、责任与成本驱动图;可选沙箱只做创建前计划评审。

  • 平台:浏览器、绘图工具和华为云官方文档;权限:默认匿名只读。若教师提供沙箱,先用 `whoami` 对应的云身份页或 IAM 页面核对仅限指定项目的角色,不请求管理员权限。
  • 画 ECS—EVS—VPC—OBS—RDS 架构,分别标出对象上传、事务请求、数据库备份和运维控制路径;每条连线写协议或访问类型。
  • 建立选型表:数据形态、持久性、可用区、恢复、网络暴露、身份、可观测性、退出与成本驱动;逐项映射来源:ECS 文档支持计算单元组成,EVS 文档的 EVS/SFS/OBS 对比表同时支持块存储与对象存储差异,VPC 和 RDS 文档分别支持网络与托管数据库声明。所有产品声明附官方 URL 和学习者实际访问日期。
  • 安全:只使用虚构数据、禁填 Access Key 和生产地址;清理:本课不默认创建云资源。获批沙箱必须先记录 resource_id 与 `aiknow.exercise` 标签,删除前双重核验,创建失败或归属不明时停止清理并通知负责人。

自测与答案

第 1 题

用户上传图片供多个应用读取,更适合先评估 EVS 还是 OBS?为什么?

尚未检查本题。

查看答案与评价要点

参考答案:先评估 OBS,因为需求是通过对象接口共享非结构化对象;EVS 是附加给计算实例的块存储,访问与挂载边界不同。

评价要点:选择 OBS 并说明对象 API;准确区分 EVS 块存储语义

第 2 题

使用 RDS 后,哪些责任仍不能交给云提供方?

尚未检查本题。

查看答案与评价要点

参考答案:应用账号与最小权限、数据分类、查询和 schema、备份保留选择、恢复验收、密钥和网络访问等仍需用户负责或共同负责。

评价要点:列出至少三项用户或共同责任;明确托管不等于责任消失

尚未完成自测。

今日完成标准

  • 架构图正确覆盖五类服务、四条数据/控制路径与至少三个故障或权限边界
  • 提交创建前检查与精确清理清单,成本部分只使用计费驱动和待核验变量

常见错误与纠正提示

  • 把 EVS 与 OBS 都写成普通网盘,忽略块设备和对象 API 差异
  • 认为 RDS 托管等于无需备份恢复验收或应用权限治理
  • 先创建公网资源再补安全组、标签和预算计划

分层任务

基础任务

在给定架构图上标注五类服务和责任边界。

标准任务

完成小应用选型表、网络数据路径和创建前检查单。

挑战任务

增加跨可用区故障与退出迁移推演,比较恢复和成本驱动变化。

关联知识点

延伸阅读

学习状态:未学习

Day 17

云原生理念

建议时长:60 分钟

本日 CO:CO1 CO8

本日概要

把 12-Factor 视为服务化应用设计检查表,而不是必须拆成微服务的口号:代码库、依赖、配置、后端服务、build-release-run、无状态进程、端口绑定、并发、可处置性、开发生产一致、日志事件流和一次性管理任务共同提高可部署性。再将声明式期望状态、不可变制品与小步发布连接起来,同时识别数据库状态、密钥和迁移不能靠“无状态”一笔带过。

听书与视频

本日听书

5 分钟 · MP3 · 双主持人讲解

B 站讲解

【IT老齐307】云计算与云原生是什么关系?

IT老齐 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能解释 12-Factor 各原则解决的部署问题及其边界
  • 能区分 build-release-run 三阶段以及代码、配置、制品的身份
  • 能把无状态进程、后端服务、日志事件流与平台职责联系起来
  • 能用差距证据决定是否需要微服务、声明式配置或不可变制品

核心讲解

原则服务于可部署性,不服务于名词数量

12-Factor 要求一套受版本控制的代码库对应多个部署,显式声明和隔离依赖,把会因部署而变的配置置于环境,将数据库等后端当作可替换附加资源,并严格区分 build-release-run。它还建议进程无状态、通过端口提供服务、以进程模型扩展、快速启动和优雅终止、缩小开发生产差距、把日志作为事件流、把管理任务作为一次性进程。每项都需要可观察的实现证据。

这些原则不等于“所有系统都必须微服务”。一个结构清楚的单体同样可以外置配置、生成不可变制品、执行健康检查并输出结构化日志;反之,拆成多个服务却共享数据库密码、手工修改运行容器、没有 trace context,只会扩大故障面。架构选择应从团队边界、独立发布需求和故障隔离出发。

声明式期望状态仍需要验证闭环

声明式 API 描述“希望有三个可用副本”,控制器不断比较实际状态与期望状态并尝试收敛。不可变基础设施强调以新制品替换而非登录机器手改;两者能降低配置漂移,却不能保证声明本身正确。镜像 digest、配置版本、数据库迁移顺序、readiness、回滚兼容性和变更证据仍决定发布是否安全。

把日志写到标准输出只是起点,平台还要采集、保留、访问控制和关联;把密码放入环境也不自动安全,秘密值仍需受控存储、最小权限和轮换。学习者应把每项原则写成“当前证据—风险—最小改造—验收信号”,避免只给符合/不符合的主观标签。

实践任务

审查一个虚构小应用的配置、日志、启动、状态和发布流程,形成 12-Factor 差距表与最小改造计划。

  • 平台:任意文本编辑器和 POSIX shell;权限:只读审查教师提供的虚构仓库清单,不访问真实 CI 变量、密钥库或生产日志。
  • 逐项填写 12-Factor 差距表,至少引用配置、依赖锁定、启动、日志、状态和管理任务六类具体证据;为每项标注事实或推断。
  • 画出 commit → build 制品 → release(制品加配置)→ run 的身份链,为每一段定义可核验 ID 与失败停止点。
  • 安全:示例配置只写变量名,不写秘密值;清理:所有草稿创建在 `mktemp -d` 返回目录,记录 `work_dir`,结束时确认目录含本次随机标记且无他人文件后仅删除该目录。

自测与答案

第 1 题

把数据库密码硬编码进仓库违反哪项核心边界,移到环境变量是否已经完成全部安全工作?

尚未检查本题。

查看答案与评价要点

参考答案:违反配置与代码分离;移到环境只是交付方式之一,还需要秘密存储、访问控制、避免日志泄露和轮换。

评价要点:指出配置与代码分离;补充秘密存储、访问或轮换边界

第 2 题

为什么同一个镜像 digest 可以参与多个 release?

尚未检查本题。

查看答案与评价要点

参考答案:build 产生制品;release 将该制品与特定部署配置结合。同一不可变制品可与不同环境配置形成不同 release。

评价要点:区分 build 与 release;说明配置使 release 身份不同

尚未完成自测。

今日完成标准

  • 完成十二项差距表,至少六项有具体仓库或运行证据和验收信号
  • 提交 build-release-run 身份链与一个不依赖手改运行实例的改造顺序

常见错误与纠正提示

  • 把 12-Factor 等同微服务数量,忽略单体也能采用这些运行原则
  • 认为配置放环境变量后秘密自动安全
  • 把声明式配置当成正确性证明,不设计 readiness、回滚和数据兼容验证

分层任务

基础任务

用教师提供的证据卡匹配十二项原则。

标准任务

完成差距、风险、改造和验收四列表。

挑战任务

为有状态迁移设计向前兼容、回滚受限与观测信号。

关联知识点

延伸阅读

学习状态:未学习

Day 18

Kubernetes深入

建议时长:90 分钟

本日 CO:CO1 CO8

本日概要

从控制平面和工作 Node 解释 Kubernetes:API server 接受期望状态,etcd 保存集群状态,scheduler 选择 Node,controller manager 推动实际状态收敛,kubelet 管理 Pod,容器运行时执行容器。再用 Deployment 管理无状态副本与更新、Service 以 selector 提供稳定访问、Ingress 为 HTTP/HTTPS 路由且必须由控制器实现;同时注明官方已建议新设计评估 Gateway API,Ingress API 冻结但仍稳定。

听书与视频

本日听书

5 分钟 · MP3 · 双主持人讲解

B 站讲解

如何快速搞懂云原生的核心,我推荐读一下《深入剖析Kubernetes》

bitebyte · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能沿 API 请求解释控制平面组件、Node、kubelet、Pod 和容器运行时的协作
  • 能区分 Pod、Deployment、Service 与 Ingress 的职责和 selector 关系
  • 能在最小权限和专用 namespace 中验证声明状态、实际状态和访问路径
  • 能以资源 UID、镜像 digest、事件、日志和清理记录证明一次部署

核心讲解

控制回路与工作负载对象

客户端向 API server 提交对象,认证、授权和准入通过后,期望状态写入集群状态存储;scheduler 为未绑定 Pod 选择 Node,controller manager 中的控制器不断比较期望与实际,Node 上 kubelet 通过容器运行时使 Pod 运行。这个过程不是一次性脚本链:任何一步都可能等待、拒绝或重试,排障必须同时观察对象条件、事件、调度、镜像拉取和应用就绪。

Pod 是最小可部署计算对象,但直接创建的裸 Pod 不提供应用级更新和副本管理;Deployment 管理 ReplicaSet,声明副本和滚动更新;Service 根据 label selector 抽象一组后端,端口存在不代表应用 ready;Ingress 描述 HTTP/HTTPS 路由,只有安装并配置对应 Ingress controller 才会生效。官方建议新设计评估 Gateway,课程仍用 Ingress 理解基础路由边界。

隔离实验资源,而不是赌随机名称不会撞

实验同时随机化 `profile_name` 和 `namespace_name`,创建前确认它们不存在,创建后保存 namespace UID 并加 `aiknow.exercise=$lab_token` 归属标签。所有 kubectl 命令显式写 context 和 namespace,先用 `kubectl auth can-i` 验证权限;镜像变量必须是教师批准的 `name@sha256:digest`,拒绝 latest 和隐式更新。访问仅通过绑定 127.0.0.1 的本机转发。

清理不使用任何全量删除。先比较当前 namespace UID 与保存值,再读取归属标签;两者都匹配才删除该 namespace。只有本轮确实创建了 minikube profile、名称与随机令牌匹配并且归属记录存在时,才执行指定 profile 删除。创建失败、context 改变、UID 或标签不一致时停止,不尝试清理同名资源,更不能操作 default、共享或生产 namespace。

实践任务

在本人专用、随机 profile 的 minikube 本地集群中,用随机 namespace 部署教师批准且以 digest 固定的小应用,验证 Deployment、Service、就绪与回环访问,再按保存的 UID 和归属标签精确清理。

  • 平台:macOS/Linux、POSIX shell、本机 Docker、minikube 与 kubectl。权限:仅本人本机容器运行时,不用 sudo,不连接共享或生产集群。以下代码均为学习者运行,不是课程作者已经执行的结果;在同一个 shell 中依次运行,任一步失败即停止。先初始化全部状态:`command -v openssl >/dev/null || { printf '工具缺失:openssl;改走静态证据包\n' >&2; exit 2; }; set -eu; work_dir=$(mktemp -d); lab_token=$(openssl rand -hex 8); profile_name="aiknow-w3-$lab_token"; cluster_context="$profile_name"; namespace_name="aiknow-w3-$lab_token"; app_name="demo-$lab_token"; profile_created=0; profile_preexisted=0; namespace_created=0; namespace_uid=""; pf_pid=""; : "${APP_IMAGE_DIGEST:?教师必须先提供获批的 name@sha256:digest}"; case "$APP_IMAGE_DIGEST" in *@sha256:*) ;; *) printf '镜像必须固定为 name@sha256:digest\n' >&2; exit 1;; esac`。
  • 检查工具,并用 profile 清单而非运行状态判断名称是否已存在:`for tool in minikube kubectl python3 curl grep sed; do command -v "$tool" >/dev/null || { printf '工具缺失:%s;不要声称运行成功,改走静态证据包\n' "$tool" >&2; exit 2; }; done; minikube profile list -o json > "$work_dir/profile-list-before.json"; profile_preexisted=$(python3 -c 'import json,sys; target=sys.argv[1]; data=json.load(open(sys.argv[2], encoding="utf-8")); walk=lambda value: (any(str(key).casefold()=="name" and child==target for key,child in value.items()) or any(walk(child) for child in value.values())) if isinstance(value,dict) else any(walk(child) for child in value) if isinstance(value,list) else value==target; print(1 if walk(data) else 0)' "$profile_name" "$work_dir/profile-list-before.json"); case "$profile_preexisted" in 0|1) ;; *) printf 'profile 清单解析结果非法,停止\n' >&2; exit 1;; esac; test "$profile_preexisted" -eq 0 || { printf '同名 profile 已存在(包括 Stopped),停止且不得启动或删除\n' >&2; exit 1; }; minikube start -p "$profile_name" --driver=docker; profile_created=1; test "$(kubectl config get-contexts "$cluster_context" -o name)" = "$cluster_context"`。若清单读取/解析或 start 失败,保留输出并停止,不改 context、不提权;`profile_preexisted` 永久记录 start 前的所有权状态。
  • 先核对权限,再创建并记录唯一归属:`test "$(kubectl --context "$cluster_context" auth can-i create namespaces)" = yes; test "$(kubectl --context "$cluster_context" auth can-i create deployments.apps --namespace "$namespace_name")" = yes; test "$(kubectl --context "$cluster_context" auth can-i create services --namespace "$namespace_name")" = yes; kubectl --context "$cluster_context" create namespace "$namespace_name"; namespace_created=1; kubectl --context "$cluster_context" label namespace "$namespace_name" "aiknow.exercise=$lab_token"; namespace_uid=$(kubectl --context "$cluster_context" get namespace "$namespace_name" -o jsonpath='{.metadata.uid}'); test -n "$namespace_uid"`。
  • 用 kubectl 客户端生成最小 Deployment 与 ClusterIP Service 文件,并在任何服务端写入前静态校验:`kubectl create deployment "$app_name" --image="$APP_IMAGE_DIGEST" --port=8080 --dry-run=client -o yaml > "$work_dir/deployment.yaml"; kubectl label --local -f "$work_dir/deployment.yaml" "aiknow.exercise=$lab_token" -o yaml > "$work_dir/deployment.labeled.yaml"; kubectl create service clusterip "$app_name" --tcp=8080:8080 --dry-run=client -o yaml > "$work_dir/service.yaml"; kubectl label --local -f "$work_dir/service.yaml" "aiknow.exercise=$lab_token" -o yaml > "$work_dir/service.labeled.yaml"; kubectl --context "$cluster_context" -n "$namespace_name" apply --dry-run=client -f "$work_dir/deployment.labeled.yaml" -f "$work_dir/service.labeled.yaml"; kubectl --context "$cluster_context" -n "$namespace_name" apply -f "$work_dir/deployment.labeled.yaml" -f "$work_dir/service.labeled.yaml"`。这些生成命令会让 Service selector 与 Deployment 的 `app=$app_name` 标签一致;不使用 privileged、hostNetwork、NodePort、LoadBalancer、宿主 socket 或根目录挂载。
  • 等待就绪并收集可复核证据:`kubectl --context "$cluster_context" -n "$namespace_name" rollout status deployment/"$app_name" --timeout=120s; kubectl --context "$cluster_context" -n "$namespace_name" wait --for=condition=Ready pod -l "app=$app_name" --timeout=120s; kubectl --context "$cluster_context" -n "$namespace_name" get deployment,service,pod -l "app=$app_name" -o wide; kubectl --context "$cluster_context" -n "$namespace_name" get endpointslice -l "kubernetes.io/service-name=$app_name" -o yaml; kubectl --context "$cluster_context" -n "$namespace_name" get pods -l "app=$app_name" -o json > "$work_dir/pods.json"; grep -F "$APP_IMAGE_DIGEST" "$work_dir/pods.json" >/dev/null; kubectl --context "$cluster_context" -n "$namespace_name" get events --sort-by=.metadata.creationTimestamp > "$work_dir/events.txt"`。Ingress 仅生成不提交的草案,因为没有 Ingress controller 时对象不会提供路由:`kubectl create ingress "$app_name" --class=nginx --rule="demo.invalid/*=$app_name:8080" --dry-run=client -o yaml > "$work_dir/ingress.yaml"; kubectl --context "$cluster_context" -n "$namespace_name" apply --dry-run=client -f "$work_dir/ingress.yaml"`。
  • 只通过回环地址验证应用,并给后台转发进程设置退出清理:`kubectl --context "$cluster_context" -n "$namespace_name" port-forward --address 127.0.0.1 "service/$app_name" :8080 > "$work_dir/port-forward.log" 2>&1 & pf_pid=$!; trap 'test -z "$pf_pid" || { kill "$pf_pid" 2>/dev/null || true; wait "$pf_pid" 2>/dev/null || true; }' 0 1 2 15; pf_ready=0; i=0; while test "$i" -lt 30; do if grep -q 'Forwarding from 127.0.0.1:' "$work_dir/port-forward.log"; then pf_ready=1; break; fi; kill -0 "$pf_pid" 2>/dev/null || break; i=$((i + 1)); sleep 1; done; test "$pf_ready" -eq 1; local_port=$(sed -n 's/.*Forwarding from 127\.0\.0\.1:\([0-9][0-9]*\).*/\1/p' "$work_dir/port-forward.log" | head -n 1); test -n "$local_port"; curl --fail --silent --show-error --max-time 10 "http://127.0.0.1:$local_port/" > "$work_dir/response.txt"; kill "$pf_pid"; wait "$pf_pid" || true; pf_pid=""; trap - 0 1 2 15`。若应用约定的健康路径不是 `/`,教师应先在任务卡替换路径;不能把端口转发启动当作请求成功。
  • 安全:不使用 privileged、hostNetwork、NodePort、LoadBalancer、宿主挂载、生产凭据或共享 context。清理:重新验证 context、UID 和标签,只删除精确拥有的对象:`test "$namespace_created" -eq 1; test "$(kubectl config get-contexts "$cluster_context" -o name)" = "$cluster_context"; namespace_uid_now=$(kubectl --context "$cluster_context" get namespace "$namespace_name" -o jsonpath='{.metadata.uid}'); owner_label_now=$(kubectl --context "$cluster_context" get namespace "$namespace_name" -o jsonpath='{.metadata.labels.aiknow\.exercise}'); test "$namespace_uid_now" = "$namespace_uid"; test "$owner_label_now" = "$lab_token"; kubectl --context "$cluster_context" delete namespace "$namespace_name" --wait=true; namespace_created=0; test "$profile_created" -eq 1; test "$profile_preexisted" -eq 0; test "$profile_name" = "aiknow-w3-$lab_token"; test "$(kubectl config get-contexts "$cluster_context" -o name)" = "$cluster_context"; minikube delete -p "$profile_name"; profile_created=0`。任一检查不匹配就停止并请教师处理;即使同名 profile 在 start 前只是 Stopped,也属于预先存在,绝不启动或删除。禁止 default、通配资源或全部 profile。最后只删已记录的本轮文件:`rm -- "$work_dir/profile-list-before.json" "$work_dir/deployment.yaml" "$work_dir/deployment.labeled.yaml" "$work_dir/service.yaml" "$work_dir/service.labeled.yaml" "$work_dir/ingress.yaml" "$work_dir/pods.json" "$work_dir/events.txt" "$work_dir/port-forward.log" "$work_dir/response.txt"; rmdir "$work_dir"`。
  • 工具缺失时不要把说明文字当命令:若有 kubectl 但不能启动 minikube,只对教师提供的 `deployment.yaml`、`service.yaml` 运行学习者本机静态路径 `kubectl apply --dry-run=client -f deployment.yaml -f service.yaml`,并核对 namespace、`aiknow.exercise`、`app` selector、端口和 `image: name@sha256:digest`;若连 kubectl 都没有,则逐字段审查教师提供的脱敏 YAML、对象状态、事件、EndpointSlice、imageID 与回环响应静态证据包。两条替代路径都必须标注“未实际部署/未验证运行态”,只提交静态检查表和待验证项。

自测与答案

第 1 题

创建 Deployment 后 Pod 一直 Pending,应先检查哪些控制面证据?

尚未检查本题。

查看答案与评价要点

参考答案:检查 Deployment/ReplicaSet/Pod 条件与事件、scheduler 决策、资源请求、污点/容忍和节点可调度性,而不是直接删除重建。

评价要点:引用对象条件和事件;检查调度资源或节点约束

第 2 题

已有 Ingress 对象为什么仍可能没有外部路由?

尚未检查本题。

查看答案与评价要点

参考答案:Ingress 只是规则对象,需要匹配的 Ingress controller 实现;还需核对 IngressClass、Service 后端、EndpointSlice、DNS/TLS 和网络边界。

评价要点:指出需要 Ingress controller;核对 Service 后端及入口配置

尚未完成自测。

今日完成标准

  • 提交控制平面到应用的证据链,包含 context、namespace UID、归属标签、镜像 digest、对象条件、Service 后端和本机访问结果
  • 清理记录证明只删除本轮 namespace/profile;任何 UID 或标签不匹配均记录为停止清理而非强制删除

常见错误与纠正提示

  • 把 Service 当作进程健康保证,忽略 selector、EndpointSlice 和 readiness
  • 创建 Ingress 后假设路由自动存在,未确认控制器与 IngressClass
  • 在错误 context 使用默认 namespace 或批量删除命令
  • 使用浮动镜像标签导致相同清单无法复现

分层任务

基础任务

使用教师提供的 kubectl 输出包标注对象关系和失败位置,不启动集群。

标准任务

在专用 profile/namespace 完成受控部署、访问、证据采集和精确清理。

挑战任务

增加 readiness 失败与一次滚动更新,比较 Deployment 条件、事件和回滚证据。

关联知识点

延伸阅读

学习状态:未学习

Day 19

CI/CD流水线

建议时长:70 分钟

本日 CO:CO1 CO8

本日概要

用 GitLab CI 理解流水线即代码:pipeline 由 jobs 和 stages 组成,Runner 执行作业;一次变更从 commit 身份开始,经过 lint、test、build、scan、package 产生不可变制品和 digest,再由受保护环境的部署步骤引用同一制品。CI 不是“脚本跑绿”即可,缓存不等于制品,浮动标签不能证明部署内容;CD 还需要审批、最小权限、显式 resource group 处理模式、期望 revision/digest 守卫、验证与回滚/前滚策略。

听书与视频

本日听书

5 分钟 · MP3 · 双主持人讲解

B 站讲解

为什么你的代码上线总出bug?图解CI/CD流水线如何救火

五线码农_ · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能解释 pipeline、stage、job、Runner、cache、artifact 与容器制品的不同职责
  • 能设计由 commit SHA 到 image digest 再到 deployment revision 的可追踪链
  • 能把测试、扫描、审批、部署验证和回滚放入有停止条件的 CI/CD 流程
  • 能识别变量泄露、特权 Runner、浮动标签和旧流水线覆盖新部署等风险

核心讲解

从提交到不可变制品

GitLab pipeline 通常由顺序 stage 和其中可并行的 job 构成,Runner 执行 job。lint/test 证明代码在指定环境通过检查,build 将源码与锁定依赖转换为制品,artifact 用于在作业间传递或保留输出;容器 Registry 保存镜像。缓存用于加速且可能失效,不应被当作发布证据。每次输出需关联 commit SHA、工具版本、校验值或 image digest。

合理的门禁顺序是便宜且确定的检查先执行,高成本构建和扫描随后,部署只消费已经验证的同一不可变制品。若部署阶段重新构建、以 latest 拉镜像或手工修改运行实例,就断开了可追踪链。数据库迁移、配置兼容和依赖服务也必须纳入发布单元,否则应用回滚可能被不可逆数据变更阻断。

持续交付中的权限、并发与恢复

Runner 权限决定流水线能影响什么。共享 Runner 不应持有长期生产管理员密钥;敏感变量应受保护、掩码和最小范围约束,脚本禁止 echo 秘密。生产 job 在 `.gitlab-ci.yml` 声明 `resource_group: production` 只保证互斥;resource group 默认 unordered,不保证先后。维护者必须经受保护的 GitLab API 设置 `process_mode=newest_first`,并保证部署幂等。

`newest_first` 会优先最新等待 job,但较旧 job 以后仍可能获得资源,所以不能单独防回退。部署脚本从受保护的 GitOps 引用或环境控制面读取 `DESIRED_REVISION` 与 `DESIRED_IMAGE_DIGEST`,然后执行 `(test "$CI_COMMIT_SHA" = "$DESIRED_REVISION" && test "$IMAGE_DIGEST" = "$DESIRED_IMAGE_DIGEST") || { printf '陈旧 job:跳过部署\n'; exit 0; }`。只有双匹配才变更环境,并记录 revision 与 digest。

回滚必须在发布前设计:保存上一个可用 digest、配置版本、数据库兼容窗口和健康判据。部署后用请求成功、延迟、错误和关键业务 SLI 验证;失败时按预案回滚或前滚,并保留 job 日志、部署 revision 和验证输出。练习只评审 YAML 与证据图,不要求购买 Runner 分钟或连接真实 Registry。

实践任务

在本地临时目录为小应用编写 `.gitlab-ci.yml` 设计稿,定义测试、构建、制品身份、部署验证和回滚证据;不推送、不登录 Registry、不触发真实环境。

  • 平台:本地 POSIX shell 与文本编辑器;权限:只处理教师提供的无秘密示例,不登录 GitLab、不推送、不使用 Docker daemon。以 `work_dir=$(mktemp -d)` 创建本轮目录并保存路径和随机 `lab_token`。
  • 在 `.gitlab-ci.yml` 设计 lint、test、build、scan、package、deploy_verify 阶段,部署 job 明确写 `resource_group: production`;另在运维清单要求维护者通过受保护 API 设置 `process_mode=newest_first`,并记录查询回读结果。说明默认 unordered 只互斥不排序,所有部署步骤必须幂等。
  • 为部署伪代码定义受保护输入 `DESIRED_REVISION`、`DESIRED_IMAGE_DIGEST` 和当前流水线 `CI_COMMIT_SHA`、`IMAGE_DIGEST`;双匹配才部署,不匹配输出“陈旧 job:跳过部署”并成功退出。画 commit → artifact → digest → desired revision → environment revision → SLI 链及回滚/前滚条件。
  • 安全:变量只写名称,禁止真实 token、生产地址、Docker socket 和特权 Runner;清理:确认 `work_dir` 是本轮 mktemp 路径且含 `lab_token` 标记文件后只删除该目录,不删除仓库或共享 Runner 缓存。

自测与答案

第 1 题

为什么 cache 不能作为已部署制品的身份?

尚未检查本题。

查看答案与评价要点

参考答案:cache 是可失效、可覆盖的加速数据;发布需要与 commit 绑定的 artifact 校验值或不可变 image digest 及环境 revision。

评价要点:指出 cache 可失效或覆盖;给出 artifact 校验值或 digest 身份

第 2 题

为什么只写 `resource_group: production` 仍不能防止陈旧部署?给出完整控制。

尚未检查本题。

查看答案与评价要点

参考答案:resource group 默认 unordered,只保证互斥。应由维护者设置 `process_mode=newest_first`、保持 job 幂等,并在部署前把 `CI_COMMIT_SHA`/`IMAGE_DIGEST` 与受保护的 `DESIRED_REVISION`/`DESIRED_IMAGE_DIGEST` 双重比较;陈旧 job 只记录并跳过。

评价要点:指出默认 unordered 不保证执行顺序,并设置 newest_first;指出 newest_first 仍需幂等和 revision/digest 双重守卫;明确陈旧 job 不得变更环境

尚未完成自测。

今日完成标准

  • 流水线设计包含至少六个阶段、不可变制品身份、最小权限和失败停止条件
  • 提交四种失败分支、部署验证、回滚/前滚和反向覆盖防护的证据图

常见错误与纠正提示

  • 把 cache、artifact 和 Registry 镜像混为同一类永久制品
  • 部署阶段重新构建或使用 latest,导致测试对象与运行对象不一致
  • 让 Runner 持有长期管理员凭据,并在日志中输出变量
  • 只声明 resource_group 却未配置 process mode,或缺少期望 revision/digest 守卫
  • 只写成功路径,没有陈旧 job、数据兼容和恢复证据

分层任务

基础任务

给流水线卡片排序并识别 cache、artifact、digest。

标准任务

完成 YAML 设计稿和端到端身份/失败分支图。

挑战任务

设计受保护环境、短期身份、并发控制和向前兼容数据库迁移。

关联知识点

延伸阅读

学习状态:未学习

Day 20

可观测性

建议时长:65 分钟

本日 CO:CO1 CO8

本日概要

以用户问题而非工具清单组织可观测性:指标是运行时测量的聚合信号,日志记录离散事件,追踪描述一次请求经过多个组件的路径;三者用 service、environment、trace_id 等受控上下文关联。为在线服务从请求率、错误率、延迟和饱和度选择 SLI,定义窗口与分母,再从症状告警下钻到结构化日志和 span。Prometheus 标签每个组合都会生成时间序列,用户 ID 或原始 URL 等无界标签会造成基数与成本风险。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

大厂是怎么监控 Java 项目的?保姆级教程 | Prometheus + Grafana 可观测性实战

程序员鱼皮 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能区分指标、日志、追踪各自回答的问题及其关联方式
  • 能为在线应用定义带单位、分母、时间窗和阈值依据的 SLI
  • 能识别高基数标签、敏感日志、采样和保留造成的可靠性与成本风险
  • 能设计从用户症状到资源、日志和 span 的可复核证据链

核心讲解

三类信号不是三套互不相干的控制台

OpenTelemetry 将 traces、metrics、logs 视为可采集、处理和导出的遥测信号。指标适合汇总趋势、比率和告警,例如请求总数、错误数、延迟分布和进行中请求;日志保留事件上下文与错误详情;追踪用 trace/span 表达一个请求跨服务的因果路径。统一服务名、环境、版本和 trace context,才能从异常曲线定位到具体请求与日志。

可观测性从问题和 SLI 开始。成功率必须明确成功定义和总请求分母,延迟必须明确端点、单位、直方图区间与统计窗口,饱和度必须对应有限资源。CPU 图不是用户可用性的替代品;一个健康 dashboard 也不能证明故障时有可执行动作。告警需包含影响、阈值依据、查询、责任人和 runbook 入口。

遥测同样有安全、容量与费用边界

Prometheus 中每个唯一标签组合形成独立时间序列。把 user_id、email、request_id 或未规范化 URL 放入指标标签,会让基数随用户或请求增长,消耗内存、磁盘和网络;这些细节更适合受控日志或 trace。指标名称和单位要稳定,counter 用 rate 解释变化,gauge 可升可降,延迟通常需要 histogram,并在上线前估算时间序列数量。

日志与追踪可能携带个人信息、认证头、提示词或业务数据,必须先定义采集白名单、脱敏、访问、保留和删除策略。采样会降低成本但可能遗漏稀有失败,应说明规则和偏差;Collector/后端不可用时应用是否阻塞也要验证。练习只写契约和用静态样例推演,不部署 Prometheus/Grafana 到共享集群。

实践任务

为 Week 3 小应用设计不依赖特定后端的 metrics/logs/traces 遥测契约、两个 SLI 和一条从告警到根因证据的排障路线。

  • 平台:本地编辑器与教师提供的脱敏请求样例;权限:只读,不连接真实日志、Prometheus、Jaeger 或 OpenTelemetry 后端。列出用户可见失败和四个调试问题。
  • 定义两个 SLI:名称、含义、分子/分母或直方图区间、单位、窗口、允许标签及阈值依据;用上界估算标签组合数量,拒绝 user_id、email、trace_id 进入指标标签。
  • 设计结构化日志字段和 span 层级,让一个虚构 trace_id 能把入口、应用、数据库调用和失败日志关联;明确敏感字段禁止项、采样和保留。
  • 安全:样例只用虚构 ID,不含 token、Cookie、个人数据和真实提示词;清理:所有本地遥测样例放入本轮 `mktemp -d` 目录,复核脱敏后提交报告,再只删除已确认归属的临时目录。

自测与答案

第 1 题

为什么 request_id 适合日志/追踪关联,却通常不适合作为 Prometheus 指标标签?

尚未检查本题。

查看答案与评价要点

参考答案:每个 request_id 几乎唯一,会产生无界高基数时间序列;指标应保留有限维度,具体请求用日志或 trace 查找。

评价要点:解释唯一值造成高基数;提出日志或 trace 作为替代

第 2 题

“P95 延迟低于 300 ms”还缺哪些口径才能成为可复核 SLI?

尚未检查本题。

查看答案与评价要点

参考答案:至少缺服务/端点范围、成功或全部请求分母、统计窗口、直方图区间或计算方法、单位、排除规则和数据完整性。

评价要点:补充范围、单位和窗口;说明分母或计算方法

尚未完成自测。

今日完成标准

  • 提交两个完整 SLI、有限标签预算和时间序列基数上界估算
  • 用一条脱敏样例证明指标告警可关联日志与追踪,并写明采样、保留和访问边界

常见错误与纠正提示

  • 把安装 Prometheus、ELK 或 Jaeger 当作已经具备可观测性
  • 把用户 ID、原始 URL 或 request_id 放进指标标签造成基数爆炸
  • 只画 CPU dashboard,没有用户 SLI、阈值依据或处理动作
  • 记录认证头和个人数据后再寄希望于后端权限补救

分层任务

基础任务

对给定信号卡分类并补全指标单位、日志上下文和 span 关系。

标准任务

完成 SLI、遥测契约、基数预算和排障证据链。

挑战任务

比较头部/概率/错误优先采样,分析稀有错误遗漏和成本变化。

关联知识点

延伸阅读

学习状态:未学习

Day 21

周末复盘

建议时长:90 分钟

本日 CO:CO1 CO8

本日概要

把本周知识收束为一个可观测的云原生小应用部署计划:先以 IaaS/PaaS/SaaS 与部署模型说明服务边界,再完成 ECS/EVS/VPC/OBS/RDS 或等价能力选型;用 12-Factor 审查配置、制品、进程和日志;用 Kubernetes Deployment、Service 与 HTTP 入口表达期望状态;用 CI/CD 绑定 commit、digest 与 revision;最后以指标、日志、追踪、权限、恢复和成本驱动证明方案可部署而非仅可画。

听书与视频

本日听书

6 分钟 · MP3 · 双主持人讲解

B 站讲解

8 分钟云计算入门

码农有道 · 已核验 2026-08-29

在 B 站打开

学习目标

  • 能把云服务、应用原则、编排、交付和遥测连接成端到端架构
  • 能为一次变更定义从 commit 到运行 revision 再到 SLI 的证据链
  • 能以故障、恢复、权限和成本情景检验方案的可部署性
  • 能按五维四级量规定位证据缺口并完成有依据的修订

核心讲解

全景图必须能讲通一条请求和一次变更

架构图先讲用户请求:入口如何把 HTTP 流量送到 Service,selector 如何定位 Deployment 管理的 ready Pod,应用如何通过受控网络访问数据库或对象存储,失败会在哪里被检测。再讲变更:commit 触发 CI,测试与扫描通过后产生 digest,CD 将同一 digest 写入声明,控制器收敛,部署 revision 与 SLI 验证决定继续、回滚或前滚。

每个箭头应注明接口、身份和证据,而不是堆 Logo。云服务模型说明责任,12-Factor 说明应用可部署条件,Kubernetes 对象说明期望状态,流水线说明制品可信链,指标/日志/追踪说明运行反馈。若方案没有数据迁移、密钥、权限、清理和恢复,它仍只是快乐路径草图。

用五维量规审查可观察结果

架构维度检查边界、数据/控制路径和故障域;可部署性检查配置、digest、清单、readiness、发布与恢复;可观测性检查 SLI、有限标签、日志/trace 关联和告警动作;安全检查身份、最小权限、秘密、网络和数据;成本意识检查计费驱动、容量情景、遥测保留、闲置清理和预算验证。每个判断都映射 CO1 或 CO8。

优秀方案不是组件最多,而是第三方能按记录复核选择和失败路径。互评者先指出证据,再给 1–4 级;事实必须有官方 URL 与学习者实际访问日期,推断必须写依据,建议必须写适用条件。课程 `verified_on` 是作者核验日期,不能代替学习者自己的访问记录;易变价格必须回到目标区域的官方入口重新查询。

实践任务

完成“可观测的云原生小应用部署计划”作业草案,互评架构、可部署性、可观测性、安全和成本意识五个维度。

  • 平台:绘图工具、本地编辑器和本周脱敏证据包;权限:只读,不连接云账号、Registry 或共享集群。先写用户、数据、SLO、团队和预算约束。
  • 绘制请求路径与变更路径,标出服务模型/部署模型、Kubernetes 对象、数据服务、身份、digest、revision、SLI 和恢复分支。
  • 用架构、可部署、可观测、安全、成本五维量规互评;每项反馈引用图中编号、清单字段、命令输出或官方来源,完成一次修订。
  • 安全:不提交密钥、真实域名、个人数据或生产拓扑;清理:本课只产生文档。若引用 Day 18 实验,必须附 UID/标签核验和精确清理证据,不重新操作已经清理的 profile。

自测与答案

第 1 题

一张云原生架构图只有产品 Logo,最少还需要补哪些关系?

尚未检查本题。

查看答案与评价要点

参考答案:补用户请求与变更路径、接口和身份、责任边界、数据持久化、故障域、制品 digest、部署对象、SLI、恢复与成本驱动。

评价要点:包含请求和变更双路径;包含身份、故障、观测与恢复关系

第 2 题

为何总分较高仍可能不能把本周周测作为 CO8 达标证据?

尚未检查本题。

查看答案与评价要点

参考答案:CO8 要求来源、验证和限制的直接表现;必答主观题若未达到 3 级,客观题总分不能替代颗粒化证据。

评价要点:指出 CO8 需要直接表现证据;说明两道必答题的独立门槛

尚未完成自测。

今日完成标准

  • 完成请求与变更双路径全景图,五个维度均有可观察证据和 CO 映射
  • 提交一次基于量规的互评修订记录,明确事实、推断、建议、实际访问日期和待验证项

常见错误与纠正提示

  • 用产品数量或图形美观替代责任、接口和故障路径
  • 只设计首次部署,不设计版本身份、验证、回滚与数据兼容
  • 成本表只写过期单价,未记录用量、保留和网络等驱动
  • 把课程核验日期抄成自己的实际访问日期

分层任务

基础任务

使用给定全景图补全五类证据标签。

标准任务

完成小应用双路径部署计划和五维互评修订。

挑战任务

增加区域故障、流水线倒序与遥测后端不可用三项推演,比较回滚和前滚。

关联知识点

延伸阅读

学习状态:未学习