zl程序教程

您现在的位置是:首页 >  其他

当前栏目

IPFS的配置记录

2023-03-07 09:39:44 时间

IPFS

分布式文件系统, 原理类似于bt, 通过文件分块, 每个块对应CID以及各级Hash做存储和校验, 通过DHT(Distributed Hash Table)做查找和路由.

IPFS文档

https://docs.ipfs.io/ 主要看 Concepts 和 How-tos 部分
IPFS对应每个Content会产生不同的CID, 对于需要固定链接的需求, 可以通过IPNS实现, 但是IPNS不适合于快速变化的内容, IPNS的更新间隔是以分钟记的

使用IPFS做的一些服务

网关

官方有一个可用的网关列表: https://ipfs.github.io/public-gateway-checker/ 下面是测试过的一些可用网关

go-ipfs

IPFS的Go语言项目是其主要的开源实现: https://github.com/ipfs/go-ipfs/

go-ipfs的配置说明

详细的配置说明在 https://github.com/ipfs/go-ipfs/blob/master/docs/config.md 这个比手册写的详细

编译go-ipfs

参考 https://github.com/ipfs/go-ipfs#download-and-compile-ipfs

Github 项目源代码有30多MB, clone的时间会比较长, 如果太慢并且出错, 需要加个代理. 编译使用 make build 命令, 说是编译, 其实大部分时间是花在下载依赖库上,
在执行前设置一下GOPROXY避免下载超时

# 检查go版本, 要1.13以上
go version
# 设置代理
git config --global https.proxy 'socks5://127.0.0.1:10080'
# 检查
git config -l
#
git clone https://github.com/ipfs/go-ipfs.git
cd go-ipfs/
# 设置GOPROXY
export GOPROXY=https://goproxy.cn
# 检查
echo $GOPROXY
# 编译
make build
# 检查编译结果
./cmd/ipfs/ipfs version

在Amlogic S905L的Armbian上运行IPFS

从GO IPFS Github项目下载 Arm64版本, Armbian 版本为 5.99, 内核 5.30.

# 下载
wget https://github.com/ipfs/go-ipfs/releases/download/v0.5.1/go-ipfs_v0.5.1_linux-arm64.tar.gz
# 解压
tar xvf go-ipfs_v0.5.1_linux-amd64.tar.gz
# 直接运行 install.sh 安装, 这个脚本会将ipfs目录复制到 /usr/local/bin 下
cd go-ipfs
./install.sh

初始化后, 使用普通用户启动

#  查看版本
ipfs --version
# 初始化节点
ipfs init
# 查看说明
ipfs cat /ipfs/QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc/readme
 
# 这个命令不会后台运行, 建议先建一个screen session, 在screen session里执行
ipfs daemon

如果IPFS不是运行在当前电脑, 那么配置需要做两处改动后才能访问webui

一处是Addresses.API 和 Addresses.Gateway

"Addresses": {
  ...
  "API": "/ip4/127.0.0.1/tcp/5001",
  "Gateway": "/ip4/127.0.0.1/tcp/8080"
}

将API的地址改为 /ip4/0.0.0.0/tcp/5001 这样会监听所有网口, 如果你的服务器有公网IP, 这样会有安全问题, 可以将这个IP设为内网网口地址.
将Gateway的地址改为内网地址或公网地址, 如果IPFS处于内网, 外网可以通过NAT访问, 这个可以配成内网地址.

另一处是 API.HTTPHeaders, 避免从当前电脑访问IPFS的webui时, 出现cross site 错误.

"API": {
    "HTTPHeaders": {}
},

在HTTPHeaders里增加两项, 可以参考 Gateway.HTTPHeaders

"Access-Control-Allow-Methods": [
  "GET","PUT","POST"
],
"Access-Control-Allow-Origin": [
  "*"
]

修改完配置, 重启IPFS后就可以访问 http://IP:5001/webui/ 可以图形化的查看当前节点状态, 存储的块数量和大小, 连接的节点明细, 以及查看当前的配置. 这个界面甚至提供了一些演示用的文件浏览.

通过Gateway, 可以访问IPFS上的文件以及远程可以查询到CID的文件. 任何访问过的文件块都会被缓存, 再次访问时, 相应的块会直接走缓存, 不会再从远程下载.

选择文件上传后, 会在页面后台进行传输(尚未确认是否可以关闭标签页), 在状态页能看到总存储在增长. 对于不同大小的文件, 其发布可见的延迟是不一样的, 对于10MB以内的文件, 通过远程gateway很快就能发现, 对于接近500MB的文件, 大概需要半个小时到一小时. 这和节点发布自身的内容CID到其他节点的机制有关, 因为单个文件块为256KB(262144Byte), 对于500MB大小的文件, 会产生2,000多个CID, 发布需要的时间会长得多.

