2024-08-27 10:10:22
很早就有了解到今年的 KubeCon China 会在香港举办,虽然有些兴趣,但我最初是有被 KubeCon 高昂的门票价格劝退了的。
有时候不得不相信运气的魔力,机缘巧合之下,我从朋友 @Kev 处得知了 KubeCon 的「最终用户门票计划」并借此 0 元购了门票,又邀上了 0xFFFF 社区 的@Chever-John @0xdeadbeef @茗洛 三位朋友一起参加,在香港租了个 airbnb 住宿,期间也逛了香港城市中的不少地方,收货颇丰。
其实本来也尝试过邀请其他认识的朋友同事,但都因为种种原因无法参加,略感遗憾。
本文多图,也挺多技术无关的内容,为了方便想了解技术的朋友,我先做个大致的总结。
从 KubeCon 回来后我又听了些 CNCF 其他的会议视频,其中比较有印象的是这几个:
结合 KubeCon China 三天的经历,以及上面这些视频的内容,我大概的感觉是:
KubeCon China 2024 的会议视频将会陆续被添加到如下这个 Youtube Playlist 中,有兴趣的朋友可以一观:
视频相关的 PPT 可以在这里下载:
这次我主要关注的是 Istio、Gateway API 相关的议题,最近在研究 Istio 的 Ambient Mode,因此希望能够从会议中了解到更多的实现细节与其中的权衡。
三天下来听到的内容也很好的满足了我的期待,Istio / Envoy Gateway / Ingress Controller 的几位核心贡献者分享了很多这些项目的最新进展,实现细节,以及未来的发展方向。
Ambient Mode 在最近 beta 了,是我关注的重点,总结下目前了解到的几个关键点:
以及一些其他方案:
总体而言,KubeCon 是一次了解行业前沿技术动态、跟项目开发者及其他行业内的技术人面对面认识交流的好机会,可以帮助自己提升技术视野,维持技术热情与动力,不至于局限在公司业务中闭门造车。
因为要在香港呆三天,衣食住行是必须要考虑的事情。这方面我拉上的几位朋友都比较有旅行住宿的经验,我们最后在香港找了个离会场不远的 airbnb 住宿,最终的体验也是相当不错。房间干净整洁有格调,虽然我觉得稍微有点小了,但朋友说这个空间在香港都是一家三四口住的标准,已经吊打同价位的酒店了。
虽然提早定了住宿,做了点功课,但第一天就出了问题——深圳这边一直下雨导致 @Chever-John 的飞机直接被取消,改订了另一趟航班也晚点。虽然正点到达了会场,但他一晚上就睡了俩小时,在深圳定的前一晚的酒店也没住成,第一天看他整个人都听得迷迷糊糊的。不过没事,至少我听了个爽
说回正题,到了会场领完胸牌,我们就开始了为期三天的 KubeCon China 之旅。
具体的技术内容已经在前文总结过了,这里主要就贴些照片吧。
然后晚上@茗洛带着我们逛了香港的诚品书店,书店好几层,但感兴趣的书不多。后面又逛了好多电子商城、二次元周边店,我算是开了眼界。
第一天就差不多是这样,听了点技术,晚上逛了逛香港,回去休息。
首先是听了华为的演讲,介绍了 Kmesh 的方案创新,技术细节讲得很赞。想看 PPT 与视频请移步用内核原生无边车架构彻底改变服务网格 - Xin Liu, Huawei Technologies Co., Ltd.
还听了晋涛老师的十年云原生之旅:容器技术和Kubernetes生态系统的演变 - Jintao Zhang, Kong Inc.
然后晚上我们随便走了走逛了逛,看了看香港海边夜景。
第三天早上是我这次最期待的,Linus 的访谈,见到了本人,这次行程也圆满了。
第三天没什么我特别感兴趣的话题,听完 Linus 的访谈后随便逛了逛,跟几位 朋友合了个影,就搭地铁回家了。
另外朋友听了个 TiDB 的演讲,看 PPT 是有点意思的哈哈。
以及在项目展厅三天逛下来,我帆布袋领了四个,T恤领了三件,还有别的小礼品一堆,吃的喝的都不用说了,管够。另外看网上不少信息说香港的服务业态度很差,但这家酒店可能星级比较高,体验还是相当到位的。
总之,体验相当不错的,有机会的话明年还来!Love you, KubeCon China & Hong Kong!
2024-07-10 09:17:31
Kubernetes 具有非常丰富的动态伸缩能力,这体现在多个层面:
本文主要介绍新兴 Node 伸缩与管理方案 Karpenter 的优势、应用场景及使用方法。
Karpenter 项目由 AWS 于 2020 年创建,其目标是解决 AWS 用户在 EKS 上使用 Cluster Autoscaler 做集群伸缩时遇到的一些问题。在经历了几年发展后,Karnepnter 于 2023 年底被捐献给 CNCF(kubernetes/org#4258),成为目前 (2024/07/10)唯二的官方 Node 伸缩方案之一。
我于 2022 年 4 月在做 Spark 离线计算平台改造的时候尝试了 Karpenter v0.8.2,发现它的确比 Cluster Autoscaler 更好用,并在随后的两年中逐渐将它推广到了更多的项目中。目前我司在 AWS 云平台上所有的离线计算任务与大部分在线服务都是使用 Karpenter 进行的集群伸缩。另外我还为 karpenter 适配了 K3s 与 DigitalOcean 云平台用于一些特殊业务,体验良好。
Karpenter 官方目前只有 AWS 与 Azure 两个云平台的实现,也就是说只有在这两个平台上 karpenter 才能开箱即用。但考虑到它在易用性与成本方面的优势以及在可拓展性、标准化方面的努力,我对它的未来发展持乐观态度。
Cluster Autoscaler 是目前社区最流行的 Node 伸缩方案,基本所有云厂商的 Kubernetes 服务默认都会集成它。
Karpenter 与 Cluster Autoscaler 的设计理念与实现方式有很大的不同。
Cluster Autoscaler 是 Kubernetes 平台上早期的集群伸缩方案,也是目前最流行的方案。但它做的事情比较有限,最大的问题是它本身并不直接管理集群的节点,而是借助云厂商的伸缩组 (AutoScaling Group)或节点池(Node Pool)来间接地控制节点(云服务器)的数量。这样的设计导致了一些问题:
而 Karpenter 则完全从零开始实现了一套节点管理系统,它直接管理所有节点(云服务器,如 AWS EC2),负责节点的创建、删除、修改等操作。
相较 Cluster Autoscaler, Karpenter 的优势主要体现在以下几个方面:
总之,个人的使用体验上,Karpenter 吊打了 Cluster Autoscaler.
这部分建议直接阅读官方文档Karpenter - Just-in-time Nodes for Any Kubernetes Cluster.
如果你使用的是 Proxmox VE, Aliyun 等其他云平台,或者使用的是 K3s, Kubeadm 等非托管 Kubernetes 发行版,那么你就需要自己适配 Karpenter 了。
Karpenter 官方目前并未提供详细的适配文档,社区建议以用于测试的Kwok Provider 为参考,自行实现。Kwok 是一个极简的 Karpenter Provider 实现,更复杂的功能也可以参考 AWS 与 Azure 的实现。
国内云服务方面, 目前已经有人做了 Aliyun 的适配,项目地址如下:
对于个人 Homelab 玩家来说,使用 Proxmox VE + K3s 这个组合的用户应该会比较多。我个人目前正在尝试为这个组合适配 Karpenter,希望能够在未来的文章中分享一些经验。项目地址如下:
Cluster API (CAPI) 是 Kubernetes 社区提供的一个用于管理多集群的项目,从介绍上看,它跟 Karpenter 好像没啥交集。但如果你有真正了解使用过 CAPI 的话,你会发现 Karpenter 与 CAPI 有一些功能上的重叠:
Cluster API 的目标是多集群管理,并且它的设计上将 Bootstrap, ControlPlane 跟 Infrastructure 三个部分分离出来了,好处是方便各云厂商、各 Kubernetes 发行版的接入,但也导致了它的架构比较复杂、出问题排查起来会比较麻烦。
历史案例:Istio 曾经就采用了微服务架构,结果因为性能差、维护难度高被不少人喷,后来才改成了单体结构。
而 Karpenter 则是一个单体应用,它的核心功能被以 Go Library 的形式发布,用户需要基于这个库来实现自己的云平台适配。这样的设计使得 Karpenter 的架构简单、易于维护。但这也意味着 Karpenter 的可扩展性、通用性不如 Cluster API.
从结果来看,现在 Cluster API 的生态相当丰富,从Provider Implementations - Cluster API Docs 能看到已经有了很多云厂商、发行版的适配. 而 Karpenter 2023 年底才捐给 CNCF,目前只有 AWS 与 Azure 的实现,未来发展还有待观察。
那么有没有可能结合两者的优势呢?Kubernetes 社区其实就有类似的尝试:
上面这个实验性质的项目尝试使用 Karpenter 作为 Cluster API 的 Node Autoscaler,取代掉现在的 Cluster Autoscaler.
我目前对 Cluster API 有些兴趣,但感觉它还是复杂了点。我更想试试在 Karpenter 的实现中复用 Cluster API 各个 Provider 的代码,快速适配其他云厂商与 Kubernetes 发行版。
2024-05-21 10:05:00
在 2023 年年度总结中,我给 2024 年定下的目标是「工作与业余爱好上稳中求进,生活上锻炼好身体、多关心家人」,为此今年我做了许多旅行的准备。
在深圳呆了快五年,挺长时间里一直将自己局限在技术与工作中,少有时间去关注周围的世界——生存已属不易,没有多余的精力去关心其他事情。2023 年是一个分界点,工作上越来越得心应手,手头也不再紧张,个人精力跟业余时间得以解放,我自然开始追求更多的生活体验。
说是要锻炼身体,多旅游,但也没啥明确的计划,只是想着该出国走一走开开眼界,于是 3 月份到出入境管理局搞定了护照跟港澳通行证。
香港离深圳近得很,自然就想着先去香港多走走,这是缘起。
而这件事情后来的发展,现在回看起来,跟我当初折腾 NixOS 或电子电路的故事如出一辙,大概性格使然吧哈哈。
简单总结下呢,就是 4 月份去香港海边徒步了一天,从维多利亚港沿着海岸线一路走到坚尼地城,然后就爱上了这种在海边徒步的感觉,回来后也一直念念不忘,查了许多香港徒步路线的资料。
五一假期的时候跟着小红书跟 Bilibili 上的攻略,徒步了香港麦理浩径第一段的部分以及第二段全程。因为准备不足,举着手机走了一个小时夜路,并且在西湾村营地租帐篷露营了一晚上。这次体验又让我迷上了夜间徒步跟露营。一回家就查各种徒步露营装备,疯狂下单,收了一大堆快递,花掉了一万多 RMB…
接着就是 5 月 18 日,背上我 65L 的重装背包,总重量大概有 17 kg,从深圳坐地铁 + 大巴直达北潭凹,爬了一遍麦理浩径三段,夜间在水浪窝营地露营一晚,第二天一早直接打道回府。本来计划是周末两天刷完三四段,甚至又余力再走完第五段的。但是我显然高估了自己的体力,而且背着 17 kg 的重装背包,这也不是一件轻松的事情。
休息了一周后,在 5 月 25 日,我又完成了麦理浩径第四段的徒步。这次出发前根据上次的经验精简了装备,总总量应该轻了大概 1kg,但仍旧有 16kg。四段是麦径难度最高的一段,而且终点基维尔营地不接受个人预约,又导航徒步到大老山隧道站乘九巴 74X 路至广福邨下车,再步行到地铁站乘车到罗湖口岸回家,到达车站时已经是 22:20。全程差不多 9 个小时,步行超过 21 公里,是我目前的人生巅峰。
以上就是我到目前为止的香港徒步经历,目前对重装徒步兴趣浓厚,计划今年先把麦理浩径全程走完, 积累经验,后续再看看香港跟国内外的其他徒步路线。
时间:2024-04-14
这是我第一次出境游,整个行程都是临时起意,没有做任何准备,即使是过了罗湖口岸,站在东铁线地铁上的时候,我对整个行程也并无太多期待,心里想着无非是不同的人与物,无甚特殊的。但总得出去走走,看看大陆之外究竟是个什么样子,所以就这么随意地来到了香港。
具体有多随意呢?就这么说,过了口岸没多久,手机就没信号了,我这才意识到香港终归不是大陆,慌得我又出站再往回坐,在罗湖口岸连上网络开了个漫游跟流量包,这才算是正式开始了我的香港之旅。
最初期待甚少,但现实常常超出我的想象。在香港徒步的一日,我切实感受到了更宽广更多元化的世界,这是在大陆境内无法体会到的。
刚上东铁线甚至刚出地铁站的时候,我对自己已经出境这一点尚无实感,因为香港的地铁跟深圳实在太像了,不论是地铁车厢的设计还是车站的建筑风格、干净整洁的程度,都跟深圳非常相似。
后面跟朋友聊起来,才知道国内深圳地铁跟香港地铁是有合作关系的,很多技术最初都来自香港,算是一脉相承了。
在去往维多利亚港的路上,看到香港多的双层巴士、随处的繁体字跟英文标识,才逐渐感觉到这里确实是个不同的地方。
接着就到了维港的海边步道,海景很美,两岸都是高楼大厦,海上有很多游船,还有很多钓鱼的人。
接着我意识到,从我住处可全程地铁直达维港,坐个地铁再浅浅走几步路就能看到这么漂亮的海景,这不比去深圳大鹏半岛方便多了!我为此兴奋起来。这风景吊打深圳湾,但深圳湾步道上的人甚至比维港还多,只能说深圳人真的太多了…
补充:听说深圳湾以前真的是海边,但填海造路使它成了现在的烂泥滩
沿着海岸线继续走,渐渐发现人群里外国游客相当的多,粗略估算超过一半是外国人,这让我感受到了香港的国际化氛围。
海边还有很多细节值得一看。
在维港逗留玩耍了一个小时,买了点面包当午餐吃了,然后就沿着海边步道继续往前走,也没啥明确的目的地,反正累了就回家。维港的人很多,但出了维港后步道上人就少了很多,走在这样的路上看着风景,相当闲适。
悠闲、轻快地随走随停,大概一个半小时后,到达了步道的终点——坚尼地城,我还有点失望,这步道居然就这么没了。只好掉转方向往城市内走,市内倒也别有一番风景。
在市内逛了逛,确认了香港各种店铺的特点是小而美,各种店铺都非常小,但弄得比较精致,能看得出花了心思。相对而言深圳的商场店铺就大气很多了,但也缺了香港这些店铺的种种细节。
玩得尽兴,又找了家店吃饱喝足,打道回府。
这一趟下来,我的感觉是,香港确实是国际化大都市,跟深圳的气息很不一样,海边随处可见的酒吧, 比例非常高的外国游客跟在香港工作的外国人,让我感觉到了一种国际化的氛围。至于城市的繁华程度,跟深圳各有千秋。
食髓知味,在香港海边徒步一日后,我对香港徒步来了兴趣,一直瞅着机会再来一次。
到了五一假期,我终于有了机会,随便在小红书上查了些资料,发现麦理浩径一二段挺有名,还能露营,于是就决定是它了。
看天气预报最近几天都有雨,五一那天下得比较大没出门,顺便就买了迪卡侬冲锋衣、冲锋裤、速干 T 恤、大号水杯,想着明天就算有雨也要去。
幸而天公作美,第二天天气转阴,上午东西到货,又做了大半天准备才出门。因为计划是连续步行两天,所以跟着小红书上的香港旅游攻略,吃的穿的用的都带了挺多。
下午出境,首先买了 OPPO 9.9 元的香港流量包(五一特惠),然后坐地铁到深水埗(bù)地铁站整了张八达通,200 港币,其中 50 块押金。另外考虑到以后会常去香港,又多充了 100 块。
接着就是各种地图导航,首先坐小巴到西贡码头,然后查半天导航,坐九巴 94 路到麦理浩径起点。
小巴要叫停车才停,真的 I 人(内向)天敌,决定以后尽量选九巴,下一站前按个 Stop (香港人称掀钟)这种才适合 I 人。
导航本来是说坐到麦理浩夫人度假村站,但我一下没注意就坐过了,然后下车时第一次「掀钟」不熟悉,又过了一站才按到 Stop,结果就是在「北潭凹管理站」才下车(16:34),然后往回走了半个小时才到「麦理浩径起点」(17:09)。
从「麦理浩径起点」往万宜水库的路上(大网仔路)看到很多出租车来来往往,联想到之前查的攻略, 就知道这些出租车是为了接送徒步的人。我是单人徒步,为了省 150 的打车费,就选择了坐九巴到起点然后步行。
路上很多烧烤点,貌似是政府修建的,可以免费用,但没遇到过人在用这些烧烤点,可能季节或天气原因?
到达万宜水库岔路口时已经是 17:26 了,走第一段晚上肯定到不了我的目标地址「咸田湾」,而且我了解到的是二段风景最好。一番心理斗争后,我直接走了左边的路线,绕过麦径一段,直接走到西湾亭走二段的路线。
沿着大路走了整整一个小时才到西湾亭,为了省个出租车费我也是拼了。不过倒也不算亏,这两个小时的路上风景相当不错,而且没遇到几个人,体验非常棒!有种我很喜欢的孤独感。
这时已经是 18:34,天色已经快黑了,我有点慌,刚好有辆出租送人到这,我向司机问路,他好心地帮我指了路。从这里开始才是山路,前面两个小时一直走在大马路上,而且我的脚在走了两个小时后已经很痛了。
接着就手机打着灯,一直走到 19:10 才到西湾村。
看到第一个租帐篷的店,立马就整了套帐篷。押金 300 租一晚 200,跟国内比可能很贵,但跟香港劳动节期间 1300+ 的旅馆比已经性价比爆棚了!
我之前的目标是到咸水湾租帐露营篷,但到西湾村的时候天已经完全黑了,而且一路心惊胆战地连续赶了三个小时路后我也累得不行了,在往西湾村的路上我就一直憧憬着西湾村总该能找到地方住,万幸它没让我失望。
本来想吃口热乎的,但看到店里 55 港币起步的面食,我还是决定吃点自己的能量棒当晚餐。
洗澡收费 30,但人太多了,我就没洗。晚上海浪声、旁边帐篷里人的说话声等,环境变化太大,睡不着,小说看到凌晨三点,然后跑去海滩上听了听海浪声,回来的路上一路被村民家的狗狂吠,惊出我一声冷汗,万幸我还懂点这种场面的处理方式,盯着狗看,慢慢后退。即使走得远了,我还是一步三回头,置到回到营地把门关上才松了一口气。并且明白一个道理 —— 晚上还是不要这么跳脱的好…
西湾村手机信号挺好,但用的人太多带宽不够,很多站点怎么刷都刷不出来… 想起 21 年看过的《走出荒野》,讲的是通过徒步自我救赎的故事,打算翻出来读一读但网络问题根本刷不出来。
然后迷糊睡到了早上 7 点,出帐篷发现我这个营地人都走差不多了。想洗漱但意识到我带了牙刷却没带牙膏…因为最初是打算住旅馆的,谁 TM 知道居然没找到个便宜旅馆,香港的物价太 TM 离谱了, 逼得我连夜赶路到这里来住帐篷。
厕所也没上,早餐看太贵了也没吃,买了瓶 0.6L 的水(20 港币),07:24 直接出发了,早餐仍然是能量棒配水。
第二天一早从西湾村出发。
没走几步就看到了西湾营地,原来西湾村过来没几步就是西湾营地,垃圾好多…
西湾营地这有黄色标牌,写着野猪出没。朋友也提醒过我,说它们不咬人,但如果你包里有吃的,它们会弄坏你的包。
过了西湾营地又开始爬山。
07:58 到达我印象中全程风景最赞的地方 —— 接近咸田湾沙滩的一段步道。
08:15 到达咸田湾沙滩,这里人很多,帐篷也很多。从这里开始接着是往赤径去,钻的就是山路了,这一段不是海景,但也别有韵味。
10:00 到达赤径,这一处水湾风景也很美!在这里玩了很久。
10:30 到达赤径公厕解决了下个人卫生问题。意外发现赤径公厕个别涂鸦很可爱!随手一拍。
接着是从赤径往北潭凹的路,同样是起起伏伏。
路上遇到一泡插着鲜花的牛粪,很有意思,前面的女生蹲下拍照,搞得我差点以为花是她插的… 一路上再怎么陡峭的步道上都能看得到牛粪,挺原生态的哈哈。甚至回去路上在西贡码头汽车站都看到了两头牛在绿化带上吃草。
接着一路上攀,脚踝已经酸痛得不行,非常痛苦。有一段累到直接坐在地上看了 20 分钟《走出荒野》。
11:57 到达麦径二段的终点,走不动了。
又坐九巴 94 路回西贡市区,来去都是这趟车,从「北潭凹管理站」下车又从「北潭凹」上车,几乎是围着这一片走了刚好一圈。
12:30 到西贡市区,饿得不行,找一圈吃饭的地儿发现,麦当劳居然是最实惠的——因为它价格跟国内差不多。于是搞了一顿麦当劳,发现公司有点事,因为今天我 Oncall,顺便拿出 MacBook 处理了下公司的事。是的没错,我背包里还有一台 1.4kg 的 MacBook Pro,真是要了老命。
累得不行,昨晚又没洗澡,一路上疯狂出汗,浑身气味比较感人。吃完饭随便逛了逛,就打道回府了。从西贡坐九巴 299x 路到沙田站,然后转乘东铁线到罗湖口岸,再坐深圳地铁回家。
总的来说,香港西贡这块开发得更好,步道很多,原生态的同时路线也足够成熟,而且过来比深圳大鹏半岛更方便,期待下次再来。
查攻略最有用的几个 APP:
上次徒步走完麦理浩径二段后就有点上头了,刚回到家累得不行,脚都要废了,但隔天还想找个步道走走。另外就是这两次徒步都太随意,缺乏登山杖、登山鞋、背包等专业装备,而且露营还是租的人家帐篷,接着就是看各种徒步教程攻略,疯狂买买买。
买的一堆装备陆续到货,在家试用了好几天,比如说穿登山鞋上班、空调开 16 度在室内搭帐篷露营、床上铺蛋巢垫盖睡袋、晚餐吃自热米饭,等等不一而足 emmm
接着 5 月 18 跟 19 两日又是个空闲的周末,这次做足了准备,计划两天走完麦理浩径三四段。
整理背包时,意识到气罐很难处理,带着上地铁、过海关,感觉都不太行,在香港我也不知道是否好买,所以把锅具跟炉子都踢出了背包,只带了两盒海底捞自热米饭跟一些能量胶、压缩饼干以及零食。另外水带得相当充足,3L 水袋 + 600ml 小水杯,光水就有 3.6kg.
大约 9 点多出发,首先是乘东铁线到沙田站,转程九巴 299x 路到麦边站,再转乘 94 路到麦径三段的起点。
在二段终点解决完个人卫生问题,热了个身,顺便帮一批反穿麦径二段的大陆人合了个影,接着就开始上山。
三段一开始就是急攀,路面很陡,而且透露着一股年久失修的味道,路况比一二段差远了。
三段的人流量相比二段那是断崖式下降,几乎依山遇不到人,有一种远离人世的孤独感。有的人可能会喜欢热闹,但我恰恰相反,相当享受这种孤独感。
上升太快,我又负重 17 公斤,没爬几步就累到要休息,甚至有点怀疑今天能不能走完三段。但辛苦带来的收获也挺大,越往上爬,风景越美,山景与海景交相辉映,让人心旷神怡。
在山顶还解锁了一些隐藏支线,因为走的人少,灌木丛茂盛,登山杖几乎没法用,这时候就很庆幸我穿了长袖紧身运动打底衣裤,不然走这种路小腿难免挂彩。
接着就是下降。
下降路段走完,到达嶂上营地跟士多店。
又开始上升,不过跟三段起始的那段比起来,这段路还算平缓。接着我高兴没多久,就到了一段相当陡峭,几乎没有台阶的路段。
又二十多分钟后,累得不行,寻个地坐下,顺便回头看看。
继续走,没多久就到了 17 点,天开始黑了,我也提前翻出了头灯准备着随时打开。
到达营地开始搭帐篷,营地很空旷,只有我跟另一伙人露营。
18 号这一天下来一共走了 33582 步,而且背着十七八公斤爬上爬下,最后两三公里完全是咬着牙拼命爬的。
7 点多,在流动厕所解决完卫生问题,在营地逛了一圈没找到水源,只好拿折叠水桶在流动厕所的洗手池接了点水洗脸顺便擦身体。
早餐随便吃了点东西,接着就收拾帐篷打算回家,发现收拾起来还挺费劲,慢慢吞吞弄了也大概 40 分钟,而且发现蛋巢垫下面有跟毛毛虫,帐篷内还有好几只蚂蚁,还发现一只跳蚤,另外内帐外面也爬了根看着就很毒的毛毛虫…
蛋巢垫下的毛毛虫、帐篷内的跳蚤大概是昨晚搭帐篷时,把东西放在一个石墩上,从石墩上爬上来的, 蚂蚁可能是从内帐的孔洞爬进来的。总之它们吓得我收拾东西的时候检查了一遍又一遍,生怕碰到虫子或者把虫子收拾进了行李中。
总的来说,计划两日麦理浩径徒步,实际只 18 号走完麦径三段就精疲力尽了,第二日早上直接打道回府。从二段起点走到终点,用时 12:45 - 20:30,在交界处吃晚饭、休息了 1 个小时。之后从 21:50 - 22:15 走到水浪窝营地,到 22:50 才搭好帐篷。这是我第一次重装徒步,积累了宝贵的经验,也发现了许多问题,下次再徒步麦理浩径肯定能更得心应手了~
只爬完第三段就精疲力尽,我分析了主要有这几个原因:
徒步完第三段后,休息没一周,又是周末,周五下班后赶紧跑去续签了香港签证,精简了一番装备,周六上午就再次出发徒步第四段了。
这次出发前根据上次的经验精简了装备,总总量应该轻了大概 1kg,但仍旧有 16kg。主要变化:
四段是麦径难度最高的一段,而且终点基维尔营地不接受个人预约,只接受团体预约。但我还是抱着侥幸心理背着重装背包去了,想着路上总不会只有这一个营地吧(后面的经历证明我有点鲁莽了)。
早饭吃得饱饱的,又洗了澡、休息了会儿消消食,然后 10 点左右就从家里出发了。
走了约十分钟到达三段终点,在这里用直饮水机将 3L 水袋灌满,然后取出登山杖就出发了。
首先是到达上次露营过的水浪窝营地,然后沿着大路继续上山,路上没人。
沿大路到达山顶后,是沿着黄泥小路下山。这两天下雨,路面泥泞湿滑,我又背着个 16kg 的重装背包,走起来有点难度。还好有登山杖,倒不用怕滑倒。
走黄泥路下完山,接着又是沿着石阶路开始登山,石阶也有点湿滑。
登山没多久,就遇到了雾气,接着雾就越来越浓。
又到达一座山顶,在这里休息了一阵子,吃了点东西,接着突然想到我出发时没拉伸,想着补救一下, 就在这里做了个拉伸。
中间还遇到位外国女士背着个很小的跑步背包爬上来,也休息了一会儿喝了口水,往另一边去了,很快消失在了雾中。
休息好了开始下山,没多久就到了四段风景最好的一段,因为浓雾没远景看没,如果没雾这里视野会是很开阔的。
继续前行,到达昂平营地,这里是一块山顶平原草地,浓雾下也有点意境。走着走着旁边雾中出来一只狗跟一个人,说起来这路线上挺多人遛狗的,今天遇到两三波了。
因为阴天,下细雨,又这么大雾,天黑得很快,17 点后天就有点看不清路面了,开始需要灯光。头灯在包里懒得拿出来,就把背包背带上的手电夹到腰间别着的便携坐垫上照亮路面,还别说,效果不错。
到 20:10 左右,终于到达基维尔营地,听到了有人声,也看到了灯光。一番调查确认了跟之前了解到的一样,这里不接受个人露营。地图上往前看也没露营点,我有点慌了,但总之先到四段终点瞧瞧吧。走到终点发现就是基维尔营地下山的大水泥路面,既然有大路,那就能沿着它回到城市,这样想着终于有了一点安全感。
下了个山坡后实在累得不行,把便携坐垫一铺就坐下休息了,尝试用高德地图导航,但信号有点差,一直转不出来。
然后一辆车从山下开上来,看到我瘫坐在路边,停下来问我要去哪,了解清楚情况后又给我指路,还说这里徒步下去要一个多小时,路上没路灯,问我行不行,要不要他送我去车站。
手机一直没信号,我一开始是有点心动的,但不想麻烦别人,刚好手机终于加载出了导航,我对照了下跟他指的路是同一个方向,就婉拒了他,并给他展示我的手电筒表示我不担心走夜路。
高德地图给的教我先徒步到大老山隧道站乘九巴 74X 路至广福邨下车,再步行到地铁站乘车到罗湖口岸。
但它给的徒步路线有坑,我跟着导航越走就越荒凉,公路路面开叉,长满荒草,接着就直接没公路了。我慌了,仔细确认才意识到它教我往草丛里钻,仔细看草丛里还真有条路… 但这条小路显然已经半荒废,草木林立,不仔细看几乎分辨不出路线,让人忍不住怀疑这条路真的能走吗?不会走到一半成断头路吧。
还好这条灌木丛近期有人走过,沿途草木有明显被人趟过,沿途灌木上偶尔还扎了很干净显眼的飘带, 明显才扎上去没多久,这给我增加了一点对它的信心。
钻灌木丛,中间还过了条溪流,接着又是上山,好走的山路没走多远,接着又是在山上钻更深的灌木丛,我越来越慌——这真的是下山的路吗?同时我也有点担心被灌木遮挡的路面会有蛇,但现在已经很晚了,下山心切的我没时间顾虑这些,一路急行。
灌木钻了没多久就开始下山路,而且能看到山下明亮的高速公路跟城市夜景了,这让我放心了一点——至少确实是在下山朝城市里去。但这下山路可不好走,几乎是钻着灌木丛林走直线下降,而且是原生地形,非常的陡,即使有登山杖的辅助,也摔了好多跤,还好草木灌木比较密,有效减缓了摔倒的冲击, 也避免我滚下山。
下山路没走多久,我突然发现腰包里的水杯跟夹着的折叠坐垫都不见了,显然是在前面几次摔跤的时候掉了,不过也就三四十块钱,不管了,继续向下。
下山路仿佛没有尽头,万幸途中发现底下的山坳里有好几片亮光,一开始怀疑是山里废弃的房子,前面趟这条路的旅游队在房子里露营,这也给了我希望——或许能有人给点帮助跟一口吃的,一起露营也不错。
到九点半左右终于下到山脚的时候,发现是个电站之类的建筑,周围还有监控警示,挺失望的。不过到这里又是大路了,也能很明显听到不远处车辆来往的声音,悬着的心总算放了下来。
考虑到手表快没电了,先把登山记录停了,显示今天徒步了接近 21 公里,真是累到够呛。
在路边找了个地坐着休息,想到因为钻灌木林、摔跤、一路剧烈运动疯狂出汗,加之今天又下小雨,身上都是各种小叶子、木棍、汗水、沾了叶子上的雨水,这个样子可不好上车见人。见周围也没人,我直接把衣服都脱掉,换了身干净的。
登山鞋里也湿透了,刚刚钻林子导致石子叶子小木棍雨水也进去了不少,也换了备用的沙滩鞋。换鞋时不知道哪跑出来只蚂蟥在我脚面上爬,赶紧给拔掉丢了(也很庆幸我一直穿运动紧身内衣裤,不然这一趟灌木丛徒步下来,小腿刮伤不说,还可能被蚂蟥等各种虫子叮咬)。
衣服鞋子换好后又休息了挺久,然后沿着大路走了可能十多二十分钟,才终于到了山脚,远远看到不远处就有个公交站,再次导航一下,确认它就是大老山隧道站。
到达车站已经是 22:20 了,乘九巴 74X 路到广福邨下车,再步行到地铁站乘车到罗湖口岸、过关、再乘一号线时已经 23:40,这个点居然还有一趟末班车。最后到家已经过了 0 点,饿得不行搞完夜宵、休息、再洗澡,搞到两三点才睡觉。
总的来说这次徒步距离真的是到目前为止的人生巅峰了,另外这次下山路线也是我走过最险的一次,有点刺激跟后怕,高德地图坑我啊。
TODOs:
现在已经爱上了徒步这种运动方式,花钱折磨自己毫不手软(
如下是我近期发现的一些高质量徒步相关资料,对我有挺大帮助:
2024-02-21 16:26:21
本文最初发表于 如何评价NixOS? - 知乎,觉得比较有价值所以再搬运到我的博客。
我 23 年 4 月开始用 NixOS 之前看过(如何评价NixOS? - 知乎) 这个问答,几个高赞回答都从不同方面给出了很有意义的评价,也是吸引我入坑的原因之一。
现在是 2024 年 2 月,距离我入坑 NixOS 刚好 10 个月,我当初写的新手笔记已经获得了大量好评与不少的赞助,并成为了整个社区最受欢迎的入门教程之一。自 2023 年 6 月我为它专门创建一个 GitHub 仓库与单独的文档站点以来,它已经获得了 1189 个 stars,除我之外还有 37 位读者给它提了 PR:
那么作为一名已经深度使用 NixOS 作为主力桌面系统接近 10 个月的熟手,我在这里也从另一个角度来分享下我的入坑体会。
注意,这篇文章不是 NixOS 入门教程,想看教程请移步上面给的链接。
先澄清下一点,NixOS 的包非常多,Repository statistics 的包仓库统计数据如下:
上面这个 Nixpkgs 的包数量确实有挺多水分——Nixpkgs 还打包了许多编程语言的 Libraries(貌似挺多 Haskell 人用 nix 当语言包管理器用),比如Haskell Packages(18000+),R Packages(27000+),Emacs Packages(6000+) ,但即使把它们去掉后 Nixpkgs 的包数量也有大约 40000+,虽然逊色于 AUR,但这个数量再怎么算也跟「包太少」这个描述扯不上关系。
包仓库这里也是 NixOS 跟 Arch 不太同的地方,Arch 的官方包仓库收录很严格,相对的 AUR 生态相当繁荣。但任何人都能往 AUR 上传内容,虽然有一个投票机制起到一定审核作用,但个人感觉这个限制太松散了。
而 NixOS 就很不一样了,它的官方包仓库 Nixpkgs 很乐于接受新包,想为 Nixpkgs 提个 PR 加包或功能相对其他发行版而言要简单许多,这是 Nixpkgs 的包数量这么多的重要原因(GitHub 显示 Nixpkgs 有 5000+ 历史贡献者,这很夸张了)。
Nixpkgs 仓库的更新流程相对 AUR 也严格许多,PR 通常都需要通过一系列的 GitHub Actions 测试 +
Maintainer Review + Ofborg 检查与自动构建测试后才能被合并,Nixpkgs 也鼓励维护者为自己的包添加测试(包的 doCheck
默认为 true
),这些举措都提升了 Nixpkgs 的包质量。
NixOS 其实也有个与 AUR(Arch User Repository) 类似的 NUR(Nix User Repository),但因为 Nixpkgs 的宽松,NUR 反而没啥内容。
举例来说,QQ 能直接从 Nixpkgs 官方包仓库下载使用,而在 Arch 上你得用 AUR 或者 archlinux-cn.
这算是各有优势吧。NixOS 被人喷包少,主要是因为它不遵循 FHS 标准,导致大部分网上下载的 Linux 程序都不能直接在 NixOS 上运行。这当然有解决方案,我建议是首先看看 Nixpkgs 中是否已经有这个包了,有的话直接用就行。如果没有,再尝试一些社区的解决方案,或者自己给打个包。
用 NixOS 的话自己打包程序是不可避免的,因为即使 Nixpkgs 中已经有了这么多包,但它仍然不可能永远 100% 匹配你的需求,总有你想用但 Nixpkgs 跟 NUR 里边都没有的包,在 NixOS 上你常常必须要给你的包写个打包脚本,才能使它在 NixOS 上正常运行。
另外即使有些程序本身确实能在 NixOS 上无痛运行,但为了做到可复现,NixOS 用户通常也会选择自己手动给它打个包。
OK,闲话说完,下面进入正题。
首先,NixOS 比传统发行版复杂很多,也存在非常多的历史遗留问题。
举例来说,它的官方文档烂到逼得我一个刚学 NixOS 的新手自己边学边写入门文档。在我用自己的渣渣英语把笔记翻译了一遍发到 reddit (NixOS & Nix Flakes - A Guide for Beginners) 后,居然还获得了许多老外的大量好评(经过这么长时间的持续迭代,现在甚至已经变成了社区最受欢迎的新手教程之一),这侧面也说明官方文档到底有多烂。
NixOS 值不值得学或者说投入产出比是否够高?在我看来,这归根结底是个规模问题。
这里的规模,一是指你对 Linux 系统所做的自定义内容的规模,二是指你系统更新的频繁程度,三是指你 Linux 机器的数量。
下面我从个人经历的角度来讲下我以前用 Arch Linux、Ubuntu 等传统发行版的体验,以及我为什么选择了 NixOS,NixOS 又为我带来了什么样的改变。
举个例子,以前我用 Deepin Ubuntu 时我基本没对系统做过什么深入定制,一是担心把系统弄出问题修复起来头疼,二是如果不额外写一份文档或脚本记录下步骤的话,我做的所有定制都是黑盒且不可迁移的,一个月后我就全忘了,只能战战兢兢地持续维护这个随着我的使用而越来越黑盒、状态越来越混沌的系统。
如果用的是 Arch 这种滚动发行版还好,系统一点点增量更新,遇到的一般都是小问题。而对 Ubuntu Deepin 这种,原地升级只出小问题是很少见的,这基本就意味着我必须在某个时间点,在新版本的 Ubuntu 上把我以前做过的定制再全部重做一遍,更关键的是,我非常有可能已经忘了我以前做了什么,这就意味着我得花更多的时间去研究我的系统环境里到底都有些啥东西,是怎么安装配置的,这种重复劳动非常痛苦。
总之很显然的一点是,我对系统做的定制越多越复杂,迁移到新版本的难度就越大。
我想也正是因为这一点,Arch、Gentoo、Fedora 这种滚动发行版才在 Linux 爱好者圈子中如此受欢迎,喜欢定制自己系统的 Linux 用户也大都使用这类滚动发行版。
那么 Arch、Fedora 就能彻底解决问题了么?显然并不是。首先它们的更新频率比较高,这代表着你会更容易把你的系统搞出点毛病来。当然这其实是个小问题,现在 Linux 社区谁还没整上个 btrfs / zfs 文件系统快照啊,出问题回滚快照就行。它们最根本的问题是:
Docker 能解决上述问题中的一部分。首先它的容器镜像可由 Dockerfile 完全描述,也就是说它是可解释的,此外容器镜像能在不同环境中复现出完全一致的环境,这表明它是可迁移的。对于服务器环境,将应用程序全都跑在容器中,宿主机只负责跑容器,这种架构使得你只需要维护最基础的系统环境,以及一些 Dockerfile 跟 yaml 文件,这极大地降低了系统的维护成本,从而成为了 DevOps 的首选。
但 Docker 容器技术是专为应用程序提供一致的运行环境而设计的,在虚拟机、桌面环境等场景下它并不适用(当然你非要这么弄也不是不行,很麻烦就是了)。此外 Dockerfile 仍旧依赖你所编写的各种脚本、命令来构建镜像,这些脚本、命令都需要你自己维护,其运行结果的可复现能力也完全看你自己的水平。
如果你因为这些维护难题而选择极简策略——尽可能少地定制任何桌面系统与虚拟机环境,能用默认的就用默认——这就是换到 NixOS 之前的我。为了降低系统维护难度,我以前使用 Deepin Manjaro EndeavourOS 的过程中,基本没对系统配置做任何大变动。作为一名 SRE/DevOps,我在工作中就已经踩了够多的环境问题的坑,写腻写烦各种安装脚本、Ansible 配置了,业余完全不想搞这些幺蛾子。
但如果你是个喜欢定制与深入研究系统细节的极客,随着你对系统所做的定制越来越多,越来越复杂, 或者你 Homelab 与云上的 Linux 机器越来越多,你一定会在某个时间点开始编写各种部署流程的文档、部署脚本或使用一些自动化工具帮自己完成一些繁琐的工作。
文档就不用说了,这个显然很容易过时,没啥大用。如果你选择自己写自动化脚本或选用自动化工具, 它的配置会越来越复杂,而且系统更新经常会破坏掉其中一些功能,需要你手动修复。此外它还高度依赖你当前的系统环境,当你某天装了台新机器然后信心满满地用它部署环境时,大概率会遇到各种环境不一致导致的错误需要手动解决。还有一点是,你写的脚本大概率并没有仔细考量抽象、模块化、错误处理等内容,这也会导致随着规模的扩大,维护它变得越来越痛苦。
然后你发现了 NixOS,它有什么声明式的配置,你仔细看了下它的实现,哦这声明式的配置,不就是把一堆 bash 脚本封装了下,对用户只提供了一套简洁干净的 api 么,它实际干的活不跟我自己这几年写的一堆脚本一模一样?好像没啥新鲜的。
嗯接着你试用了一下,发现 NixOS 的这套系统定制脚本都存在一个叫 Nixpkgs 的仓库中,有数千人在持续维护它,几十年积累下来已经拥有了一套非常丰富、也比较稳定的声明式抽象、模块系统、类型系统、专为这套超大型的软件包仓库与 NixOS 系统配置而开发的大规模 CI 系统 Hydra、以及逐渐形成的能满足数千人协作更新这套复杂配置的社区运营模式。
你立马学习 nix 语言,然后动手把这套维护了 N 年的脚本改写成 NixOS 配置。
越写就对它越满意,改造后的配置缩水了相当多,维护难度直线下降。
很大部分以前自己用各种脚本跟工具实现的功能,都被 Nixpkgs 封装好了,只需要 enable 一下再传几个关键参数,就能无痛运行。nixpkgs 中的脚本都有专门的 maintainer 维护更新,任何发现了问题的用户也可以提个 PR 修下问题,在没经过 CI 与 staging unstable 等好几个阶段的广泛验证前,更新也不会进入 stable.
上面所说的你,嗯就是我自己。
现在回想下我当初就为了用 systemd 跑个简单的小工具而跟 systemd 疯狂搏斗的场景,泪目… 要是我当初就懂 NixOS…
有过一定编程经验的人都应该知道抽象与模块化的重要性,复杂程度越高的场景,抽象与模块化带来的收益就越高。Terraform、Kubernetes 甚至 Spring Boot 的流行都体现了这一点。NixOS 的声明式配置也是如此,它将底层的实现细节都封装起来了,并且这些底层封装大都有社区负责更新维护,还有 PR Review、CI 与多阶段的测试验证确保其可靠性,这极大地降低了我的心智负担,从而解放了我的生产力。它的可复现能力则免除了我的后顾之忧,让我不再担心搞坏系统。
NixOS 构建在 Nix 函数式包管理器这上,它的设计理念来自 Eelco Dolstra 的论文 The Purely Functional Software Deployment Model(纯函数式软件部署模型),纯函数式是指它没有副作用, 就类似数学函数 $y = f(x)$,同样的 NixOS 配置文件(即输入参数 $x$ )总是能得到同样的 NixOS 系统环境(即输出 $y$)。
这也就是说 NixOS 的配置声明了整个系统完整的状态,OS as Code!
只要你 NixOS 系统的这份源代码没丢,对它进行修改、审查,将源代码分享给别人,或者从别人的源代码中借鉴一些自己想要的功能,都是非常容易的。你简单的抄点其他 NixOS 用户的系统配置就能很确定自己将得到同样的环境。相比之下,你抄其他 Arch/Ubuntu 等传统发行版用户的配置就要麻烦的多,要考虑各种版本区别、环境区别,不确定性很高。
NixOS 的入门门槛相对较高,也不适合从来没接触过 Linux 与编程的小白,这是因为它的设计理念与传统 Linux 发行版有很大不同。但这也是它的优势所在,跨过那道门槛,你会发现一片新天地。
举例来说,NixOS 用户翻 Nixpkgs 中的实现源码实际是每个用户的基本技能,给 Nixpkgs 提 PR 加功能、加包或者修 Bug 的 NixOS 用户也相当常见。 这既是使新用户望而却步的拦路之虎,同时也是给选择了 NixOS 的 Linux 用户提供的进阶之梯。
想象下大部分 Arch 用户(比如以前的我)可能用了好几年 Arch,但根本不了解 Arch 底层的实现细节,没打过自己的包。而 NixOS 能让翻源码成为常态,实际也说明理解它的实现细节并不难。我从两个方面来说明这一点。
第一,Nix 是一门相当简单的语言,语法规则相当少,比 Java Python 这种通用语言简单了太多。因此有一定编程经验的工程师能花两三个小时就完整过一遍它的语法。再多花一点时间,读些常见 Nix 代码就没啥难度了。
第二,NixOS 良好的声明式抽象与模块化系统,将 OS 分成了许多层来实现,使用户在使用过程中, 既可以只关注当前这一层抽象接口,也可以选择再深入到下一层抽象来更自由地实现自己想要的功能(这种选择的权利,实际也给了用户机会去渐进式地理解 NixOS 本身)。举例来说,新手用户只要懂最上层的抽象就正常使用 NixOS。当你有了一点使用经验,想实现些自定义需求,挖下深挖一层抽象(比如说直接通过 systemd 的声明式参数自定义一些操作)通常就足够了。如果你已经是个 NixOS 熟手,想更极客一点,就可以再继续往下挖。
总之因为上面这两点,理解 Nixpkgs 中的源码或者使用 Nix 语言自己打几个包并不难,可以说每个有一定经验的 NixOS 用户同时也会是 NixOS 打包人。
我们看了许多人提到 NixOS 的优点,上面我也提到了不少。Nix 的圈外人听得比较多的可能主要是它解决了依赖冲突问题,能随时回滚,强大的可复现能力。如果你有实际使用过 NixOS,那你也应该知道 NixOS 的这些优势:
这些都是 NixOS 的卖点,其中一些特性现在在传统发行版上也能实现,Fedora Silverblue 等新兴的不可变发行版也在这些方面有些不错的创新。但能解决所有这些问题的系统,目前只有 NixOS(以及更小众的 Guix. 据Guix 的 README 所言,它同样基于 Nix 包管理器)。
自 NixOS 项目创建至今二十多年来,Nix 包管理器与 NixOS 操作系统一直是非常小众的技术,尤其是在国内,知道它们存在的人都是少数 Linux 极客,更别说使用它们了。
NixOS 很特殊,很强大,但另一方面它也有着相当多的历史债务,比如说:
这一堆历史债是 NixOS 一直没能得到更广泛使用的主要原因。但这些问题也是 NixOS 未来的机会,社区目前正在积极解决这些问题,我很期待看到这些问题被解决后, NixOS 将会有怎样的发展。
谁也不会对一项没前途的技术感兴趣,那么 NixOS 的未来如何呢?我是否看好它?这里我尝试使用一些数据来说明我对 NixOS 的未来的看法。
首先看 Nixpkgs 项目,它存储了 NixOS 所有的软件包及 NixOS 自身的实现代码:
上图能看到从 2021 年开始 Nixpkgs 项目的活跃度开始持续上升,Top 6 贡献者中有 3 位都是 2021 年之后开始大量提交代码,你点进 GitHub 看,能看到 Top 10 贡献者中有 5 位都是 2021 年之后加入社区的(新增的 @NickCao 与 @figsoda 都是 NixOS 中文社区资深用户)。
再看看 Nix 包管理器的提交记录,它是 NixOS 的底层技术:
上图显示 Nix 项目的活跃度在 2020 年明显上升,Top 6 贡献者中有 5 位都是在 2020 年之后才开始大量贡献代码的。
再看看 Google Trends 中 NixOS 这个关键词的搜索热度:
这个图显示 NixOS 的搜索热度有几个明显的上升时间点:
再看看 Nix/NixOS 社区从 2022 年启用的年度用户调查。
2024-04-12 更新:NixCon 2024 也有一个演讲提供了 Nix 社区的各种历史数据:Nix, State of the Union - NixCon 2024
另外 GitHub 的Octoverse 2023 也难得地提了一嘴 Nixpkgs:
Developers see benefits to combining packages and containerization. As we noted earlier, 4.3 million repositories used Docker in 2023.
> On the other side of the coin, Linux distribution NixOS/nixpkgs has been on the top list of open source projects by contributor for the last two years.
这些数据与我们前面提到的 Nixpkgs 与 Nix 项目的活跃度相符,都显示 Nix/NixOS 社区在 2021 年之后开始迅速增长壮大。
结合上面这些数据看,我对 NixOS 的未来持很乐观的态度。
从决定入坑 NixOS 到现在,短短 10 个月,我在 Linux 上取得的收获远超过去三年。我已经在 PC 上尝试了非常多的新技术新工具,我的 Homelab 内容也丰富了非常多(我目前已经有了十多台 NixOS 主机),我对 Linux 系统结构的了解也越来越深刻。
光是这几点收获,就完全值回票价了,欢迎入坑 NixOS~
2024-01-30 13:48:30
在接触电脑以来很长的一段时间里,我都没怎么在意自己的数据安全。比如说:
现在在 IT 行业工作了几年,从我当下的经验来看,企业后台的管理员如果真有兴趣,查看用户的数据真的是很简单的一件事,至少国内大部分公司的用户数据,都不会做非常严格的数据加密与权限管控。就算真有加密,那也很少是用户级别的,对运维人员或开发人员而言这些数据仍旧与未加密无异。对系统做比较大的迭代时,把小部分用户数据导入到测试环境进行测试也是挺常见的做法…
总之对我而言,这些安全隐患在过去并不算大问题,毕竟我 GitHub, Google 等账号里也没啥重要数据,银行卡里也没几分钱。
但随着我个人数据的积累与在 GitHub, Google 上的活动越来越多、银行卡里 Money 的增加(狗头),这些数据的价值也越来越大。比如说如果我的 GitHub 私钥泄漏,仓库被篡改甚至删除,以前我 GitHub 上没啥数据也没啥 stars 当然无所谓,但现在我已经无法忍受丢失 GitHub 两千多个 stars 的风险了。
在 2022 年的时候我因为对区块链的兴趣顺便学习了一点应用密码学,了解了一些密码学的基础知识, 然后年底又经历了几次可能的数据泄漏,这使我意识到我的个人数据安全已经是一个不可忽视的问题。因此,为了避免 GitHub 私钥泄漏、区块链钱包助记词泄漏、个人隐私泄漏等可能,我在 2023 年 5 月做了全面强化个人数据安全的决定,并在 0XFFFF 社区发了篇帖子征求意见——学习并强化个人的数据安全性(持续更新)。
现在大半年过去,我已经在个人数据安全上做了许多工作,目前算是达到了一个比较不错的状态。
我的个人数据安全方案,有两个核心的指导思想:
这篇文章记录下我所做的相关调研工作、我在这大半年的实践过程中逐渐摸索出的个人数据安全方案以及未来可能的改进方向。
注意这里介绍的并不是什么能一蹴而就获得超高安全性的傻瓜式方案,它需要你需要你有一定的技术背景跟时间投入,是一个长期的学习、实践与方案迭代的过程。另外如果你错误地使用了本文中介绍的工具或方案,可能反而会降低你的数据安全性,由此产生的任何损失与风险皆由你自己承担。
数据安全大概有这些方面:
就我个人而言,我的数据安全主要考虑以下几个部分:
下面就分别就这几个部分展开讨论。
硬件密钥的好处是可以防止密钥泄漏,但 YubiKey 在国内无官方购买渠道,而且价格不菲,只买一个 YubiKey 的话还存在丢失的风险。
另一方面其实基于现代密码学算法的软件密钥安全性对我而言是足够的,而且软件密钥的使用更加方便。或许在未来,我会考虑使用canokey-core、OpenSK、solokey 等开源方案 DIY 几个硬件密钥,但目前我并不觉得有这必要。
我们一般都是直接使用 ssh-keygen
命令生成 SSH 密钥对,OpenSSH 目前主要支持两种密钥算法:
RSA 跟 ED25519 都是被广泛使用的密码学算法,其安全性都是经过严格验证的,因此我们可以放心使用。但为了在密钥泄漏的情况下,能够尽可能减少损失,强烈建议给个人使用的密钥添加 passphrase 保护。
那这个 passphrase 保护到底有多安全呢?
有一些密码学知识的人应该知道,pssphrase 保护的实现原理通常是:通过 KDF 算法(或者叫慢哈希算法、密码哈希算法)将用户输入的 passphrase 字符串转换成一个二进制对称密钥,然后再用这个密钥加解密具体的数据。
因此,使用 pssphrase 加密保护的 SSH Key 的安全性,取决于:
那么,OpenSSH 的 passphrase 是如何实现的?是否足够安全?
我首先 Google 了下,找到一些相关的文章(注意如下文章内容与其时间点相关,OpenSSH 的新版本会有些变化):
在 OpenSSH release notes 中搜索 passphrase 跟 kdf 两个关键字,找到些关键信息如下:
OpenSSH 9.4/9.4p1 (2023-08-10)
* ssh-keygen(1): increase the default work factor (rounds) for the
bcrypt KDF used to derive symmetric encryption keys for passphrase
protected key files by 50%.
----------------------------------
OpenSSH 6.5/6.5p1 (2014-01-30)
* Add a new private key format that uses a bcrypt KDF to better
protect keys at rest. This format is used unconditionally for
Ed25519 keys, but may be requested when generating or saving
existing keys of other types via the -o ssh-keygen(1) option.
We intend to make the new format the default in the near future.
Details of the new format are in the PROTOCOL.key file.
所以从 2014 年发布的 OpenSSH 6.5 开始,ed25519 密钥的 passphrase 才是使用 bcrypt KDF 生成的。而对于其他类型的密钥,仍旧长期使用基于 MD5 hash 的密钥格式,没啥安全性可言。
即使 2023-08-10 发布的 9.4 版本增加了默认的 bcrypt KDF rounds 次数,它的安全性仍然很值得怀疑。bcrypt 本身的安全性就越来越差,现代化的加密工具基本都已经升级到了 scrypt 甚至 argon2. 因此要想提升安全性,最好是能更换更现代的 KDF 算法,或者至少增加 bcrypt KDF 的 rounds 数量。
我进一步看了 man ssh-keygen
的文档,没找到任何修改 KDF 算法的参数,不过能通过 -a
参数来修改 KDF 的 rounds 数量,OpeSSh 9.4 的 man 信息中写了默认使用 16 rounds.
考虑到大部分人都使用默认参数生成 Key,而且绝大部分用户都没有密码学基础,大概率不知道
KDF、Rounds 是什么意思,我们再了解下 ssh-keygen
默认参数。在 release note 中我进一步找到这个:
OpenSSH 9.5/9.5p1 (2023-10-04)
Potentially incompatible changes
--------------------------------
* ssh-keygen(1): generate Ed25519 keys by default. Ed25519 public keys
are very convenient due to their small size. Ed25519 keys are
specified in RFC 8709 and OpenSSH has supported them since version 6.5
(January 2014).
也就是说从 2023-10-04 发布的 9.5 开始,OpenSSH 才默认使用 ED25519。
结合上面的分析可以推断出,目前绝大部分用户都是使用的 RSA 密钥,且其 passphrase 的安全性很差,不加 passphrase 就是裸奔,加了也很容易被破解。如果你使用的也这种比较老的密钥类型,那千万别觉得自己加了 passphrase 保护就很安全,这完全是错觉(
即使是使用最新的 ssh-keygen 生成的 ED25519 密钥,其默认也是用的 bcrypt 16 rounds 生成加密密钥,其安全性在我看来也是不够的。
总结下,在不考虑其他硬件密钥/SSH CA 的情况下,最佳的 SSH Key 生成方式应该是:
ssh-keygen -t ed25519 -a 256 -C "xxx@xxx"
rounds 的值根据你本地的 CPU 性能来定,我在 Macbook Pro M2 上测了下,64 rounds 大概是 0.5s,128 rounds 大概需要 1s,256 rounds 大概 2s,用时与 rounds 值是线性关系。
考虑到我的个人电脑性能都还挺不错,而且只需要在每次重启电脑后通过 ssh-add ~/.ssh/xxx
解锁一次,后续就一直使用内存中的密钥了,一两秒的时间还是可以接受的,因此我将当前使用的所有 SSH
Key 都使用上述参数重新生成了一遍。
在所有机器上使用同一个 SSH 密钥,这是我过去的做法,但这样做有几个问题:
因此,我现在的做法是:
我通过这种方式缩小了风险范围,即使某台机器的密钥泄漏,也只需要重新生成并替换这台机器上的密钥即可。
搜到些资料:
TODO 待研究。
我曾经大量使用了 Chrome/Firefox 自带的密码存储功能,但用到现在其实也发现了它们的许多弊端。有同事推崇 1Password 的使用体验,它的自动填充跟同站点的多密码管理确实做得非常优秀,但一是要收费,二是它是商业的在线方案,基于零信任原则,我不太想使用这种方案。
作为开源爱好者,我最近找到了一个非常适合我自己的方案:password-store.
这套方案使用 gpg 加密账号密码,每个文件就是一个账号密码,通过文件树来组织与匹配账号密码与 APP/站点的对应关系,并且生态完善,对 firefox/chrome/android/ios 的支持都挺好。
缺点是用 GPG 加密,上手有点难度,但对咱来说完全可以接受。
我在最近使用 pass-import 从 firefox/chrome 中导入了我当前所有的账号密码,并对所有的重要账号密码进行了一次全面的更新,一共改了二三十个账号,全部采用了随机密码。
当前的存储同步与多端使用方式:
我的详细 pass 配置见ryan4yin/nix-config/password-store.
其他相关资料:
遇到过的一些问题与解法:
GnuPG 是一个很有历史,而且使用广泛的加密工具,但它的安全性如何呢?
我找到些相关文档:
简单总结下,GnuPG 的每个 secret key 都是随机生成的,互相之间没有关联(即不像区块链钱包那样具有确定性)。生成出的 key 被使用 passphrase 加密保存,每次使用时都需要输入 passphrase 解密。
那么还是之前在调研 OpenSSH 时我们提到的问题:它使用的 KDF 算法与参数是否足够安全?
OpenPGP 标准定义了String-to-Key (S2K) 算法用于从 passphrase 生成对称加密密钥,GnuPG 遵循该规范,并且提供了相关的参数配置选项,相关参数的文档OpenPGP protocol specific options 内容如下:
--s2k-cipher-algo name
Use name as the cipher algorithm for symmetric encryption with a passphrase if --personal-cipher-preferences and --cipher-algo are not given. The default is AES-128.
--s2k-digest-algo name
Use name as the digest algorithm used to mangle the passphrases for symmetric encryption. The default is SHA-1.
--s2k-mode n
Selects how passphrases for symmetric encryption are mangled. If n is 0 a plain passphrase (which is in general not recommended) will be used, a 1 adds a salt (which should not be used) to the passphrase and a 3 (the default) iterates the whole process a number of times (see --s2k-count).
--s2k-count n
Specify how many times the passphrases mangling for symmetric encryption is repeated. This value may range between 1024 and 65011712 inclusive. The default is inquired from gpg-agent. Note that not all values in the 1024-65011712 range are legal and if an illegal value is selected, GnuPG will round up to the nearest legal value. This option is only meaningful if --s2k-mode is set to the default of 3.
默认仍旧使用 AES-128 做 pssphrase 场景下的对称加密,数据签名还是用的 SHA-1,这俩都已经不太安全了,尤其是 SHA-1,已经被证明存在安全问题。因此,使用默认参数生成的 GPG 密钥,其安全性是不够的。
为了获得最佳安全性,我们需要:
使用如下参数生成 GPG 密钥:
gpg --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo SHA512 --s2k-cipher-algo AES256 ...
加密、签名、认证都使用不同的密钥,每个密钥只用于特定的场景,这样即使某个密钥泄漏,也不会影响其他场景的安全性。
为了在全局使用这些参数,可以将它们添加到你的 ~/.gnupg/gpg.conf
配置文件中。
详见我的 gpg 配置ryan4yin/nix-config/gpg
我日常同时在使用 macOS 与 NixOS,因此不论是需要离线存储的灾难恢复数据,还是需要在多端访问的个人数据,都需要一个跨平台的加密备份与同步工具。
前面提到的 pass 使用 GnuPG 进行文件级别的加密,但在很多场景下这不太适用,而且 GPG 本身也太重了,还一堆历史遗留问题,我不太喜欢。
为了其他数据备份与同步的需要,我需要一个跨平台的加密工具,目前调研到有如下这些:
进一步调研后,我选择了 age, rclone 与 restic 作为我的跨平台加密备份与同步工具。这三个工具都比较活跃,stars 很高,使用的也都是比较现代的密码学算法:
对于 Nix 相关的 secrets 配置,我使用了 age 的一个适配库 agenix 完成其自动加解密配置,并将相关的加密数据保存在我的 GitHub 私有仓库中。详见 ryan4yin/nix-config/secrets. 关于这个仓库的详细加解密方法,在后面第八节「桌面电脑的数据安全」中会介绍。
相关数据包括:GitHub, Twitter, Google 等重要账号的二次认证恢复代码、账号数据备份、PGP 主密钥与吊销证书等等。
这些数据日常都不需要用到,但在账号或两步验证设备丢失时就非要使用到其中的数据才能找回账号或吊销某个证书,是非常重要的数据。
我目前的策略是:使用 rclone + 1024bits 随机密码加密存储到两个 U 盘中(双副本),放在不同的地方,并且每隔半年到一年检查一遍数据。
对应的 rclone 解密配置本身也设置了比较强的 passphrase 保护,并通过我的 secrets 私有 Git 仓库多端加密同步。
相关数据包括:个人笔记、重要的照片、录音、视频、等等。
因为日常就需要在多端访问,因此显然不能离线存储。
不包含个人隐私的笔记,我直接用公开 GitHub 仓库 [ryan4yin/knowledge] (https://github.com/ryan4yin/knowledge/) 存储了,不需要加密。
对于不便公开的个人笔记,有这些考虑:
我一开始考虑直接使用基于 Git 仓库的方案,能获得 Git 的所有功能,同时还避免额外自建一个笔记服务。找到个 GitJournal ,数据存在 GitHub 私有仓库用了一个月,功能不太多但够用。但发现它项目不咋活跃,基于 SSH 协议的 Git 同步在大仓库上也有些毛病,而且数据明文存在 Git 仓库里,安全性相对差一些。
另外找到个 git-crypt 能在 Git 上做一层透明加密,但没找到支持它的移动端 APP,而且项目也不咋活跃。
在 https://github.com/topics/note-taking 下看了些流行项目,主要有这些:
在移动端使用 Synthing 或 Git 等第三方工具同步笔记数据,都很麻烦,而且安全性也不够。因此目前看在移动端也能用得舒服的话,最稳妥的选择是第一类笔记 APP,简单试用后我选择了最流行的 Joplin.
我的桌面电脑都是 macOS 与 NixOS,Homlab 虚拟机也已经 all in NixOS,另外我目前没有任何云上服务器。
另外虽然也有两台 Windows 虚拟机,但极少对它们做啥改动,只要做好虚拟机快照的备份就 OK 了。
对于 NixOS 桌面系统与 Homelab 虚拟机,我当前的方案如下:
--iter-time
,计算出 unlock
key 的用时,默认 2s,安全起见咱设置成了 5s)
cryptsetup --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter-time 5000 --key-size 256 --pbkdf argon2id --use-urandom --verify-passphrase luksFormat device
ssh-add
这个新的私钥,使其能够访问到我的私有 secrets 仓库。/etc/ssh/ssh_host_ed25519_key.pub
发送到一台旧的可解密
secrets 仓库数据的主机上。如果该文件不存在则先用 sudo ssh-keygen -A
生成。nixos-rebuild switch
或 darwin-rebuild switch
成功部署我的 nix-config 了,agenix 会自动使用新主机的系统私钥/etc/ssh/ssh_host_ed25519_key
解密 secrets 仓库中的数据并完成部署工作。对于 macOS,它本身的磁盘安全我感觉就已经做得很 OK 了,而且它能改的东西也比较有限。我的安全设置如下:
在使用 nix-darwin 跟 NixOS 的情况下,整个 macOS/NixOS 的系统环境都是通过我的ryan4yin/nix-config 声明式配置的,因此桌面电脑的灾难恢复根本不是一个问题。
只需要简单的几行命令就能在一个全新的系统上恢复出我的 macOS / NixOS 桌面环境,所有密钥也会由 agenix 自动解密并放置到正确的位置。
要说有恢复难题的,也就是一些个人数据了,这部分已经在前面第七小节介绍过了,用 rclone/restic 就行。
/etc/ssh/ssh_host_ed25519_key.pub
公钥加密,在部署时自动使用对应的私钥解密。这套方案的大部分部署工作都是由我的 Nix 配置自动完成的,整个流程的自动化程度很高,所以这套方案带给我的额外负担并不大。
secrets 这个私有仓库是整个方案的核心,它包含了所有重要数据(password-store/rclone/…)的解密密钥。如果它丢失了,那么所有的数据都无法解密。
但好在 Git 仓库本身是分布式的,我所有的桌面电脑上都有对应的完整备份,我的灾难恢复存储中也会定期备份一份 secrets/password-store 两个仓库的数据过去以避免丢失。
另外需要注意的是,为了避免循环依赖,secrets 与 password-store 这两个仓库的备份不应该使用 rclone 再次加密,而是直接使用 age 对称加密。这样只要我还记得 age 的解密密码、gpg 密钥的 passphrase 等少数几个密码,就能顺着整条链路解密出所有的数据。
绝大部分密码都建议设置为包含大小写跟部分特殊字符的密码学随机字符串,通过 pass 加密保存与多端同步与自动填充,不需要额外记忆。考虑到我们基本不会需要手动输入这些密码,因此它们的长度可以设置得比较长,比如 16-24 位(不使用更长密码的原因是,许多站点或 APP 都限制了密码长度,这种长度下使用 passphrase 单词组的安全性相对会差一点,因此也不推荐)。
再通过一些合理的密码复用手段,可以将需要记忆的密码数量降到 3 - 5 个,并且确保日常都会输入,避免遗忘。
不过这里需要注意一点,就是 SSH 密钥、GPG 密钥、系统登录密码这三个密码最好不要设成一样。前面我们已经做了分析,这三个 passphrase 的加密强度区别很大,设成一样的话,使用 bcrypt 的 SSH 密钥将会成为整个方案的短板。
而关于密码内容的设计,这个几核心 pssphrase 的长度都是不受限的,有两个思路(注意不要在密码中包含任何个人信息):
don't-do-evil_I-promise-this-would-become-not-a-dark-corner
这样的。fsD!.*v_F*sdn-zFkJM)nQ
这样的。第一种方式的优点是,这些单词都是常用单词,记忆起来会比较容易,而且也不容易输错。
第二种方式的优点是,密码学随机字符串可以以更短的长度达到与第一种方式相当的安全性。但它的缺点也比较明显——容易输错,而且记忆起来也不容易。
两种方式是都可以,如果你选择第二种方式,可以专门编些小故事来通过联想记忆它们,hint 中也能加上故事中的一些与密码内容无直接关联的关键字帮助回忆。毕竟人类擅长记忆故事,但不擅长记忆随机字符。举个例子,上面的密码 fsD!.*v_F*sdn-zFkJM)nQ
,可以找出这么些联想:
fs
: 「佛说」这首歌里面的歌词D!
: 头文字D!.*
: 地面上的光斑(.),天上的星光(*)v_
: 嘴巴张开(v)睡得很香的样子,口水都流到地上了(_)F*sdn
: F*ck 软件定义网络(sdn)zFkJM
: 在政府(zf)大门口(k),看(k) 见了 Jack Ma (JM) 在跳脱yi舞…)nQ
: 宁静的夏夜,凉风习习,天上一轮弯月,你(n)问(Q)我,当下这一刻是否足够把上面这些联想串起来,就是一个怀旧、雷人、结尾又有点温馨的无厘头小故事了,肯定能令你自己印象深刻。故事写得够离谱的话,你可能想忘都忘不掉了。
总之就是用这种方式,然后把密码中的每个字符都与故事中的某个关键字联系起来,这样就能很容易地记住这个密码了。如果你对深入学习如何记忆这类复杂的东西感兴趣,可以看看这本我最想要的记忆魔法书.
最后一点,就是定期更新一遍这些密码、SSH 密钥、GPG 密钥。所有数据的加密安全性都是随着时间推移而降低的,曾经安全的密码学算法在未来也可能会变得不再安全(这方面 MD5, SHA-1 都是很好的例子),因此定期更新这些密码跟密钥是很有必要的。
几个核心密码更新起来会简单些,可以考虑每年更新一遍,而密钥可以考虑每两三年更新一遍(时间凭感觉说的哈,没有做论证)。其他密码密钥则可以根据数据的重要性来决定更新频率。
前面已经基本都提到了,这里再总结下:
ssh-add
使用,只需要在系统启动后输入一次密码即可,也不麻烦。这里考虑我的 GPG 子密钥泄漏了、pass 密码仓库泄漏了等各种情况下的灾难恢复流程。
TODO 后续再慢慢补充。
目前我的主要个人数据基本都已经通过上述方案进行了安全管理。但还有这些方面可以进一步改进:
安全总是相对的,而且其中涉及的知识点不少,我 2022 年学了密码学算是为此打下了个不错的基础, 但目前看前头还有挺多知识点在等待着我。我目前仍然打算以比较 casual 的心态去持续推进这件事情,什么时候兴趣来了就推进一点点。
这套方案也可能存在一些问题,欢迎大家审阅指正。