From b4ed240d715f07bcd41bee6b3c09c7ab68cf9fda Mon Sep 17 00:00:00 2001 From: Arunponugoti Date: Sun, 18 May 2025 22:45:30 +0530 Subject: [PATCH 1/3] 2nd version --- .env | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 48774fc..0000000 --- a/.env +++ /dev/null @@ -1,8 +0,0 @@ -# Database Configuration -POSTGRES_USER=postgres -POSTGRES_PASSWORD=secret_password -POSTGRES_DB=messages - -# Node.js Configuration -NODE_ENV=development -API_PORT=3000 \ No newline at end of file From b9cf813274a932c360888508f30be20204b9f113 Mon Sep 17 00:00:00 2001 From: Arunponugoti Date: Sun, 18 May 2025 22:48:07 +0530 Subject: [PATCH 2/3] 2nd versione --- .gitignore | 28 ++++ K8s-trobuleshooting-guide.md | 227 +++++++++++++++++++++++++++++++++ backend/server.js | 10 +- k8s/backend.yaml | 33 +++++ k8s/configmap.yaml | 9 ++ k8s/database.yaml | 48 +++++++ k8s/frontend.yaml | 32 +++++ k8s/postgres-init-scripts.yaml | 18 +++ 8 files changed, 400 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 K8s-trobuleshooting-guide.md create mode 100644 k8s/backend.yaml create mode 100644 k8s/configmap.yaml create mode 100644 k8s/database.yaml create mode 100644 k8s/frontend.yaml create mode 100644 k8s/postgres-init-scripts.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7c2f5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Environment variables +.env +.env.* +*.env + +# Kubernetes secrets +k8s/**/secret*.yaml +**/secrets/*.yaml + +# Logs +**/logs +*.log + +# Node +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# IDE +.vscode/ +.idea/ + +# OS specific +.DS_Store +Thumbs.db + +www \ No newline at end of file diff --git a/K8s-trobuleshooting-guide.md b/K8s-trobuleshooting-guide.md new file mode 100644 index 0000000..1fc5150 --- /dev/null +++ b/K8s-trobuleshooting-guide.md @@ -0,0 +1,227 @@ +# Kubernetes 3-Tier Application Troubleshooting Guide + +This document covers common issues, troubleshooting steps, and solutions when deploying a 3-tier application (Frontend, Backend, Database) to Kubernetes. + +## Architecture Overview + +Our application consists of: + +- **Frontend**: NGINX serving static files and proxying API requests +- **Backend**: Node.js Express service connecting to PostgreSQL +- **Database**: PostgreSQL storing application data + +## Common Issues and Solutions + +### 1. NGINX Host Resolution Failure + +#### Error +``` +[emerg] host not found in upstream "backend" in /etc/nginx/conf.d/default.conf:14 +``` + +#### Root Cause +NGINX is configured to proxy requests to a host named `backend`, but the Kubernetes service providing that backend has a different name (`backend-service`). + +#### Solution Options + +**Option 1**: Rename the service to match NGINX configuration +```yaml +apiVersion: v1 +kind: Service +metadata: + name: backend # Changed from backend-service +spec: + selector: + app: backend + ports: + - port: 3000 +``` + +**Option 2**: Update NGINX configuration to use the correct service name +``` +# In NGINX default.conf, change +proxy_pass http://backend; +# to +proxy_pass http://backend-service:3000; +``` + +**Prevention Tip**: Always ensure service names in Kubernetes match exactly what's expected in application configurations. + +### 2. Database Authentication Failure + +#### Error +``` +Error fetching messages: error: password authentication failed for user "postgres" +``` + +#### Root Cause +Environment variable naming mismatch between container conventions: +- PostgreSQL container uses `POSTGRES_PASSWORD` +- Node.js app uses `DB_PASSWORD` + +#### Solution +Update the Kubernetes Secret to include variables for both naming conventions: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: db-credentials +type: Opaque +stringData: + # For PostgreSQL container + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "secret_password" + POSTGRES_DB: "messages" + # For Node.js application + DB_USER: "postgres" + DB_PASSWORD: "secret_password" + DB_NAME: "messages" +``` + +**Prevention Tip**: When connecting different systems, be aware that environment variable conventions may differ between applications. + +### 3. Missing Database Schema/Tables + +#### Error +``` +Error: relation "messages" does not exist +``` + +#### Root Cause +When migrating from Docker Compose to Kubernetes, database initialization scripts aren't automatically carried over. In Docker Compose, initialization scripts in the `./database` directory might be automatically mounted to `/docker-entrypoint-initdb.d/` where PostgreSQL executes them. + +#### Solution +1. Create a ConfigMap for database initialization: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-init-scripts +data: + init.sql: | + CREATE TABLE IF NOT EXISTS messages ( + id SERIAL PRIMARY KEY, + author VARCHAR(100) NOT NULL, + content TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP + ); + + INSERT INTO messages (author, content) VALUES + ('System', 'Welcome to the message board!'); +``` + +2. Mount the ConfigMap to the database container: + +```yaml +spec: + template: + spec: + containers: + - name: database + # ... + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + - name: postgres-init-scripts + mountPath: /docker-entrypoint-initdb.d + volumes: + - name: postgres-init-scripts + configMap: + name: postgres-init-scripts +``` + +**Prevention Tip**: Always consider database initialization when migrating to Kubernetes. PostgreSQL only runs initialization scripts on first startup with an empty data directory. + +## Port Forwarding in k3d + +When using k3d (Kubernetes in Docker), additional port mapping is needed to access NodePort services from the host. + +#### Solution Options + +**Option 1**: Create cluster with port mapping +```bash +k3d cluster create myapp --api-port 6550 -p "30080:30080@loadbalancer" +``` + +**Option 2**: Update existing cluster +```bash +docker stop k3d-myapp-serverlb +docker update --publish 30080:30080 k3d-myapp-serverlb +docker start k3d-myapp-serverlb +``` + +**Option 3**: Use kubectl port-forward +```bash +kubectl port-forward svc/frontend-service 8080:80 +``` + +## Useful Troubleshooting Commands + +### Service and Pod Status +```bash +# List all pods and their status +kubectl get pods + +# List all services +kubectl get svc + +# Get detailed information about a pod +kubectl describe pod +``` + +### Log Inspection +```bash +# View logs for a specific pod +kubectl logs + +# View logs for all pods with a specific label +kubectl logs -l app=backend + +# Stream logs in real-time +kubectl logs -f +``` + +### Container Debugging +```bash +# Execute a command in a pod +kubectl exec -it -- + +# Get a shell in a pod +kubectl exec -it -- bash + +# Check environment variables +kubectl exec -it -- env +``` + +### Testing Connectivity +```bash +# Test connectivity between pods +kubectl exec -it -- curl + +# Test DNS resolution +kubectl exec -it -- nslookup +``` + +## Common Kubernetes Gotchas + +1. **Volume Persistence**: StatefulSet PVCs persist data even when pods are deleted. If you need a fresh database, you must delete the PVC. + +2. **Namespace Isolation**: Services from different namespaces aren't directly accessible. Use fully-qualified names (`service.namespace.svc.cluster.local`). + +3. **Image Pull Policy**: With local development, use `imagePullPolicy: IfNotPresent` or `Never` to use locally built images. + +4. **Init Containers**: Consider using init containers for database schema initialization rather than relying on PostgreSQL's init scripts. + +5. **Health Checks**: Implement readiness and liveness probes to ensure application availability and proper rolling updates. + +## Conclusion + +Most issues when moving to Kubernetes revolve around: +- Service discovery and naming +- Environment variable configuration +- Volume management and persistence +- Container initialization + +By methodically troubleshooting these areas, most application deployment issues in Kubernetes can be resolved. \ No newline at end of file diff --git a/backend/server.js b/backend/server.js index da2892f..2c64af6 100644 --- a/backend/server.js +++ b/backend/server.js @@ -24,11 +24,11 @@ app.use(express.json()); // Database connection const pool = new Pool({ - host: process.env.DB_HOST || 'localhost', - port: process.env.DB_PORT || 5432, - user: process.env.DB_USER || 'postgres', - password: process.env.DB_PASSWORD || 'postgres', - database: process.env.DB_NAME || 'messages' + host: process.env.DB_HOST, + port: process.env.DB_PORT, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME }); // Simple logging middleware diff --git a/k8s/backend.yaml b/k8s/backend.yaml new file mode 100644 index 0000000..8845611 --- /dev/null +++ b/k8s/backend.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Service +metadata: + name: backend +spec: + selector: + app: backend + ports: + - port: 3000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend +spec: + replicas: 1 + selector: + matchLabels: + app: backend + template: + metadata: + labels: + app: backend + spec: + containers: + - name: backend + image: k3d-myapp-backend:latest + imagePullPolicy: IfNotPresent + envFrom: + - configMapRef: + name: app-config + - secretRef: + name: db-credentials \ No newline at end of file diff --git a/k8s/configmap.yaml b/k8s/configmap.yaml new file mode 100644 index 0000000..31823b8 --- /dev/null +++ b/k8s/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: app-config +data: + NODE_ENV: "development" + API_PORT: "3000" + DB_HOST: "database-service" + DB_PORT: "5432" \ No newline at end of file diff --git a/k8s/database.yaml b/k8s/database.yaml new file mode 100644 index 0000000..ca2c53d --- /dev/null +++ b/k8s/database.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: Service +metadata: + name: database-service +spec: + selector: + app: database + ports: + - port: 5432 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: database +spec: + serviceName: database-service + replicas: 1 + selector: + matchLabels: + app: database + template: + metadata: + labels: + app: database + spec: + containers: + - name: database + image: postgres:13 + envFrom: + - secretRef: + name: db-credentials + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + - name: postgres-init-scripts + mountPath: /docker-entrypoint-initdb.d + volumes: + - name: postgres-init-scripts + configMap: + name: postgres-init-scripts + volumeClaimTemplates: + - metadata: + name: postgres-data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/k8s/frontend.yaml b/k8s/frontend.yaml new file mode 100644 index 0000000..bb958b4 --- /dev/null +++ b/k8s/frontend.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: frontend-service +spec: + type: NodePort + selector: + app: frontend + ports: + - port: 80 + nodePort: 30080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend +spec: + replicas: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + image: k3d-myapp-frontend:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 \ No newline at end of file diff --git a/k8s/postgres-init-scripts.yaml b/k8s/postgres-init-scripts.yaml new file mode 100644 index 0000000..be2e2cd --- /dev/null +++ b/k8s/postgres-init-scripts.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-init-scripts +data: + init.sql: | + -- Create messages table if it doesn't exist + CREATE TABLE IF NOT EXISTS messages ( + id SERIAL PRIMARY KEY, + author VARCHAR(100) NOT NULL, + content TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP + ); + + -- Add some initial data + INSERT INTO messages (author, content) VALUES + ('System', 'Welcome to the Docker Learning Project message board!'), + ('Docker', 'Learn about containers, images, volumes, and networks!'); \ No newline at end of file From 826eee1db9b838a51ec05795b1f4c009340dffc7 Mon Sep 17 00:00:00 2001 From: arunponugoti1 <160697898+arunponugoti1@users.noreply.github.com> Date: Wed, 28 May 2025 09:20:01 +0530 Subject: [PATCH 3/3] Create secret.yaml --- k8s/secret.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 k8s/secret.yaml diff --git a/k8s/secret.yaml b/k8s/secret.yaml new file mode 100644 index 0000000..3c1753b --- /dev/null +++ b/k8s/secret.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Secret +metadata: + name: db-credentials +type: Opaque +stringData: + # For PostgreSQL container + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "secret_password" + POSTGRES_DB: "messages" + # For Node.js application + DB_USER: "postgres" + DB_PASSWORD: "secret_password" + DB_NAME: "messages"