在webui上添加文件, 需要等文件上传完整后, 才能做pin操作, 如果是通过CID上传文件, 在提交CID后并不会触发文件同步, 对这个CID进行pin操作后, 会触发ipfs开始从其他节点同步, 等文件从其他节点同步完成后, 会出现在pin列表.

安装到服务

创建文件 /etc/systemd/system/ipfs.service 写入

[Unit]
Description=IPFS Daemon
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=simple
ExecStart=/usr/local/bin/ipfs daemon --enable-namesys-pubsub
User=milton
[Install]
WantedBy=multi-user.target

然后通过systemctl 添加

配置说明

IPFS对外提供的端口主要是3个: API, Gateway和Swarm, 其中

  • API: 默认使用端口5001, 在上面提供了webui, 用于管理控制IPFS. 设置监听网口时应当注意不要开放到公网
  • Gateway: 默认使用端口8080, 在上面提供ipfs/CID的内容查找下载服务
  • Swarm: 默认使用端口4001, 这个端口用于监听其他IPFS节点的请求
  • Addresses.NoAnnounce 添加需要排除的内网IP, 这些IP不会发布, 但是注意不要排除127.0.0.1和::1, 这两个貌似被用于其他节点检测当前节点是否支持ipv4或ipv6, 如果排除掉, 会无法与其他节点保持连接(能ping能connect, 但是swarm peers里查不到)
  • Swarm.AddrFilters 添加需要忽略的内网IP, 对于在ID上announce内网IP的peer, 这些内网IP的地址会被过滤掉
  • Discovery.MDNS.Enabled 将这个选项改为false, 就不会在内网发起节点搜索
  • Peering.Peers 添加需要保持连接的节点

固定节点

对于自建的网络, 需要让自己的节点之间保持连接, 但是IPFS默认的机制下, 即使将自建节点设置为bootstrap, 在启动一段时间后, 在连接的节点不断增加后, 依然会将与其他自建节点之间的连接关闭. 要保持连接, 需要使用配置文件中的Peering部分, 格式如下, 第二个为ipfs.runfission.com的接入地址

{
  "Peering": {
    "Peers": [
      {
        "ID": "QmPeerID1",
        "Addrs": ["/ip4/18.1.1.1/tcp/4001"]
      },
      {
        "ID": "QmVLEz2SxoNiFnuyLpbXsH6SvjPTrHNMU88vCQZyhgBzgw",
        "Addrs": ["/ip4/3.215.160.238/tcp/4001", "/ip4/3.215.160.238/udp/4001/quic"]
      }
    ]
  }
  ...
}

使用Peering配置的节点:

  1. 在连接管理中会保护与这个节点之间的连接, IPFS永远不会主动(自动)关闭这个连接, 在连接数达到上限时也不会关闭这个连接.
  2. 在启动时就会建立连接
  3. 如果因为网络原因或对方节点掉线等原因导致连接丢失, IPFS会不断尝试重新连接, 尝试的间隔长度在5秒至10分钟之间随机.

在公网NAT下运行IPFS

运行环境

公网IP的服务器是Centos7, 公网IP为118.119.120.121, 内网IP为192.168.13.10
内网服务器Ubuntu18.04, 内网IP为192.168.13.25

在公网服务器上设置端口转发

配置一下全局转发开关

firewall-cmd --permanent --zone=public --add-masquerade

将公网IP端口4002转发至内网服务器的4001端口

# TCP端口转发
firewall-cmd --permanent --zone=public --add-forward-port=port=4002:proto=tcp:toaddr=192.168.13.25:toport=4001
# UDP端口转发
firewall-cmd --permanent --zone=public --add-forward-port=port=4002:proto=udp:toaddr=192.168.13.25:toport=4001
# 设置生效
firewall-cmd --reload
# 检查
firewall-cmd --zone=public --list-all

如果网关是OpenWRT路由, 则直接在防火墙->端口转发中添加转发规则即可. 注意在添加完转发规则后, 还需要在通信规则中允许WAN到此设备此端口的访问.

限制连接的节点数量

需要通过Swarm/ConnMgr/HighWater 这个参数,在0.6.0时这个设置并不能很好地工作,长时间运行服务器后节点数量会远超设置的限制,在0.7.0上是有效的

"Swarm": {
    ...
    "ConnMgr": {
        "GracePeriod": "30s",
        "HighWater": 500,
        "LowWater": 100,
        "Type": "basic"
    },
    ...
}

在内网服务器上配置IPFS服务

# 安装过程略
 
# 初始化为服务器模式
ipfs init --profile=server
 
