docs: add week 5 and 6 update docs and update README

This commit is contained in:
ikechukwu Elizabeth
2026-04-29 04:28:55 +01:00
parent 6cbfd8a846
commit 63ded19e73
3 changed files with 255 additions and 7 deletions
+26 -7
View File
@@ -12,7 +12,7 @@ Built in public, one week at a time.
- Containerization with Docker
- CI/CD automation with GitHub Actions, Amazon ECR, and Docker Hub
- Infrastructure as Code with Terraform
- Cloud deployment on AWS
- Cloud deployment on AWS EC2
- Container orchestration with Kubernetes
- Monitoring and observability with Prometheus and Grafana
@@ -41,8 +41,8 @@ Built in public, one week at a time.
| 2 | Dockerize the backend | [Done](docs/week-2-update.md) |
| 3 | React frontend and Docker Compose | [Done](docs/week-3-update.md) |
| 4 | CI/CD pipeline with GitHub Actions, ECR and Docker Hub | [Done](docs/week-4-update.md) |
| 5 | Terraform infrastructure setup | Upcoming |
| 6 | Cloud deployment on AWS EC2 | Upcoming |
| 5 | Terraform infrastructure and CI/CD pipeline extension | [Done](docs/week-5-update.md) |
| 6 | Cloud deployment on AWS EC2 | [Done](docs/week-6-update.md) |
| 7 | Database integration | Upcoming |
| 8 | Kubernetes deployment | Upcoming |
| 9 | Monitoring with Prometheus and Grafana | Upcoming |
@@ -97,15 +97,34 @@ Frontend runs on http://localhost:80
## CI/CD Pipeline
Every pull request and push to `main` triggers a four-stage pipeline:
Every pull request and push to `main` triggers a five-stage pipeline:
```
lint -> unit-test -> build-and-integration-test -> publish
lint -> unit-test -> build-and-integration-test -> publish -> terraform-apply
```
The publish stage runs on merge to `main` only. Images are pushed to both Amazon ECR and Docker Hub, tagged with `latest` and the short Git SHA for traceability.
- `terraform-plan` runs on every pull request — shows exactly what infrastructure will change before merging
- `terraform-apply` runs on merge to `main` — infrastructure is provisioned by the pipeline, never from a local machine
- The `publish` stage pushes images to both Amazon ECR and Docker Hub, tagged with `latest` and the short Git SHA
AWS authentication uses OIDC - no static credentials stored in GitHub secrets.
AWS authentication uses OIDC — no static credentials stored in GitHub secrets.
---
## Infrastructure
All infrastructure is provisioned with Terraform and lives in `infra/terraform/`.
| Resource | Details |
|---|---|
| VPC | Custom VPC with public subnet |
| Networking | Internet gateway, route tables |
| Security | Security groups with least-privilege rules |
| Compute | EC2 t3.micro running Amazon Linux 2023 |
| IAM | Instance profile with SSM and ECR permissions |
| State | S3 remote backend with native state locking |
EC2 instances configure themselves on first boot via a user data script — Docker is installed, images are pulled from ECR, and containers start automatically. No SSH required. All access via AWS SSM Session Manager.
---
+119
View File
@@ -0,0 +1,119 @@
# Week 5 — Terraform Infrastructure and CI/CD Pipeline Extension
## What I Built
Week 5 added two major pieces: full AWS infrastructure provisioned with Terraform, and an extended CI/CD pipeline that owns infrastructure changes end to end.
---
## Terraform Bootstrap
Before the main infrastructure, I created a bootstrap layer in `infra/terraform/bootstrap/` to set up remote state storage.
- S3 bucket with versioning, AES256 encryption, and public access blocked
- Native state locking using `use_lockfile = true` — available from Terraform 1.10 onwards
- No DynamoDB table required — Terraform writes a `.tflock` file directly to S3
This is the modern approach. One less AWS resource to manage, same production-grade protection.
---
## Main Infrastructure
All resources live in `infra/terraform/` and are split across focused files:
**`vpc.tf`**
- Custom VPC (`10.0.0.0/16`)
- Public subnet (`10.0.1.0/24`) in `us-east-1a`
- Internet gateway attached to the VPC
- Route table with a default route to the internet gateway
- Route table association to the public subnet
**`security-group.tf`**
- Security group allowing inbound HTTP (port 80) from anywhere
- All outbound traffic allowed
- Port 22 (SSH) intentionally closed — access via SSM only
**`iam.tf`**
- IAM role for EC2 with two managed policies attached:
- `AmazonSSMManagedInstanceCore` — enables SSM Session Manager access
- `AmazonEC2ContainerRegistryReadOnly` — allows pulling images from ECR
- Instance profile wrapping the role
**`ec2.tf`**
- Data source querying AWS at plan time for the latest Amazon Linux 2023 AMI — no hardcoded AMI ID
- EC2 `t3.micro` instance in the public subnet
- 20GB encrypted `gp3` root volume
- User data script that runs on first boot:
- Installs Docker and starts the service
- Authenticates to ECR
- Pulls backend and frontend images
- Starts both containers with `--restart unless-stopped`
**`outputs.tf`**
- Public IP of the EC2 instance — printed after every apply
---
## CI/CD Pipeline Extension
Added two new jobs to `.github/workflows/ci-cd.yml`:
**`terraform-plan`**
- Triggers on every pull request
- Runs `terraform init` and `terraform plan`
- Shows exactly what will change before any merge
- Depends on `build-and-integration-test` passing first
**`terraform-apply`**
- Triggers on merge to `main` only
- Runs `terraform init` and `terraform apply -auto-approve`
- Infrastructure is created by the pipeline — never from a local machine
Both jobs authenticate to AWS using the existing OIDC role. No static credentials.
---
## Production Discipline
The local machine provisions once to validate everything works. Then `terraform destroy` hands control to the pipeline permanently. From that point forward, infrastructure changes only happen through Git — a PR shows the plan, a merge triggers the apply.
---
## Architecture After Week 5
```
GitHub
│
├── Pull Request → terraform-plan (shows what will change)
│
└── Merge to main → lint → unit-test → build → publish → terraform-apply
│
AWS Infrastructure
VPC / Subnet / SG
IAM / EC2
```
---
## Files Added
```
infra/terraform/
├── vpc.tf
├── security-group.tf
├── iam.tf
├── ec2.tf
└── outputs.tf
.github/workflows/ci-cd.yml (terraform-plan and terraform-apply jobs added)
```
---
## Screenshots
See `docs/week-05/` for:
- Terraform plan output
- Terraform apply output showing 13 resources created
- GitHub Actions pipeline with all jobs passing
+110
View File
@@ -0,0 +1,110 @@
# Week 6 — Cloud Deployment on AWS EC2
## What I Built
Week 6 took everything built in Week 5 and made it live. TaskFlow — the full-stack Node.js and React application — is now running on AWS EC2, deployed automatically by the CI/CD pipeline with zero manual server setup.
---
## How Deployment Works
When a PR merges to `main`, the pipeline:
1. Runs lint, unit tests, and integration tests
2. Builds Docker images and pushes them to Amazon ECR
3. Runs `terraform apply` — creates or updates infrastructure
4. The EC2 instance boots and runs a user data script automatically
The user data script handles everything on first boot:
```
1. Update the system packages
2. Install Docker and start the service
3. Wait for Docker to be fully ready
4. Add ec2-user to the docker group
5. Install AWS CLI
6. Authenticate to ECR using the IAM instance profile
7. Pull task-backend:latest from ECR
8. Pull task-frontend:latest from ECR
9. Start backend container on port 3000 (restart unless stopped)
10. Wait for backend to be ready
11. Start frontend container on port 80 (restart unless stopped)
```
No SSH. No manual commands. The instance configures itself.
---
## Access Method
All server access is through **AWS SSM Session Manager** — not SSH.
- Port 22 is closed on the security group
- The EC2 IAM role has `AmazonSSMManagedInstanceCore` attached
- Sessions are opened via the AWS console or AWS CLI
This is the production-standard approach. No key pairs to manage, no inbound SSH exposure, full audit trail of every session in AWS CloudTrail.
---
## What Runs on EC2
| Container | Image Source | Port | Restart Policy |
|---|---|---|---|
| task-backend | Amazon ECR | 3000 (internal) | unless-stopped |
| task-frontend | Amazon ECR | 80 (public) | unless-stopped |
The frontend container runs Nginx, which serves the React build and proxies `/api` requests to the backend container.
---
## Architecture After Week 6
```
Internet
│
▼
EC2 Public IP :80
│
▼
task-frontend (Nginx)
│
├── Serves React frontend (/)
│
└── Proxies /api requests → task-backend :3000
│
▼
Express API
(in-memory store)
```
---
## Key Decisions
**Why no Docker Compose on EC2?**
The containers are run directly with `docker run` in the user data script. Docker Compose adds a dependency that needs to be installed separately on Amazon Linux 2023. Direct `docker run` with `--link` keeps the bootstrap simple and reliable.
**Why `--restart unless-stopped`?**
If the EC2 instance reboots, Docker restarts the containers automatically. The application comes back online without any intervention.
**Why ECR and not Docker Hub?**
ECR is private, in the same AWS region as the EC2 instance, and authenticated via IAM — no credentials to manage. Pulls are fast and free within the same region.
---
## Files Changed
```
infra/terraform/ec2.tf (user data script updated — sleep added for Docker readiness)
```
---
## Screenshots
See `docs/week-06/` for:
- TaskFlow running live in the browser at the EC2 public IP
- SSM Session Manager connection to the EC2 instance
- Docker containers running on the instance (`docker ps`)
- GitHub Actions pipeline showing full run with terraform-apply