★ StableBlock is REST API written in Go, deployed using k8s and simulates lightweight blockchain operations and protected with JWT
StableBlock is REST API written in Go, deployed to local Kubernetes cluster that runs behind Docker Desktop and simulates lightweight blockchain operations
• Docker Image based on golang:1.24.2-alpine3.21
• Local Kubernetes cluster: k8s cluster that runs behind Docker Desktop
• postgres service: ClusterIP with 5432 port
• stableblock-api service: NodePort 30080
• postgres deployment with 1 replica
• stableblock-api deployment with 10 replicas
• stableblock namespace
• Two Makefiles: Makefile.k8s and Makefile.local
- Clone the repo ✅
git clone https://github.com/r3v5/StableBlock.git
- Navigate to the project directory ✅
cd StableBlock
- Create a .env file in root directory for local development ✅
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=postgres
DB_SSLMODE=disable
DB_DSN=postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable
JWT_SECRET=buterinthegodnow
- Build docker image ✅
docker build -f infra/docker/Dockerfile -t stableblock-api:v1 .
- Verify image is created ✅
docker images
- In folder infra/k8s create configmap.yml (config file for k8s deployment) ✅
apiVersion: v1
kind: ConfigMap
metadata:
name: stableblock-config
namespace: stableblock
data:
DB_HOST: "postgres"
DB_PORT: "5432"
DB_NAME: "postgres"
DB_SSLMODE: "disable"
- In folder infra/k8s create secret.yml (config file for k8s deployment) ✅
apiVersion: v1
kind: Secret
metadata:
name: stableblock-secrets
namespace: stableblock
type: Opaque
stringData:
DB_USER: "postgres"
DB_PASSWORD: "postgres"
JWT_SECRET: "buterinthegodnow"
DB_DSN: "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable"
- Create stableblock namespace in Kubernetes cluster ✅
kubectl create -f infra/k8s/namespace.yml
Output should be similar to this:
namespace/stableblock created
- Create PersistentVolumeClaim for db in Kubernetes cluster ✅
kubectl create -f infra/k8s/postgres-pvc.yml
Output should be similar to this:
persistentvolumeclaim/postgres-pvc created
- Create ConfigMap in Kubernetes cluster ✅
kubectl create -f infra/k8s/configmap.yml
Output should be similar to this:
configmap/stableblock-config created
- Create Secret in Kubernetes cluster ✅
kubectl create -f infra/k8s/secret.yml
Output should be similar to this:
secret/stableblock-secrets created
- Create Postgres Service in Kubernetes cluster ✅
kubectl create -f infra/k8s/postgres-service.yml
Output should be similar to this:
service/postgres created
- Make deployment of Postgres Service in Kubernetes cluster ✅
kubectl create -f infra/k8s/postgres-deployment.yml
Output should be similar to this:
deployment.apps/postgres created
- Verify that services and deployments of Postgres were created in Kubernetes cluster ✅
kubectl get all -n stableblock
Output should be similar to this:
NAME READY STATUS RESTARTS AGE
pod/postgres-6d9d5894dc-pdzp6 1/1 Running 0 53s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/postgres ClusterIP 10.110.210.175 <none> 5432/TCP 6m41s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/postgres 1/1 1 1 53s
NAME DESIRED CURRENT READY AGE
replicaset.apps/postgres-6d9d5894dc 1 1 1 53s
- Create NodePort Service in Kubernetes cluster ✅
kubectl create -f infra/k8s/stable-block-api-service.yml
Output should be similar to this:
service/stableblock-api created
- Finally make a deployment of NodePort service with 10 replicas in Kubernetes cluster ✅
kubectl create -f infra/k8s/stable-block-api-deployment.yml
Output should be similar to this:
deployment.apps/stableblock-api created
- Get all pods, services and deployments for given namespace Kubernetes cluster ✅
kubectl get all -n stableblock
Output should be similar to this:
NAME READY STATUS RESTARTS AGE
pod/postgres-6d9d5894dc-pdzp6 1/1 Running 0 13m
pod/stableblock-api-6bf4465676-4x24d 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-5mgvq 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-9fxf7 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-bx8rn 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-cskdp 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-cwscw 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-h6scp 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-ng4qn 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-t4zvv 1/1 Running 0 8m34s
pod/stableblock-api-6bf4465676-td6wc 1/1 Running 0 8m34s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/postgres ClusterIP 10.110.210.175 <none> 5432/TCP 18m
service/stableblock-api NodePort 10.110.46.133 <none> 8080:30080/TCP 9m53s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/postgres 1/1 1 1 13m
deployment.apps/stableblock-api 10/10 10 10 8m34s
NAME DESIRED CURRENT READY AGE
replicaset.apps/postgres-6d9d5894dc 1 1 1 13m
replicaset.apps/stableblock-api-6bf4465676 10 10 10 8m34s
- List the pods, select any from stable-block-api and run migrations on it ✅
kubectl exec -it stableblock-api-6bf4465676-4x24d -n stableblock -- make -f Makefile.k8s migrate-up
Output should be similar to this:
migrate -path database/migrations -database "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable" up
20250406135230/u init (15.89675ms)
20250411124832/u add_date_created_to_accounts (19.840417ms)
- Then verify the current migration version ✅
kubectl exec -it stableblock-api-6bf4465676-4x24d -n stableblock -- make -f Makefile.k8s migrate-version
Output should be similar to this:
migrate -path database/migrations -database "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable" version
20250411124832
- All is good, then call welcome endpoint in Postman or using curl and explore docs to see all the endpoints ✅
curl --location 'http://localhost:30080/api/v1/welcome/'
Output should be similar to this:
{
"message": "Welcome to StableBlock 👋"
}
- To launch project locally without k8s, just run this command ✅
go run main.go
Output should be similar to this:
2025/04/11 18:38:38 ✅ Connected to database.
Published Postman collection: API docs
Ian Miller - linkedin
Project Link: https://github.com/r3v5/StableBlock