I only get one CID, why do I get **multiple** CIDs?

Hi, I have installed ipfs clister in kebernetes.
I have uploaded an image with REST Api /aa call. I get this as response:

response: {"name":"","cid":"QmQGYxCYyuRgkBwf3mzE9cstfRCXzkeL6HDv1ENF5CbRUB","size":13,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmWCHpu8gM2y6AUAa7jmsPKjSBReqPD9ykpXh6t6WCXptB","size":25,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"6ed9e6ca24df38be0b54d3d00","cid":"QmeJRJqjWzdhUfwRJWCpvg9i1scbtBifqTukcS76jgyUMn","size":9203,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmcjeQaN5gKA3qAntZPkTUxfbiMswTm6cTtn829SJpXVFQ","size":15,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmQt3wmQ9QDnWMWf1EYXbMQcvArXygJFEgqD9HmfRpbH3s","size":11,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmcNzWmuM8F6nrE8HSQWLjoApjbQhJiYAjiGDotw9oS8t4","size":19,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}
{"name":"","cid":"QmNUoXf9j388gnAFEkemnMzXmgDADxWpEriEtQ4hYaVLLD","size":16,"allocations":["12D3KooWCftZqAa6W7zofy43Yd2NH1Pm96Sn13izocUpzb3riW89","12D3KooWMR5G1RvYPRPGq8a9hpHp3EwQ4UKnbqbK6C8oSCXcJqo2","QmRmxTNfxx5tjo1dqPKd9tdjxMCAk5MbXDPYWzJGdUT8XW"]}

I only get one CID, why do I get multiple CIDs?

Hello. Can you explain in more detail where did you obtain this response?

Hi Hector,
I have installed ipfs cluster in kubernetes. Here is my ipfs-cluster.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ipfs-cluster
  namespace: ipfs-cluster
spec:
  serviceName: ipfs-cluster
  replicas: 3
  selector:
    matchLabels:
      app: ipfs-cluster
  template:
    metadata:
      labels:
        app: ipfs-cluster
    spec:
      initContainers:
        - name: configure-ipfs
          image: "ipfs/kubo:v0.31.0"
          command: ["sh", "/custom/configure-ipfs.sh"]
          volumeMounts:
            - name: ipfs-storage
              mountPath: /data/ipfs
            - name: configure-script
              mountPath: /custom
      containers:
        - name: ipfs
          image: "ipfs/kubo:v0.31.0"
          imagePullPolicy: IfNotPresent
          env:
            - name: IPFS_FD_MAX
              value: "4096"
          ports:
            - name: swarm
              protocol: TCP
              containerPort: 4001
            - name: swarm-udp
              protocol: UDP
              containerPort: 4002
            - name: api
              protocol: TCP
              containerPort: 5001
            - name: ws
              protocol: TCP
              containerPort: 8081
            - name: http
              protocol: TCP
              containerPort: 8080
          livenessProbe:
            tcpSocket:
              port: swarm
            initialDelaySeconds: 30
            timeoutSeconds: 5
            periodSeconds: 15
          volumeMounts:
            - mountPath: /data/ipfs
              name: ipfs-storage
            - name: configure-script
              mountPath: /custom
          resources:
            {}
        - name: ipfs-cluster
          image: "ipfs/ipfs-cluster:latest"
          imagePullPolicy: IfNotPresent
          command: ["sh", "/custom/entrypoint.sh"]
          envFrom:
            - configMapRef:
                name: env-config
          env:
            - name: BOOTSTRAP_PEER_ID
              valueFrom:
                configMapKeyRef:
                  name: env-config
                  key: bootstrap-peer-id
            - name: BOOTSTRAP_PEER_PRIV_KEY
              valueFrom:
                secretKeyRef:
                  name: secret-config
                  key: bootstrap-peer-priv-key
            - name: CLUSTER_SECRET
              valueFrom:
                secretKeyRef:
                  name: secret-config
                  key: cluster-secret
            - name: CLUSTER_MONITOR_PING_INTERVAL
              value: "3m"
            - name: SVC_NAME
              value: ipfs-cluster
          ports:
            - name: api-http
              containerPort: 9094
              protocol: TCP
            - name: proxy-http
              containerPort: 9095
              protocol: TCP
            - name: cluster-swarm
              containerPort: 9096
              protocol: TCP
          livenessProbe:
            tcpSocket:
              port: cluster-swarm
            initialDelaySeconds: 5
            timeoutSeconds: 5
            periodSeconds: 10
          volumeMounts:
            - name: cluster-storage
              mountPath: /data/ipfs-cluster
            - name: configure-script
              mountPath: /custom
          resources:
            {}

      volumes:
      - name: configure-script
        configMap:
          name: ipfs-cluster-set-bootstrap-conf


  volumeClaimTemplates:
    - metadata:
        name: cluster-storage
      spec:
        storageClassName: local-path
        accessModes: ["ReadWriteOnce"]
        # persistentVolumeReclaimPolicy: Retain
        resources:
          requests:
            storage: 5Gi
    - metadata:
        name: ipfs-storage
      spec:
        storageClassName: local-path
        accessModes: ["ReadWriteOnce"]
        # persistentVolumeReclaimPolicy: Retain
        resources:
          requests:
            storage: 200Gi

