Collective pinning and composition for IPFS.
Go Other
Latest commit 857e381 Feb 15, 2017 @hsanjuan hsanjuan committed with hsanjuan Double-delay on test to allow leader re-election.
License: MIT
Signed-off-by: Hector Sanjuan <hector@protocol.ai>
Permalink
Failed to load latest commit information.
.gx gx publish 0.0.2 Jan 25, 2017
allocator/numpinalloc go vet fixes Feb 15, 2017
api go vet fixes Feb 15, 2017
informer/numpin Documentation: captain log, readme and golint fixes Feb 15, 2017
ipfs-cluster-ctl Issue #41: Add Replication factor Feb 14, 2017
ipfs-cluster-service Issue #41: Add Replication factor Feb 14, 2017
state/mapstate Documentation: captain log, readme and golint fixes Feb 15, 2017
test go vet fixes Feb 15, 2017
.gitignore Issue #20: Download a local installation of gx Jan 25, 2017
.travis.yml Small improvements to coverage.sh and travis.yml Feb 14, 2017
CAPTAIN.LOG.md Documentation: captain log, readme and golint fixes Feb 15, 2017
LICENSE ipfscluster-server executable Dec 21, 2016
Makefile Issue #41: Add Replication factor Feb 14, 2017
README.md Documentation: captain log, readme and golint fixes Feb 15, 2017
ROADMAP.md Fix #15: Peers() provides lots of information now Jan 26, 2017
architecture.md Documentation: captain log, readme and golint fixes Feb 15, 2017
cluster.go go vet fixes Feb 15, 2017
cluster_test.go Issue #41: Add Replication factor Feb 14, 2017
config.go Issue #41: Add Replication factor Feb 14, 2017
config_test.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
consensus.go Issue #41: Add Replication factor Feb 14, 2017
consensus_test.go Issue #41: Add Replication factor Feb 14, 2017
coverage.sh Small improvements to coverage.sh and travis.yml Feb 14, 2017
debug.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
ipfs_http_connector.go Issue #41: Add Replication factor Feb 14, 2017
ipfs_http_connector_test.go Move testing mocks to subpackage so they can be re-used Feb 9, 2017
ipfscluster.go Documentation: captain log, readme and golint fixes Feb 15, 2017
ipfscluster_test.go Double-delay on test to allow leader re-election. Feb 15, 2017
log_op.go Issue #41: Add Replication factor Feb 14, 2017
log_op_test.go Issue #41: Add Replication factor Feb 14, 2017
logging.go Improve raft log forwarder Feb 9, 2017
map_pin_tracker.go Issue #41: Add Replication factor Feb 14, 2017
nodebug.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
package.json Update deps to latest raft and gorpc Jan 26, 2017
peer_manager.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
peer_manager_test.go Issue #41: Add Replication factor Feb 14, 2017
peer_monitor.go Documentation: captain log, readme and golint fixes Feb 15, 2017
peer_monitor_test.go Issue #41: Add Replication factor Feb 14, 2017
raft.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
release.sh Improve packages.json and add release script Jan 25, 2017
rest_api.go Issue #41: Add Replication factor Feb 14, 2017
rest_api_test.go Issue #41: Add Replication factor Feb 14, 2017
rpc_api.go go vet fixes Feb 15, 2017
silent.go Fix #24: Auto-join and auto-leave operations for Cluster Feb 7, 2017
util.go Issue #41: Add Replication factor Feb 14, 2017
version.go Make sure the commit string gets set. Fix PublicKey. Output JSON in c… Jan 24, 2017

README.md

ipfs-cluster

standard-readme compliant GoDoc Go Report Card Build Status Coverage Status

Collective pinning and composition for IPFS.

WORK IN PROGRESS

DO NOT USE IN PRODUCTION

ipfs-cluster is a tool which groups a number of IPFS nodes together, allowing to collectively perform operations such as pinning.

In order to do so IPFS Cluster nodes use a libp2p-based consensus algorithm (currently Raft) to agree on a log of operations and build a consistent state across the cluster. The state represents which objects should be pinned by which nodes.

Additionally, cluster nodes act as a proxy/wrapper to the IPFS API, so they can be used as a regular node, with the difference that pin add, pin rm and pin ls requests are handled by the Cluster.

IPFS Cluster provides a cluster-node application (ipfs-cluster-service), a Go API, a HTTP API and a command-line tool (ipfs-cluster-ctl).

Current functionality only allows pinning in all cluster peers, but more strategies (like setting a replication factor for each pin) will be developed.

Table of Contents

Background

