MoreRSS

site iconMobility修改

关注服务端开发, 架构设计,个人成长等
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Mobility的 RSS 预览

Vercel封禁163邮箱后,我是怎么恢复博客的

2026-05-11 19:30:00

前几天写了篇新文章,照常往 Vercel 部署,结果 pipeline 直接报错了。一开始以为是构建问题,折腾了一会儿才发现不对——是 Vercel 账号出了状况。用 163 邮箱注册的账号怎么都登不上去了。后来才搞清楚,Vercel 把整个 163.com 邮箱根域给封禁了。

先说说 Vercel 是什么

如果你是搞独立博客的,大概率听过或者正在用 Vercel。简单说,它是一个前端部署平台,支持自动从 GitHub 仓库拉代码、构建、部署,给你的网站分配一个域名,还自带 CDN 加速。很多人的博客就是 GitHub Pages + Vercel 的组合——代码放在 GitHub,用 Vercel 来部署和托管。

我自己的博客也是这么搞的。GitHub Pages 本来也能直接部署静态页面,但 Vercel 在自定义域名、HTTPS、CDN 这些方面用起来更方便,所以就选了它。

163 邮箱被封禁的来龙去脉

大概在 2026 年 5 月 4 号左右,大量使用 163 邮箱注册 Vercel 的用户发现,自己的账号突然无法登录了。我在网上搜了一下,发现不只是我一个人遇到这个问题。NodeSeek、V2EX 这些论坛上都有人在讨论。

根据网上的信息,Vercel 在 2026 年 4 月中旬遭遇了一次比较严重的安全事件。黑客团伙 ShinyHunters 通过一个第三方 AI 工具入侵了 Vercel 的内部系统,窃取了员工数据、企业后台权限和一些部署凭证,还索要了 200 万美元的赎金。

这次封禁 163 邮箱,大概率是安全事件后的应对措施之一。可能是因为 163 邮箱在此次事件中被大量用于恶意注册或攻击行为,也可能只是 Vercel 对某些邮箱域名做了更严格的风控。具体原因 Vercel 没有公开说明,但结果就是:整个 163.com 邮箱域名被一刀切了。

影响范围不小。很多国内开发者和独立博客作者都是用 163 邮箱注册的 Vercel,这次封禁直接导致这些人的博客全部无法访问。

不过如果你现在 Vercel 账号还处于登录状态(比如工作电脑的浏览器还保持着登录),其实是可以抢救一下的:进账号设置,添加一个新邮箱(Outlook、Gmail 都行),然后把 163 邮箱去掉。这样账号就能继续正常使用,不需要重新部署。网上有人分享了这个方法,能省不少事。但如果你跟我一样,发现的时候已经完全登不上去了,那就只能走下面的重建流程了。

回忆我的博客部署架构

账号被封了,博客打不开了,第一件事就是得搞清楚自己的博客到底是怎么部署的。说实话,这个博客配置的时间已经比较久了,当时配完之后就没怎么动过,具体流程已经记不太清了。

花了不少功夫才回忆起来,大概的链路是这样的:

  1. 博客源码放在 GitHub 仓库里
  2. Vercel 连接 GitHub 仓库,负责构建和部署
  3. 域名解析这块,分了两层:阿里云的 DNS 指向 Cloudflare,Cloudflare 再指向 Vercel

为什么要搞这么复杂?主要是为了用 Cloudflare 的 CDN 和安全防护能力。阿里云做域名注册商,Cloudflare 做中间层的 DNS 管理和 CDN,Vercel 做最终的静态页面托管。当年配的时候也是参考了网上的一些教程,虽然链路长了点,但稳定运行了很久,也就没再动过。

恢复过程:新账号 + 重新部署

搞清楚部署架构之后,恢复操作其实并不复杂。

第一步:注册新的 Vercel 账号

