You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A full-stack PERN (PostgreSQL, Express, React, Node.js) task manager app deployed to AWS EC2 via a fully automated CI/CD pipeline using GitHub Actions and Docker.
12
+
A full-stack PERN (PostgreSQL, Express, React, Node.js) task manager app with two deployment modes — Docker Compose on AWS EC2 and Kubernetes via kind/k3s — both automated through GitHub Actions.
12
13
13
-
> **v2 of this project** — previously deployed with Jenkins. Migrated to GitHub Actions to remove the need for a separate CI server. See [task-manager-cicd-pipeline](https://github.com/kithupag/task-manager-cicd-pipeline) for the Jenkins version.
14
+
> **v2 of this project** — previously deployed with Jenkins. Migrated to GitHub Actions and extended with Kubernetes support. See [task-manager-cicd-pipeline](https://github.com/yourusername/task-manager-cicd-pipeline) for the Jenkins version.
│ │ └── secret.yaml # DB credentials as k8s Secret
102
+
│ ├── backend/
103
+
│ │ └── deployment.yaml # Backend Deployment + Service
104
+
│ └── frontend/
105
+
│ └── deployment.yaml # Frontend Deployment + NodePort Service
106
+
│
83
107
├── database.sql # Mounted into postgres on fresh deploy
84
-
├── docker-compose.yaml # Production compose — image tags pinned by pipeline
108
+
├── docker-compose.yaml # Local dev + EC2 compose deployment
85
109
└── README.md
86
110
```
87
111
88
112
---
89
113
90
-
## 🔧 Key Technical Decisions
114
+
## Key Technical Decisions
91
115
92
116
**GitHub Actions over Jenkins**
93
117
Jenkins requires a dedicated server running 24/7. GitHub Actions runs on GitHub's infrastructure — no server to maintain, no Docker socket to mount, no SSH keys to manage inside a container. The pipeline logic is identical, the operational overhead is zero.
@@ -119,7 +143,7 @@ All three containers report real status. Backend and frontend are checked via HT
119
143
120
144
---
121
145
122
-
## 🔄 Comparison with Jenkins Version
146
+
## Comparison with Jenkins Version
123
147
124
148
| | Jenkins Version | GitHub Actions Version |
125
149
|--|----------------|----------------------|
@@ -134,7 +158,7 @@ All three containers report real status. Backend and frontend are checked via HT
134
158
135
159
---
136
160
137
-
## 🛠️ Local Development Setup
161
+
## Local Development Setup
138
162
139
163
### Prerequisites
140
164
- Docker & Docker Compose
@@ -168,7 +192,7 @@ DB_NAME=todo_db
168
192
169
193
---
170
194
171
-
## 📡 API Endpoints
195
+
## API Endpoints
172
196
173
197
| Method | Endpoint | Description |
174
198
|--------|----------|-------------|
@@ -180,7 +204,7 @@ DB_NAME=todo_db
180
204
181
205
---
182
206
183
-
## ⚙️ Replicating This Pipeline
207
+
## Replicating This Pipeline
184
208
185
209
### GitHub Secrets Required
186
210
@@ -221,7 +245,23 @@ mkdir -p ~/task-manager
221
245
222
246
---
223
247
224
-
## 💡 Lessons Learned
248
+
## Kubernetes Concepts Used
249
+
250
+
**Deployment** — manages desired pod state. If a pod crashes Kubernetes automatically replaces it.
251
+
252
+
**Service** — provides stable DNS names (, , ) so pods can reach each other regardless of their changing IPs.
253
+
254
+
**PersistentVolumeClaim** — requests persistent storage for postgres so data survives pod restarts.
255
+
256
+
**Secret** — stores database credentials as base64-encoded values injected as environment variables — never hardcoded in manifests.
257
+
258
+
**NodePort Service** — exposes the frontend on port 30080 on every node, accessible from outside the cluster.
259
+
260
+
**Readiness + Liveness Probes** — readiness controls when traffic is sent to a pod, liveness restarts pods that stop responding. Both use HTTP checks.
261
+
262
+
---
263
+
264
+
## Lessons Learned
225
265
226
266
**From migrating Jenkins → GitHub Actions:**
227
267
- Pipeline concepts are identical across tools — triggers, jobs, steps, secrets. Learning one makes the next trivial.
@@ -230,29 +270,44 @@ mkdir -p ~/task-manager
230
270
- `needs:`in GitHub Actions is more explicit than Jenkins stage ordering — you declare job dependencies intentionally.
231
271
- A running container might be from an old image — always verify the tag matches your latest build number before debugging.
232
272
273
+
**From migrating to Kubernetes:**
274
+
- `kubectl apply`succeeds even if the pod crashes seconds later — always verify with `kubectl wait`
275
+
- Pod ready does not mean application ready — use `pg_isready` not just Kubernetes readiness probes
276
+
- `-it`flags don't work in CI pipelines — no TTY available, always remove from `kubectl exec` in automation
277
+
- Kubernetes service names are DNS — containers reach each other by service name, not IP
278
+
- `kubectl describe pod`is more useful than `kubectl logs` when a pod won't start
279
+
233
280
**Carried over from Jenkins version:**
234
281
- Always use relative URLs in React — `localhost` in fetch calls breaks in production
235
282
- `docker compose ps`showing `Up` is not the same as healthy — always add health checks
236
283
- Env vars with duplicate keys in JS objects silently use the last value — never hardcode credentials
237
284
238
285
---
239
286
240
-
## 📌 Improvements
287
+
## 📌
241
288
242
-
### ✅ Completed
243
-
- [x] Migrated from Jenkins to GitHub Actions
289
+
### Completed
290
+
- [x] Migrated from Jenkins to GitHub Actions — zero CI server overhead
244
291
- [x] Automated database table creation via `docker-entrypoint-initdb.d/`
245
292
- [x] Docker health checks on all services
246
293
- [x] Pinned image tags — exact build number deployed, never `:latest`
247
-
248
-
### 🔜 Up Next
249
-
- [ ] Provision EC2 infrastructure with Terraform
294
+
- [x] Kubernetes manifests for all three services
295
+
- [x] CI pipeline deploys to real kind cluster on every push
0 commit comments