注:此版本仅适用于ipfs/go-ipfs:v0.4.18 版本
IPFS多节点 才能构建一个本地的分布式文件系统,在联盟链开发环境下,多数会使用到IPFS多节点私有网存储文件。
一、IPFS二进制安装
1.1 下载ipfs二进制文件
wget https://dist.ipfs.io/go-ipfs/v0.4.18/go-ipfs_v0.4.18_linux-amd64.tar.gz
注:
因为此网站在国外,如果是自己本机下载,需要翻墙,或者使用非大陆服务器下载此文件也可
或者在github上下载,链接如下:
https://github.com/ipfs/go-ipfs/releases
1.2 解压ipfs
[root@localhost ipfs]# tar zxvf go-ipfs_v0.4.18_linux-amd64.tar.gz
go-ipfs/build-log
go-ipfs/install.sh
go-ipfs/ipfs
go-ipfs/LICENSE
go-ipfs/README.md
1.3 将ipfs可执行文件放置bin目录下
[root@localhost ipfs]# cd go-ipfs
[root@localhost go-ipfs]# ls
build-log install.sh ipfs LICENSE README.md
[root@localhost go-ipfs]# cp ipfs /usr/local/bin
1.4 测试ipfs是否安装成功
[root@localhost go-ipfs]# ipfs version
ipfs version 0.4.18
1.5 初始化本地仓库
和git类似,ipfs节点也需要先初始化一个本地仓库。执行init子命令来初始化本地仓库:
[root@localhost go-ipfs]# ipfs init
initializing IPFS node at /root/.ipfs
generating 2048-bit RSA keypair...done
peer identity: QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd
to get started, enter:
ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme
[root@localhost go-ipfs]# cd /root/.ipfs/
[root@localhost .ipfs]# ls
blocks config datastore datastore_spec keystore version
注:
初始化只能执行一次,若不删除初始化生成的文件,再次初始化,==则会报错,如下==:
[root@localhost .ipfs]# ipfs init
initializing IPFS node at /root/.ipfs
Error: ipfs configuration file already exists!
Reinitializing would overwrite your keys.
1.6 验证ipfs初始化成功
[root@localhost .ipfs]# ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme
Hello and Welcome to IPFS!
██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗ ███████╗
██║██╔═══╝ ██╔══╝ ╚════██║
██║██║ ██║ ███████║
╚═╝╚═╝ ╚═╝ ╚══════╝
If you're seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!
-------------------------------------------------------
| Warning: |
| This is alpha software. Use at your own discretion! |
| Much is missing or lacking polish. There are bugs. |
| Not yet secure. Read the security notes for more. |
-------------------------------------------------------
Check out some of the other files in this directory:
./about
./help
./quick-start <-- usage examples
./readme <-- this file
./security-notes
1.6 IPFS 配置文件修改
[root@localhost .ipfs]# vim config
16 "API": "/ip4/0.0.0.0/tcp/5001",
18 "Gateway": "/ip4/0.0.0.0/tcp/8080",
注:
原文件5001及8080端口仅能本地访问,此处需要修改为所有IP可访问
1.7 查看节点ID
[root@localhost .ipfs]# ipfs id
{
"ID": "Qmcjz9AU1tCcTqvPrjxG631vTGrSs1JrHL4ircwXbhkL6B",
"PublicKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3UzDcvzPClmHT4iT+Zyxf384MAk7cB4e1s4/3BtBIKeWwE8W6BxNNQbuPya3JlmITQ9Yz6Cq/dzB1cdnNRvEP3TMQucFGe4NyyGMRkyfwDlVsstJwX+el5adyXH+4UfsglCq+qkGjM899zHQLFgv/tGkmdh4tLBwJTs98vjRJd29oik+4pHP9iERNuC1JZiB+2z/gP77rDONlqG61g07cwtCUgA+6AigRrncwfXUONBT7cmzoVcR4qTPbUgPsz5UWcgweAbuUmM1kcjLk3Qw2Uf4NUzctbbZ3o+syv4NduLBRqMaxwWIkmoGs4IECBv360UQ0nCN4cQO5StvFkgZAgMBAAE=",
"Addresses": null,
"AgentVersion": "go-ipfs/0.4.18/",
"ProtocolVersion": "ipfs/0.1.0"
}
注:
==Qmcjz9AU1tCcTqvPrjxG631vTGrSs1JrHL4ircwXbhkL6B== 为你的节点ID,每个节点都会有一个唯一的ID
1.7 跨域资源共享CORS配置
[root@localhost .ipfs]#ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["http://10.20.28.11:5001", "https://webui.ipfs.io"]'
[root@localhost .ipfs]# ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST", "OPTIONS"]'
[root@localhost .ipfs]# ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'
注意:"http://10.20.28.11:5001"中的IP地址为自己服务器的IP地址
1.8 启动节点
[root@localhost .ipfs]# ipfs daemon
Initializing daemon...
go-ipfs version: 0.4.18-
Repo version: 7
System version: amd64/linux
Golang version: go1.11.1
Successfully raised file descriptor limit to 2048.
Swarm listening on /ip4/10.20.29.192/tcp/4001
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/172.17.0.1/tcp/4001
Swarm listening on /ip4/172.18.0.1/tcp/4001
Swarm listening on /ip4/172.19.0.1/tcp/4001
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /p2p-circuit
Swarm announcing /ip4/10.20.29.192/tcp/4001
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip4/172.17.0.1/tcp/4001
Swarm announcing /ip4/172.18.0.1/tcp/4001
Swarm announcing /ip4/172.19.0.1/tcp/4001
Swarm announcing /ip6/::1/tcp/4001
API server listening on /ip4/127.0.0.1/tcp/5001
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready
==注意:==
此时可在浏览器中访问此节点,地址:http://10.20.28.11:5001/webui
可能无法打开,因为需要设置API: ==/ip4/IP地址/tcp/5001==
1.9 再次查看节点ID
再次打开一个终端,查看节点ID
[root@localhost .ipfs]# ipfs id
{
"ID": "QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"PublicKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZFkZ6QnFE2MR9JdH92E2ax6sKXNH1dVF6NzIstJ4IppBZQjwzJdymhuwn8zSoMuT0bYqS+18TWeKPq3OtMy5HdA+Oe0Ij3dAZ5e4jB6Ty5Im9WEq34gkpcj1GOYutt1NSJPU0Q/VzvxkmtfDQ7EdXI0iRTpUvcE8GBy1sftaHMRd5Z1C1TK8nUuqxfJYfdL7ntlvFogqCZq7F1DXRch8mwdFLh1SKQpKUb7BLInrqcwPvE2QK9RRLX0BUSRzD9tqO7vVIdgHaQhpElLbiXGroK54qSXOIP6ElegJVbWKnuJkCsB3Tc0AqEm3KG1aAZet55RVh7WSkk63z4z7p9yAVAgMBAAE=",
"Addresses": [
"/ip4/127.0.0.1/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"/ip4/10.20.29.192/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"/ip4/172.17.0.1/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"/ip4/172.18.0.1/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"/ip4/172.19.0.1/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd",
"/ip6/::1/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd"
],
"AgentVersion": "go-ipfs/0.4.18/",
"ProtocolVersion": "ipfs/0.1.0"
}
1.10 添加节点
我们的私有网络中已经有了第一个ipfs节点,现在需要将第二个节点加入网络中,==在启动第二个节点的服务前==,需要先将第一个启动节点的信息作为第二个节点的boostrap的信息,记得一定是启动前,若不是,则需要重启
[root@ipfs2 .ipfs]# ipfs bootstrap add /ip4/10.20.29.192/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd
added /ip4/10.20.29.192/tcp/4001/ipfs/QmQvFWKbn2QLrrMzC1NzwgfKpXVtqfiA5PB3ePHK5xkajd
注意!!!
以上添加这个节点这个步骤,并不已经代表ipfs私有链中,所有节点已经互相同步,在第二个节点中添加第一个节点的boostrap信息,代表第二个节点会将文件信息共享给第一个节点,但第一个节点并不会将自己的信息共享给第二个节点,所以,目前应该在第一个节点中添加第二个节点的boostrap信息,并重启第二个节点,为以防万一,建议都进行重启,如此,才能实现真正意义上的信息共享、分布式存储。
以上相关步骤,代表ipfs私有链已搭建成功
二、多节点共享密钥
注:
同一个IPFS私链内的所有节点必须共享同一个密钥才能加入。
首先我们使用密钥创建工具,创建一个密钥。
密钥工具下载地址: https://github.com/Kubuxu/go-ipfs-swarm-key-gen
2.1 安装go语言环境
因为密钥生成需要go 支持,如果本地服务器未安装 go ,请先下载安装 go
2.1.1 下载go安装包
[root@localhost mnt]# wget https://studygolang.com/dl/golang/go1.11.linux-amd64.tar.gz
[root@localhost go]# ls
go1.11.linux-amd64.tar.gz
2.1.2 解压安装包
[root@localhost mnt]# tar zxvf go1.11.linux-amd64.tar.gz
[root@localhost mnt]# ls
go go1.11.linux-amd64.tar.gz
[root@localhost mnt]# cd go
[root@localhost go]# ls
api AUTHORS bin CONTRIBUTING.md CONTRIBUTORS doc favicon.ico lib LICENSE misc PATENTS pkg README.md robots.txt src test VERSION
2.1.3 设置go的环境变量
export GOROOT=/mnt/go #go的安装路径
export GOPATH=/mnt/godemo #go下载的安装包路径,默认在root目录下
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
2.1.4 生效go语言环境
[root@localhost go]# source /etc/profile
2.1.5 查看go语言版本
[root@localhost go]# go version
go version go1.11 linux/amd64
2.2 安装秘钥工具
2.2.1 下载秘钥
[root@localhost mnt]# go get -u github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen
2.2.2 安装秘钥
下载后的秘钥安装包在go的安装包目录下
[root@localhost mnt]# cd godemo/
[root@localhost godemo]# ls
bin src
[root@localhost godemo]# cd bin
[root@localhost bin]# ls
ipfs-swarm-key-gen
[root@localhost bin]# pwd
/mnt/godemo/bin
[root@localhost bin]# ipfs-swarm-key-gen > ~/.ipfs/swarm.key
2.2.3 查看生成的swarm.key
安装完后,查看生成的swarm.key
[root@localhost bin]# cd /root/.ipfs/
[root@localhost .ipfs]# ls
api blocks config datastore datastore_spec keystore repo.lock swarm.key version
[root@localhost .ipfs]# cat swarm.key
/key/swarm/psk/1.0.0/
/base16/
07e09ee139320cd410cd48dda9dcd57f4978ca1be5f813aaea8d9faa9073f146
注意:
此秘钥不能向其他人透露,否则别人可加入到你的节点中!!!
2.2.4 将密钥同步到其余节点 ~/.ipfs 目录下
将生成后的秘钥复制到其余节点的~/.ipfs 目录下
三、IPFS多节点测试
3.1 进入一个节点go-ipfs目录下创建一个文件
[root@localhost ipfs]# vim word.txt
hello,word!
3.2 调用ipfs add 命令,将文件上传至ipfs网络
[root@localhost ipfs]# ipfs add word.txt
added QmUG7T1SJPTMz4vJQ1adGonWUGtfLYT6PhNvZ92Hm6KSDK word.txt
12 B / 12 B [========================================================================================================================================] 100.00%
3.3在另一个IPFS节点中查看
切换至另一个ipfs节点查看此文件
[root@ipfs2 mnt]# ipfs cat QmUG7T1SJPTMz4vJQ1adGonWUGtfLYT6PhNvZ92Hm6KSDK
hello,word!
可以查看到此内容,说明两个ipfs 节点已经连通。
3.4 相关测试:
3.4.1 节点宕机测试
此时如果停掉第一个节点:
[root@localhost ipfs]# ps -elf |grep ipfs
0 S root 4271 2737 0 80 0 - 28166 pipe_w 18:12 pts/0 00:00:00 grep --color=auto ipfs
可看到第一个节点ipfs服务不在运行中
[root@localhost ipfs]# ps -elf |grep ipfs
0 S root 4271 2737 0 80 0 - 28166 pipe_w 18:12 pts/0 00:00:00 grep --color=auto ipfs
此时使用第二个节点查看哈希值
[root@ipfs2 mnt]# ipfs cat QmUG7T1SJPTMz4vJQ1adGonWUGtfLYT6PhNvZ92Hm6KSDK
hello,word!
依然可以查到次哈希值相对应的文件内容
3.4.2 文件内容重复测试
目前已有一个文件内容为:hello,word!的文件,再次创建一个与此文件不同文件名,相同文件内容的文件,进行上传。
[root@localhost ipfs]# vim hello,txt
hello,word!
[root@localhost ipfs]# ipfs add hello,txt
added QmUG7T1SJPTMz4vJQ1adGonWUGtfLYT6PhNvZ92Hm6KSDK hello,txt
12 B / 12 B [=============================================================================================================] 100.00%
你会发现,这两个文件上传后的哈希值一样,因为它们的文件内容是一样的。
IPFS 会为每一个不同文件内容的的文件分配一个独一无二的哈希值(可理解为文件指纹,会根据文件的内容创建),所以如果这两个文件的内容不一样,即使是两个文件内容只有一个比特的不同,一个字母的不一样,其哈希值也会不一样。
正是因为IPFS这种分配哈希值的方式,使得IPFS可以支持基于文件内容进行寻址。
至此,本篇IPFS节点的私有网已经搭建完成
四、相关说明
4.1 repo
4.1.1 什么是repo?
ipfs在启动之前,需要先运行ipfs init初始化,什么意思?就是生成该程序的配置信息和初始的数据库,就像一个商店要开张营业,货物提前采购好,那这些初始化的数据放置在哪里呢?位于每个用户的家目录下.ipfs目录下,如下图(我是使用root用户的身份登录的)
[root@localhost ~]# pwd
/root
[root@localhost ~]# ls .ipfs/
api config datastore_spec repo.lock version
blocks datastore keystore swarm.key
那这些存储配置信息和数据库的目录,就叫repo(全称:repository,即仓库)
4.1.2 repo的作用
当要向ipfs申请数据时,ipfs先会去本地的repo目录下查找需要的数据,repo目录里的数据分成两部分,一部分是metadata(元数据),一部分是block数据(真正的内容)。metaddata可以想象成是商店的账本,账本上记录了所有商店的产品清单(目录),而block就是摆放在商店里的具体的内容。
运行 ipfs repo stat 命令,查看repo的状态:
[root@localhost .ipfs]# ipfs repo stat
NumObjects: 158
RepoSize: 34631931 #数据大小,单位:KB
StorageMax: 10000000000 最大存储空间,单位:B
RepoPath: /root/.ipfs repo路径
Version: fs-repo@7
4.2 Bootstrap list
4.2.1 什么是bootstrap list?
如果ipfs只是通过自己的仓库查找数据,那就太狭隘了,ipfs还会根据bootstrap 列表,了解网络上其他节点的对等体列表,如果自己的仓库里没有需要的数据,就通过bootstrap列表,查到其它的节点是否有需要的数据。 IPFS自带有默认的受信任对等列表。
[root@ipfs2 ~]# ipfs bootstrap list
/ip4/10.20.29.192/tcp/4001/ipfs/QmVuJ9AMFCAw2VTaGH2hQZtqbPbsQgotPoxe3sPufPTLUv
注:
列出IPFS受信任对等列表(即节点)
ipfs bootstrap list
删除无用的IPFS受信任对等列表(即节点)
ipfs bootstrap rm 节点信息
--all bool 删除全部bootstrap节点
添加需要信任的对等列表(即节点)
ipfs bootstrap add 节点信息
4. pinning
4.1 什么是pinning?
Pinning 在IPFS里是一个很重要的概念,当我们每次请求一个网络上的内容的时候,IPFS总是会把内容先同步到本地提供服务,而为了防止 IPFS 存储空间不停增长,实际上使用cache 机制来处理文件, 如果文件在一段时间内没有被使用,文件会被”回收“。 Pinning 的作用就是把文件”钉“住,确保文件在本地不被”回收“。 如果是重要的文件,就可以使用 Pinning 防止文件被删除
IPFS默认会把新上传的文件做Pinning.
清除repo缓存,但被pinning的文件不会被清除
例:
[root@localhost mnt]# ipfs add abc.txt
[root@localhost mnt]# ipfs pin ls QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq recursive
IPFS 提供了pin命令进行Pinning操作, 比如我们查询下某一个hash 是否被pin:
例:
[root@localhost mnt]# ipfs pin ls QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
Error: path 'QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq' is not pinned
可以使用 pin add 手动钉住一个文件
例:
[root@localhost mnt]# ipfs pin add QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
pinned QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq recursively
如果要删除pin的状态,使用pin rm
例:
[root@localhost mnt]# ipfs pin rm QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
unpinned QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
[root@localhost mnt]#
[root@localhost mnt]# ipfs pin ls QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq
Error: path 'QmP56kXx8ERiUVaLvgs1jHzrHoGLoRvd7nvZsQ2Xh2KGTq' is not pinned
注:
pin rm 的参数 -r 表示递归的删除pin 状态,对于没有pin住的文件, 如果执行GC操作 ipfs repo gc文件会被删除。
5、 工作原理
IPFS获取数据的流程:
第一步:先查询Pinning 如果没有,则进入第二步
第二步:查询本地的repo ,如果没有,则进入第三步
第三步:根据bootstrap list 查寻其它节点 ,如果没有,就真的没有
6、IPFS端口
注:
如果需要把文件同步到网络,就需要开启 daemon 服务, 使用命令:ipfs deamon
开启 daemon 之后,Swarm 就会尝试连接其他的节点,同步数据,同时在本地还会开启两个服务:API服务及Web网关服务,下面分别介绍下:
6.1 API服务
API服务,默认在5001端口,可以通过 http://localhost:5001/webui 进行访问,界面如:
注:
如果需要所有人在自己的终端下可访问此页面,则需要在/root/.ipfs目录下,修改config文件中两盒配置,如下:
"API": "/ip4/0.0.0.0/tcp/5001",
"Announce": [],
"Gateway": "/ip4/0.0.0.0/tcp/8080",
此页面是IPFS的一个Web版的管理控制台, 可以通过这个控制台添加文件,查看节点连接情况等等。
6.2网关服务:
默认在8080端口, 由于当前浏览器还不支持通过IPFS协议(ipfs://)来访问文件,如果我们要在浏览器里访问文件的话,就需要借助于IPFS 提供的网关服务,由浏览器先访问到网关,网关去获取IPFS网络杀过了的文件。 有了网关服务,就可以通过这个链接:http://localhost:8080/ipfs/QmQgMZKqHzyEdyJja5ioF8WaXrbUDVjqhJDoaUKDymgioi 来访问刚刚上传到ipfs 的文件。
ipfs 也提供了官方的网关服务:https://ipfs.io/, 因此也可以通过 https://ipfs.io/ipfs/QmQgMZKqHzyEdyJja5ioF8WaXrbUDVjqhJDoaUKDymgioi (需要翻墙)来访问刚刚上传到ipfs 的文件。