Since the start of IPFS it was clear that a tool to coordinate a number of different nodes (and the content they are supposed to store) would add a great value to the IPFS ecosystem. Naïve approaches are possible, but they present some weaknesses, specially at dealing with error handling, recovery and implementation of advanced pinning strategies.

ipfs-cluster aims to address this issues by providing a IPFS node wrapper which coordinates multiple cluster peers via a consensus algorithm. This ensures that the desired state of the system is always agreed upon and can be easily maintained by the cluster peers. Thus, every cluster node knows which content is tracked, can decide whether asking IPFS to pin it and can react to any contingencies like node reboots.

Maintainers and Roadmap

This project is captained by @hsanjuan. See the captain's log for a written summary of current status and upcoming features. You can also check out the project's Roadmap for a high level overview of what's coming and the project's Waffle Board to see what issues are being worked on at the moment.

Install

In order to install the ipfs-cluster-service the ipfs-cluster-ctl tool simply download this repository and run make as follows:

$ go get -u -d github.com/ipfs/ipfs-cluster
$ cd $GOPATH/src/github.com/ipfs/ipfs-cluster
$ make install

This will install ipfs-cluster-service and ipfs-cluster-ctl in your $GOPATH/bin folder.

Usage

ipfs-cluster-service

ipfs-cluster-service runs a cluster peer. Usage information can be obtained running:

$ ipfs-cluster-service -h

Before running ipfs-cluster-service for the first time, initialize a configuration file with:

$ ipfs-cluster-service -init

The configuration will be placed in ~/.ipfs-cluster/service.json by default.

You can add the multiaddresses for the other cluster peers the bootstrap_multiaddresses variable. For example, here is a valid configuration for a single-peer cluster:

{
    "id": "QmXMhZ53zAoes8TYbKGn3rnm5nfWs5Wdu41Fhhfw9XmM5A",
    "private_key": "<redacted>",
    "cluster_peers": [],
    "bootstrap": [],
    "leave_on_shutdown": false,
    "cluster_multiaddress": "/ip4/0.0.0.0/tcp/9096",
    "api_listen_multiaddress": "/ip4/127.0.0.1/tcp/9094",
    "ipfs_proxy_listen_multiaddress": "/ip4/127.0.0.1/tcp/9095",
    "ipfs_node_multiaddress": "/ip4/127.0.0.1/tcp/5001",
    "consensus_data_folder": "/home/hector/go/src/github.com/ipfs/ipfs-cluster/ipfs-cluster-service/d1/data",
    "state_sync_seconds": 60,
    "replication_factor": -1
}

The configuration file should probably be identical among all cluster peers, except for the id and private_key fields. Once every cluster peer has the configuration in place, you can run ipfs-cluster-service to start the cluster.

Clusters using cluster_peers

The cluster_peers configuration variable holds a list of current cluster members. If you know the members of the cluster in advance, or you want to start a cluster fully in parallel, set cluster_peers in all configurations so that every peer knows the rest upon boot. Leave bootstrap empty (although it will be ignored anyway)

Clusters using bootstrap

When the cluster_peers variable is empty, the multiaddresses bootstrap can be used to have a peer join an existing cluster. The peer will contact those addresses (in order) until one of them succeeds in joining it to the cluster. When the peer is shut down, it will save the current cluster peers in the cluster_peers configuration variable for future use.

Bootstrap is a convenient method, but more prone to errors than cluster_peers. It can be used as well with ipfs-cluster-service --bootstrap <multiaddress>. Note that bootstrapping nodes with an old state (or diverging state) from the one running in the cluster may lead to problems with the consensus, so usually you would want to bootstrap blank nodes.

Debugging

ipfs-cluster-service offers two debugging options:

  • --debug enables debug logging from the ipfs-cluster, go-libp2p-raft and go-libp2p-rpc layers. This will be a very verbose log output, but at the same time it is the most informative.
  • --loglevel sets the log level ([error, warning, info, debug]) for the ipfs-cluster only, allowing to get an overview of the what cluster is doing. The default log-level is info.

ipfs-cluster-ctl

ipfs-cluster-ctl is the client application to manage the cluster nodes and perform actions. ipfs-cluster-ctl uses the HTTP API provided by the nodes and it is completely separate from the cluster service. It can talk to any cluster peer (--host) and uses localhost by default.

After installing, you can run ipfs-cluster-ctl --help to display general description and options, or alternatively ipfs-cluster-ctl help [cmd] to display information about supported commands.

In summary, it works as follows:

