# Deploy IPFS cluster peer

> IPFS Cluster provides data orchestration across a swarm of IPFS daemons by allocating, replicating and tracking a global pinset distributed among multiple peers. [Source](https://cluster.ipfs.io)

### Prerequisites

Before we start, you need to:

#### Step 1 - Deploy IPFS Peer

Deploy an ipfs peer `Peer` because it's required by `ClusterPeer`. Check our [Deploy IPFS Peer](https://docs.kotal.co/tutorials/ipfs/peer) tutorial.

#### Step 2 - Generate Cluster Secret

Create a cluster secret which secures access to the cluster:

```bash
CLUSTER_SECRET=$(openssl rand -hex 32)
kubectl create secret generic cluster-secret --from-literal=secret=$CLUSTER_SECRET
```

{% hint style="warning" %}
Cluster secret must be 32-byte hex-encoded (64 characters) without the leading `0x`. It must be hold in data field called `secret` in the Kubernetes secret.
{% endhint %}

#### Step 3 - Generate ID and Private Key

Create cluster peer ID and private key using [ipfs-key](https://github.com/whyrusleeping/ipfs-key)

```bash
ipfs-key -type ed25519 | base64
```

It will return an output similar to the following:

```
Generating a 2048 bit ed25519 key...
Success!
ID for generated key: 12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq
CAESQOH/DvUJmeJ9z6m3wAStpkrlBwJQxIyNSK0YGf0EI5ZRGpwsWxl4wmgReqmHl8LQjTC2iPM0QbYAjeY3Z63AFnI=
```

#### Step 4 - Deploy Private Key Secret

create Kubernetes secret from the generated private key in step(3) above.

```bash
CLUSTER_PEER_PRIVATEKEY=CAESQOH/DvUJmeJ9z6m3wAStpkrlBwJQxIyNSK0YGf0EI5ZRGpwsWxl4wmgReqmHl8LQjTC2iPM0QbYAjeY3Z63AFnI=
kubectl create secret generic cluster-peer-privatekey --from-literal=key=$CLUSTER_PEER_PRIVATEKEY
```

### Deploying First Cluster Peer

Now we're ready to deploy the cluster peer and connect it to the peer we've deployed in step(1)

{% code title="cluster-peer.yaml" %}

```yaml
apiVersion: ipfs.kotal.io/v1alpha1
kind: ClusterPeer
metadata:
  Name: cluster-peer
spec:
  consensus: crdt
  # from step(3)
  id: "12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq"
  # from step(4)
  privateKeySecretName: cluster-peer-privatekey
  # from step(1)
  peerEndpoint: /dns4/peer-sample/tcp/5001
  # from step(2)
  clusterSecretName: cluster-secret
```

{% endcode %}

{% hint style="info" %}
Note that `id` and `privateKeySecretName` are optional, they're useful to get predictable cluster peer id to be used in future steps as bootstrap peer.
{% endhint %}

Let's deploy cluster peer manifest file:

```bash
kubectl apply -f cluster-peer.yaml
```

Kotal operator will notice your `cluster-peer` and will create all the necessary pods, persistent volumes, services, configmaps, and secrets.

You can fetch the deployed IPFS `ClusterPeer` using:

```bash
kubectl get clusterpeers
```

It will return an output similar to the following:

```bash
NAME           CLIENT                 CONSENSUS
cluster-peer   ipfs-cluster-service   crdt
```

### Fetch Cluster Peer Logs

Get the pods created for our cluster peer:

```bash
kubectl get pods
```

It will return an output similar to the following:

```
NAME             READY   STATUS    RESTARTS   AGE
cluster-peer-0   1/1     Running   0          2m
```

Check the logs of the running cluster peer:

```bash
kubectl logs -f cluster-peer-0
```

It will return an output similar to the following:

```
2021-04-30T00:31:24.109Z	INFO	service	ipfs-cluster-service/daemon.go:46	Initializing. For verbose output run with "-l debug". Please wait...
2021-04-30T00:31:24.133Z	INFO	cluster	ipfs-cluster/cluster.go:136	IPFS Cluster v0.13.2+git812c8e3631d4d6771a6e04112e12cd7726e23f7a listening on:

        /ip4/10.244.0.8/tcp/9096/p2p/12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq
        /ip4/127.0.0.1/tcp/9096/p2p/12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq

2021-04-30T00:31:24.134Z	INFO	ipfsproxy	ipfsproxy/ipfsproxy.go:320	IPFS Proxy: /ip4/127.0.0.1/tcp/9095 -> /ip4/127.0.0.1/tcp/5001
2021-04-30T00:31:24.134Z	INFO	restapi	rest/restapi.go:521	REST API (HTTP): /ip4/127.0.0.1/tcp/9094
2021-04-30T00:31:24.134Z	INFO	crdt	go-ds-crdt@v0.1.20/crdt.go:278	crdt Datastore created. Number of heads: 0. Current max-height: 0
2021-04-30T00:31:24.136Z	INFO	cluster	ipfs-cluster/cluster.go:651	Cluster Peers (without including ourselves):
2021-04-30T00:31:24.136Z	INFO	cluster	ipfs-cluster/cluster.go:653	    - No other peers
2021-04-30T00:31:24.136Z	INFO	cluster	ipfs-cluster/cluster.go:666	** IPFS Cluster is READY **
```

As you can see from the logs that our cluster peer is up and running as indicated by the healthy logs `IPFS Cluster is READY`.

### Update Cluster Pinset

Let's add some content to the pinset by executing commands inside cluster peer container:

```bash
$ kubectl exec -it cluster-peer-0 -- sh
# now we're inside cluster-peer container

$ echo "kotal simplifies Blockchain DevOps" > kotal.txt

# add kotal.txt to the pinset
$ ipfs-cluster-ctl add kotal.txt
added QmUiwYtz1VxeryVCpTLWqrbeUi9HyGH4AnpSG6BrmdMhzL kotal.txt

# leave cluster-peer container
$ exit
```

Let's fetch the pinset of the ipfs peer by executing commands inside peer -created in step(1)- container:

```bash
$ kubectl exec -it peer-sample-0 -- sh
# now we're inside peer-sample container

# List objects pinned to local storage
$ ipfs pin ls
QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn recursive
QmUiwYtz1VxeryVCpTLWqrbeUi9HyGH4AnpSG6BrmdMhzL recursive

$ ipfs cat QmUiwYtz1VxeryVCpTLWqrbeUi9HyGH4AnpSG6BrmdMhzL
kotal simplifies Blockchain DevOps

# leave ipfs peer container
$ exit
```

As you can see, content pinned by the cluster peer, has been added to the pinset of the ipfs peer and available in its local storage.

### Deploying Second Cluster Peer

The only prerequisite to the second cluster peer is to:

#### Step 1 - Deploy IPFS Peer

Deploy an ipfs peer `Peer`, and **name it** `peer-sample-two`. Check our [Deploy IPFS Peer](https://docs.kotal.co/tutorials/ipfs/peer) tutorial.

We will reuse cluster secret that was generated in step(2) during deploying first cluster peer above.

{% code title="cluster-peer-two.yaml" %}

```yaml
apiVersion: ipfs.kotal.io/v1alpha1
kind: ClusterPeer
metadata:
  Name: cluster-peer-two
spec:
  # from step(1)
  peerEndpoint: /dns4/peer-sample-twp/tcp/5001
  # generated during deploying first cluster peer in step(2)
  clusterSecretName: cluster-secret
  # first cluster peer listening address
  bootstrapPeers:
    - /ip4/cluster-peer/tcp/9096/p2p/12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq
```

{% endcode %}

{% hint style="info" %}
The first cluster peer multiaddress is predictable because we've used a pre-generated id and private key in step(3). `/ip4/{cluster peer k8s service name}/tcp/9096/p2p/{cluster peer ID}`
{% endhint %}

Deploying this cluster manifest will deploy a cluster peer that connects to the first cluster peer and will connect to its own ipfs peer `peer-sample-two` instance.

```bash
kubectl apply -f cluster-peer-two.yaml
```

You can fetch the deployed cluster peers by:

```bash
kubectl get clusterpeers
```

It will return an output similar to the following:

```
NAME               CLIENT                 CONSENSUS
cluster-peer       ipfs-cluster-service   crdt
cluster-peer-two   ipfs-cluster-service   crdt
```

### Fetch Second Cluster Peer Logs

Get the pods created by our cluster peer:

```bash
kubectl get pods
```

It will return an output similar to the following:

```
NAME                 READY   STATUS    RESTARTS   AGE
cluster-peer-0       1/1     Running   0          10m
cluster-peer-two-0   1/1     Running   0          2m
```

Check the logs of cluster peer two:

```bash
kubectl logs -f cluster-peer-two-0
```

It will return an output similar to the following:

```
2021-05-01T19:17:12.043Z	INFO	service	ipfs-cluster-service/daemon.go:46	Initializing. For verbose output run with "-l debug". Please wait...
2021-05-01T19:17:12.352Z	INFO	cluster	ipfs-cluster/cluster.go:136	IPFS Cluster v0.13.2+git812c8e3631d4d6771a6e04112e12cd7726e23f7a listening on:

        /ip4/10.244.0.35/tcp/9096/p2p/12D3KooWGVZek7gdarvj7gePvnV9x8ekSeSdruYojgj5dmU466Wv
        /ip4/127.0.0.1/tcp/9096/p2p/12D3KooWGVZek7gdarvj7gePvnV9x8ekSeSdruYojgj5dmU466Wv


2021-05-01T19:17:12.441Z	INFO	restapi	rest/restapi.go:521	REST API (HTTP): /ip4/127.0.0.1/tcp/9094
2021-05-01T19:17:12.441Z	INFO	ipfsproxy	ipfsproxy/ipfsproxy.go:320	IPFS Proxy: /ip4/127.0.0.1/tcp/9095 -> /ip4/127.0.0.1/tcp/5001
2021-05-01T19:17:12.441Z	INFO	service	ipfs-cluster-service/daemon.go:218	Bootstrapping to /dns4/cluster-peer/tcp/9096/p2p/12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq
2021-05-01T19:17:12.442Z	INFO	crdt	go-ds-crdt@v0.1.20/crdt.go:278	crdt Datastore created. Number of heads: 0. Current max-height: 0
2021-05-01T19:17:12.442Z	INFO	crdt	crdt/consensus.go:277	'trust all' mode enabled. Any peer in the cluster can modify the pinset.
2021-05-01T19:17:12.447Z	INFO	cluster	ipfs-cluster/cluster.go:651	Cluster Peers (without including ourselves):
2021-05-01T19:17:12.447Z	INFO	cluster	ipfs-cluster/cluster.go:653	    - No other peers
2021-05-01T19:17:12.448Z	INFO	cluster	ipfs-cluster/cluster.go:666	** IPFS Cluster is READY **
2021-05-01T19:17:12.551Z	INFO	cluster	ipfs-cluster/cluster.go:1020	12D3KooWGVZek7gdarvj7gePvnV9x8ekSeSdruYojgj5dmU466Wv: joined 12D3KooWBcEtY8GH4mNkri9kM3haeWhEXtQV7mi81ErWrqLYGuiq's cluster
```

As you can see cluster peer two is up and running as indicated by the healthy logs and `IPFS Cluster is READY`.

Cluster peer two has joined the first cluster peer as indicated by the highlighted log line `joined 12D...uiq's cluster`

Finally, delete all peers and cluster peers:

```bash
kubectl delete peers --all
kubectl delete clusterpeers --all
```

Kubernetes garbage collector will delete all the resources that has been created by Kotal IPFS `Peer` and `ClusterPeer` controllers.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kotal.co/tutorials/ipfs/cluster.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