这次学聪明了,不用 163 邮箱了,用 Outlook 重新注册了一个 Vercel 账号。其实 Gmail 也行,但考虑到这次是 Vercel 封禁了特定邮箱域名,用国外主流的邮箱服务会更稳妥一些。

第二步:重新部署 GitHub 项目

登录新账号后,连接 GitHub,把博客仓库导入 Vercel。Vercel 自动识别了项目类型,构建和部署都是自动完成的,跟之前的操作基本一样。

第三步:重新配置域名

这一步是关键。因为之前域名解析是阿里云 → Cloudflare → Vercel 的链路,重新部署后需要把域名绑定到新的 Vercel 项目上。

让我惊喜的是,现在 Vercel 在添加自定义域名的时候,已经支持自动修改 Cloudflare 的 DNS 配置了。以前我记得需要手动去 Cloudflare 后台添加 CNAME 记录,现在 Vercel 直接通过 API 帮你搞定,点几下就完事了。

整个恢复过程,从注册新账号到博客重新可以访问,大概花了不到半小时。

几点经验

  1. 不要用国内邮箱注册海外服务。163、QQ 邮箱这类国内邮箱,在海外服务的风控体系里天然就是高风险对象。这次是 Vercel,下次可能是别的服务。建议主力账号用 Gmail 或 Outlook。

  2. 记录好自己的部署架构。这次最浪费时间的环节就是回忆部署链路。当时配置完觉得都记住了,结果过了这么久早就忘得差不多了。建议把部署架构和关键配置写在笔记里,哪怕只是几句话。

  3. Vercel 现在对 Cloudflare 的集成做得不错。以前手动配 DNS 的时候容易出错,现在自动化程度高了很多,重新部署的成本降低了不少。

  4. 有条件的话,做好备份和多平台准备。这次运气好,恢复起来比较快。但如果 GitHub 仓库也出了问题,或者 Vercel 彻底封了项目而不只是账号,恢复就会麻烦很多。重要的博客内容,建议在本地或者别的平台也有一份。

写在最后

这次 Vercel 封禁 163 邮箱的事,算是给所有用国内邮箱注册海外服务的人提了个醒。平台侧的安全措施我们控制不了,但自己的账号安全和部署架构,还是可以提前做好准备的。

如果你也遇到了 Vercel 163 邮箱被封、Vercel 账号无法登录的问题,希望这篇文章能帮到你。恢复的核心思路就是:换一个邮箱重新注册,把项目重新部署一遍,域名重新绑定一下。操作不复杂,但前提是你得记得自己的部署链路。

原文地址: http://lichuanyang.top/posts/39648/

用LLM管理安全开发规范:一次llm-wiki实践

2026-05-11 15:38:16

最近在整理团队的安全开发规范时,遇到了一个老问题:安全规范文档越积越多,但真正用的时候却找不到。每次新人入职,都要翻遍各种文档才能拼凑出完整的安全规范;每次出安全故障,事后总结的经验也散落在各处,下次遇到类似问题还得重新排查。

我试过用Confluence、Notion、甚至Git仓库的README来管理,但效果都不理想。直到看到了Karpathy提的llm-wiki思路,才觉得这可能是个突破口。

Karpathy的llm-wiki是什么?

Karpathy在Gist里提了个想法:让LLM维护一个Wiki中间层。原话是”the wiki is a persistent, compounding artifact”——这个Wiki层就像个编译器,把原始文档编译成结构化数据,这样LLM每次回答问题时就不用从头在原始文档里”找”信息,直接查Wiki就行。

我觉得这个思路特别妙。传统文档管理是”存”和”找”,而llm-wiki是”编译”和”查询”。原始文档可能很乱、有重复、甚至有矛盾,但Wiki层是干净、结构化、有交叉引用的。

举个例子:我们团队有十几份安全开发规范文档,从输入验证到渗透测试都有,还有近十份安全故障复盘报告。这些文档格式不一,有的在Word里,有的在Markdown里,有的甚至只是Slack聊天记录。如果让LLM直接处理这些原始材料,效率会很低。但如果先”编译”成Wiki,效果就完全不一样了。

