Kubernetes Deployment Guide
Deploy Guts nodes on Kubernetes using Helm or raw manifests.
Prerequisites
- Kubernetes 1.28+ cluster
- kubectl configured with cluster access
- Helm 3.12+ (for Helm deployment)
- StorageClass with dynamic provisioning
- LoadBalancer or Ingress controller (for external access)
Helm Deployment (Recommended)
Add Repository
bash
helm repo add guts https://charts.guts.network
helm repo updateBasic Installation
bash
# Create namespace
kubectl create namespace guts
# Install with defaults
helm install guts-node guts/guts-node \
--namespace guts
# Check status
kubectl get pods -n guts -wProduction Installation
bash
helm install guts-node guts/guts-node \
--namespace guts \
--create-namespace \
--set replicaCount=3 \
--set persistence.enabled=true \
--set persistence.size=500Gi \
--set persistence.storageClass=gp3 \
--set resources.requests.cpu=2 \
--set resources.requests.memory=8Gi \
--set resources.limits.cpu=8 \
--set resources.limits.memory=32Gi \
--set metrics.enabled=true \
--set serviceMonitor.enabled=trueCustom Values File
Create values.yaml:
yaml
# Replica configuration
replicaCount: 3
# Image settings
image:
repository: ghcr.io/guts-network/guts-node
tag: "latest"
pullPolicy: IfNotPresent
# Service configuration
service:
type: LoadBalancer
api:
port: 8080
p2p:
port: 9000
metrics:
port: 9090
# Persistence
persistence:
enabled: true
size: 500Gi
storageClass: "gp3"
accessModes:
- ReadWriteOnce
# Resources
resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "8"
memory: "32Gi"
# Node configuration
config:
logLevel: "info"
logFormat: "json"
consensus:
enabled: true
useSimplex: true
blockTimeMs: 2000
# Probes
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Monitoring
metrics:
enabled: true
serviceMonitor:
enabled: true
interval: 15s
# Security
podSecurityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
# Pod disruption budget
podDisruptionBudget:
enabled: true
minAvailable: 2
# Node affinity
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: guts-node
topologyKey: kubernetes.io/hostnameInstall with custom values:
bash
helm install guts-node guts/guts-node \
--namespace guts \
--create-namespace \
-f values.yamlRaw Manifest Deployment
Namespace
yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: guts
labels:
app.kubernetes.io/name: gutsConfigMap
yaml
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: guts-config
namespace: guts
data:
config.yaml: |
api:
addr: "0.0.0.0:8080"
p2p:
addr: "0.0.0.0:9000"
metrics:
addr: "0.0.0.0:9090"
logging:
level: "info"
format: "json"
consensus:
enabled: true
use_simplex_bft: true
block_time_ms: 2000Secret (Node Keys)
yaml
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: guts-node-keys
namespace: guts
type: Opaque
stringData:
# Generate keys: guts-node keygen
node-0.key: |
<private-key-hex>
<public-key-hex>
node-1.key: |
<private-key-hex>
<public-key-hex>
node-2.key: |
<private-key-hex>
<public-key-hex>StatefulSet
yaml
# statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: guts-node
namespace: guts
spec:
serviceName: guts-node
replicas: 3
podManagementPolicy: Parallel
selector:
matchLabels:
app.kubernetes.io/name: guts-node
template:
metadata:
labels:
app.kubernetes.io/name: guts-node
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: guts-node
image: ghcr.io/guts-network/guts-node:latest
imagePullPolicy: IfNotPresent
ports:
- name: api
containerPort: 8080
protocol: TCP
- name: p2p-tcp
containerPort: 9000
protocol: TCP
- name: p2p-udp
containerPort: 9000
protocol: UDP
- name: metrics
containerPort: 9090
protocol: TCP
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: GUTS_DATA_DIR
value: /data
- name: GUTS_LOG_LEVEL
value: info
- name: GUTS_LOG_FORMAT
value: json
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /etc/guts/config.yaml
subPath: config.yaml
- name: keys
mountPath: /etc/guts/keys
readOnly: true
resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "8"
memory: "32Gi"
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
volumes:
- name: config
configMap:
name: guts-config
- name: keys
secret:
secretName: guts-node-keys
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
storageClassName: gp3
resources:
requests:
storage: 500GiServices
yaml
# services.yaml
---
# Headless service for P2P
apiVersion: v1
kind: Service
metadata:
name: guts-node-headless
namespace: guts
spec:
clusterIP: None
selector:
app.kubernetes.io/name: guts-node
ports:
- name: p2p-tcp
port: 9000
targetPort: 9000
protocol: TCP
- name: p2p-udp
port: 9000
targetPort: 9000
protocol: UDP
---
# LoadBalancer for API
apiVersion: v1
kind: Service
metadata:
name: guts-node-api
namespace: guts
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: guts-node
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
- name: https
port: 443
targetPort: 8080
protocol: TCPApply Manifests
bash
kubectl apply -f namespace.yaml
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f statefulset.yaml
kubectl apply -f services.yamlIngress Configuration
NGINX Ingress
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: guts-ingress
namespace: guts
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- guts.example.com
secretName: guts-tls
rules:
- host: guts.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: guts-node-api
port:
number: 80Monitoring Integration
ServiceMonitor (Prometheus Operator)
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: guts-node
namespace: guts
labels:
release: prometheus
spec:
selector:
matchLabels:
app.kubernetes.io/name: guts-node
endpoints:
- port: metrics
interval: 15s
path: /metricsPodMonitor (Alternative)
yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: guts-node
namespace: guts
spec:
selector:
matchLabels:
app.kubernetes.io/name: guts-node
podMetricsEndpoints:
- port: metrics
interval: 15sNetwork Policies
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: guts-node
namespace: guts
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: guts-node
policyTypes:
- Ingress
- Egress
ingress:
# Allow API from anywhere
- ports:
- port: 8080
protocol: TCP
# Allow P2P from anywhere
- ports:
- port: 9000
protocol: TCP
- port: 9000
protocol: UDP
# Allow metrics from monitoring namespace
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- port: 9090
protocol: TCP
egress:
# Allow all outbound
- {}Pod Disruption Budget
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: guts-node
namespace: guts
spec:
minAvailable: 2
selector:
matchLabels:
app.kubernetes.io/name: guts-nodeHorizontal Pod Autoscaler
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: guts-node
namespace: guts
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: guts-node
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80Backup with Velero
yaml
# Schedule daily backups
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: guts-daily
namespace: velero
spec:
schedule: "0 2 * * *"
template:
includedNamespaces:
- guts
storageLocation: default
volumeSnapshotLocations:
- default
ttl: 720h # 30 daysTroubleshooting
Pod Not Starting
bash
# Check pod status
kubectl describe pod -n guts guts-node-0
# Check logs
kubectl logs -n guts guts-node-0 --previous
# Check events
kubectl get events -n guts --sort-by='.lastTimestamp'Storage Issues
bash
# Check PVC status
kubectl get pvc -n guts
# Check StorageClass
kubectl get storageclass
# Debug PVC
kubectl describe pvc -n guts data-guts-node-0Network Issues
bash
# Test DNS resolution
kubectl exec -n guts guts-node-0 -- nslookup guts-node-headless
# Test connectivity
kubectl exec -n guts guts-node-0 -- curl -v http://guts-node-1.guts-node-headless:8080/health