Skip to content

Commit 3ecbcc3

Browse files
committed
docs: rewrite README to lead with pipeline architecture and design decisions
1 parent 8da414d commit 3ecbcc3

1 file changed

Lines changed: 61 additions & 103 deletions

File tree

README.md

Lines changed: 61 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,99 @@
1-
# GitHub Actions EC2 Pipeline
1+
# github-actions-ec2-pipeline
22

3-
A simple Node.js application with a CI/CD pipeline using GitHub Actions to deploy to an EC2 instance.
3+
> GitHub Actions pipeline that builds, tests, versions, and deploys a Node.js app
4+
> to AWS EC2 — zero manual steps after initial setup.
45
5-
This project is a demonstration of how to set up a full CI/CD pipeline for a Node.js application. It includes a simple Express application, a set of tests, and a GitHub Actions workflow that automatically builds, tests, and deploys the application to an AWS EC2 instance.
6+
[![CI Pipeline](https://github.com/darestack/github-actions-ec2-pipeline/actions/workflows/ci.yml/badge.svg)](https://github.com/darestack/github-actions-ec2-pipeline/actions/workflows/ci.yml)
67

7-
## Features
8+
---
89

9-
- **Node.js Express Application:** A simple REST API with a few endpoints.
10-
- **CI/CD Pipeline:** A GitHub Actions workflow that automates the entire build, test, and deployment process.
11-
- **Zero-Downtime Deployment:** The deployment script uses `pm2 reload` to ensure that the application is always available, even during deployments.
12-
- **Rollback Mechanism:** The deployment script automatically creates a backup of the previous release. If a deployment fails, it automatically rolls back to the previous version.
13-
- **Automated Versioning and Releases:** The pipeline automatically bumps the version number, creates a tag, and generates a GitHub release.
14-
- **Health Checks:** The CI/CD pipeline includes a health check step to ensure that the application is running correctly after a deployment.
15-
- **Monitoring:** A separate GitHub Actions workflow runs every 5 minutes to check the health of the application and sends a notification if it's down.
10+
## Pipeline Overview
1611

17-
## CI/CD Pipeline
18-
19-
The CI/CD pipeline is split into two workflows: `ci.yml` for Continuous Integration and `release.yml` for Continuous Deployment.
20-
21-
### `ci.yml` - Continuous Integration
22-
23-
This workflow runs on every push to the `main`, `development`, and `feature/*` branches. It consists of two jobs:
24-
25-
1. **`build-and-test`:** This job builds the application and runs the test suite.
26-
2. **`bump-version`:** This job runs only on the `main` branch after the `build-and-test` job succeeds. It automatically bumps the patch version of the application and creates a new Git tag (e.g., `v1.0.1`). The tagging step uses a Personal Access Token stored as `REPO_ACCESS_TOKEN`.
27-
28-
### `release.yml` - Continuous Deployment
29-
30-
This workflow is triggered whenever a new tag is pushed to the repository (tags starting with 'v\*'). It consists of two jobs:
31-
32-
1. **`deploy`:**
33-
34-
- Checks out the code
35-
- Sets up deployment environment variables from GitHub secrets
36-
- Creates a deployment package (tar.gz)
37-
- Deploys to EC2 using SSH:
38-
- Copies the package to /tmp/
39-
- Executes the deployment script at /var/www/app/scripts/deploy.sh
40-
41-
2. **`create-release`:**
42-
- Runs after successful deployment
43-
- Creates a GitHub Release with the tag name using `GITHUB_TOKEN` and `permissions: contents: write`
44-
45-
To trigger this workflow:
46-
47-
```bash
48-
git tag v1.0.0
49-
git push origin v1.0.0
5012
```
51-
52-
### Deployment Diagram
53-
54-
```mermaid
55-
graph TD
56-
A[Push to main] --> B{CI Workflow};
57-
B --> C[Build and Test];
58-
C --> D[Bump Version & Create Tag];
59-
D --> E{Release Workflow};
60-
E --> F[Deploy to Production];
61-
F --> G[Create GitHub Release];
13+
Push to main / feature branch
14+
15+
└── ci.yml
16+
├── build-and-test: npm ci → Jest tests → pass/fail gate
17+
└── bump-version (main only): patch version bump → git tag v1.x.x
18+
19+
└── release.yml (triggered by tag v*)
20+
├── deploy: tar.gz → SCP to EC2 → deploy.sh (PM2 reload, atomic symlink swap)
21+
└── create-release: GitHub Release with changelog
6222
```
6323

64-
## Technologies Used
24+
### Key Design Decisions
6525

66-
- **Node.js 20.x (LTS)**
67-
- **Express**
68-
- **Jest** for testing
69-
- **GitHub Actions** for CI/CD
70-
- **AWS EC2** for hosting
71-
- **PM2** for process management
72-
- **Bootstrap** for the frontend
26+
| Decision | Implementation | Why |
27+
|---|---|---|
28+
| **Zero-downtime deploy** | `pm2 reload` + atomic symlink swap (`current → release-timestamp`) | App stays up during deployment; rollback is a symlink change |
29+
| **Auto-rollback** | `deploy.sh` keeps previous release; restores on failure | No manual intervention if deploy breaks the app |
30+
| **Automatic versioning** | `bump-version` job creates `v1.x.x` tags on every merge to main | Release history is automatic; no manual tagging |
31+
| **Health check monitoring** | Scheduled workflow every 5 min; creates a GitHub Issue on failure | On-call alert without a third-party service |
32+
| **Separate CI / CD workflows** | `ci.yml` + `release.yml` split by tag trigger | CD only runs on verified, tagged builds — not every push |
7333

74-
## Local Setup
34+
---
7535

76-
1. Clone the repository:
36+
## Workflows
7737

78-
```bash
79-
git clone https://github.com/daretechie/github-actions-ec2-pipeline.git
80-
```
38+
### `ci.yml` — Continuous Integration
39+
Triggers: push to `main`, `development`, `feature/*` branches + all PRs
8140

82-
2. Install the dependencies:
41+
1. **`build-and-test`**: `npm ci` → Jest test suite → pass required before merge
42+
2. **`bump-version`** (main only): increments patch version, pushes `v1.x.x` tag — triggers `release.yml`
8343

84-
```bash
85-
npm install
86-
```
44+
### `release.yml` — Continuous Deployment
45+
Triggers: new tag matching `v*`
8746

88-
3. Start the application:
47+
1. **`deploy`**: packages build → SCP to EC2 → runs `/var/www/app/scripts/deploy.sh`
48+
- Installs dependencies in release dir → atomic symlink `current``pm2 reload`
49+
- On failure: restores previous symlink → `pm2 reload` (auto-rollback)
50+
2. **`create-release`**: publishes GitHub Release with tag name
8951

90-
```bash
91-
npm start
92-
```
52+
### `health-check.yml` — Uptime Monitoring
53+
Runs every 5 minutes. Hits `/api/health`. Creates a GitHub Issue if the check fails.
9354

94-
4. The application will be available at `http://localhost:3000`.
55+
---
9556

96-
## Configuration
57+
## Required GitHub Secrets
9758

98-
The CI/CD pipeline requires the following secrets to be set in the GitHub repository:
59+
| Secret | Purpose |
60+
|---|---|
61+
| `PROD_EC2_HOST` | Production EC2 hostname or IP |
62+
| `PROD_EC2_USER` | SSH username |
63+
| `PROD_EC2_KEY` | Private SSH key (PEM format) |
64+
| `REPO_ACCESS_TOKEN` | PAT with `repo` scope — needed for `bump-version` to push tags |
9965

100-
- `PROD_EC2_HOST`: The hostname or IP address of the production EC2 instance.
101-
- `PROD_EC2_USER`: The username for the production EC2 instance.
102-
- `PROD_EC2_KEY`: The private SSH key for the production EC2 instance.
103-
- `DEV_EC2_HOST`: The hostname or IP address of the development EC2 instance.
104-
- `DEV_EC2_USER`: The username for the development EC2 instance.
105-
- `DEV_EC2_KEY`: The private SSH key for the development EC2 instance.
106-
- `REPO_ACCESS_TOKEN`: A Personal Access Token (classic) with `repo` scope. This is required for the `bump-version` job to create tags that trigger `release.yml`.
66+
Also set: **Actions → General → Workflow permissions → Read and write** (allows built-in token to create releases and issues).
10767

108-
Optional:
109-
- `HEALTHCHECK_ISSUE_TOKEN`: A Personal Access Token (classic) with `repo` scope if you prefer creating issues from the scheduled health-check with a PAT instead of the built-in token.
68+
---
11069

111-
Repository Settings → Actions → General:
112-
- Set Workflow permissions to “Read and write permissions” to allow the built-in token to create releases and issues.
70+
## Application Stack
11371

114-
## Health Check and Monitoring
72+
`Node.js 20 LTS` · `Express` · `Jest` · `PM2` · `GitHub Actions` · `AWS EC2`
11573

116-
- Health endpoint: `/api/health`.
117-
- Workflow: `.github/workflows/health-check.yml` runs every 5 minutes and can be run manually via “Run workflow”.
118-
- On failure, it creates an issue in the repository (requires write permissions as noted above).
74+
---
11975

120-
## Deployment and Access
76+
## Local Setup
12177

122-
- Zero-downtime releases with PM2: the deploy script runs the app via the stable symlink `current/src/server.js` and swaps releases atomically.
123-
- The app listens on `0.0.0.0:3000`. You can access it at:
124-
- `http://YOUR_EC2_PUBLIC_IP:3000/`
125-
- `http://YOUR_EC2_PUBLIC_IP:3000/api/health`
126-
- If you prefer port 80/443, add an Nginx reverse proxy in front of the app. Example server block (HTTP only):
78+
```bash
79+
git clone https://github.com/darestack/github-actions-ec2-pipeline.git
80+
cd github-actions-ec2-pipeline
81+
npm install
82+
npm test
83+
npm start
84+
# → http://localhost:3000
85+
# → http://localhost:3000/api/health
86+
```
12787

88+
To add Nginx as a reverse proxy on the EC2 instance (port 80 → 3000):
12889
```nginx
12990
server {
13091
listen 80;
13192
server_name _;
132-
13393
location / {
13494
proxy_pass http://127.0.0.1:3000;
13595
proxy_set_header Host $host;
13696
proxy_set_header X-Real-IP $remote_addr;
137-
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
138-
proxy_set_header X-Forwarded-Proto $scheme;
13997
}
14098
}
14199
```

0 commit comments

Comments
 (0)