1. Answers
  2. Set Up A 3-tier Web App On AWS Using EC2 & RDS

Set Up a 3-Tier Web App on AWS Using EC2 & RDS

Solution Overview

In this guide, we will set up a 3-tier web application on AWS using Pulumi. The three tiers will consist of:

  1. Web Tier: EC2 instances running a web server.
  2. Application Tier: EC2 instances running the application logic.
  3. Database Tier: Amazon RDS for the database.

We will use Pulumi’s AWS SDK to provision and manage these resources.

Step-by-Step Explanation

Prerequisites

  1. Ensure you have Pulumi installed. You can follow the installation guide here.
  2. Set up AWS credentials. You can follow the guide here.

Step 1: Create a new Pulumi project

  1. Create a new directory for your project and navigate into it:
    mkdir my-3tier-webapp
    cd my-3tier-webapp
    
  2. Initialize a new Pulumi project:
    pulumi new aws-typescript
    

Step 2: Define the VPC

  1. In the index.ts file, define a new VPC:
    import * as aws from "@pulumi/aws";
    
    const vpc = new aws.ec2.Vpc("vpc", {
        cidrBlock: "10.0.0.0/16",
    });
    

Step 3: Define Subnets

  1. Define subnets for each tier:
    const webSubnet = new aws.ec2.Subnet("web-subnet", {
        vpcId: vpc.id,
        cidrBlock: "10.0.1.0/24",
        availabilityZone: "us-west-2a",
    });
    
    const appSubnet = new aws.ec2.Subnet("app-subnet", {
        vpcId: vpc.id,
        cidrBlock: "10.0.2.0/24",
        availabilityZone: "us-west-2b",
    });
    
    const dbSubnet = new aws.ec2.Subnet("db-subnet", {
        vpcId: vpc.id,
        cidrBlock: "10.0.3.0/24",
        availabilityZone: "us-west-2c",
    });
    

Step 4: Define Security Groups

  1. Define security groups for each tier:
    const webSecurityGroup = new aws.ec2.SecurityGroup("web-sg", {
        vpcId: vpc.id,
        ingress: [
            { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
        ],
        egress: [
            { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
    
    const appSecurityGroup = new aws.ec2.SecurityGroup("app-sg", {
        vpcId: vpc.id,
        ingress: [
            { protocol: "tcp", fromPort: 8080, toPort: 8080, cidrBlocks: ["0.0.0.0/0"] },
        ],
        egress: [
            { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
    
    const dbSecurityGroup = new aws.ec2.SecurityGroup("db-sg", {
        vpcId: vpc.id,
        ingress: [
            { protocol: "tcp", fromPort: 3306, toPort: 3306, cidrBlocks: ["0.0.0.0/0"] },
        ],
        egress: [
            { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
    

Step 5: Provision EC2 Instances

  1. Provision EC2 instances for the web and application tiers:
    const webServer = new aws.ec2.Instance("web-server", {
        ami: "ami-0c55b159cbfafe1f0", // Amazon Linux 2 AMI
        instanceType: "t2.micro",
        subnetId: webSubnet.id,
        securityGroups: [webSecurityGroup.name],
        tags: { "Name": "web-server" },
    });
    
    const appServer = new aws.ec2.Instance("app-server", {
        ami: "ami-0c55b159cbfafe1f0", // Amazon Linux 2 AMI
        instanceType: "t2.micro",
        subnetId: appSubnet.id,
        securityGroups: [appSecurityGroup.name],
        tags: { "Name": "app-server" },
    });
    

Step 6: Provision RDS Instance

  1. Provision an RDS instance for the database tier:
    const dbInstance = new aws.rds.Instance("db-instance", {
        engine: "mysql",
        instanceClass: "db.t2.micro",
        allocatedStorage: 20,
        dbSubnetGroupName: new aws.rds.SubnetGroup("db-subnet-group", {
            subnetIds: [dbSubnet.id],
        }).name,
        vpcSecurityGroupIds: [dbSecurityGroup.id],
        skipFinalSnapshot: true,
    });
    

Step 7: Output the Connection Information

  1. Output the connection information for the web server and database:
    export const webServerPublicIp = webServer.publicIp;
    export const dbEndpoint = dbInstance.endpoint;
    

Summary

By following these steps, you have set up a 3-tier web application on AWS using Pulumi. The application consists of EC2 instances for the web and application tiers and an RDS instance for the database tier. Pulumi’s AWS SDK makes it easy to provision and manage these resources in a repeatable and scalable manner.

Full Code Example

import * as aws from "@pulumi/aws";

// Step 2: Define the VPC
const vpc = new aws.ec2.Vpc("vpc", {
    cidrBlock: "10.0.0.0/16",
});

// Step 3: Define Subnets
const webSubnet = new aws.ec2.Subnet("web-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.1.0/24",
    availabilityZone: "us-west-2a",
});

const appSubnet = new aws.ec2.Subnet("app-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.2.0/24",
    availabilityZone: "us-west-2b",
});

const dbSubnet = new aws.ec2.Subnet("db-subnet", {
    vpcId: vpc.id,
    cidrBlock: "10.0.3.0/24",
    availabilityZone: "us-west-2c",
});

// Step 4: Define Security Groups
const webSecurityGroup = new aws.ec2.SecurityGroup("web-sg", {
    vpcId: vpc.id,
    ingress: [
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
    ],
    egress: [
        { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
    ],
});

const appSecurityGroup = new aws.ec2.SecurityGroup("app-sg", {
    vpcId: vpc.id,
    ingress: [
        { protocol: "tcp", fromPort: 8080, toPort: 8080, cidrBlocks: ["0.0.0.0/0"] },
    ],
    egress: [
        { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
    ],
});

const dbSecurityGroup = new aws.ec2.SecurityGroup("db-sg", {
    vpcId: vpc.id,
    ingress: [
        { protocol: "tcp", fromPort: 3306, toPort: 3306, cidrBlocks: ["0.0.0.0/0"] },
    ],
    egress: [
        { protocol: "tcp", fromPort: 0, toPort: 0, cidrBlocks: ["0.0.0.0/0"] },
    ],
});

// Step 5: Provision EC2 Instances
const webServer = new aws.ec2.Instance("web-server", {
    ami: "ami-0c55b159cbfafe1f0", // Amazon Linux 2 AMI
    instanceType: "t2.micro",
    subnetId: webSubnet.id,
    securityGroups: [webSecurityGroup.name],
    tags: { "Name": "web-server" },
});

const appServer = new aws.ec2.Instance("app-server", {
    ami: "ami-0c55b159cbfafe1f0", // Amazon Linux 2 AMI
    instanceType: "t2.micro",
    subnetId: appSubnet.id,
    securityGroups: [appSecurityGroup.name],
    tags: { "Name": "app-server" },
});

// Step 6: Provision RDS Instance
const dbInstance = new aws.rds.Instance("db-instance", {
    engine: "mysql",
    instanceClass: "db.t2.micro",
    allocatedStorage: 20,
    dbSubnetGroupName: new aws.rds.SubnetGroup("db-subnet-group", {
        subnetIds: [dbSubnet.id],
    }).name,
    vpcSecurityGroupIds: [dbSecurityGroup.id],
    skipFinalSnapshot: true,
});

// Step 7: Output the Connection Information
export const webServerPublicIp = webServer.publicIp;
export const dbEndpoint = dbInstance.endpoint;

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up