[go: up one dir, main page]

0% found this document useful (0 votes)
8 views19 pages

SimpleTimeService POC Guide

The document provides a complete guide for creating a SimpleTimeService microservice using Python, Docker, and AWS infrastructure with Terraform. It outlines prerequisites, step-by-step instructions for building the application, creating Docker images, and deploying the infrastructure on AWS. The guide includes details on project structure, API response, security features, and deployment/testing procedures.

Uploaded by

him0952000
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views19 pages

SimpleTimeService POC Guide

The document provides a complete guide for creating a SimpleTimeService microservice using Python, Docker, and AWS infrastructure with Terraform. It outlines prerequisites, step-by-step instructions for building the application, creating Docker images, and deploying the infrastructure on AWS. The guide includes details on project structure, API response, security features, and deployment/testing procedures.

Uploaded by

him0952000
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

SimpleTimeService POC - Complete Guide

Prerequisites
Python 3.8+ installed
Docker installed

Docker Hub account


GitHub account

AWS account with CLI access


Terraform installed

TASK 1: Create the Microservice

Step 1: Create Project Structure

bash

mkdir simpletimeservice-poc
cd simpletimeservice-poc
mkdir app
mkdir terraform

Step 2: Create the Python Application


Create app/app.py :
python

from flask import Flask, request, jsonify


import datetime
import os

app = Flask(__name__)

@app.route('/')
def get_time_and_ip():
# Get current timestamp
current_time = datetime.datetime.now().isoformat()

# Get visitor IP address


# Check for forwarded IP first (for load balancers)
visitor_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
if visitor_ip:
visitor_ip = visitor_ip.split(',')[0].strip()

response = {
"timestamp": current_time,
"ip": visitor_ip
}

return jsonify(response)

if __name__ == '__main__':
port = int(os.environ.get('PORT', 8080))
app.run(host='0.0.0.0', port=port)

Create app/requirements.txt :

Flask==2.3.3

Step 3: Create Dockerfile


Create app/Dockerfile :
dockerfile

FROM python:3.11-slim

# Create non-root user


RUN groupadd -r appuser && useradd -r -g appuser appuser

# Set working directory


WORKDIR /app

# Copy requirements first for better caching


COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code


COPY app.py .

# Change ownership to non-root user


RUN chown -R appuser:appuser /app

# Switch to non-root user


USER appuser

# Expose port
EXPOSE 8080

# Run the application


CMD ["python", "app.py"]

Step 4: Test Locally

bash

cd app
python app.py
# Open another terminal and test:
curl http://localhost:8080

Step 5: Build and Test Docker Image


bash

cd app
docker build -t simpletimeservice:latest .
docker run -p 8080:8080 simpletimeservice:latest
# Test: curl http://localhost:8080

Step 6: Push to Docker Hub

bash

# Login to Docker Hub


docker login

# Tag your image (replace 'yourusername' with your Docker Hub username)
docker tag simpletimeservice:latest yourusername/simpletimeservice:latest

# Push to Docker Hub


docker push yourusername/simpletimeservice:latest

Step 7: Create README for App


Create app/README.md :

markdown

# SimpleTimeService

A simple microservice that returns current timestamp and visitor IP.

## Local Development
```bash
pip install -r requirements.txt
python app.py

Docker

bash

# Build
docker build -t simpletimeservice .

# Run
docker run -p 8080:8080 simpletimeservice

API
GET / - Returns JSON with timestamp and visitor IP

## TASK 2: Create AWS Infrastructure with Terraform

### Step 8: Create Terraform Files

Create `terraform/variables.tf`:
```hcl
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}

variable "project_name" {
description = "Name of the project"
type = string
default = "simpletimeservice"
}

variable "container_image" {
description = "Docker image for the application"
type = string
default = "yourusername/simpletimeservice:latest"
}

variable "container_port" {
description = "Port the container listens on"
type = number
default = 8080
}

Create terraform/terraform.tfvars :

hcl

aws_region = "us-east-1"
project_name = "simpletimeservice"
container_image = "yourusername/simpletimeservice:latest"
container_port = 8080