$ ipfs-cluster-ctl id                                                       # show cluster peer and ipfs daemon information
$ ipfs-cluster-ctl peers ls                                                 # list cluster peers
$ ipfs-cluster-ctl peers add /ip4/1.2.3.4/tcp/1234/<peerid>                 # add a new cluster peer
$ ipfs-cluster-ctl peers rm <peerid>                                        # remove a cluster peer
$ ipfs-cluster-ctl pin add Qma4Lid2T1F68E3Xa3CpE6vVJDLwxXLD8RfiB9g1Tmqp58   # pins a CID in the cluster
$ ipfs-cluster-ctl pin rm Qma4Lid2T1F68E3Xa3CpE6vVJDLwxXLD8RfiB9g1Tmqp58    # unpins a CID from the cluster
$ ipfs-cluster-ctl status                                                   # display tracked CIDs information
$ ipfs-cluster-ctl sync Qma4Lid2T1F68E3Xa3CpE6vVJDLwxXLD8RfiB9g1Tmqp58      # sync information from the IPFS daemon
$ ipfs-cluster-ctl recover Qma4Lid2T1F68E3Xa3CpE6vVJDLwxXLD8RfiB9g1Tmqp58   # attempt to re-pin/unpin CIDs in error state

Debugging

ipfs-cluster-ctl provides a --debug flag which allows to inspect request paths and raw response bodies.

Quick start: Building and updating an IPFS Cluster

Step 0: Run your first cluster node

This step creates a single-node IPFS Cluster.

First initialize the configuration:

node0 $ ipfs-cluster-service init
ipfs-cluster-service configuration written to /home/user/.ipfs-cluster/service.json

Then run cluster:

node0> ipfs-cluster-service
13:33:34.044  INFO    cluster: IPFS Cluster v0.0.1 listening on: cluster.go:59
13:33:34.044  INFO    cluster:         /ip4/127.0.0.1/tcp/9096/ipfs/QmQHKLBXfS7hf8o2acj7FGADoJDLat3UazucbHrgxqisim cluster.go:61
13:33:34.044  INFO    cluster:         /ip4/192.168.1.103/tcp/9096/ipfs/QmQHKLBXfS7hf8o2acj7FGADoJDLat3UazucbHrgxqisim cluster.go:61
13:33:34.044  INFO    cluster: starting Consensus and waiting for a leader... consensus.go:163
13:33:34.047  INFO    cluster: PinTracker ready map_pin_tracker.go:71
13:33:34.047  INFO    cluster: waiting for leader raft.go:118
13:33:34.047  INFO    cluster: REST API: /ip4/127.0.0.1/tcp/9094 rest_api.go:309
13:33:34.047  INFO    cluster: IPFS Proxy: /ip4/127.0.0.1/tcp/9095 -> /ip4/127.0.0.1/tcp/5001 ipfs_http_connector.go:168
13:33:35.420  INFO    cluster: Raft Leader elected: QmQHKLBXfS7hf8o2acj7FGADoJDLat3UazucbHrgxqisim raft.go:145
13:33:35.921  INFO    cluster: Consensus state is up to date consensus.go:214
13:33:35.921  INFO    cluster: IPFS Cluster is ready cluster.go:191
13:33:35.921  INFO    cluster: Cluster Peers (not including ourselves): cluster.go:192
13:33:35.921  INFO    cluster:     - No other peers cluster.go:195

Step 1: Add new members to the cluster

Initialize and run cluster in a different node(s):

node1> ipfs-cluster-service init
ipfs-cluster-service configuration written to /home/user/.ipfs-cluster/service.json
node1> ipfs-cluster-service
13:36:19.313  INFO    cluster: IPFS Cluster v0.0.1 listening on: cluster.go:59
13:36:19.313  INFO    cluster:         /ip4/127.0.0.1/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85 cluster.go:61
13:36:19.313  INFO    cluster:         /ip4/192.168.1.103/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85 cluster.go:61
13:36:19.313  INFO    cluster: starting Consensus and waiting for a leader... consensus.go:163
13:36:19.316  INFO    cluster: REST API: /ip4/127.0.0.1/tcp/7094 rest_api.go:309
13:36:19.316  INFO    cluster: IPFS Proxy: /ip4/127.0.0.1/tcp/7095 -> /ip4/127.0.0.1/tcp/5001 ipfs_http_connector.go:168
13:36:19.316  INFO    cluster: waiting for leader raft.go:118
13:36:19.316  INFO    cluster: PinTracker ready map_pin_tracker.go:71
13:36:20.834  INFO    cluster: Raft Leader elected: QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85 raft.go:145
13:36:21.334  INFO    cluster: Consensus state is up to date consensus.go:214
13:36:21.334  INFO    cluster: IPFS Cluster is ready cluster.go:191
13:36:21.334  INFO    cluster: Cluster Peers (not including ourselves): cluster.go:192
13:36:21.334  INFO    cluster:     - No other peers cluster.go:195

