MENU

飞出个分布式网站

March 29, 2021 • 开发

星际文件系统(InterPlanetary File System,缩写 IPFS)是一个旨在创建持久且分布式存储和共享文件的网络传输协议。同时它也是一种内容可寻址的对等超媒体分发协议。

它的分布式储存提供了天然的 CDN,我们基于这点搭建我们的静态网站。IPFS 的原理十分复杂,涉及了内容寻址、P2P、区块链等前沿技术,我也还是正在进行初步了解也就不涉及相关知识以免误人子弟了。

原理部分针对我们分发网站并无任何影响,我们仅需要知道 IPFS 是通过文件哈希值(Hash)进行储存和分发的即可,当你修改内容时哈希值会发生变化,这也导致我们访问原先路由将无法获取最新内容。这些是 IPFS 版本化储存的表现,值得一提的是通过哈希值校验是否存在相同哈希值的文件是市面上网盘实现减少存储空间成本和快速上传的一种解决方案,知道了这点,现在我们继续。

IPFS

你需要自行完成 IPFS 安装的准备工作,我们采用命令行(ipfs-cli)+抽象构成的方式进行讲述,以避免不同平台或以后 GUI 存在差异,操作需要自行带入相关数据。

首先启动 IPFS

ipfs daemon

当你看到 Daemon is ready,那么启动成功了。

Initializing daemon
...
Daemon is ready

我们可以通过 http://localhost:5001/webui 查看 WebUI,在此不再过多陈述。

我使用 Hexo 所生成的静态文件进行演示

ipfs add -r <dir>

最后一行打印的哈希值也就是整个文件夹的 CID,我们可以通过 IPFS 网关访问它。

added <hash> <dir>/<file.ext>
...
added <cid> <dir>

https://ipfs.io/ipfs/QmcjGAxisoXfUqF2kjxMBBFisTgZ8xABdeLmudEj7zhXFD

分析链接可以得出 IPFS 地址的基本结构:<gateway>/ipfs/<cid>/<file.ext>

我们上传的文件将由我们这一节点进行分发,当有其他节点访问我们的文件时,其也将成为分发我们文件的一个节点。但由于 IPFS 垃圾收集机制,访问我们文件的节点在一段时间后将会失效。

现在我们引入一个新的概念固定(Pin),我们通过对站点进行固定,那么它将持续性地由我们这一节点进分发,直到我们的守护进程结束或取消固定。我们所分发的文件默认设定了固定,但访问我们的节点并不会固定该内容。

为了保证我们的守护进程结束后仍有节点,我们需要借助公共服务来固定站点,根据 IPFS 的设计,我们可以使用越多的公共节点进行固定以实现冗余。

远程固定

在 IPFS 0.8.0 中新增了远程固定功能,为了使整个工作流更加通畅,我们也通过命令行进行固定。

IPFS 官方文档中推荐使用 Pinata,先通过网页获取到 JWT Token,如果你不确定你实际需要哪些权限,可以暂时先勾选 Admin,以后再根据需求进行调整。JWT Token 只会显示一次需要妥善保管,基于安全性考虑你也可以对使用数进行限制。

IPFS 的很多设计中我们都能看到 Git 的影子,先来添加远程固定服务。

ipfs pin remote service add pinata https://api.pinata.cloud/psa <JWT_Token>

将上传文件获得的 cid 固定在远程节点中

ipfs pin remote add --service=pinata --name=<custorm> <cid>

IPNS

在开头我们就提到了每修改一次文件哈希值即 CID 都会发生改变,那么我们将无法通过固定链接获取最新内容。IPNS 应运而生,和 DNS 相似的名称也突出了它 IPFS 中所起的作用。

将文件映射至 IPNS

ipfs name publish /ipfs/<cid>

成功后会有信息返回,Publish to 后的字符串即你的 IPNS Key。绑定后,你的网站将被 IPNS 映射到相应 key 上。

Published to <key>: /ipfs/<cid>

https://ipfs.io/ipns/k51qzi5uqu5dgt30ovq0xjy09wkko409symoeqex5vytfidhjnm058iultoyeq

IPNS 地址与 IPFS 区别不大,<gateway>/ipns/<key>/<file.ext>

以后更新文件时只需将新的 cid 重新映射到相应的 IPNS 即可。如果你你需要搭建多个站点,那么你就需要创建新的 IPNS,获取新的 key。

ipfs key gen SecondKey

你得到了一个新的 Key

k51qzi5uqu5dhfq5x2n3zc0y9z8fgt390djioje2fkxg0u2vez0lgju4wtyxz4

在执行 publish 操作时,通过 --key=SecondKey 参数差异进行区分。

为了避免映射错误,我们还可以进行校验

ipfs name resolve k51qzi5uqu5dgt30ovq0xjy09wkko409symoeqex5vytfidhjnm058iultoyeq
/ipfs/QmcjGAxisoXfUqF2kjxMBBFisTgZ8xABdeLmudEj7zhXFD

DNSLink

IPNS 链接对于人类而言可读性极差,我们可以通过 DNSLink 将我们的域名与之绑定。

首先创建一个 TXT 记录,在你想绑定的名称前加上 _dnslink 作为名称,内容则是 dnslink=/ipns/<key>

再来创建个 CNAME 记录将你想绑定的域名交由 IPFS 网关,如 gateway.ipfs.iocloudflare-ipfs.com,你也可以通过公开网关列表进行查询。

可以查看我用 Hexo 生成的测试站点:https://ipfs-test.scvoet.me