-
Notifications
You must be signed in to change notification settings - Fork 1
๐ก How To? Terraform Locust๋ก ๋ถํ ํ ์คํธ ์งํํ๊ธฐ
Terraform์ ๋ ์ ์ฐ๋ ๋ฐฉ๋ฒ๋ณด๋ค๋, ํ ์คํธ ํ๊ฒฝ ๊ตฌ์ถ์ ๋ถํธํจ์ ํด๊ฒฐํ๋ ค๋ ์๋จ์ผ๋ก ์ฌ์ฉํ์ต๋๋ค~
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
terraform version
terraform -install-autocomplete
main.tf
provider "aws" {
region = "ap-northeast-2" # ๋ฆฌ์ ์ ap-northeast-2๋ก ์ค์
}
resource "aws_instance" "terrafor-example-miiiinju" {
ami = "ami-056a29f2eddc40520" # ์ง์ ๋ AMI ID
instance_type = "t3.micro" # ์ง์ ๋ ์ธ์คํด์ค ํ์
key_name = "team5_guys_pub" # ์ง์ ๋ ํค ํ์ด ์ด๋ฆ
subnet_id = "subnet-ac32f2f3" # default subnet
vpc_security_group_ids = ["sg-0946e533330930594"] # ์ฌ์ฉํ ๋ณด์ ๊ทธ๋ฃน์ ID
tags = {
Name = "miiiinju-terraform"
}
root_block_device {
delete_on_termination = true # ์ธ์คํด์ค ์ข
๋ฃ ์ EBS ๋ณผ๋ฅจ ์ญ์
}
credit_specification {
cpu_credits = "standard"
}
enable_monitoring = false
}
terraform init
terraform plan
terraform apply
๋ถ์ฐ ๋ชจ๋๋ฅผ ์ง์ํ๋ Python ๊ธฐ๋ฐ์ ๋ถํ ํ ์คํธ ์คํ์์ค
Python ์๋๋ฆฌ์ค๋ฅผ ํตํด ๊ฐ๋จํ๊ฒ ํ ์คํธ๋ฅผ ์ํํ ์ ์์
from locust import HttpUser, TaskSet, task, between
class UserBehavior(TaskSet):
@task(1)
def index(self):
self.client.get("/")
@task(2)
def about(self):
self.client.get("/about")
class WebsiteUser(HttpUser):
tasks = [UserBehavior]
wait_time = between(5, 15)
UserBehavior : ์ฌ์ฉ์๊ฐ ์ํํ ์์ ์ ์ ์
@task : ์์ ์ ์ฐ์ ์์๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค. ์์ ์์์์๋, about ๋ฉ์๋๊ฐ index ๋ฉ์๋๋ณด๋ค ๋ ๋ฐฐ ๋ ์์ฃผ ์คํ๋๋๋ก ์ค์ ๋จ
์ด๋ฅผ ๋ฐํ์ผ๋ก ๋ถํํ ์คํธ์์ ์ฌ์ฉํ ์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ค์์ต๋๋ค.
import random
import string
from datetime import datetime, timedelta
from locust import HttpUser, task
class MyUser(HttpUser):
@task
def send_post_request(self):
# HTTP ํค๋ ์ค์
headers = {
"App-Key": "f1607246-611e-4532-a08b-6023be328739",
"Content-Type": "application/json"
}
# ๋ก๊ทธ ๋ ๋ฒจ ์ค์
log_levels = ["info", "error", "debug", "warn", "trace"]
# ๋๋ค ๋ฌธ์์ด ์์ฑ ํจ์
def random_string(length=10):
letters = string.ascii_letters + string.digits
return ''.join(random.choice(letters) for _ in range(length))
# ๋๋ค ํ์์คํฌํ ์์ฑ ํจ์
def random_timestamp():
start_time = datetime(2023, 1, 1) # ์์์ ์์ ๋ ์ง
end_time = datetime.now()
random_time = start_time + (end_time - start_time) * random.random()
return random_time.isoformat()
# ์ ์กํ ๋ฐ์ดํฐ ์ค์ (100๊ฐ์ ๋ก๊ทธ ํญ๋ชฉ)
payload = []
for _ in range(100):
log_entry = {
"level": random.choice(log_levels),
"data": random_string(100), # 100์๋ฆฌ ๋๋ค ๋ฌธ์์ด
"timestamp": random_timestamp()
}
payload.append(log_entry)
# POST ์์ฒญ ๋ณด๋ด๊ธฐ
with self.client.post("/logs", json=payload, headers=headers, catch_response=True) as response:
if response.status_code == 201:
response.success()
else:
response.failure(f"Failed with status code {response.status_code}")
๋ก๊ทธ๋ฅผ ์์ฑํ๋ API ํฌ๋งท์ ๋ง๊ฒ ์์ฒญ์ ๋ณด๋ด๋ Python์ฝ๋๋ฅผ ์์ฑํ์ผ๋ฉฐ, ๋ก๊ทธ๋ ๋ฒจ์ ์์๋ก ๋๋คํ๊ฒ ๊ณ ๋ฅด๋๋ก ๋ง๋ค์์ต๋๋ค.
- ํญ์ EC2๋ฅผ ์ผ๋ ์ํ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์๋, ํ์ํ ๋ ์ ๊น terraform์ผ๋ก ์ธ์คํด์ค๋ฅผ ์ผ์ ๋ถํ ํ ์คํธ๋ฅผ ์ํํ ์ดํ, ์ข ๋ฃํ๋ ๊ธฐ๋ฅ์ด ํ์ํฉ๋๋ค.
- ๋ฐ๋ผ์ EC2๋ฅผ ๋งค๋ฒ ์ผ์ ํ๊ฒฝ ์ค์ ์ ์ํํ๊ธฐ์๋ ์๊ฐ ๋ถ๋ด์ด ํฌ๋ฏ๋ก, ๋ฏธ๋ฆฌ ์ธํ ํด์ ์ปค์คํ AMI๋ฅผ ๋ง๋ค์ด๋ ๋ค ์ด๋ฅผ ํตํด EC2 ์ธ์คํด์ค๋ฅผ ๋ง๋ค์์ต๋๋ค.
-> ๊ฐ์๊ธฐ ์ฌ์ฉํ ์ผ์ด ์๊ฒผ์ ๋์๋ EC2 ์ธ์คํด์ค๋ฅผ ์๋ก ๋ง๋ค๋๋ผ๋ ๊ธฐ์กด์ ์ธํ ์์ ์ด ๋ฏธ๋ฆฌ ๋ค ๋ผ์์ผ๋ฏ๋ก ์๊ฐ์ ์ ์ฝํ ์ ์์ต๋๋ค.
- EC2๋ฅผ ๊ธฐ๋ณธ ubuntu ์ด๋ฏธ์ง๋ฅผ ํตํด ์ง์ ๋ง๋ ํ, Locust ๊ตฌ๋์ ํ์ํ python, locust ์ค์น ๋ฑ์ ์์ ์ ์ํํ์ต๋๋ค.
aws ec2 create-image \
--instance-id {์ธ์คํด์ค-ID} \
--name "locust-ami" \
--no-reboot
resource "aws_instance" "locust_master" {
ami = "ami-046fdc13144b0da31" # ์ง์ ๋ง๋ AMI
instance_type = "t3.small"
# Security Group for Locust Master and Workers
resource "aws_security_group" "locust_sg" {
name = "locust_cluster_sg"
description = "Security group for Locust master and workers"
vpc_id = "vpc-3106975a" # VPC ID
ingress {
description = "Allow HTTP Web UI"
from_port = 8089
to_port = 8089
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "Allow Locust Worker to Master communication"
from_port = 5557
to_port = 5558
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "Allow SSH"
from_port = 22
to_port = 22
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 = "team5_locust_security_group"
}
}
8089๋ฒ ํฌํธ: Locust Web UI์ ์ ๊ทผํ๊ธฐ ์ํด ์ด๋ ค ์์ด์ผ ํจ. ์ด ํฌํธ๋ฅผ ํตํด ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ ์ ์์.
5557-5558๋ฒ ํฌํธ: Locust Worker์ Master ๊ฐ์ ํต์ ์ ์ํด ํ์. ์ด ํฌํธ๋ฅผ ํตํด ์์ปค๊ฐ ๋ง์คํฐ์๊ฒ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ ์กํ ์ ์์.
# Locust Master Instance
resource "aws_instance" "locust_master" {
ami = "ami-046fdc13144b0da31" # ์ง์ ๋ง๋ AMI
instance_type = "t3.small"
key_name = "team5_guys_pub"
subnet_id = "subnet-ac32f2f3"
vpc_security_group_ids = [aws_security_group.locust_sg.id]
tags = {
Name = "team5_locust_master"
}
์์ ๊ฐ์ด vpc_security_group_ids
๋ฅผ ํตํด ์์์ ๋ง๋ security group์ ์ง์ ์ฐธ์กฐํ ์ ์์
user_data = <<-EOF
#!/bin/bash
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
echo "Starting Locust Master setup"
# Decode and create locustfile.py
echo "${local.locustfile_content}" | base64 --decode > /home/ubuntu/locustfile.py
# Ensure locustfile.py is owned by ubuntu user
chown ubuntu:ubuntu /home/ubuntu/locustfile.py
chmod 644 /home/ubuntu/locustfile.py
# Create log file for Locust master and ensure ownership
touch /home/ubuntu/locust_master.log
chown ubuntu:ubuntu /home/ubuntu/locust_master.log
# Install Locust if not already installed
if ! command -v locust &> /dev/null; then
apt update
apt install -y python3-pip
pip3 install locust
fi
# Start Locust Master as ubuntu user
su - ubuntu -c "nohup locust -f /home/ubuntu/locustfile.py --master --master-bind-port=5557 --web-port=8089 > /home/ubuntu/locust_master.log 2>&1 &"
EOF
}
User Data ์คํฌ๋ฆฝํธ๋ ์ธ์คํด์ค๊ฐ ์์๋ ๋ ์๋์ผ๋ก ์คํ๋๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ํ ์ ์๋ ์คํฌ๋ฆฝํธ์ ๋๋ค.
exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1)
User Data ์คํฌ๋ฆฝํธ์ ์ถ๋ ฅ์ /var/log/user-data.log์ ๊ธฐ๋กํ๊ฒ ํ๋ ์คํฌ๋ฆฝํธ
echo "${local.locustfile_content}" | base64 --decode > /home/ubuntu/locustfile.py
์๋ locustfile ๋ด์ฉ์ locustfile.py๋ก ์ง์ ์ฐ๋ ์ญํ ์ ํ๋๋ฐ, "๊ฐ ์ฌ๋ผ์ง๋ ํ์์ด ์์ด base64๋ก ์ธ์ฝ๋ฉ ์ดํ decodingํ์ฌ ์ ์ฅํ๊ฒ ๋ง๋ค์์ต๋๋ค.
# Ensure locustfile.py is owned by ubuntu user
chown ubuntu:ubuntu /home/ubuntu/locustfile.py
chmod 644 /home/ubuntu/locustfile.py
# Create log file for Locust master and ensure ownership
touch /home/ubuntu/locust_master.log
chown ubuntu:ubuntu /home/ubuntu/locust_master.log
user_data๊ฐ root๊ถํ์ผ๋ก ์คํ๋๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ์ฌ์ฉ์ ๊ถํ์ผ๋ก๋ ์คํํ ์ ์๊ฒ ํ๊ธฐ์ํด chown์ ์ํํด์คฌ์ต๋๋ค.
su - ubuntu -c "nohup locust -f /home/ubuntu/locustfile.py --master --master-bind-port=5557 --web-port=8089 > /home/ubuntu/locust_master.log 2>&1 &"
- ๐ก How To? Chat-GPT ๋ฆฌ๋ทฐ์ด ๋์ ํ๊ธฐ
- ๐ก How To? ๋๋ฉ์ธ ์ค์ ํ๊ธฐ
- ๐ก How To? NGINX๋ก CORS ์ค์ ํ๊ธฐ
- ๐ก How To? JavaScript SDK ๊ฐ๋ฐํ๊ธฐ
- ๐ก How To? Java SDK ๊ฐ๋ฐํ๊ธฐ
- ๐ก How To? AWS Lambda๋ก ๋ถํ ํ ์คํธ ์งํํ๊ธฐ
- ๐ก How To? Terraform + Locust๋ก ๋ถํ ํ ์คํธ ์งํํ๊ธฐ
- โ๏ธ Refactoring: ๋ก๊ทธ ์ ์ฅ์ ํ๋ฒ์ ํ์!
- ๐จ ์๋ฒฝํ์ง ์์ ์๋๋ฐ์ค ํ ์คํธ๊ฐ ๋ถ๋ฌ์จ ํญํ
- ๐ก How To? ๋๋ฒ๊น ์ฉ ๊ฒฝ์์ด ๋ฐ์ํ์ง ์๋ Long ์นด์ดํฐ ๋ง๋ค๊ธฐ!
- ๐ก How To? Queue์ poll๊ณผ push๋ ์ ํ ์ค๋ ๋์์ ๋ด๋นํ๊ฒ ํ์๊น?