In my nextJs app I make an axios call:

         const IPFS_CLUSTER_RESTAPI_URL = http://10.43.90.35:9094;

         // to read the file
        const fileStream = fs.createReadStream(filePath);
        const metadata = {
            name: fields['name'],
            description: fields['description'],
            image: fileStream,
            attributes: [{
                trait_type: "Version",
                value: "1.0"
            }, {
                trait_type: "marketplace",
                value: "ART"
            }],
        };
   
        //Upload NFT to IPFS & Filecoin
        const response = await axios.post(IPFS_CLUSTER_RESTAPI_URL + '/add', metadata, {
            headers: {
                'Content-Type': 'multipart/form-data'
            },
        });

You get multiple CIDs like that when you upload multiple files through a single multipart request to /add. The last one is usually the ā€œrootā€ cid.

I believe that you are uploading the metadata as ā€œform-dataā€ in your POST, and thus making a request with multiple parts.

Cluster-pin metadata in cluster /add endpoint goes as part of the query params to the request (i.e. ?name=myname&meta-description=desc&meta-attributes=a,b,c). Note that metadata field names must be prepended by ā€œmeta-ā€.

See:

Yes, I use the metadata as ā€˜form-data’ in my POST call.
I don’t see anything about root-CID, all CID are the same.
How do I get only one CID?

Don’t use the metadata as form-data as this is equivalent to adding multiple files, and so you get one CID per file.

ok, that means don’t use multipart/form-data.
How do I send the image file?

ohne multipart/form-data bekomme ich einen Fehler:
Anfrage fehlgeschlagen mit Statuscode 400

It’s explained in the docs I sent.

Hi @hector ,
Thank you, now I only get a CID. But I still had to use form-data:

const metadata = JSON.stringify({
            "meta-name": fields['name'],
            "meta-description": fields['description'],
            "meta-file": fs.createReadStream(filePath),
            "meta-attributes": [{
                trait_type: "Version",
                value: "1.0"
            }, {
                trait_type: "marketplace",
                value: "ARTWISTA"
            }],
        });

formData.append("meta-data", metadata);
        //Upload NFT to IPFS & Filecoin
        const response = await axios.post(IPFS_CLUSTER_RESTAPI_URL + '/add', 
            formData, {
            maxBodyLength: Infinity,
            headers: {
              'Content-Type': `multipart/form-data;`,
              // Authorization: `Bearer ${JWT_SECRET_IPFS_CLUSTER}`
            }
          });

One more question, now i want to use IPFS gateway local in kubernetes:

Curl 
http://10.43.90.35:8080/ipfs/QmVmrV76aiVcULqGQfH8kYkQXzhpvtVYy9e7hAQXjt4AaQ

But no answer there. Do you have an idea?

In this case it seems you are uploading a json with embedded binary data, which I’m not sure is the best (should probably base64 it first).

Possibly your gateway is only listening on localhost and you need to change Addresses.Gateway to use 0.0.0.0 .

Thanks @hector ,

  1. yes, a json is uploaded
  2. yes, my service mapped to localhost:
Gateway server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

These commands in the script do not seem to work:

ipfs config --json Addresses.Gateway /ip4/0.0.0.0/tcp/8080

what script? Where did you find that command?

apiVersion: v1
kind: ConfigMap
metadata:
  name: ipfs-cluster-set-bootstrap-conf
  namespace: ipfs-cluster
data:
  entrypoint.sh: |
    #!/bin/sh
    user=ipfs
    sleep 10
    # This is a custom entrypoint for k8s designed to connect to the bootstrap
    # node running in the cluster. It has been set up using a configmap to
    # allow changes on the fly.


  
..........