Create terraform/main.tf :
hcl
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = var.aws_region
}

# Data sources
data "aws_availability_zones" "available" {
state = "available"
}

# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true

tags = {
Name = "${var.project_name}-vpc"
}
}

# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id

tags = {
Name = "${var.project_name}-igw"
}
}

# Public Subnets
resource "aws_subnet" "public" {
count = 2

vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true

tags = {
Name = "${var.project_name}-public-subnet-${count.index + 1}"
}
}

# Private Subnets
resource "aws_subnet" "private" {
count = 2

vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 10}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]

tags = {
Name = "${var.project_name}-private-subnet-${count.index + 1}"
}
}

# NAT Gateways
resource "aws_eip" "nat" {
count = 2

domain = "vpc"
depends_on = [aws_internet_gateway.main]

tags = {
Name = "${var.project_name}-nat-eip-${count.index + 1}"
}
}

resource "aws_nat_gateway" "main" {


count = 2

allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id

tags = {
Name = "${var.project_name}-nat-gw-${count.index + 1}"
}
}

# Route Tables
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}

tags = {
Name = "${var.project_name}-public-rt"
}
}

resource "aws_route_table" "private" {


count = 2

vpc_id = aws_vpc.main.id

route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.main[count.index].id
}

tags = {
Name = "${var.project_name}-private-rt-${count.index + 1}"
}
}

# Route Table Associations


resource "aws_route_table_association" "public" {
count = 2

subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "private" {


count = 2

subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private[count.index].id
}

# Security Groups
resource "aws_security_group" "alb" {
name_prefix = "${var.project_name}-alb-"
vpc_id = aws_vpc.main.id

ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "${var.project_name}-alb-sg"
}
}

resource "aws_security_group" "ecs_tasks" {


name_prefix = "${var.project_name}-ecs-tasks-"
vpc_id = aws_vpc.main.id

ingress {
from_port = var.container_port
to_port = var.container_port
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "${var.project_name}-ecs-tasks-sg"
}
}

# ECS Cluster
resource "aws_ecs_cluster" "main" {
name = var.project_name

setting {
name = "containerInsights"
value = "enabled"
}

tags = {
Name = var.project_name
}
}

# ECS Task Definition


resource "aws_ecs_task_definition" "app" {
family = var.project_name
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn

container_definitions = jsonencode([
{
name = var.project_name
image = var.container_image
portMappings = [
{
containerPort = var.container_port
protocol = "tcp"
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.ecs.name
awslogs-region = var.aws_region
awslogs-stream-prefix = "ecs"
}
}
}
])

tags = {
Name = var.project_name
}
}

# CloudWatch Log Group


resource "aws_cloudwatch_log_group" "ecs" {
name = "/ecs/${var.project_name}"
retention_in_days = 7
tags = {
Name = var.project_name
}
}

# IAM Role for ECS Task Execution


resource "aws_iam_role" "ecs_task_execution_role" {
name = "${var.project_name}-ecs-task-execution-role"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}
]
})
}

resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {


role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

# Application Load Balancer


resource "aws_lb" "main" {
name = var.project_name
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id

tags = {
Name = var.project_name
}
}

resource "aws_lb_target_group" "app" {


name = var.project_name
port = var.container_port
protocol = "HTTP"
vpc_id = aws_vpc.main.id
target_type = "ip"
health_check {
enabled = true
healthy_threshold = 2
interval = 30
matcher = "200"
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 2
}

tags = {
Name = var.project_name
}
}

resource "aws_lb_listener" "app" {


load_balancer_arn = aws_lb.main.arn
port = "80"
protocol = "HTTP"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}

# ECS Service
resource "aws_ecs_service" "app" {
name = var.project_name
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = 2
launch_type = "FARGATE"

network_configuration {
security_groups = [aws_security_group.ecs_tasks.id]
subnets = aws_subnet.private[*].id
}

load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = var.project_name
container_port = var.container_port
}
depends_on = [aws_lb_listener.app]

tags = {
Name = var.project_name
}
}

Create terraform/outputs.tf :

hcl