# 修改配置, 看下面具体说明
vi .ipfs/config
 
# 启动
ipfs daemon

服务器模式和普通模式相比, 有几点变化

  1. Addresses.NoAnnounce 服务器模式会列出所有的内网IP, 这些IP不会发布
  2. Swarm.AddrFilters 服务器模式会列出所有内网IP, 对于使用内网IP来连接的peer, 都会被过滤掉
  3. Discovery.MDNS.Enabled 服务器模式时这个选项为false, 避免在内网发起节点搜索

需要配置的地方除了普通节点的API, Gateway和API HTTPHeaders, 还需要配置 Addresses.Announce , 需要添加本节点的公网IP和端口

"Announce": [
  "/ip4/118.119.120.121/tcp/4002",
  "/ip4/118.119.120.121/udp/4002/quic"
],

遇到的问题

使用OpenWRT配置的网关不存在这个问题, 但是使用Centos做网关时似乎不能将外网IP正确传入, 导致大量第三方节点的显示IP为网关IP, 对本节点连接可以成功, 但是ping失败. 所以对于 Swarm.AddrFilters 里面的列表要删除同网段的部分.

具体原因可以通过本节点的swarm peers看到, 从本节点主动连接的节点, 记录的是公网IP, 但是本节点被动连接(即通过网关118.119.120.121连接)的节点, 记录的都是网关的内网IP, 按照AddrFilters的规则, 这些节点会被丢弃. 就会出现ipfs swarm connect 成功, 但是 ipfs ping 失败的问题.

$ ipfs swarm peers
/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
/ip4/111.231.85.77/tcp/4001/p2p/QmWv1eLMNHPpwYKzREQBEpDfYjW6YXCrVpVyBZVjAuSd2i
...
/ip4/192.168.13.10/tcp/10041/p2p/QmXUZth5Pr2u1cW65F7gUeFwjkZFfduE1dwqiysNnrTwXd
/ip4/192.168.13.10/tcp/10053/p2p/QmPM3bepMUKpYTza67coD1Ar3efL7FPBFbGRMc42QLf4q9
/ip4/192.168.13.10/tcp/10202/p2p/QmVBzjW2MyNrSuR48GjcqB6SAJTnw8Y9zaFbgbegh4bRx4
/ip4/192.168.13.10/tcp/1024/p2p/QmbBEfFfw59Vya9CJuzgt4qj9f57sPZGiyK7fup8iKqkTr
/ip4/192.168.13.10/tcp/1025/p2p/QmcmhwCeLkBJvcq6KJzN58BRZg1B1N8m3uA3JyQKpVn64E
...
/ip4/192.168.13.10/udp/6681/quic/p2p/QmcSCBpek4YF5aAsY7bUMxiL7tacoYMeXUJUpU4wctqX4w
/ip4/192.168.13.10/udp/8050/quic/p2p/QmWeuXCNKAHfbineKMqo3U3dvVSz2em1w67pj5Up6tkUXo
/ip4/206.189.69.143/tcp/31071/p2p/12D3KooWHDr5W3Tse17mr4HSzuQm44dVQYp8Bb638mQknsyeHXSP
/ip4/206.189.69.250/tcp/30511/p2p/12D3KooWRd1BNPd8PMfxpCT7TNCFY4XSZsy8v8Cmm36H136yxzub
...

再进一步检查是否可以从本节点访问被动连接的节点, 取其中一个Peer ID做ping测试

ipfs ping QmXUZth5Pr2u1cW65F7gUeFwjkZFfduE1dwqiysNnrTwXd
PING QmXUZth5Pr2u1cW65F7gUeFwjkZFfduE1dwqiysNnrTwXd.
Pong received: time=26.43 ms
Pong received: time=25.70 ms
Pong received: time=26.31 ms
...

说明这些记录为网关内网IP的节点是可用的, 应当保留

这些通过网关连接的节点, 可以分为两类: 无公网IP的节点和有公网IP的节点:

  • 对于有公网IP的节点, 尚不清楚是否会在初次连接后使用对方Announce的地址回ping, 如果会并且会根据此结果更新节点的地址, 那么这些节点会在这个显示为内网IP的列表中短暂停留后, 更新为公网IP地址, 这样在其他节点接入后, 共享节点信息时, 其他节点可以通过其公网IP地址进行连接.
  • 对于无公网IP的节点, 服务器节点根据对方Announce的地址回ping是无法连接的, 只能通过本方网关的内网IP进行连接, 所以会一直停留在这个显示为内网IP的列表中. 这些节点是无法共享给其他节点的.

优化下载速度

如果是希望通过CID读取文件, 首先要选择速度较快的网关, 通过ipfs.io网关获取文件是最可靠的, 但是因为连接问题, 速度可能会很慢.

