hirosystems/stacks-devnet-api

Update Pods to appropriate workload spec

Closed this issue ยท 3 comments

Deploying workloads as standalone pods can be dangerous, as once a pod is deleted for any reason, even accidentally, it won't be recreated by the cluster.

To improve availability of the workloads, they should be converted to either a Deployment for a stateless pod, or StatefulSet for a stateful pod.

This means the DevNet API would likely have to update any pod-related K8s APIs being used to either deployment or statefulset APIs in order to maintain the same functionality.
For example, with this change the Devnet api would no longer be creating or deleting pods. It would instead be creating and deleting 2 deployments and 1 statefulset. Once those are deployed, the k8s controllers will automatically handle creating or removing pods associated with those workload resources.

An additional benefit of using a statefulset is that the PVC can be managed within the statefulset's definition, allowing you to remove the separate PVC template.

@CharlieC3, okay, this makes sense. Would it be possible for you or someone from the DevOps team to convert the current pod manifests to a deployment or stateful set?

From there (or in parallel), I can implement the programatic deployment of whichever asset type is chosen.

@MicaiahReid Here are some examples taken from the pod manifests here.

I've added some additional fields like affinity to ensure the workloads run on the correct nodes. I also added a volumeClaimTemplates definition to the stacks-blockchain-api STS as previously mentioned. This means when using the stacks-blockchain-api STS, you won't need this PVC manifest anymore as it would become redundant.

I also took the liberty to fix some minor things like the PVC storage size definition, I added resources definitions for each container, upgraded the PG container to 15. I added some standard labels we use across the cluster (feel free to apply them elsewhere too).
I also ran a dry-run with these to verify their syntax correctness.

I wouldn't fret too much on the smaller details though, we can tackle that in a separate issue.

bitcoind-chain-coordinator

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: bitcoind-chain-coordinator
    app.kubernetes.io/instance: "{user_id}"
    app.kubernetes.io/managed-by: stacks-devnet-api
    app.kubernetes.io/name: bitcoind-chain-coordinator
  name: bitcoind-chain-coordinator
  namespace: "{namespace}"
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: bitcoind-chain-coordinator
      app.kubernetes.io/instance: "{user_id}"
      app.kubernetes.io/managed-by: stacks-devnet-api
      app.kubernetes.io/name: bitcoind-chain-coordinator
  template:
    metadata:
      labels:
        app.kubernetes.io/component: bitcoind-chain-coordinator
        app.kubernetes.io/instance: "{user_id}"
        app.kubernetes.io/managed-by: stacks-devnet-api
        app.kubernetes.io/name: bitcoind-chain-coordinator
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: cloud.google.com/gke-preemptible
                    operator: DoesNotExist
      containers:
        - command:
            - /usr/local/bin/bitcoind
            - -conf=/etc/bitcoin/bitcoin.conf
            - -nodebuglogfile
            - -pid=/run/bitcoind.pid
          image: quay.io/hirosystems/bitcoind:devnet-v3
          imagePullPolicy: IfNotPresent
          name: bitcoind
          ports:
            - containerPort: 18444
              name: p2p
              protocol: TCP
            - containerPort: 18443
              name: rpc
              protocol: TCP
          volumeMounts:
            - mountPath: /etc/bitcoin
              name: bitcoind
              readOnly: true
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 256Mi
        - command:
            - ./stacks-network
            - --namespace=$(NAMESPACE)
            - --manifest-path=/etc/stacks-network/project/Clarinet.toml
            - --network-manifest-path=/etc/stacks-network/project/settings/Devnet.toml
            - --deployment-plan-path=/etc/stacks-network/project/deployments/default.devnet-plan.yaml
            - --project-root-path=/etc/stacks-network/project/
          env:
            - name: NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
          image: hirosystems/stacks-network-orchestrator:rpc-error
          imagePullPolicy: Always
          name: chain-coordinator
          ports:
            - containerPort: 20445
              name: coordinator-in
              protocol: TCP
            - containerPort: 20446
              name: coordinator-con
              protocol: TCP
          volumeMounts:
            - mountPath: /etc/stacks-network/project
              name: project-manifest
            - mountPath: /etc/stacks-network/project/settings
              name: devnet
            - mountPath: /etc/stacks-network/project/deployments
              name: deployment-plan
            - mountPath: /etc/stacks-network/project/contracts
              name: project-dir
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 256Mi
      volumes:
        - configMap:
            name: bitcoind
          name: bitcoind
        - configMap:
            name: project-manifest
          name: project-manifest
        - configMap:
            name: devnet
          name: devnet
        - configMap:
            name: deployment-plan
          name: deployment-plan
        - configMap:
            name: project-dir
          name: project-dir

