Skip to content

Commit 6f90db5

Browse files
Raeveen PasupathyInspectorGadget
Raeveen Pasupathy
authored andcommitted
initial commit
0 parents  commit 6f90db5

14 files changed

+355
-0
lines changed

.github/workflows/deploy.yaml

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Deploy Terraform Module
2+
on:
3+
workflow_dispatch:
4+
jobs:
5+
generate-terraform-plan:
6+
name: Generate Terraform Plan
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v3
10+
- name: Configure AWS Credentials
11+
uses: aws-actions/configure-aws-credentials@v1
12+
with:
13+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
14+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
15+
aws-region: ${{ secrets.AWS_REGION }}
16+
- name: Terraform Init
17+
uses: hashicorp/setup-terraform@v2
18+
with:
19+
terraform_version: 1.1.7
20+
- name: Terraform Plan
21+
run: |
22+
terraform init
23+
terraform plan \
24+
-out="plan.out"
25+
- name: Upload Terraform Plan
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: terraform-plan
29+
path: plan.out
30+
deploy:
31+
name: Deploy to environment
32+
needs: generate-terraform-plan
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v3
36+
- name: Setup QEMU
37+
uses: docker/setup-qemu-action@v2
38+
with:
39+
platforms: 'arm64,arm'
40+
- uses: docker/setup-buildx-action@v2
41+
- name: Configure AWS Credentials
42+
uses: aws-actions/configure-aws-credentials@v1
43+
with:
44+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
45+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
46+
aws-region: ${{ secrets.AWS_REGION }}
47+
- name: Terraform Init
48+
uses: hashicorp/setup-terraform@v2
49+
with:
50+
terraform_version: 1.1.7
51+
- name: Download Plan
52+
uses: actions/download-artifact@v4
53+
with:
54+
name: terraform-plan
55+
- name: Install Python 3
56+
uses: actions/setup-python@v3
57+
with:
58+
python-version: "3.9"
59+
- name: Terraform Apply
60+
run: |
61+
terraform init
62+
terraform apply plan.out

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
.terraform
3+
.terraform.lock.hcl

Dockerfile

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
FROM ollama/ollama:latest
2+
COPY --from=inspectorgadget12/lambda-runtime-adapter /lambda-runtime-adapter /opt/extensions/lambda-adapter
3+
4+
ENV OLLAMA_HOST=0.0.0.0:8080
5+
ENV HOME=/mnt/ollama
6+
7+
# Pre-pull the model during build
8+
RUN ollama serve & sleep 2 && ollama pull llama3 && pkill ollama
9+
10+
EXPOSE 8080
11+
12+
# Add a script to run the model
13+
COPY <<EOF /run.sh
14+
#!/bin/bash
15+
16+
echo "Starting Ollama server..."
17+
ollama serve &
18+
SERVE_PID=$!
19+
20+
echo "Waiting for Ollama server to be ready..."
21+
while ! curl -s localhost:8080/api/tags >/dev/null 2>&1; do
22+
sleep 1
23+
done
24+
25+
echo "Running llama3 model..."
26+
ollama run llama3 &
27+
LLAMA_PID=$!
28+
29+
# Keep the container running and wait for both processes
30+
wait $SERVE_PID $LLAMA_PID
31+
EOF
32+
33+
RUN chmod +x /run.sh
34+
35+
ENTRYPOINT ["/run.sh"]

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Ollama on AWS Lambda
2+
3+
# Technologies
4+
1. Terraform
5+
2. AWS Lambda
6+
3. Docker
7+
4. Bash Scripting
8+
9+
# Description
10+
This project exerts the simple way on running Ollama on AWS Lambda. This leverages the power of serverless computing to run Ollama on AWS Lambda while staying relevant to the AWS Free Tier. This project is a simple demonstration of how to run Ollama on AWS Lambda.
11+
12+
Please do not use this method for Production use-case as the inteferencing is still slow on AWS Lambda. But this is a great way of running Ollama on AWS Lambda for testing purposes or learning purposes.
13+
14+
# Setting up the environment
15+
1. `git clone https://github.com/InspectorGadget/ollama-on-lambda.git`
16+
2. Update `backend.tf` with your S3 Bucket name.
17+
3. Run `terraform init`
18+
4. Verify the changes that would be performed on your environment.
19+
5. Run `terraform apply`
20+
6. Wait for the changes to be applied.
21+
7. Perform inferencing with your newly deployed Ollama instance.

backend.tf

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
terraform {
2+
backend "s3" {
3+
bucket = "ollama-on-aws-lambda-state"
4+
key = "terraform.tfstate"
5+
region = "ap-southeast-1"
6+
}
7+
}

data.tf

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Current account
2+
data "aws_caller_identity" "current" {}
3+
4+
# Current region
5+
data "aws_region" "current" {}
6+
7+
# Get VPC by ID
8+
data "aws_vpc" "main" {
9+
id = var.vpc_id
10+
}
11+
12+
# Get Private Subnets
13+
data "aws_subnets" "private" {
14+
filter {
15+
name = "vpc-id"
16+
values = [var.vpc_id]
17+
}
18+
19+
filter {
20+
name = "tag:Name"
21+
values = ["*Private*"]
22+
}
23+
}
24+
25+
# Get Public Subnets
26+
data "aws_subnets" "public" {
27+
filter {
28+
name = "vpc-id"
29+
values = [var.vpc_id]
30+
}
31+
32+
filter {
33+
name = "tag:Name"
34+
values = ["*Public*"]
35+
}
36+
}
37+