我的实现过程

第一步:生成CLAUDE.md

我首先把Karpathy的Gist链接丢给Claude,让它基于这个思路生成一份CLAUDE.md文件。这个文件相当于给LLM的”操作手册”,告诉它如何维护Wiki。

生成的CLAUDE.md包含了几个关键部分:

  • 三层架构说明(raw → wiki → output)
  • Wiki页面规范(frontmatter格式、交叉引用规则)
  • 摄入工作流(如何处理新素材)
  • 查询工作流(如何回答用户问题)
  • Lint检查(如何保证Wiki健康)

实际用下来,我发现模型生成的结果基本可用,没有做太多微调。只是另外让AI生成了output层,用于存放最终的规范文档。这样三层架构就完整了:raw放原始素材,wiki放结构化Wiki,output放最终输出。

第二步:收集和整理原始素材

这是最耗时的一步。我把散落在各处的安全开发规范文档和故障案例都收集起来,统一放到raw/sources/目录下。为了保持原貌,我没有修改这些文件的内容,也没有统一格式——PDF、Word、PPT、Markdown等各种格式直接放到raw层就行,模型都可以处理。

具体来说,我收集了:

  • 十几份安全开发规范文档:涵盖输入验证、SQL注入防护、XSS防护、CSRF防护、敏感数据保护、日志安全等
  • 近十份安全故障复盘报告:包括SQL注入漏洞、越权访问、敏感信息泄露、会话劫持等真实案例
  • 几份安全架构方案文档:涉及零信任架构、安全编码指南、渗透测试流程等

这些素材质量参差不齐。有的写得很规范,有清晰的标题和列表;有的就是随手记的笔记,甚至还有截图。但没关系,llm-wiki的妙处就在于它能处理这种”脏数据”。

第三步:让LLM生成Wiki层

有了CLAUDE.md和原始素材,就可以让LLM开始工作了。我这里用的是Claude,主要是因为它的上下文窗口足够大,能一次性处理较多内容。

具体操作是这样的:

  1. 把CLAUDE.md作为系统提示词
  2. 告诉LLM:”请按照CLAUDE.md中的规范,处理raw/sources/目录下的所有素材,生成wiki层”
  3. LLM会依次读取每个原始文件,提取关键信息,生成对应的Wiki页面

这个过程不是一次就能完成的。LLM生成的初版Wiki会有一些问题:

  • 交叉引用不够充分
  • 有些概念没有被提取成独立页面
  • 页面之间的逻辑关系不够清晰

所以需要多轮迭代。我会检查生成的Wiki,指出问题,让LLM修正。比如:
“这个故障案例里提到了’连接池配置不当’,但为什么没有对应的concept页面?请创建一个[[connection-pool-best-practices]]页面,并在故障案例里引用它。”

经过5-6轮迭代,Wiki层才逐渐成型。

第四步:生成最终规范文档

Wiki层准备好后,就可以生成最终的规范文档了。我让LLM基于Wiki层,生成一份面向开发者的、可直接阅读的规范文档。

这里有个设计决策:最终文档是放在output/目录下,而不是直接修改原始素材。这样保持了三层架构的清晰性:

  • raw/:原始素材,不可修改
  • wiki/:结构化Wiki,LLM维护
  • output/:最终输出,人类阅读

生成的规范文档有几个特点:

  1. 每个规范条目都有”为什么”——不只是说”要这样做”,还解释”为什么要这样做”
  2. 相关的故障案例会作为”反面教材”链接在旁边
  3. 有交叉引用,比如”数据库连接池配置”会链接到”连接池最佳实践”这个concept页面

实际效果

阅读体验

