环境介绍

节点名称 IP地址 系统版本
Node01 192.168.99.21 Centos7
Node02 192.168.99.22 Centos7
Node03 192.168.99.23 Centos7

开始安装

注意:以下操作三个节点都需要执行

安装docker和docker-compose

1
$ curl https://www.putianhui.cn/package/script/install_docker.sh | bash

创建ipfs数据目录和docker-compose文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ mkdir -p /data/ipfs/{data,staging}
$ cd /data/ipfs

$ cat >docker-compose.yaml <<EOF
version: '3'
services:
ipfs:
image: ipfs/kubo:v0.20.0
container_name: ipfs
restart: always
# 挂载持久化目录
volumes:
- ./staging:/export
- ./data:/data/ipfs
# 这里使用host-networt网络模式
network_mode: "host"
#ports:
# - 4001:4001
# - 0.0.0.0:10053:5001
# - 0.0.0.0:10052:8080
entrypoint: /sbin/tini -- /usr/local/bin/start_ipfs daemon --migrate=true --enable-gc
EOF

创建ipfs私有服务的密钥

IPFS私有服务其实就是指的一群IPFS节点使用的是同一个key,非同一个key无法加入到同一个集群中

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
# 获取工具代码
$ go get github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen

# 使用go get获取ipfs-swarm-key-gen没反应
# 此时修改一下环境变量启动GOPROXY,再用go get -v即可,-v参数能够显示go get执行的进度
export GO111MODULE=on
export GOPROXY=https://goproxy.io

# 切换到刚刚获取的源代码目录,这个是我获取的源代码存放路径,具体要看你自己的目录切换进去
$ cd ~/go/pkg/mod/github.com/\!kubuxu/go-ipfs-swarm-key-gen@v0.0.0-20170218193930-0ee739ec6d32

$ ipfs-swarm-key-gen > ~/.private_ipfs/swarm.key


###################################################################################
## 上面不成功是因为下载的文件没有编译
## 所以直接用下面的方法,注意下载路径

# 下载密钥工具
$ git clone https://github.com/Kubuxu/go-ipfs-swarm-key-gen.git

# 编译go-ipfs-swarm-key-gen,注意这里需要提前准备好golang环境,当前目录会成一个ipfs-swarm-key-gen的可执行二进制文件
$ go build -o ipfs-swarm-key-gen ipfs-swarm-key-gen/main.go

# 生成密钥
$ ./ipfs-swarm-key-gen > ~/.ipfs/swarm.key

# 分发密钥,将生成的swarm.key秘钥文件分发到三台机器的数据持久化/data/ipfs/data目录下
scp ~/.ipfs/swarm.key root@192.168.99.21:/data/ipfs/data
scp ~/.ipfs/swarm.key root@192.168.99.22:/data/ipfs/data
scp ~/.ipfs/swarm.key root@192.168.99.23:/data/ipfs/data

启动三个节点的docker-compose容器

1
2
3
4
5
6
7
# 切换到docker-compose文件所在目录
$ cd /data/ipfs
$ ls
data docker-compose.yaml staging

# 启动docker-compose容器
$ docker-compose up -d

进入ipfs容器中,设置webui跨域白名单

1
2
3
4
5
6
# 进入容器中
$ docker exec -it ipfs sh