docker-compose.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
services:
2+
ollama:
3+
container_name: ollama
4+
build:
5+
context: .
6+
dockerfile: Dockerfile
7+
platforms:
8+
- linux/arm64
9+
ports:
10+
- "8080:8080"
11+
volumes:
12+
- ollama:/tmp/.ollama
13+
14+
volumes:
15+
ollama:

ecr.tf

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# ECR Repository
2+
resource "aws_ecr_repository" "ecr" {
3+
name = "${var.project_name}-runtime"
4+
}
5+
6+
# Build Image
7+
resource "null_resource" "build" {
8+
depends_on = [
9+
aws_ecr_repository.ecr
10+
]
11+
12+
triggers = {
13+
build_number = timestamp()
14+
}
15+
16+
provisioner "local-exec" {
17+
interpreter = [
18+
"/bin/sh",
19+
"-c"
20+
]
21+
22+
command = <<-COMMAND
23+
# Login to ECR (AWS STS AssumeRole)
24+
aws ecr get-login-password --region ${data.aws_region.current.name} | docker login --username AWS --password-stdin ${data.aws_caller_identity.current.account_id}.dkr.ecr.${data.aws_region.current.name}.amazonaws.com
25+
26+
# Build Image
27+
docker build -t ${aws_ecr_repository.ecr.repository_url}:latest . -f Dockerfile --platform linux/arm64 --provenance=false
28+
29+
# Push Image
30+
docker push ${aws_ecr_repository.ecr.repository_url}:latest
31+
COMMAND
32+
}
33+
}

function_url.tf

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource "aws_lambda_function_url" "ollama" {
2+
depends_on = [
3+
aws_lambda_function.ollama,
4+
null_resource.post_deployment
5+
]
6+
7+
function_name = aws_lambda_function.ollama.function_name
8+
authorization_type = "NONE"
9+
invoke_mode = "RESPONSE_STREAM"
10+
11+
cors {
12+
allow_credentials = true
13+
allow_origins = ["*"]
14+
allow_methods = ["*"]
15+
allow_headers = ["date", "keep-alive"]
16+
expose_headers = ["keep-alive", "date"]
17+
max_age = 86400
18+
}
19+
}

iam.tf

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
resource "aws_iam_role" "lambda" {
2+
name = "${var.project_name}-role"
3+
assume_role_policy = <<-EOF
4+
{
5+
"Version": "2012-10-17",
6+
"Statement": [
7+
{
8+
"Action": "sts:AssumeRole",
9+
"Principal": {
10+
"Service": [
11+
"lambda.amazonaws.com",
12+
"apigateway.amazonaws.com",
13+
"events.amazonaws.com"
14+
]
15+
},
16+
"Effect": "Allow",
17+
"Sid": ""
18+
}
19+
]
20+
}
21+
EOF
22+
}
23+
24+
# Attach Basic Execution Policy to Lambda Role
25+
resource "aws_iam_role_policy_attachment" "lambda" {
26+
depends_on = [
27+
aws_iam_role.lambda
28+
]
29+
30+
role = aws_iam_role.lambda.name
31+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
32+
}
33+
34+
# Attach AWSLambdaVPCAccessExecutionRole
35+
resource "aws_iam_role_policy_attachment" "vpc" {
36+
depends_on = [
37+
aws_iam_role.lambda
38+
]
39+
40+
role = aws_iam_role.lambda.name
41+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
42+
}

lambda.tf

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Create AWS Lambda Function from ECR Image
2+
resource "aws_lambda_function" "ollama" {
3+
depends_on = [
4+
aws_ecr_repository.ecr,
5+
null_resource.build,
6+
aws_iam_role.lambda
7+
]
8+
9+
function_name = var.project_name
10+
architectures = [
11+
"arm64",
12+
]
13+
package_type = "Image"
14+
image_uri = "${aws_ecr_repository.ecr.repository_url}:latest"
15+
role = aws_iam_role.lambda.arn
16+
memory_size = 10240
17+
timeout = 900
18+
19+
ephemeral_storage {
20+
size = 10240
21+
}
22+
23+
environment {
24+
variables = {
25+
RUST_LOG = "debug"
26+
PORT = "8080"
27+
HOME = "/mnt/ollama"
28+
AWS_LWA_INVOKE_MODE = "response_stream"
29+
}
30+
}
31+
}
32+
33+
# Update Lambda Image to latest with Lambda API
34+
resource "null_resource" "post_deployment" {
35+
depends_on = [
36+
aws_lambda_function.ollama,
37+
null_resource.build
38+
]
39+
40+
triggers = {
41+
build_number = timestamp()
42+
}
43+
44+
provisioner "local-exec" {
45+
interpreter = [
46+
"/bin/sh",
47+
"-c"
48+
]
49+
50+
command = <<-COMMAND
51+
# Update Lambda Image to latest with Lambda API
52+
aws lambda update-function-code --function-name ${aws_lambda_function.ollama.function_name} --image-uri ${aws_ecr_repository.ecr.repository_url}:latest
53+
COMMAND
54+
}
55+
}

main.tf

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
terraform {
2+
required_providers {
3+
aws = {
4+
source = "hashicorp/aws"
5+
version = "~> 5.0"
6+
}
7+
null = {
8+
source = "hashicorp/null"
9+
version = "> 3.0"
10+
}
11+
}
12+
}
13+
14+
provider "aws" {
15+
region = "ap-southeast-1"
16+
}

output.tf

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
output "lambda_function_url" {
2+
value = aws_lambda_function_url.ollama.function_url
3+
}

variable.tf

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
variable "project_name" {
2+
default = "ollama-on-aws-lambda"
3+
}
4+
5+
variable "vpc_id" {
6+
default = "vpc-08f4f76fa7689a36b"
7+
}

0 commit comments

Comments
 (0)