A cloud-native counter application built with Kubernetes, featuring a React frontend, REST API backend, and PostgreSQL database.
KubeCounter is a full-stack web application demonstrating modern Kubernetes deployment practices. It showcases a three-tier architecture with proper service mesh configuration, persistent storage, zero-trust network policies, and Gateway API routing.
- Frontend: React-based client served via Nginx
- Backend: REST API server (Port 8080)
- Database: PostgreSQL 16 with persistent storage
- Ingress: Gateway API (HTTPRoute) with path-based routing
- Security: Granular NetworkPolicies enforcing zero-trust segmentation
- Kubernetes-native deployment managed with Kustomize
- Zero-trust network security with granular NetworkPolicies
- Secret management for database credentials
- Persistent data storage with StatefulSets
- Gateway API routing for frontend and API
- PostgreSQL database with initialization scripts
- Consistent labeling and best practices
KubeCounter implements a zero-trust network model using Kubernetes NetworkPolicies:
- Default Deny All: Restricts all incoming and outgoing traffic across the namespace by default
- Frontend Policy: Allows inbound HTTP traffic on port 80 from ingress gateways and DNS egress
- Backend Policy: Allows inbound API traffic on port 8080 from frontend pods/gateways, DNS egress, and outbound egress on port 5432 to PostgreSQL
- Database Policy: Restricts inbound database traffic on port 5432 strictly to backend API pods only
- Kubernetes cluster (v1.33+)
- kubectl configured
- Gateway API controller / Gateway installed
- Docker images available at
mmaous/kubecounter-clientandmmaous/kubecounter-server
git clone https://github.com/yourusername/kubecounter.git
cd kubecounterUsing Kustomize (recommended):
kubectl apply -k kube/overlays/devOr apply individual base manifests:
# Create namespace and default deny security policy
kubectl apply -f kube/base/namespace.yaml
kubectl apply -f kube/base/default-deny.yaml
# Deploy PostgreSQL
kubectl apply -f kube/base/postgres/statefulset.yaml
kubectl apply -f kube/base/postgres/service.yaml
kubectl apply -f kube/base/postgres/networkpolicy.yaml
# Deploy backend API
kubectl apply -f kube/base/backend/deployment.yaml
kubectl apply -f kube/base/backend/service.yaml
kubectl apply -f kube/base/backend/networkpolicy.yaml
# Deploy frontend
kubectl apply -f kube/base/frontend/deployment.yaml
kubectl apply -f kube/base/frontend/service.yaml
kubectl apply -f kube/base/frontend/httproute.yaml
kubectl apply -f kube/base/frontend/networkpolicy.yamlkubectl get pods -n kubecounter
kubectl get netpol -n kubecounter
kubectl get httproute -n kubecounterThe application will be available at your gateway hostname:
- Frontend:
https://kubecounter.mmlabs.me/ - API:
https://kubecounter.mmlabs.me/api/
Default credentials are configured via Kustomize secret generator:
- Username:
devuser - Password:
devpass
Backend configuration (see kube/base/backend/deployment.yaml):
DB_HOST: PostgreSQL service hostname (postgres-svc)DB_PORT: PostgreSQL port (5432)DB_NAME: Database name (counterdb)DB_USER: Database username (from secret)DB_PASSWORD: Database password (from secret)SERVER_PORT: API server port (8080)
kubecounter/
├── backend/
│ ├── Dockerfile
│ └── main.go
├── frontend/
│ ├── Dockerfile
│ └── src/
├── kube/
│ ├── base/
│ │ ├── kustomization.yaml
│ │ ├── namespace.yaml
│ │ ├── default-deny.yaml
│ │ ├── backend/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── networkpolicy.yaml
│ │ ├── frontend/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ ├── httproute.yaml
│ │ │ └── networkpolicy.yaml
│ │ └── postgres/
│ │ ├── statefulset.yaml
│ │ ├── service.yaml
│ │ ├── init.sql
│ │ └── networkpolicy.yaml
│ └── overlays/
│ └── dev/
│ └── kustomization.yaml
└── README.md
The application uses a simple counter schema:
CREATE TABLE counters (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
value INTEGER DEFAULT 0
);All components are configured with resource limits:
- Frontend: 128Mi memory, 250m CPU
- Backend: 128Mi memory, 250m CPU
- Database: 10Gi persistent storage
kubectl get pods -n kubecounter
kubectl describe pod <pod-name> -n kubecounterkubectl get netpol -n kubecounter
kubectl describe netpol <policy-name> -n kubecounterkubectl logs -n kubecounter deployment/kubecounter-server
kubectl logs -n kubecounter deployment/kubecounter-client
kubectl logs -n kubecounter statefulset/app-postgreskubectl exec -it app-postgres-0 -n kubecounter -- psql -U devuser -d counterdb- Connection timeouts or 503 errors: Ensure
frontend-network-policyandbackend-network-policyare applied to allow gateway and inter-pod traffic throughdefault-deny-all. - Database connection errors: Verify backend network policy permits egress on port 5432 and PostgreSQL network policy allows ingress from backend pods.
- HTTPRoute not routing: Ensure Gateway API controller is installed and
core-gatewayis running.
To build and push new Docker images:
# Backend
docker build -t mmaous/kubecounter-server:latest ./backend
docker push mmaous/kubecounter-server:latest
# Frontend
docker build -t mmaous/kubecounter-client:latest ./frontend
docker push mmaous/kubecounter-client:latest