# 设置webui允许跨域白名单
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["*"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'

进入ipfs容器,分别获取三个节点各自的ID,然后互相将另外两个节点加入进来

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
# 进入容器中
$ docker exec -it ipfs sh


# 分别获取三个节点各自的ID
# node01
$ ipfs id |grep "ID"
"ID": "12D3KooWPzfVaGoXTdwZUWpBais8rZoNTj1d2BRFD9GxUB6XRGdE",
# node02
$ ipfs id |grep "ID"
"ID": "12D3KooWJmQ8XoHR9v6d5RLBd3KQzu2TZ6bcDBCwnoT1FEGvSSmK",
# node03
$ ipfs id |grep "ID"
"ID": "12D3KooWNALaAp2D6Q1Cb5UjvnJwnuW2TKXh1YBYtRNjW1uzpY9s",


# 三个节点互相将另外两个节点加入进来
# node01执行命令,注意对应ip为22-23节点的ip和对应节点的ID
$ ipfs bootstrap add /ip4/192.168.99.22/tcp/4001/p2p/12D3KooWJmQ8XoHR9v6d5RLBd3KQzu2TZ6bcDBCwnoT1FEGvSSmK
$ ipfs bootstrap add /ip4/192.168.99.23/tcp/4001/p2p/12D3KooWNALaAp2D6Q1Cb5UjvnJwnuW2TKXh1YBYtRNjW1uzpY9s

# node02执行命令,注意对应ip为21、23节点的ip和对应节点的ID
$ ipfs bootstrap add /ip4/192.168.99.21/tcp/4001/p2p/12D3KooWPzfVaGoXTdwZUWpBais8rZoNTj1d2BRFD9GxUB6XRGdE
$ ipfs bootstrap add /ip4/192.168.99.23/tcp/4001/p2p/12D3KooWNALaAp2D6Q1Cb5UjvnJwnuW2TKXh1YBYtRNjW1uzpY9s

# node03执行命令,注意对应ip为21、22节点的ip和对应节点的ID
$ ipfs bootstrap add /ip4/192.168.99.21/tcp/4001/p2p/12D3KooWPzfVaGoXTdwZUWpBais8rZoNTj1d2BRFD9GxUB6XRGdE
$ ipfs bootstrap add /ip4/192.168.99.22/tcp/4001/p2p/12D3KooWJmQ8XoHR9v6d5RLBd3KQzu2TZ6bcDBCwnoT1FEGvSSmK


# 退出容器
$ exit

# 重启三个节点的docker-compose容器
$ cd /data/ipfs
$ docker-compose restart

等待前面容器重新启动成功之后,就可以浏览器访问 http://节点ip:5001/webui访问到weiui页面了

验证ipfs网络可用性

通过命令行验证

任何一个节点进入到ipfs容器

1
2
3
4
5
6
7
8
9
$ docker exec -it ipfs sh

# 上传一个文件测试,上传成功后会返回一个hash值
$ ipfs add /data/ipfs/version
added QmU718ekePHsiEVhbRRvmRhkGb4aJwqeCoqGSD6mvdXSG6 version

# 其他节点通过文件hash查看文件内容验证上传内容
$ ipfs cat QmU718ekePHsiEVhbRRvmRhkGb4aJwqeCoqGSD6mvdXSG6
13

通过golang-api代码验证

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package main

import (
"bytes"
"context"
"fmt"
shell "github.com/ipfs/go-ipfs-api"
"io/ioutil"
"os"
)

type Ipfs struct {
Url string
Sh *shell.Shell
}

func NewIpfs(url string) *Ipfs {
sh := shell.NewShell(url)
return &Ipfs{
Url: url,
Sh: sh,
}
}

// UploadIPFS 上传数据到ipfs
func (i *Ipfs) UploadIPFS(str string) (hash string, err error) {
hash, err = i.Sh.Add(bytes.NewBufferString(str), shell.Pin(true))
if err != nil {
return
}
return
}

// UnPinIPFS 从ipfs上删除数据
func (i *Ipfs) UnPinIPFS(hash string) (err error) {
err = i.Sh.Unpin(hash)
if err != nil {
return
}

err = i.Sh.Request("repo/gc", hash).
Option("recursive", true).
Exec(context.Background(), nil)
if err != nil {
return
}

return nil
}

// CatIPFS 从ipfs下载数据
func (i *Ipfs) CatIPFS(hash string) (string, error) {
read, err := i.Sh.Cat(hash)
if err != nil {
return "", err
}
body, err := ioutil.ReadAll(read)

return string(body), nil
}

func main() {
//创建一个ipfs实例对象
sh := NewIpfs("192.168.99.21:5001")

//// 添加文件内容验证
cid, err := sh.UploadIPFS("hello world!")
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s", err)
os.Exit(1)
}else {
fmt.Printf("添加成功 HASH: %s", cid)
}

// 通过hash查看文件验证
read, err := sh.CatIPFS("QmYRedAmdac69zYs2BHeTmRHnajymahmfgWobQEw46M5CH")
if err != nil {
fmt.Println(err)
}
fmt.Println(read)
}