צעדים ראשונים עם localstack
לוקאל סטאק https://github.com/localstack/localstack הוא פרויקט שמטרתו הפעלת גירסה מקומית של AWS אצלכם על המחשב בתוך קונטיינר. הם מכסים עשרות סרביסים של AWS בחשבון החינמי, ויש גם חשבון בתשלום שכולל יותר יכולות לחלק מהסרביסים ויותר סרביסים. מה שאהבתי במיוחד בעבודה עם local stack זה שהקוד לא צריך להשתנות - הממשק שלהם זהה לממשק של AWS מלבד פקודת קונפיגורציה אחת שמגדירה את ה endpoint שלהם במקום של AWS.
בואו נראה איך להתקין ולעבוד עם סרביס S3 של לוקאל סטאק דרך שלושה סקריפטים.
1. התקנת הכלים
את לוקאל סטאק אפשר להתקין מדף ההתקנה שלהם כאן:
https://docs.localstack.cloud/getting-started/installation/
אחרי ההתקנה הייתי צריך להוסיף את התיקיה שלהם לתיקיות הקבצים של Docker Desktop מתוך ההגדרות של דוקר, וגם להתקין סקריפט שעוטף את aws באמצעות הפקודה:
pip install awscli-local
הפעלתי את local stack עם:
$ localstack start -d
ואחרי זה הרצתי את פקודת הסטטוס כדי לראות את הסרביסים שקיבלתי:
$ localstack status services
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
┃ Service ┃ Status ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━┩
│ acm │ ✔ available │
│ apigateway │ ✔ available │
│ cloudformation │ ✔ available │
│ cloudwatch │ ✔ available │
│ config │ ✔ available │
│ dynamodb │ ✔ available │
│ dynamodbstreams │ ✔ available │
│ ec2 │ ✔ available │
│ es │ ✔ available │
│ events │ ✔ available │
│ firehose │ ✔ available │
│ iam │ ✔ available │
│ kinesis │ ✔ available │
│ kms │ ✔ available │
│ lambda │ ✔ available │
│ logs │ ✔ available │
│ opensearch │ ✔ available │
│ redshift │ ✔ available │
│ resource-groups │ ✔ available │
│ resourcegroupstaggingapi │ ✔ available │
│ route53 │ ✔ available │
│ route53resolver │ ✔ available │
│ s3 │ ✔ running │
│ s3control │ ✔ available │
│ scheduler │ ✔ available │
│ secretsmanager │ ✔ available │
│ ses │ ✔ available │
│ sns │ ✔ available │
│ sqs │ ✔ available │
│ ssm │ ✔ available │
│ stepfunctions │ ✔ available │
│ sts │ ✔ available │
│ support │ ✔ available │
│ swf │ ✔ available │
│ transcribe │ ✔ available │
└──────────────────────────┴─────────────┘
2. עבודה עם S3
נמשיך לכמה סקריפטים ב Ruby שעובדים עם S3 בשביל הדוגמה. בכולם השורה הכי חשובה היא:
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566'
region: 'us-east-2',
force_path_style: true
)
הסקריפט הראשון יוצר bucket חדש על s3 שרץ על local stack:
require "aws-sdk-s3"
class BucketCreateWrapper
attr_reader :bucket
def initialize(bucket)
@bucket = bucket
end
def create?(region)
@bucket.create(create_bucket_configuration: { location_constraint: region })
true
rescue Aws::Errors::ServiceError => e
puts "Couldn't create bucket. Here's why: #{e.message}"
false
end
def location
if @bucket.nil?
"None. You must create a bucket before you can get its location!"
else
@bucket.client.get_bucket_location(bucket: @bucket.name).location_constraint
end
rescue Aws::Errors::ServiceError => e
"Couldn't get the location of #{@bucket.name}. Here's why: #{e.message}"
end
end
def run_demo
region = "us-east-2"
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: region,
force_path_style: true, # Enable 'force_path_style' => true, if bucket name is non DNS compliant
)
bucket_name = "test-bucket"
wrapper = BucketCreateWrapper.new(Aws::S3::Bucket.new(bucket_name))
return unless wrapper.create?(region)
puts "Created bucket #{wrapper.bucket.name}."
puts "Your bucket's region is: #{wrapper.location}"
end
run_demo if $PROGRAM_NAME == __FILE__
סקריפט שני כותב קובץ לאותו bucket:
require 'aws-sdk-s3'
region = "us-east-2"
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: region,
force_path_style: true, # Enable 'force_path_style' => true, if bucket name is non DNS compliant
)
s3_client = Aws::S3::Client.new
bucket_name = 'test-bucket'
object_key = 'demo.txt'
file_content = "This is a demo file uploaded via Ruby to my LocalStack S3.\n"
begin
response = s3_client.put_object(
bucket: bucket_name,
key: object_key,
body: file_content
)
puts "File '#{object_key}' uploaded successfully to '#{bucket_name}'!"
rescue Aws::S3::Errors::ServiceError => e
puts "Error uploading file: #{e.message}"
end
וסקריפט שלישי עדיין ברובי קורא את הקובץ ומדפיס את תוכנו:
require 'aws-sdk-s3'
Aws.config.update(
endpoint: 'http://s3.localhost.localstack.cloud:4566', # update with localstack endpoint
region: 'us-east-2',
force_path_style: true # Enable 'force_path_style' => true, if bucket name is non DNS complian
)
s3_client = Aws::S3::Client.new
bucket_name = 'test-bucket'
object_key = 'demo.txt'
begin
response = s3_client.get_object(bucket: bucket_name, key: object_key)
file_contents = response.body.read
puts "Contents of '#{object_key}' in bucket '#{bucket_name}':\n\n"
puts file_contents
rescue Aws::S3::Errors::NoSuchKey => e
puts "File '#{object_key}' not found: #{e.message}"
rescue Aws::S3::Errors::ServiceError => e
puts "Error retrieving file: #{e.message}"
end
לסיום אפשר למחוק את הבאקט עם הסקריפט פייתון שהתקנו קודם בהפעלת:
$ awslocal s3 rb s3://test-bucket --force
סך הכל הפיתוח עם local stack מאפשר עבודה באותו ממשק כמו AWS אבל מקומית לגמרי. ברור שבסיום הפיתוח צריך לבדוק הכל על AWS ובטח יהיו בעיות ועוד צריך לדבר על הרשאות והכל נכון. אבל למי שרוצה להתחיל פיתוח שיגיע ל AWS אבל בינתיים רק לראות שדברים עובדים אצלנו על המחשב לוקאל סטאק יכול לתת פיתרון מצוין ומהיר.