This output provides a comprehensive CI/CD pipeline configuration for your "Test Project Name" using GitHub Actions, tailored for a Node.js application and deployment to AWS. The pipeline incorporates standard stages including linting, testing, building (Docker image), pushing to Amazon Elastic Container Registry (ECR), and deploying to Amazon Elastic Container Service (ECS).
Below is the complete YAML configuration for your GitHub Actions workflow. You should save this file as .github/workflows/main.yml in your project repository.
---
### 2. Explanation of Pipeline Stages
The generated pipeline is structured into logical stages (jobs) to ensure code quality, build integrity, and reliable deployment.
* **`lint`**:
* **Purpose**: Enforces code style and catches potential errors early.
* **Actions**: Checks out the repository, sets up Node.js, installs project dependencies, and runs the `npm run lint` command (you must have a `lint` script defined in your `package.json`).
* **`test`**:
* **Purpose**: Verifies the application's functionality and prevents regressions.
* **Actions**: Runs after `lint` completes successfully. It checks out the repository, sets up Node.js, installs dependencies, and executes the `npm test` command (you must have a `test` script defined in your `package.json`).
* **`build_and_push_docker`**:
* **Purpose**: Creates a Docker image of your Node.js application and pushes it to Amazon ECR.
* **Actions**: Runs only on pushes to the `main` branch after `test` has passed.
* Configures AWS credentials using GitHub Secrets.
* Logs into ECR.
* Builds a Docker image using the `Dockerfile` in your repository root.
* Tags the image with the Git SHA and `latest`.
* Pushes both tagged images to your specified ECR repository.
* **Output**: Exports the full ECR image URI for use in the deployment stage.
* **`deploy_to_aws`**:
* **Purpose**: Deploys the newly built Docker image to your AWS ECS cluster.
* **Actions**: Runs only on pushes to the `main` branch after `build_and_push_docker` has completed.
* Configures AWS credentials.
* Downloads your existing ECS task definition (`.aws/task-definition.json`) and updates the image URI for the specified container with the newly pushed ECR image.
* Deploys the updated task definition to the specified ECS service and cluster, waiting for the service to stabilize.
---
### 3. AWS Setup Requirements
Before running this pipeline, you need to configure the following in your AWS account and GitHub repository:
1. **AWS IAM User/Role**:
* Create an IAM user or role with programmatic access.
* Attach policies that grant necessary permissions:
* **ECR**: `AmazonEC2ContainerRegistryPowerUser` (or more restrictive permissions for `ecr:GetAuthorizationToken`, `ecr:BatchCheckLayerAvailability`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`).
* **ECS**: `AmazonECS_FullAccess` (or more restrictive permissions for `ecs:DescribeServices`, `ecs:UpdateService`, `ecs:RegisterTaskDefinition`, `ecs:DescribeTaskDefinition`).
* **S3 (optional)**: If your `task-definition.json` is stored in S3, you'll need `s3:GetObject` permission.
* Record the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
2. **GitHub Repository Secrets**:
* In your GitHub repository, navigate to `Settings > Secrets and variables > Actions > New repository secret`.
* Add the following secrets:
* `AWS_ACCESS_KEY_ID`: Your AWS IAM access key ID.
* `AWS_SECRET_ACCESS_KEY`: Your AWS IAM secret access key.
3. **AWS ECR Repository**:
* Create an ECR repository with the name specified in `ECR_REPOSITORY` (e.g., `test-project-name`).
4. **AWS ECS Cluster, Service, and Task Definition**:
* Set up an ECS cluster (e.g., `test-project-cluster`).
* Create an ECS service (e.g., `test-project-service`) within that cluster.
* Define an ECS task definition (e.g., `test-project-task-definition`).
* **Crucially**: You need a `task-definition.json` file in your repository (as specified in the `deploy_to_aws` job: `.aws/task-definition.json`). This file should contain a placeholder for the image, which the `aws-actions/amazon-ecs-render-task-definition` action will update.
* Example `task-definition.json` (ensure `containerDefinitions[0].name` matches `CONTAINER_NAME` env var):
env section at the top of the YAML file with your specific NODE_VERSION, AWS_REGION, ECR_REPOSITORY, ECS_CLUSTER, ECS_SERVICE, ECS_TASK_DEFINITION, and CONTAINER_NAME.Dockerfile: If you don't have one, create a Dockerfile in your repository root..aws/task-definition.json: Ensure this file exists and is correctly configured for your ECS setup.package.json Scripts: Verify npm run lint and npm test commands are correctly defined and work locally.AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to your GitHub repository secrets.main: Once configured, push your changes to the main branch to trigger the pipeline.deploy jobs for staging, production, etc., triggered by different branches or manual approvals, each with their own AWS credentials and environment variables.npm test command correctly invokes your chosen testing framework (e.g., Jest, Mocha).npm run lint correctly invokes your chosen linter (e.g., ESLint).The "DevOps Pipeline Generator" workflow has successfully generated a comprehensive CI/CD pipeline configuration for your Node.js project, tailored for GitHub Actions and deployment to AWS ECS. This output provides the complete YAML configuration, along with necessary supporting files and detailed instructions to get your pipeline up and running.
Project Name: Test Project Name
CI Platform: GitHub Actions
Language: Node.js
Deployment Target: AWS (specifically AWS ECR for Docker images and AWS ECS for container orchestration)
Pipeline Stages: Linting, Testing, Docker Build & Push, ECS Deployment
This pipeline ensures that every code change undergoes automated quality checks, is packaged into a Docker image, pushed to Amazon Elastic Container Registry (ECR), and then deployed to Amazon Elastic Container Service (ECS).
Below is the complete GitHub Actions workflow configuration. Save this content as .github/workflows/main.yml in the root of your project repository.
name: Test Project Name CI/CD
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch: # Allows manual triggering of the workflow
env:
AWS_REGION: us-east-1 # Default AWS region for your resources
ECR_REPOSITORY: test-project-name # Name of your Amazon ECR repository
ECS_CLUSTER: test-project-name-cluster # Name of your Amazon ECS cluster
ECS_SERVICE: test-project-name-service # Name of your Amazon ECS service
ECS_TASK_DEFINITION_PATH: .aws/task-definition.json # Path to your base ECS task definition file
CONTAINER_NAME: test-project-name-container # Name of the container defined in your task definition
jobs:
lint-and-test:
name: Lint and Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20' # Specify your Node.js version
cache: 'npm' # Cache npm dependencies
- name: Install dependencies
run: npm ci
- name: Run Lint
run: npm run lint # Assumes a 'lint' script in package.json (e.g., using ESLint)
- name: Run Tests
run: npm test # Assumes a 'test' script in package.json (e.g., using Jest)
build-and-push-docker:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: lint-and-test # This job depends on lint-and-test succeeding
outputs:
# Output the path to the rendered task definition for the next job
rendered_task_definition_path: rendered-task-definition.json
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and Push Docker Image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }} # Use Git SHA as image tag for uniqueness
run: |
echo "Building Docker image: $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
echo "Pushing Docker image to ECR..."
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "Docker image pushed successfully."
- name: Generate Task Definition
id: generate-task-definition
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ github.workspace }}/${{ env.ECS_TASK_DEFINITION_PATH }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
- name: Save rendered task definition
run: echo "${{ steps.generate-task-definition.outputs.task-definition }}" > rendered-task-definition.json
- name: Upload rendered task definition as artifact
uses: actions/upload-artifact@v4
with:
name: task-definition-artifact
path: rendered-task-definition.json
deploy-to-ecs:
name: Deploy to AWS ECS
runs-on: ubuntu-latest
needs: build-and-push-docker # This job depends on build-and-push-docker succeeding
environment: production # Use a GitHub Environment for deployment protection rules
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Download rendered task definition artifact
uses: actions/download-artifact@v4
with:
name: task-definition-artifact
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: rendered-task-definition.json # Path to the downloaded artifact file
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true # Wait for the ECS service to reach a stable state
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Required for wait-for-service-stability
The generated pipeline consists of three sequential jobs, ensuring a robust and reliable deployment process:
lint-and-test* Purpose: Ensures code quality, adherence to style guidelines, and functional correctness.
* Steps:
* Checkout code: Retrieves your project's source code.
* Setup Node.js: Configures the specified Node.js environment and caches npm dependencies for faster subsequent runs.
* Install dependencies: Installs all project dependencies using npm ci (clean install, recommended for CI).
* Run Lint: Executes your project's linting script (e.g., eslint .). Action Required: Ensure you have an npm run lint script defined in your package.json.
* Run Tests: Executes your project's test suite (e.g., jest). Action Required: Ensure you have an npm test script defined in your package.json.
* Failure Impact: If linting or testing fails, the pipeline stops, preventing faulty code from proceeding.
build-and-push-docker* Purpose: Creates a Docker image of your application and pushes it to Amazon ECR.
* Dependencies: Runs only if lint-and-test succeeds.
* Steps:
* Checkout code: Retrieves your project's source code.
* Configure AWS Credentials: Sets up AWS authentication using secrets.
* Login to Amazon ECR: Authenticates the Docker client with your ECR registry.
* Build and Push Docker Image: Builds the Docker image based on your Dockerfile and pushes it to the specified ECR repository, tagged with the Git SHA for unique versioning.
* Generate Task Definition: Uses the aws-actions/amazon-ecs-render-task-definition action to dynamically update your base ECS task definition with the newly pushed Docker image's URI.
* Save rendered task definition: Saves the dynamically generated task definition to a file.
* Upload rendered task definition as artifact: Makes the generated task definition available for the subsequent deploy-to-ecs job.
* Failure Impact: If the Docker image cannot be built or pushed, the deployment process is halted.
deploy-to-ecs* Purpose: Deploys the new Docker image by updating your Amazon ECS service.
* Dependencies: Runs only if build-and-push-docker succeeds.
* Steps:
* Configure AWS Credentials: Sets up AWS authentication.
* Download rendered task definition artifact: Retrieves the task definition generated in the previous job.
* Deploy Amazon ECS task definition: Updates your ECS service with the new task definition, triggering a rolling update of your application instances. The wait-for-service-stability option ensures the deployment is successful before the job completes.
* Environment: Uses a GitHub production environment, allowing you to enforce deployment protection rules (e.g., manual approval, specific branch deployment).
Before enabling this GitHub Actions workflow, you need to configure your AWS environment and GitHub repository:
* AWS Account & Region: Ensure you have an AWS account and have specified your desired AWS_REGION in the workflow's env section (e.g., us-east-1).
* IAM User/Role for GitHub Actions:
* Create an IAM user or, preferably, an IAM Role for GitHub Actions (using OIDC for enhanced security).
* Grant this user/role the necessary permissions for ECR and ECS:
* ecr:GetAuthorizationToken
* ecr:BatchCheckLayerAvailability
* ecr:GetDownloadUrlForLayer
* ecr:GetRepositoryPolicy
* ecr:DescribeRepositories
* ecr:ListImages
* ecr:DescribeImages
* ecr:BatchGetImage
* ecr:InitiateLayerUpload
* ecr:UploadLayerPart
* ecr:CompleteLayerUpload
* ecr:PutImage
* ecs:DescribeServices
* ecs:UpdateService
* ecs:DescribeTaskDefinition
* ecs:RegisterTaskDefinition
* iam:PassRole (for the task execution role and task role)
* ECR Repository: Create an ECR repository named test-project-name (or whatever you set for ECR_REPOSITORY in the workflow).
* ECS Cluster & Service: Create an ECS Cluster (test-project-name-cluster) and an ECS Service (test-project-name-service) within that cluster.
* ECS Task Definition File (.aws/task-definition.json):
* Create a directory .aws/ in your project root.
* Create a file .aws/task-definition.json with your base ECS task definition. This file will be updated by the pipeline.
* Important: Replace YOUR_AWS_ACCOUNT_ID with your actual AWS account ID and ensure the image field in containerDefinitions uses a placeholder like YOUR_ECR_REGISTRY/test-project-name:latest as it will be dynamically replaced by the pipeline.
* AWS Credentials Secrets:
* Go to your GitHub repository settings -> Secrets and variables -> Actions -> Repository secrets.
* Add two new repository secrets:
* AWS_ACCESS_KEY_ID: Your AWS IAM user/role access key ID.
* AWS_SECRET_ACCESS_KEY: Your AWS IAM user/role secret access key.
* Security Best Practice: Consider using OpenID Connect (OIDC) with GitHub Actions for more secure, keyless authentication to AWS.
* GitHub Environment (Optional but Recommended):
* Go to your GitHub repository settings -> Environments.
* Create a new environment named production.
* You can add protection rules here, such as "Required reviewers" or "Wait timer," to control deployments to production.
* Dockerfile: Create a Dockerfile in the root of your project.
* package.json: Ensure your package.json includes lint and test scripts.
To make the generated pipeline immediately actionable, here are examples of the Dockerfile, .aws/task-definition.json, and package.json that the pipeline expects.
Dockerfile (root of your project)
# Use a slim Node.js base image for building
FROM node:20-alpine AS builder
# Set working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json to leverage Docker cache
COPY package*.json ./
# Install production dependencies
RUN npm ci --only=production
# Copy the rest of your application code
COPY . .
# If your Node.js app has a build step (e.g., for React or TypeScript), uncomment and adjust:
# RUN npm run build
# Expose the port your application listens on (e.g., for an Express app)
EXPOSE 3000
# Command to run your application
CMD ["node", "src/index.js"]
.aws/task-definition.json (inside .aws/ directory)
{
"family": "test-project-name-task",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskExecutionRole",
"taskRoleArn": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "test-project-name-container",
"image": "YOUR_ECR_REGISTRY/test-project-name:latest",
"portMappings": [
{
"containerPort": 3000,
"hostPort": 3000,
"protocol": "tcp"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/test-project-name-logs",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"environment": [
{
"name": "NODE_ENV",
"value": "production"
}
]
}
]
}
Important Customizations for task-definition.json:
YOUR_AWS_ACCOUNT_ID with your actual AWS account ID.executionRoleArn and taskRoleArn with the ARNs of your ECS task execution and task roles. These roles grant permissions for ECS to pull images, send logs, and for your application to interact with other AWS services.cpu and memory based on your application's resource requirements.containerPort matches the EXPOSE port in your Dockerfile and the port your application listens on.logConfiguration to send container logs to CloudWatch Logs. Create the /ecs/test-project-name-logs log group in CloudWatch if it doesn't exist.image field will be dynamically updated by the aws-actions/amazon-ecs-render-task-definition@v1 action.package.json (root of your project)
{
"name": "test-project-name",
"version": "1.0.0",
"description": "A sample Node.js project for CI/CD.",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"express": "^4.19.2"
},
"devDependencies": {
"eslint": "^8.57.0",
"jest": "^29.7.0"
}
}
Action Required:
main entry point is correct (e.g., src/index.js).eslint and jest (or your preferred linting/testing tools) as dev dependencies.src/index.js (or your application's entry point) and include some basic Express app for testing purposes.env section at the top of the workflow file for your specific project names, region, and resource identifiers.node-version: '20' in the lint-and-test job and in your Dockerfile to match your project's Node.js version.npm run lint and npm test scripts if your project uses different commands or testing frameworks.staging, production) by introducing conditional deployments based on branches or manual triggers, and using different GitHub Environments for each.lint-and-test job.\n