> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Deploy AWS EC2

> Learn to deploy a Dockerized Node.js application on AWS EC2 using a Jenkins Pipeline, covering all necessary steps and configurations.

In this guide, you’ll learn how to deploy a Dockerized Node.js application to an AWS EC2 instance using a Jenkins Pipeline. We’ll cover every step—from adding a deploy stage and managing Docker containers on EC2, to conditional execution and verifying your deployment.

**Table of Contents**

1. [Prerequisites](#prerequisites)
2. [Adding the Deploy Stage](#1-adding-the-deploy-stage)
3. [Stopping & Removing the Existing Container](#2-stopping--removing-the-existing-container)
4. [Running the New Container](#3-running-the-new-container)
5. [Wrapping in a `script` Block](#4-wrapping-in-a-script-block)
6. [Conditional Execution with `when`](#5-conditional-execution-with-when)
7. [Verifying the Deployment](#6-verifying-the-deployment)
8. [Links and References](#links-and-references)

***

## Prerequisites

* A Jenkins instance with the **SSH Agent** plugin installed
* An AWS EC2 Ubuntu server accessible via SSH
* A Dockerized application pushed to a Docker registry
* Jenkins credentials configured for:
  * SSH key (e.g., `aws-dev-deploy-ec2-instance`)
  * MongoDB username & password (`mongo-db-username`, `mongo-db-password`)

***

## 1. Adding the Deploy Stage

After your `Push Docker Image` stage, insert a new stage called **Deploy - AWS EC2**. Here’s the skeleton of your declarative pipeline:

```groovy theme={null}
pipeline {
    agent any

    stages {
        stage('Build Docker Image') { /* ... */ }
        stage('Trivy Vulnerability Scanner') { /* ... */ }
        stage('Push Docker Image') { /* ... */ }
        stage('Deploy - AWS EC2') {
            steps { /* To be implemented */ }
        }
    }

    post {
        always { /* ... */ }
    }
}
```

| Stage Name                  | Description                            |
| --------------------------- | -------------------------------------- |
| Build Docker Image          | Build and tag your Docker image        |
| Trivy Vulnerability Scanner | Scan the image for vulnerabilities     |
| Push Docker Image           | Push the image to your Docker registry |
| Deploy - AWS EC2            | SSH into EC2 and restart the container |

We’ll use the [SSH Agent plugin](https://plugins.jenkins.io/ssh-agent) to authenticate to EC2 using the private key credential `aws-dev-deploy-ec2-instance`.

***

## 2. Stopping & Removing the Existing Container

Use an SSH one-liner to detect if the `solar-system` container is running, then stop and remove it:

```bash theme={null}
ssh -o StrictHostKeyChecking=no ubuntu@3.140.244.188 "
if sudo docker ps -a | grep -q 'solar-system'; then
    echo 'Container found. Stopping...'
    sudo docker stop solar-system && sudo docker rm solar-system
    echo 'Container stopped and removed.'
fi
"
```

<Callout icon="lightbulb" color="#1CB2FE">
  Suppressing `StrictHostKeyChecking` avoids interactive host key prompts, which is essential for unattended CI/CD pipelines.
</Callout>

***

## 3. Running the New Container

Next, start a fresh container with your environment variables. These variables come from the global `environment` block in your Jenkinsfile:

```bash theme={null}
ssh -o StrictHostKeyChecking=no ubuntu@3.140.244.188 "
sudo docker run --name solar-system \
  -e MONGO_URI=$MONGO_URI \
  -e MONGO_USERNAME=$MONGO_USERNAME \
  -e MONGO_PASSWORD=$MONGO_PASSWORD \
  -p 3000:3000 \
  -d siddharth67/solar-system:$GIT_COMMIT
"
```

Define your environment variables at the top of the Jenkinsfile:

```groovy theme={null}
pipeline {
    agent any

    environment {
        MONGO_URI         = 'mongodb+srv://supercluster.d83jj.mongodb.net/superData'
        MONGO_USERNAME    = credentials('mongo-db-username')
        MONGO_PASSWORD    = credentials('mongo-db-password')
        SONAR_SCANNER_HOME = tool 'sonarqube-scanner-610'
    }

    stages { /* ... */ }
}
```

| Variable        | Source                                 |
| --------------- | -------------------------------------- |
| MONGO\_URI      | Hard-coded connection string           |
| MONGO\_USERNAME | Jenkins credential `mongo-db-username` |
| MONGO\_PASSWORD | Jenkins credential `mongo-db-password` |
| GIT\_COMMIT     | Jenkins built-in variable              |

***

## 4. Wrapping in a `script` Block

Because we’re using conditional logic (`if`), wrap the SSH commands in a `script` step inside the declarative stage:

```groovy theme={null}
stage('Deploy - AWS EC2') {
    steps {
        script {
            sshagent(['aws-dev-deploy-ec2-instance']) {
                sh '''
                ssh -o StrictHostKeyChecking=no ubuntu@3.140.244.188 "
                if sudo docker ps -a | grep -q 'solar-system'; then
                    echo 'Container found. Stopping...'
                    sudo docker stop solar-system && sudo docker rm solar-system
                    echo 'Container stopped and removed.'
                fi

                sudo docker run --name solar-system \
                  -e MONGO_URI=$MONGO_URI \
                  -e MONGO_USERNAME=$MONGO_USERNAME \
                  -e MONGO_PASSWORD=$MONGO_PASSWORD \
                  -p 3000:3000 -d siddharth67/solar-system:$GIT_COMMIT
                "
                '''
            }
        }
    }
    post {
        always { /* cleanup or notifications */ }
    }
}
```

***

## 5. Conditional Execution with `when`

Run the deploy stage only on feature branches by adding a `when` condition. You can also configure this filter in the Jenkins UI:

```groovy theme={null}
stage('Deploy - AWS EC2') {
    when {
        branch 'feature/*'
    }
    steps {
        script {
            sshagent(['aws-dev-deploy-ec2-instance']) {
                sh '''<same SSH block as above>'''
            }
        }
    }
}
```

<Callout icon="lightbulb" color="#1CB2FE">
  Using `when { branch 'feature/*' }` ensures that deployment only triggers for feature branches, preventing accidental prod deployments.
</Callout>

***

## 6. Verifying the Deployment

1. **Check Jenkins Console**
   ```bash theme={null}
   ssh -o StrictHostKeyChecking=no ubuntu@3.140.244.188 "
   if sudo docker ps -a | grep -q 'solar-system'; then
       echo 'Container found. Stopping...'
       sudo docker stop solar-system && sudo docker rm solar-system
   fi
   "
   ```
   **Sample logs:**
   ```plaintext theme={null}
   Warning: Permanently added '3.140.244.188' (ECDSA) to the list of known hosts.
   Container found. Stopping...
   Container stopped and removed.
   Unable to find image 'siddharth67/solar-system:5376ef9094c...' locally
   Status: Downloaded newer image for siddharth67/solar-system:5376ef9094c...
   cab883d639d9
   ```

2. **On the EC2 Instance**
   ```bash theme={null}
   sudo docker ps
   ```
   **Expected output:**
   ```plaintext theme={null}
   CONTAINER ID   IMAGE                                        NAMES
   cab88363d990   siddharth67/solar-system:5376ef09...         solar-system

   COMMAND             CREATED          STATUS             PORTS
   "docker-entrypoint.s..." About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp
   ```

3. **Access the Application**\
   Open a browser and navigate to:
   ```text theme={null}
   http://<EC2_PUBLIC_IP>:3000
   ```

Integration testing should follow to validate your application endpoints and data flow.

***

## Links and References

* [AWS EC2 Documentation](https://aws.amazon.com/ec2/)
* [Jenkins Pipeline](https://www.jenkins.io/doc/book/pipeline/)
* [SSH Agent Plugin](https://plugins.jenkins.io/ssh-agent)
* [Docker Documentation](https://docs.docker.com/)

Happy Deploying!

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/certified-jenkins-engineer/module/e16e4b93-31c4-479b-96b8-f0d26cde31cd/lesson/bbebaeeb-ba14-42f1-ab36-e2d692e3123a" />
</CardGroup>