output "load_balancer_dns" {
description = "DNS name of the load balancer"
value = aws_lb.main.dns_name
}

output "load_balancer_url" {
description = "URL of the application"
value = "http://${aws_lb.main.dns_name}"
}

Step 9: Create Terraform README


Create terraform/README.md :

markdown

# SimpleTimeService Infrastructure

This Terraform configuration creates AWS infrastructure to host the SimpleTimeService c

## Prerequisites
- AWS CLI configured with appropriate credentials
- Terraform installed

## AWS Authentication
Set up AWS credentials using one of these methods:

### Option 1: AWS CLI


```bash
aws configure

Option 2: Environment Variables


bash

export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_REGION="us-east-1"

Option 3: IAM Role (for EC2)


If running on EC2, attach an appropriate IAM role.

Deployment
1. Update terraform.tfvars with your Docker image name

2. Initialize Terraform:

bash

terraform init

3. Plan the deployment:

bash

terraform plan

4. Apply the configuration:

bash

terraform apply

Resources Created
VPC with public and private subnets
ECS Fargate cluster

Application Load Balancer

Security groups
IAM roles

Cleanup

bash

terraform destroy
### Step 10: Create Main Project README

Create root `README.md`:


```markdown
# SimpleTimeService POC

A complete microservice solution with Docker containerization and AWS


infrastructure.

## Project Structure

.
├── app/ # Application code and Dockerfile
│ ├── app.py
│ ├── requirements.txt
│ ├── Dockerfile
│ └── README.md
├── terraform/ # Infrastructure as Code
│ ├── main.tf
│ ├── variables.tf
│ ├── terraform.tfvars
│ ├── outputs.tf
│ └── README.md
└── README.md

## Quick Start

### 1. Clone Repository


```bash
git clone <your-repo-url>
cd simpletimeservice-poc

2. Build and Test Application

bash

cd app
docker build -t simpletimeservice .
docker run -p 8080:8080 simpletimeservice

Test: curl http://localhost:8080


3. Deploy Infrastructure

bash

cd terraform
# Update terraform.tfvars with your Docker image
terraform init
terraform plan
terraform apply

API Response

json

{
"timestamp": "2024-01-15T10:30:45.123456",
"ip": "192.168.1.100"
}

Features
✅ Non-root container user
✅ Minimal Docker image
✅ AWS ECS Fargate deployment
✅ Load balancer with health checks
✅ Private subnet deployment
✅ Infrastructure as Code
Security
Application runs as non-root user in container

ECS tasks deployed in private subnets

Security groups restrict access appropriately


No secrets committed to repository
### Step 11: Deploy and Test

```bash
# 1. Initialize Terraform
cd terraform
terraform init

# 2. Update terraform.tfvars with your Docker image name


# Edit: container_image = "yourusername/simpletimeservice:latest"

# 3. Plan deployment
terraform plan

# 4. Apply (this will take 5-10 minutes)


terraform apply

# 5. Test the deployed service


# Use the load_balancer_url from the output
curl http://your-load-balancer-dns-name

Step 12: Push to GitHub

bash

# Initialize git repository


git init
git add .
git commit -m "Initial commit: SimpleTimeService POC"

# Create repository on GitHub, then:


git remote add origin https://github.com/yourusername/simpletimeservice-poc.git
git push -u origin main

Important Notes

Security Considerations
Never commit AWS credentials to git
Use IAM roles when possible

Application runs as non-root user


ECS tasks are in private subnets only

Cost Optimization
Use terraform destroy when done testing

ECS Fargate charges by CPU/memory usage

NAT Gateways have hourly charges

Troubleshooting
Check ECS service logs in CloudWatch

Verify Docker image is publicly accessible


Ensure AWS credentials are properly configured
Check security group rules if connectivity issues occur

Testing Checklist
Application builds successfully with docker build
Container runs with docker run
Application responds correctly to curl
Terraform plan executes without errors
Terraform apply creates all resources
Load balancer URL returns correct JSON response
Application shows visitor's IP correctly

This POC demonstrates containerization, infrastructure as code, and cloud deployment best practices.

You might also like