最终的规范文档可以直接用Obsidian打开阅读。因为是Markdown格式,支持:

  • 代码块高亮
  • 内部链接跳转(点击就能跳转到相关概念或故障案例)
  • 标签筛选(比如筛选所有#安全相关的规范)

更重要的是,每条安全规范都关联着真实的故障案例。比如在”SQL注入防护”这条规范旁边,就链接着[[sql-injection-vulnerability-incident]]这个故障案例,详细描述了漏洞是怎么产生的、造成了什么影响、怎么修复的。这样开发者不仅能知道”要怎么做”,还能看到”不这么做会出什么问题”。

比起以前散落在各处的文档,阅读体验好了不止一个量级。

LLM问答

更强大的是LLM问答能力。因为有了Wiki层,LLM回答问题时特别准。比如我问:
“数据库批量更新时要注意什么?”

LLM会:

  1. 先在Wiki里找到[[batch-operation-security]]这个concept页面
  2. 结合[[sql-injection-batch-incident]]这个故障案例
  3. 给出具体的建议:必须使用参数化查询、禁止字符串拼接SQL、批量操作要有事务控制、超大批次要分页处理等
  4. 还会解释为什么:因为批量操作一旦出问题,影响范围是单条操作的N倍

再比如问:”用户上传文件怎么处理才安全?”

LLM会:

  1. 找到[[file-upload-security]]这个concept页面
  2. 结合[[malicious-file-upload-incident]]这个故障案例
  3. 给出具体建议:文件类型白名单校验、文件内容检测、重命名存储、限制文件大小、隔离存储等

这比让LLM在十几份原始文档里”找”答案要靠谱得多。

持续更新

最让我满意的是更新机制。当有新的规范文档或故障报告时,我只需要:

  1. 把新文件放到raw/sources/目录下
  2. 告诉LLM:”有新素材需要摄入”
  3. LLM会自动更新Wiki层和规范文档

比如上周我们出了个新的安全故障:因为用户输入未过滤导致XSS漏洞。我把故障报告放到raw目录后,LLM自动:

  1. 创建了[[xss-user-input-incident]]这个故障案例页面
  2. 更新了[[input-validation-security]]这个concept页面,补充了XSS相关的注意事项
  3. 在规范文档的”输入验证规范”章节增加了相关条目

遇到的问题和解决方案

问题1:LLM生成的Wiki质量不稳定

刚开始时,LLM生成的Wiki质量波动很大。有时能很好地提取关键信息,有时会漏掉重要内容。

解决方案:我细化了CLAUDE.md里的Wiki页面规范。比如要求每个页面必须有:

  • Summary行:一句话描述核心内容
  • Tags行:用#标签标记主题
  • 明确的页面类型(concept/entity/source/comparison)

对于安全故障案例,还要求包含:漏洞类型、攻击向量、影响范围、修复方案、预防措施。这样LLM就有更清晰的指导,生成质量稳定了很多。

问题2:交叉引用经常断裂

Wiki的核心价值在于交叉引用,但LLM经常创建单向链接,或者链接到不存在的页面。

解决方案:在CLAUDE.md里强化了交叉引用规则:

  1. 必须双向链接:如果A页面引用了[[B]],那么B页面也必须引用[[A]]
  2. frontmatter里的related字段必须和正文里的[[wiki-link]]一致
  3. 只能引用已存在的页面,需要先创建再引用

我还加了Lint检查,定期检查断裂链接和孤儿页面。

问题3:处理非结构化素材效率低

有些原始素材质量很差,比如截图、手写笔记、甚至是Slack聊天记录的导出。LLM处理这些素材时效率很低。

解决方案:对于这类素材,我会先手动整理成结构化的Markdown,再交给LLM处理。虽然增加了前期工作量,但保证了最终质量。

一些经验教训

  1. 不要追求一步到位。llm-wiki是个迭代过程。第一版Wiki肯定不完美,但可以通过持续迭代改进。

  2. CLAUDE.md要不断优化。随着使用,你会发现CLAUDE.md里缺失的规则。比如我后来加了”安全故障案例必须包含:漏洞类型、攻击向量、影响范围、修复方案、预防措施”这样的结构化要求。

  3. 保持三层架构的纯净。raw/就是raw/,不要修改;wiki/由LLM维护;output/面向人类。混在一起会越来越乱。

  4. 定期做健康检查。我会每周跑一次Lint,检查断裂链接、孤儿页面、单向链接等问题。发现问题及时修复。

  5. 接受不完美。LLM生成的Wiki不会100%准确,会有遗漏和错误。但相比完全靠人工维护,已经好太多了。

总结

用llm-wiki管理安全开发规范,本质上是把”文档管理”变成了”知识工程”。原始文档是”原材料”,Wiki是”半成品”,规范文档是”成品”。LLM在这个过程中充当了”编译器”和”维护者”的角色。

这个方法最大的价值是可持续性。传统的文档管理,时间一长就会荒废,因为维护成本太高。而llm-wiki把维护成本转移给了LLM,人类只需要:

  1. 提供原始素材(这个避免不了)
  2. 检查和修正LLM的工作(比从头写轻松多了)
  3. 使用最终产出(享受成果)

如果你也在为安全开发规范的管理头疼,不妨试试这个思路。不用完全照搬我的实现,关键是理解”Wiki中间层”这个核心理念。至于具体用什么工具、怎么组织目录,都可以根据实际情况调整。

毕竟,工具是为人服务的,不是吗?

原文地址: http://lichuanyang.top/posts/88001/

Vaadin框架教程:Java工程师的前端开发秘籍

2024-03-06 19:36:22

后端工程师开发前端的痛点,通常来说莫过于太过繁琐,经常要为了一些很小的事查半天。Vaadin很好的解决了这个痛点,为后端工程师提供易上手、方便使用的前端代码编写解决方案,今天我们就来了解一下。

大家好,今天跟大家介绍一个对后端工程师特别有价值的工具——Vaadin。

说起来,上手前端基本的html, css开发,确实并不难,但是如果只会这些基本的东西,开发起来会很繁琐。如果想要使用前端生态中的各种轮子,虽说便利度提升了,但学习成本也会同步上升。所以,如果不是职业的全栈工程师,只是作为一个后端,想临时写点前端代码,比如自己想做点小项目,通常来说都会有个很痛苦的过程。

Vaadin很好的解决了这个痛点。通过vaadin包装好的常用前端组件,我们几乎可以零学习成本的编写出功能完备、不太难看的页面。对于后端背景的程序员来说,无疑会大幅度降低自己做些小项目的成本。

Vaadin提供的功能,就是可以直接用java代码来写页面。Vaadin提供了多种输入框、表单等等封装好的前端样式,而且与springboot做了深度的融合,使用起来非常方便。

Vaadin的实际原理并不复杂,主要是基于服务端渲染,即在后端生成最终的html代码,交给浏览器。服务端渲染,这个并不罕见,与客户端渲染的优势和劣势,我们在这里不多讲。当然,对于vaadin来说,使用服务端渲染,似乎也没什么好说的,毕竟是写的后端代码,直接在后端做渲染,是个再正常不过的实现路径。Vaadin的引擎对前后端之间的交互做了封装,所以对使用者来说,前后端之间的交互是无感的,在页面层,我们也可以正常的调用后端service.

下面是我写的一段代码示例,可以更直观的感受Vaadin的作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Route(value = "path", layout = MainView.class)
@PageTitle("路径规划")
public class PathView extends VerticalLayout {

@Autowired
private PathService pathService;

public PathView() {
TextField start = new TextField();
TextField end = new TextField();
HorizontalLayout path = new HorizontalLayout();
path.add(start, end);
Button pathCalculate = new Button("calculate path");

VerticalLayout result = new VerticalLayout();
TextField transferNum = new TextField();
TextField distance = new TextField();
Text stations = new Text("");
result.add(
new H3("换乘数: "),
transferNum,
new H3("总距离 :"),
distance,
new H3("途径站点详情:"),
stations
);

pathCalculate.addClickListener(click -> {
PathInfoVO pathResult = pathService.getPath(start.getValue(), end.getValue());
System.out.println(pathResult);
stations.setText(StringUtils.join(pathResult.getDetail(), ","));
transferNum.setValue(String.valueOf(pathResult.getTransferNum()));
distance.setValue(String.valueOf(pathResult.getDistance()));
});

add(
new Text("hello world"),
path,
pathCalculate,
result
);
}
}

这段代码中,我们完全使用java代码对页面中的各个组件进行了编排,包括button的click函数,也是使用java开发者习惯的方式定义,并且能够直接调用其他后端service, 可以说是几乎零学习成本了。

详细代码和运行效果,可以到 项目地址中查看。

如果你对Vaadin感兴趣,或者有任何问题或想法,欢迎在评论区交流。一起探索如何更好地利用Vaadin,提升我们的开发效率吧!

原文地址: https://lichuanyang.top/posts/43947/

hexo多语言方案总结及最佳实践

2024-01-22 18:12:31

对于hexo的多语言方案,官方并没有提供很完备的支持,但是网络上有很多人尝试过不同的解决方案。今天,我们对这些方案简单做个总结,看看我们需要的多语言方案是什么样子的。

其实,hexo的多语言方案,说白了就是两个思路,一个是在文章维度切换语言,借助hexo原生的能力和hexo-generator-i18n等插件,用一套框架维护两个语言的内容;另一个则是独立维护不同语言的样式、内容,在站点维度切换语言,只是在域名层面合并到同一个域名。

具体要选择什么方案,取决于大家想要一个什么样的多语言网站。一开始我想象中的多语言网站的是第一种,即统一的首页,在首页和每篇文章上都支持切换语言,对每篇文章,可以通过切换语言,直达对应的其他语言译文上。

这个思路,借助于hexo-generator-i18n插件,可以实现,但要做比较多的定制开发。所以,我又重新思量了一下思路,我要的多语言网站应该是什么样。重新考虑之后,逐渐觉得第二种思路才是更合理的。我们要做一个多语言网站的目的是什么?对我来说,其实就是要获取一些英文流量。作为一个未备案网站,已经很久无法获取百度的搜索流量了,google在中国占的份额又太低,所以单凭中文内容,很难从搜索中获取较高流量。所以我希望通过提供一些英文内容,获取英文流量。这个目标下,完全不需要对所有的文章都维护多语言版本。何况,不同文章的语言受众也的确有很大区别,所以,语言的切换可以直接在站点层面进行。

具体操作方式上,一种是直接维护多个站点,两个站点内容、样式完全独立,只是部署在同一个域名下。比如中文站点根路径是lichuanyang.top,英文站点根路径是lichuanyang.top/en . 两个站点上各做一个跳转链接,向对方跳转。

我采用的是另一种方式,相比上述方式,成本小一些,不需要实际维护两个站点。原理大致如下:

在本地,同样维护两个站点。但是英文站点不会去做实际的部署,只是用作生成静态网页的工具。英文版的内容生成之后,直接复制到中文网站的对应目录下,只对中文网站做部署即可。

具体操作步骤如下:

  • 将博客目录整体复制一份,作为英文博客目录. 例如,我的博客根目录叫blog.source, 复制出一个blog.source.en. 这步完成后,如果博客源码也是以git维护的,可以直接在原目录的外层直接新建一个git项目,在外层做管理就行了。 示例如下:

    1
    2
    blog(git根目录)/blog.source
    /blog.source.en
  • 将en目录下的文章全部删除;站点描述等文本调整为英文内容;英文语言设置为en;英文站点根 (_config.yml中的root配置)设置成/en

  • 在两个站点下增加跳转链接。我是借助菜单功能,直接在菜单里加一个其他语言项。 next主题中配置如下:

    1
    2
    3
    中文站 :    English: /en || fa fa-language
    英文站: 中文: https://lichuanyang.top || fa fa-language

  • 之后配置基本就完成了,可以在en目录下写英文文章,流程与之前写中文文章时完全一致

  • 最后就是生成和发布环节了,这一步要注意,每次生成时,我们需要先生成中文站点,再生成英文站点并将英文内容复制到中文目录下,避免生成中文内容时将英文内容覆盖掉。具体操作示例如下:

    1
    hexo clean && hexo g &&cd ../blog.source.en && hexo clean && hexo g && cd ../blog.source &&cp -r ../blog.source.en/public/. public/en/ && hexo s

    命令最后一段,使用hexo s就是本地启动,使用hexo d就是发布出去,和正常使用时一样。

这样,我们就有了一个好用的多语言站点了。之后,写中文内容就在中文目录下进行,写英文内容就在英文目录下进行, 最后执行一下上边的命令就可以了。

原文地址: http://lichuanyang.top/posts/40400/

知乎增强工具-评论时间精确到秒

2023-12-22 17:24:18

一个优化知乎显示的油猴工具

之前在 小众软件 上看到一个知乎评论区时间展示混乱的吐槽,有大佬立刻就给了一个油猴脚本。

用了一段时间很舒服,然后前几天知乎做了个更新,导致展示开始混乱。研究了一下,做了更新,想着就发布到GreasyFork上吧,后边知乎再有调整,可以直接从线上更新。

脚本地址: 安装地址

大家感兴趣的话,欢迎留言,后边考虑做个油猴脚本的开发教程。

原文地址: http://lichuanyang.top/posts/44912/

kubernetes是什么-实用向教程

2023-01-28 19:06:17

这篇教程不会关注 kubernetes 的部署、架构、实现方式等内部原理,而是完全从一个使用 kubernetes 的开发人员的视角去介绍kubernetes是什么,从而帮助了解如何更好的去利用 kubernetes 的特性。

基本介绍

对于kubernetes是什么,一个比较官方的定义,Kubernetes是一个开源容器编排平台,管理大规模分布式容器化软件应用,简称为k8s.

通俗一些来讲,k8s 的核心理念是以应用为中心,向下屏蔽基础设施的差异,向上通过容器镜像实现应用的标准化,帮助开发人员在仅需关注应用本身,无需考虑部署、容灾、伸缩等运维细节的情况下,开发出大规模、可靠的分布式应用。

优势

如上所述,k8s的核心优势就是降低运维成本,让应用开发人员能够专注于应用本身。具体来讲,包括如下几点:

  • 便捷的部署流程和大规模的复制分发能力:应用提供标准化的容器镜像,之后的部署发布流程都可以做到自动化;应用也无需再做更多的事情就可以实现跨平台、跨区域的部署。
  • 服务自愈能力:自动摘除不健康的节点并做恢复。
  • 敏捷的自动伸缩:根据设定的系统负载,做快速的自动伸缩,实现系统处理能力和成本之间的平衡。

主要概念及实现方式介绍

这篇kubernetes教程的剩余部分会从应用开发人员视角,介绍需要了解的k8s概念,主要包括以下几类:

  • Pod, service, deployment等基本概念
  • spec+controller这套基本实现原理
  • k8s提供给应用的扩展点

spec+controller

这是k8s内部大部分逻辑的实现方式,了解这个逻辑,可以帮助开发人员更好的理解某些特定情况下k8s的行为。

如果翻看k8s的yaml配置,就会发现k8s的大部分组件中都有一个或若干个spec字段,它的含义很好理解,就是对于某个属性的期望值,比如一个服务节点数量的期望值。

controller的作用就是持续监测期望值和实际指标是否一致,不一致时就进行相应的操作进行处理,比如发现节点数不够了,就会启动对应数量的新节点。

这样,无论是上线、扩缩容、还是故障恢复,我们会发现这些逻辑都变得非常清晰,都是触发一下对容器数期望值或实际值的调整,然后让controller去增删节点就可以了。

这套机制是k8s里广泛使用的一个底层设计原则,作用是解开监控和操作逻辑之间的耦合。举个例子,我们在很多情况下都需要触发启动新的节点,包括要做扩容时、部分节点挂了时、要上线时,等等。这些完全没关联的场景如何去触发相同的操作,代码要如何保持整洁呢?k8s的做法就是用一个期望值的概念做中间层,将操作的触发时机和操作本身拆分成独立的逻辑。

了解了这个逻辑,我们可以更容易的理解k8s是怎么工作的。 比如基于HPA做自动扩容,就是根据当前的CPU使用情况,和期望的CPU使用量,决定是增加还是减少节点。

Deployment

Deployment 用于指示 k8s 如何创建和更新应用程序,我们通常理解的一个“服务”、“应用”大体上就对应在deployment这一层上。 像镜像、内存cpu使用限制、节点数、环境变量等各种配置,都是在deployment上。

Pod

pod比较好理解,就是我们通常理解的一个节点。pod是 k8s 中最小可管理单元。

Service

Service是一个需要着重了解的概念,它是一个抽象层,它选择具备某些特征的 Pod(容器组)并为它们定义一个访问方式。 通常的应用场景下,deployment和service是一一对应的,但实际上deployment和service之间并没有必然的联系。

一个请求恰好可以打到某个deployment关联的所有pod上,看起来是一件非常正常的事情。而事实上,这件事情的发生不是由于这些pod通过一个deployment产生,而是因为deployment上配置了一个标签,通过这个deployment生成的pod都获得了这个标签; 同时,另外存在一个service, 设置通过这个标签选择pod, 请求进入的是通过service选择出的一批pod.

探针(probe)和钩子(hook)

k8s提供了一些用于应用扩展的接口,其中就包括probe和hook, 可以帮助应用更好的利用k8s的能力。

k8s提供了 liveness和 readiness 探针,顾名思义,liveness probe的作用是判断应用是否存活,readiness probe的作用是判断应用是否已经启动完毕。

应用可以用http接口等不同形式提供探针,k8s则负责在探测到不同状态时做不同的操作。比如说探测到liveness probe返回状态异常,则可以认为此节点已经丢失,对此节点做删除处理。

hook则支持应用在一些特定阶段插入一些行为,比如preStop hook, 运行应用关闭之前先做一些操作,可以用来做graceful shutdown.

实践思考

通过对本篇kubernetes教程上文列出的概念的了解,相信大家可以从应用开发人员的视角完全理解kubernetes是什么, 也可以大致想象出应用方使用k8s的基本思路: 构建标准镜像,暴露出必要的监控数据,剩下的事情都交给k8s来做。

在准确的数据下,k8s可以帮我们做好系统的自愈、扩缩容等操作,而我们要做的是,结合应用场景,尽量给出更加准确的监控数据。

举一些例子,比如说应用提供的liveness探针,如何能尽量确保准确的展示系统的健康状态,某个接口可以访问,某个端口可以调通,能否等价的说明这个应用是否健康。

比如说k8s以cpu、内存等指标来判断系统负载时,这些机器指标能否真实的展现出应用的真实负载,是否有可能连接池、IO等其他瓶颈会在cpu、内存等瓶颈到来之前就达到。

这些都是需要应用方结合应用的实际情况精心设计的。

此外,k8s的设计理念决定了在k8s环境下,“重启”会是一件非常稀松平常的事,像硬件故障、小概率的死循环、不健康的gc, 等不同类型的问题,都可以在k8s的自主重启下实现自愈; 自动的扩缩容扩充中,也会经常性的有节点启停。 所以说,应用需要让自己的启动流程顺畅一些,避免大量耗时或大量资源消耗。