Add them to the original cluster with ipfs-cluster-ctl peers add <multiaddr>. The command will return the ID information of the newly added member:

node0> ipfs-cluster-ctl peers add /ip4/192.168.1.103/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85
{
  "id": "QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85",
  "public_key": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtjpvI+XKVGT5toXTimtWceONYsf/1bbRMxLt/fCSYJoSeJqj0HUtttCD3dcBv1M2rElIMXDhyLUpkET+AN6otr9lQnbgi0ZaKrtzphR0w6g/0EQZZaxI2scxF4NcwkwUfe5ceEmPFwax1+C00nd2BF+YEEp+VHNyWgXhCxncOGO74p0YdXBrvXkyfTiy/567L3PPX9F9x+HiutBL39CWhx9INmtvdPB2HwshodF6QbfeljdAYCekgIrCQC8mXOVeePmlWgTwoge9yQbuViZwPiKwwo1AplANXFmSv8gagfjKL7Kc0YOqcHwxBsoUskbJjfheDZJzl19iDs9EvUGk5AgMBAAE=",
  "addresses": [
    "/ip4/127.0.0.1/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85",
    "/ip4/192.168.1.103/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85"
  ],
  "cluster_peers": [
    "/ip4/192.168.123.103/tcp/7096/ipfs/QmU7JJftGsP1zM8H37XwvfA7dwdepsB7xVnJA6sKpozc85"
  ],
  "version": "0.0.1",
  "commit": "83baa5c859b9b17b2deec4f782d1210590025c80",
  "rpc_protocol_version": "/ipfscluster/0.0.1/rpc",
  "ipfs": {
    "id": "QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewur2n",
    "addresses": [
      "/ip4/127.0.0.1/tcp/4001/ipfs/QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewur2n",
      "/ip4/192.168.1.103/tcp/4001/ipfs/QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewur2n"
    ]
  }
}

You can repeat the process with any other nodes.

Step 3: Remove no longer needed nodes

You can use ipfs-cluster-ctl peers rm <multiaddr> to remove and disconnect any nodes from your cluster. The nodes will be automatically shutdown. They can be restarted manually and re-added to the Cluster any time:

node0> ipfs-cluster-ctl peers rm QmbGFbZVTF3UAEPK9pBVdwHGdDAYkHYufQwSh4k1i8bbbb
Request succeeded

The node1 is then disconnected and shuts down:

13:42:50.828 WARNI    cluster: this peer has been removed from the Cluster and will shutdown itself in 5 seconds peer_manager.go:48
13:42:51.828  INFO    cluster: stopping Consensus component consensus.go:257
13:42:55.836  INFO    cluster: shutting down IPFS Cluster cluster.go:235
13:42:55.836  INFO    cluster: Saving configuration config.go:283
13:42:55.837  INFO    cluster: stopping Cluster API rest_api.go:327
13:42:55.837  INFO    cluster: stopping IPFS Proxy ipfs_http_connector.go:332
13:42:55.837  INFO    cluster: stopping MapPinTracker map_pin_tracker.go:87

Go

IPFS Cluster nodes can be launched directly from Go. The Cluster object provides methods to interact with the cluster and perform actions.

Documentation and examples on how to use IPFS Cluster from Go can be found in godoc.org/github.com/ipfs/ipfs-cluster.

API

TODO: Swagger

This is a quick summary of API endpoints offered by the Rest API component (these may change before 1.0):

Method Endpoint Comment
GET /id Cluster peer information
GET /version Cluster version
GET /peers Cluster peers
POST /peers Add new peer
DELETE /peers/{peerID} Remove a peer
GET /pinlist List of pins in the consensus state
GET /pins Status of all tracked CIDs
POST /pins/sync Sync all
GET /pins/{cid} Status of single CID
POST /pins/{cid} Pin CID
DELETE /pins/{cid} Unpin CID
POST /pins/{cid}/sync Sync CID
POST /pins/{cid}/recover Recover CID

Architecture

The best place to get an overview of how cluster works, what components exist etc. is the architecture.md doc.

Contribute

PRs accepted.

Small note: If editing the README, please conform to the standard-readme specification.

License

MIT © Protocol Labs, Inc.