____ ___
_______| | ___ __
\_ __ | | \ \/ /
| | \| | / \ /
|__| |______/ \_/
Optimized VS Code and Code Spaces
This repository provides a fully configured development environment optimized for working with AWS services, including serverless Lambda deployments, using GitHub Codespaces. It includes the AWS CLI, AWS SAM CLI, Boto3, and additional tools necessary for serverless development.
Created by Reuven Cohen (rUv), this environment is designed to streamline and optimize the deployment of AWS Lambda functions with optional VPC configurations.
The purpose of this repository is to provide a ready-to-use development setup that simplifies the process of developing, testing, and deploying serverless applications on AWS. By leveraging GitHub Codespaces and Docker, developers can ensure consistency across different development environments and accelerate their workflow.
- AWS CLI: Manage AWS services directly from the command line.
- AWS SAM CLI: Build, test, and deploy serverless applications.
- Boto3: Python SDK for AWS services.
- Docker: Containerize and manage your Lambda functions.
- Pre-configured Environment: Ready-to-use settings and dependencies.
- Extensions: Includes useful VS Code extensions for Docker, AWS Toolkit, and more.
Ensure you have the following:
- Access to GitHub Codespaces.
- AWS account and credentials.
Clone this repository to your local machine:
git clone https://github.com/ruvnet/aws-dev.git
cd aws-dev
Set up your AWS credentials as environment variables. Add the following lines to your .bashrc
, .bash_profile
, or .zshrc
:
export AWS_ACCESS_KEY_ID=your_access_key_id
export AWS_SECRET_ACCESS_KEY=your_secret_access_key
export AWS_DEFAULT_REGION=us-east-1
After updating, source the file to apply the changes:
source ~/.bashrc
# or
source ~/.bash_profile
# or
source ~/.zshrc
The repository includes a .devcontainer
folder with the necessary configuration files.
{
"name": "AWS Dev Container",
"build": {
"dockerfile": "Dockerfile",
"context": "."
},
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/workspaces/aws-dev/.venv/bin/python"
},
"extensions": [
"amazonwebservices.aws-toolkit-vscode",
"kddejong.vscode-cfn-lint",
"redhat.vscode-yaml",
"hashicorp.terraform",
"ms-python.python",
"ms-azuretools.vscode-docker",
"amazonwebservices.aws-sam-cli-toolkit"
],
"postCreateCommand": "python3 -m venv .venv && . .venv/bin/activate && pip install --upgrade pip && pip install -r deployment/requirements.txt -r hello_world/requirements.txt",
"forwardPorts": [8000],
"remoteUser": "vscode",
"remoteEnv": {
"AWS_ACCESS_KEY_ID": "${localEnv:AWS_ACCESS_KEY_ID}",
"AWS_SECRET_ACCESS_KEY": "${localEnv:AWS_SECRET_ACCESS_KEY}",
"AWS_DEFAULT_REGION": "${localEnv:AWS_DEFAULT_REGION}"
}
}
# Base image
FROM mcr.microsoft.com/vscode/devcontainers/base:0-buster
# Install AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
unzip awscliv2.zip && \
./aws/install && \
rm -rf awscliv2.zip ./aws
# Install system dependencies
RUN apt-get update && apt-get install -y \
jq \
python3 \
python3-pip \
python3-distutils \
python3-venv \
docker.io \
build-essential \
curl \
sudo \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/*
# Manually install pip (if needed)
RUN curl -O https://bootstrap.pypa.io/get-pip.py && \
python3 get-pip.py && \
rm get-pip.py
# Install Rust (needed for maturin)
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
# Install maturin with specific version and other dependencies
RUN pip install --upgrade pip && \
pip install maturin==1.0.0 typing-extensions==4.6.3
# Install other Python dependencies
RUN pip install boto3 fastapi pydantic uvicorn
# Install AWS SAM CLI
RUN pip install aws-sam-cli
# Install GitHub CLI
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \
sudo apt update && \
sudo apt install -y gh
# Ensure pip is available globally
RUN ln -s /usr/bin/pip3 /usr/bin/pip
# Set the default shell to bash
SHELL ["/bin/bash", "-c"]
# Set user
USER vscode
-
Start the FastAPI Server:
uvicorn deployment.deploy_script:app --reload
-
Deploy via API Call: Use a tool like
curl
or Postman to send a POST request to the/deploy
endpoint with the required payload.Example payload:
{ "repository_name": "my-repo", "image_tag": "latest", "python_script": "def lambda_handler(event, context): return {'statusCode': 200, 'body': 'Hello, World!'}", "requirements": "requests\n", "vpc_id": "vpc-12345678", "subnet_ids": ["subnet-12345678", "subnet-87654321"], "security_group_ids": ["sg-12345678"] }
The repository includes an example serverless application structure to get you started.
.
.
├── .devcontainer
│ ├── devcontainer.json
│ └── Dockerfile
├── .gitignore
├── deployment
│ ├── deploy_script.py
│ ├── requirements.txt
├── hello_world
│ ├── app.py
│ ├── requirements.txt
├── scripts
│ ├── get-pip.py
│ ├── rust.sh
│ ├── setup.sh
├── template.yaml
└── README.md
import os
import subprocess
import boto3
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional, List
app = FastAPI()
class DeployRequest(BaseModel):
repository_name: str
image_tag: str
python_script: str
requirements: str
vpc_id: Optional[str] = None
subnet_ids: Optional[List[str]] = None
security_group_ids: Optional[List[str]] = None
@app.post("/deploy")
def deploy(request: DeployRequest):
# Step 1: Create a virtual environment
os.system("python3 -m venv venv")
os.system("source venv/bin/activate")
# Step 2: Write the Python script to a file
with open("app.py", "w") as f:
f.write(request.python_script)
# Step 3: Write the requirements to a file
with open("requirements.txt", "w") as f:
f.write(request.requirements)
# Step 4: Install dependencies
os.system("venv/bin/pip install -r requirements.txt")
# Step 5: Create a Dockerfile
dockerfile_content = f"""
FROM public.ecr.aws/lambda/python:3.8
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["app.lambda_handler"]
"""
with open("Dockerfile", "w") as f:
f.write(dockerfile_content)
# Step 6: Build the Docker image
image_name = f"{request.repository_name}:{request.image_tag}"
os.system(f"docker build -t {image_name} .")
# Step 7: Authenticate Docker to AWS ECR
region = "us-west-2" # Change to your desired region
account_id = boto3.client('sts').get_caller_identity().get('Account')
ecr_uri = f"{account_id}.dkr.ecr.{region}.amazonaws.com"
os.system(f"aws ecr get-login-password --region {region} | docker login --username AWS --password-stdin {ecr_uri}")
# Step 8: Create ECR repository if it doesn't exist
ecr_client = boto3.client('ecr', region_name=region)
try:
ecr_client.create_repository(repositoryName=request.repository_name)
except ecr_client.exceptions.RepositoryAlreadyExistsException:
pass
# Step 9: Tag and push the Docker image to ECR
os.system(f"docker tag {image_name} {ecr_uri}/{image_name}")
os.system(f"docker push {ecr_uri}/{image_name}")
# Step 10: Create or update the Lambda function
lambda_client = boto3.client('lambda', region_name=region)
function_name = "my-lambda-function"
try:
response = lambda_client.create_function(
FunctionName=function_name,
Role=f"arn:aws:iam::{account_id}:role/lambda-execution-role",
Code={
'ImageUri': f"{ecr_uri}/{image_name}"
},
PackageType='Image',
Publish=True,
VpcConfig={
'Subnet
Ids': request.subnet_ids or [],
'SecurityGroupIds': request.security_group_ids or []
} if request.vpc_id else {}
)
except lambda_client.exceptions.ResourceConflictException:
response = lambda_client.update_function_code(
FunctionName=function_name,
ImageUri=f"{ecr_uri}/{image_name}",
Publish=True
)
if request.vpc_id:
lambda_client.update_function_configuration(
FunctionName=function_name,
VpcConfig={
'SubnetIds': request.subnet_ids or [],
'SecurityGroupIds': request.security_group_ids or []
}
)
return {"message": "Deployment successful", "image_uri": f"{ecr_uri}/{image_name}", "lambda_arn": response['FunctionArn']}
# Run the FastAPI app
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
boto3
fastapi
pydantic
uvicorn
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': 'Hello, World!'
}
boto3
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.lambda_handler
Runtime: python3.8
CodeUri: hello_world/
Description: A simple Hello World function.
MemorySize: 128
Timeout: 3
Policies:
- AWSLambdaBasicExecutionRole
- Environment Variables: The dev container is configured to use your local environment variables for AWS credentials.
- Custom Scripts: You can add custom scripts and configurations as needed.
This project is licensed under the MIT License. See the LICENSE file for details.