This GitHub Actions pipeline implements a comprehensive CI/CD workflow for a Node.js application with Docker containerization and AWS ECR integration. The pipeline follows a multi-stage approach: preparation, building, containerization, promotion, and deployment.
The pipeline consists of six sequential jobs that work together to deliver code from repository to production:
prepare → config_aws (parallel)
↓
build
↓
docker
↓
promote
↓
deploy
Purpose: Extract and store the application version for use across all subsequent jobs.
Steps:
- Checks out the repository code
- Executes
version_extract.shto read version frompackage.json - Creates a
version.yamlfile containing the extracted version - Uploads the version file as a GitHub Actions artifact for downstream jobs
Runner: ubuntu-latest
Purpose: Establish AWS credentials and authenticate with Amazon ECR.
Steps:
- Configures AWS credentials using repository secrets
- Authenticates with Amazon ECR to enable Docker image push/pull operations
Runner: ubuntu-latest
Note: This job runs independently but its purpose appears redundant since other jobs configure AWS credentials individually.
Purpose: Build the Node.js application and create a distributable artifact.
Dependencies: prepare
Steps:
- Checks out repository code
- Downloads the version artifact from the prepare job
- Loads version into environment variables using
load_version.sh - Sets up Node.js 20 with npm caching
- Installs application dependencies
- Packages the application into a versioned tarball using
package_artifact.sh - Uploads the packaged artifact for the docker job
Artifact naming convention: cicd-aseel-{VERSION}-{SHORT_SHA}.tgz
Runner: ubuntu-latest
Purpose: Build and push the Docker image to AWS ECR with a test tag.
Dependencies: build
Steps:
- Checks out repository code
- Downloads version and build artifacts
- Loads version into environment variables
- Extracts the application tarball using
extract_artifact.sh - Configures AWS credentials and logs into ECR
- Builds Docker image using the Dockerfile
- Pushes image to ECR with tag format:
{VERSION}-test
Image Tag Format: {ECR_URI}/cicd-aseel:{VERSION}-test
Runner: ubuntu-latest
Purpose: Promote the tested Docker image by removing the test suffix and creating a production-ready tag.
Dependencies: docker
Steps:
- Checks out repository code
- Configures AWS credentials and logs into ECR
- Executes
promote.shscript which:- Queries ECR for the latest image with a "test" tag
- Pulls that image locally
- Creates a new tag by removing the "-test" suffix
- Pushes the promoted image back to ECR
- Outputs the
BASE_TAGfor use in deployment
Example: 1.0.0-test → 1.0.0
Outputs:
BASE_TAG: The production version tag without "-test" suffix
Runner: ubuntu-latest
Purpose: Deploy the promoted Docker image to the target server.
Dependencies: promote
Steps:
- Checks out repository code
- Downloads version artifact
- Loads version into environment variables
- SSH into the target server and:
- Authenticates with AWS ECR
- Pulls the promoted Docker image using the
BASE_TAGfrom the promote job - Stops and removes any existing container named "nodeapp"
- Runs a new container with the updated image on port 3000
Container Configuration:
- Name:
nodeapp - Port Mapping:
3000:3000 - Mode: Detached (
-d)
Runner: ubuntu-latest
Extracts the version number from package.json and creates a version.yaml file. This ensures version consistency across all pipeline stages.
Process:
- Reads version from
package.jsonusingjq - Sets
VERSIONenvironment variable - Creates
version.yamlwith the version string
Loads the version from version.yaml into the GitHub Actions environment.
Process:
- Parses
version.yamlto extract the version value - Sets
VERSIONenvironment variable for the current job
Creates a compressed tarball of the application code.
Process:
- Generates artifact name:
cicd-aseel-{VERSION}-{SHORT_SHA}.tgz - Creates temporary directory structure
- Copies all files except temporary directories, artifacts, and git folders
- Creates compressed tarball in
artifacts/directory - Cleans up temporary files
Excluded from packaging:
artifact-temp/artifacts/.git/.github/
Extracts the packaged application artifact for Docker image building.
Process:
- Creates an
app/directory (mentioned in the Dockerfile) - Identifies the correct artifact file matching the version pattern
- Extracts the tarball contents into the app directory
Handles the promotion of test images to production-ready images.
Process:
- Queries AWS ECR for images in the
cicd-aseelrepository - Filters for images with tags containing "test"
- Identifies the most recently pushed test image using
jq - Pulls the image locally
- Creates a new tag by removing the "-test" suffix
- Pushes the promoted image back to ECR
- Exports
BASE_TAGto$GITHUB_ENVand$GITHUB_OUTPUT
Environment Variables Required:
AWS_REGION: AWS region for ECRECR_URI: ECR repository URI
Outputs:
BASE_TAG: Production version tag (exported for deploy job)
Usage:
chmod +x common/promote.sh
./common/promote.shThe pipeline requires the following GitHub repository secrets:
| Secret Name | Description |
|---|---|
AWS_ACCESS_KEY |
AWS access key ID for ECR access |
AWS_SECRET_ACCESS_KEY |
AWS secret access key for ECR access |
AWS_REGION |
AWS region where ECR repository exists |
ECR_URI |
URI of the ECR repository |
HOST |
Target deployment server IP |
HOST_NAME |
SSH username for the deployment server |
KEY |
SSH private key for server authentication |
The pipeline implements a two-stage tagging approach:
- Test Stage: Images are tagged as
{VERSION}-testafter building - Production Stage: After validation, the
-testsuffix is removed, creating production tags like{VERSION}
Example Flow:
Build → 1.2.3-test
Promote → 1.2.3
This strategy provides a clear separation between testing and production-ready images while maintaining traceability through version numbers.
- AWS ECR Repository: Repository named
cicd-aseelmust exist - Target Server: Server must have:
- Docker installed
- AWS CLI installed and configured
- SSH access enabled
- GitHub Secrets: All required secrets configured in repository settings