stacks-blockchain-api

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app.kubernetes.io/component: stacks-blockchain-api
    app.kubernetes.io/instance: "{user_id}"
    app.kubernetes.io/managed-by: stacks-devnet-api
    app.kubernetes.io/name: stacks-blockchain-api
  name: stacks-blockchain-api
  namespace: "{namespace}"
spec:
  replicas: 1
  serviceName: stacks-blockchain-api
  selector:
    matchLabels:
      app.kubernetes.io/component: stacks-blockchain-api
      app.kubernetes.io/instance: "{user_id}"
      app.kubernetes.io/managed-by: stacks-devnet-api
      app.kubernetes.io/name: stacks-blockchain-api
  template:
    metadata:
      labels:
        app.kubernetes.io/component: stacks-blockchain-api
        app.kubernetes.io/instance: "{user_id}"
        app.kubernetes.io/managed-by: stacks-devnet-api
        app.kubernetes.io/name: stacks-blockchain-api
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: cloud.google.com/gke-preemptible
                    operator: DoesNotExist
      containers:
        - name: stacks-blockchain-api
          envFrom:
            - configMapRef:
                name: stacks-blockchain-api
                optional: false
          image: hirosystems/stacks-blockchain-api
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3999
              name: api
              protocol: TCP
            - containerPort: 3700
              name: eventport
              protocol: TCP
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 256Mi
        - name: postgres
          envFrom:
            - configMapRef:
                name: stacks-blockchain-api-pg
                optional: false
          image: postgres:15
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 5432
              name: postgres
              protocol: TCP
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: stacks-blockchain-api-pg
              subPath: postgres
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              memory: 512Mi
  volumeClaimTemplates:
    - metadata:
        name: stacks-blockchain-api-pg
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: premium-rwo
        resources:
          requests:
            storage: 1Gi

stacks-blockchain

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: stacks-blockchain
    app.kubernetes.io/instance: "{user_id}"
    app.kubernetes.io/managed-by: stacks-devnet-api
    app.kubernetes.io/name: stacks-blockchain
  name: stacks-blockchain
  namespace: "{namespace}"
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/component: stacks-blockchain
      app.kubernetes.io/instance: "{user_id}"
      app.kubernetes.io/managed-by: stacks-devnet-api
      app.kubernetes.io/name: stacks-blockchain
  template:
    metadata:
      labels:
        app.kubernetes.io/component: stacks-blockchain
        app.kubernetes.io/instance: "{user_id}"
        app.kubernetes.io/managed-by: stacks-devnet-api
        app.kubernetes.io/name: stacks-blockchain
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: cloud.google.com/gke-preemptible
                    operator: DoesNotExist
      containers:
        - command:
            - stacks-node
            - start
            - --config=/src/stacks-blockchain/Stacks.toml
          env:
            - name: STACKS_LOG_PP
              value: "1"
            - name: BLOCKSTACK_USE_TEST_GENESIS_CHAINSTATE
              value: "1"
            - name: STACKS_LOG_DEBUG
              value: "0"
          image: quay.io/hirosystems/stacks-node:devnet-v3
          imagePullPolicy: IfNotPresent
          name: stacks-blockchain
          ports:
            - containerPort: 20444
              name: p2p
              protocol: TCP
            - containerPort: 20443
              name: rpc
              protocol: TCP
          volumeMounts:
            - mountPath: /src/stacks-blockchain
              name: stacks-blockchain
              readOnly: true
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 256Mi
      volumes:
        - configMap:
            name: stacks-blockchain
          name: stacks-blockchain

๐ŸŽ‰ This issue has been resolved in version 1.1.0 ๐ŸŽ‰

The release is available on GitHub release

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€