如果是希望通过CID发送文件, 要务必保证对方使用的网关在当前存放文件的实例的连接列表中, 所以维护一个速度较快的网关列表很重要, 将这些网关加入自己的Peering.Peers, 将极大提升自己的文件发布速度.

升级IPFS

大版本的升级, 需要使用fs-repo-migrations 工具, 参考Doc里的说明, 就是两步, 备份.ipfs目录, 运行 fs-repo-migrations 命令, 在这之前需要把ipfs服务停掉.

IPFS Desktop

在Windows10下安装IPFS Desktop, 默认安装到用户目录下 C:\Users\Milton\AppData\Local\Programs\IPFS Desktop, 安装完成后程序目录265M,
数据目录在 C:\Users\Milton.ipfs, 格式和内容与go-ipfs无异. 后台有两个IPFS Desktop进程, 两个ipfs进程, 共占用内存约500M.

状态窗口实际上是一个webview, 展示了webui的内容.

配置只是在默认的配置上将水位线改为50, 300, 其他是一样的.

资源如果存在(缓存)于直接连接的节点则可以访问, 否则无法访问.

IPFS私有网络和集群

参考 https://labs.eleks.com/2019/03/ipfs-network-data-replication.html

将IPFS运行为服务, 开机自启动

# 创建服务文件
sudo vi /etc/systemd/system/ipfs.service
 
# 文件内容
[Unit]
Description=IPFS Daemon
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=simple
ExecStart=/usr/local/bin/ipfs daemon --enable-namesys-pubsub
User=root
[Install]
WantedBy=multi-user.target
# 文件内容结束
 
# 添加服务
sudo systemctl daemon-reload
sudo systemctl enable ipfs
sudo systemctl start ipfs
sudo systemctl status ipfs

将IPFS Cluster添加为服务

# 创建服务
sudo nano /etc/systemd/system/ipfs-cluster.service
 
# 文件内容开始, 注意After里有ipfs服务, 以此保证启动顺序
[Unit]
Description=IPFS-Cluster Daemon
Requires=ipfs
After=syslog.target network.target remote-fs.target nss-lookup.target ipfs
[Service]
Type=simple
ExecStart=/home/ubuntu/gopath/bin/ipfs-cluster-service daemon
User=root
[Install]
WantedBy=multi-user.target
# 文件内容结束
 
# 添加到系统服务
sudo systemctl daemon-reload
sudo systemctl enable ipfs-cluster
sudo systemctl start ipfs-cluster
sudo systemctl status ipfs-cluster

IPFS的应用场景

经过实际测试, 对于在公众网络中的IPFS节点, 一旦建立了连接进行CID的发布和读取速度是很快的, 除去网络本身的延迟, 从请求到开始传输基本上在2秒内, 传输速度取决于两点间的带宽.

文件共享

IPFS对内容的索引形式很适合做团队间的文件共享, 因为每一次改动都会产生索引变化, 可以做版本化控制. 分布式的文件接入点和下载点方便集群伸缩扩展, 带缓存的特性能降低热点数据对带宽资源的影响.

音视频分发

用于取代现有的PT下载网络. 因为PT传播的单个文件很大, 需要对整个PT群中的节点做统一的pin管理, 一方面确保各终端节点对热点内容的访问速度, 另一方面确保长尾内容有足够的备份, 不会丢失.

流媒体和下载加速

IPFS的特性, 天然地可以用于取代CDN服务. 静态文件例如图片, CSS, JS, 以及压缩包, 甚至一些时效性要求不高的直播业务. 现在运营商宽带已经普及IPv6, 这些有公网IPv6地址的家庭带宽资源可以充分利用起来做区域内容加速.

libp2p

libp2p是从IPFS中独立出来的一个封装好的p2p模块, 模块中已经内置了PeerId, MultiAddress, Protocol Handler这些机制, 可以很方便扩展出自己的应用.

Go语言的实现 https://github.com/libp2p/go-libp2p, 样例代码 https://github.com/libp2p/go-libp2p-examples

在代码里的使用, 一般是以下步骤:

  1. 创建Host
  2. 对指定的协议, 在Host上SetStreamHandler
  3. 如果本地还有端口提供服务, 则创建对应服务并监听端口
  4. 指定目标节点和协议, 创建Stream
  5. 往Stream写数据
  6. 从Stream读数据, 根据业务需求关闭或不关闭Stream

在Host启动后如果需要保持运行, 可以使用以下方式

# 方法1, 使用select
select {} // hang forever
 
# 方法2, 使用内置服务的ListenAndServe
http.ListenAndServe(serveArgs, p)
 
# 方法3, 使用channel
<-make(chan struct{}) // hang forever