Tek bir terraform apply komutuyla CAPTCHA çözüm katmanınızın tamamını — ECS worker'ları, otomatik ölçeklendirme ve gizli anahtar yönetimi — ayağa kaldırabilirsiniz. Terraform bu altyapıyı kod olarak tanımlar; aynı yapılandırmayı dev, staging ve production ortamlarında birebir çoğaltır, sürümler, gözden geçirir ve iş bittiğinde tek komutla yıkarsınız. Bu rehber, CaptchaAI worker'larını AWS üzerinde üretime hazır biçimde Terraform ile nasıl kuracağınızı adım adım gösterir — panelde elle tıklamadan, tekrarlanabilir ve denetlenebilir bir kurulumla.
Mimari genel bakış
Kurulum üç katmana ayrılır; bu ayrım sayesinde tek bir kod tabanından dev, staging ve production ortamlarını yönetirsiniz:
modules/captcha-worker— ECS/EC2 kaynaklarını tutan, yeniden kullanılabilir modül.environments/*.tfvars— her ortamın worker sayısını, CPU/bellek ve eşzamanlılık değerlerini belirleyen ortama özel dosyalar.- Uzak state (
backend "s3") — S3'te tutulan, DynamoDB ile kilitlenen ortak durum dosyası.
terraform/
├── main.tf # Provider config
├── variables.tf # Input variables
├── outputs.tf # Output values
├── modules/
│ └── captcha-worker/
│ ├── main.tf # ECS/EC2 resources
│ ├── variables.tf # Module inputs
│ └── outputs.tf # Module outputs
├── environments/
│ ├── dev.tfvars
│ ├── staging.tfvars
│ └── production.tfvars
Ön koşullar
Başlamadan önce şunların hazır olduğundan emin olun:
- Terraform 1.5 veya üstü ve yapılandırılmış AWS kimlik bilgileri.
- CaptchaAI API anahtarı ve iş yükünüze uygun bir plan (thread sayısı için aşağıdaki bölüme bakın).
- ECR'ye gönderilmiş bir worker container imajı.
- State için bir S3 bucket ve kilitleme için bir DynamoDB tablosu.
Temel Terraform yapılandırması
Provider ve uzak state backend
State dosyasını S3'te tutar, DynamoDB tablosuyla kilitlersiniz; böylece iki mühendis aynı anda apply çalıştırdığında state bozulmaz. encrypt = true state'i şifreler.
# main.tf
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "captcha-workers/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
}
Girdi değişkenleri
worker_count, worker_cpu ve captchaai_concurrency gibi değişkenler her ortamda farklı değer alır. Varsayılanlar burada dururken, ortama özgü değerler .tfvars dosyalarında yaşar.
# variables.tf
variable "aws_region" {
description = "AWS region for deployment"
type = string
default = "us-east-1"
}
variable "environment" {
description = "Environment name (dev, staging, production)"
type = string
}
variable "worker_count" {
description = "Number of CAPTCHA solving workers"
type = number
default = 3
}
variable "worker_cpu" {
description = "CPU units for each worker (1024 = 1 vCPU)"
type = number
default = 512
}
variable "worker_memory" {
description = "Memory in MB for each worker"
type = number
default = 1024
}
variable "max_workers" {
description = "Maximum workers for auto-scaling"
type = number
default = 10
}
variable "captchaai_concurrency" {
description = "Concurrent CAPTCHA tasks per worker"
type = number
default = 10
}
API anahtarını güvenli saklama
API anahtarını asla .tf dosyasına veya değişken varsayılanına yazmayın. Bunun yerine şu ilkeleri izleyin:
- Anahtarı AWS Secrets Manager'da saklayın; Terraform sadece secret kaynağını oluşturur, değeri tutmaz.
- ECS görev tanımı anahtarı yalnızca
valueFromile referansla çeker. - Anahtar çalışma anında container'a enjekte edilir, böylece düz metin olarak state dosyasına düşmez.
# secrets.tf — Store API key in AWS Secrets Manager
resource "aws_secretsmanager_secret" "captchaai_api_key" {
name = "${var.environment}/captchaai-api-key"
description = "CaptchaAI API key for CAPTCHA solving workers"
}
# Reference secret in ECS task (never in plain text)
data "aws_secretsmanager_secret_version" "captchaai_api_key" {
secret_id = aws_secretsmanager_secret.captchaai_api_key.id
}
ECS worker kümesi
Fargate tabanlı worker'lar, containerInsights ile izlenebilir bir kümede çalışır. Her container API anahtarını Secrets Manager'dan alır, görevleri kuyruğunuzdan çeker ve sonucu res.php uç noktasından sorgular. Görev tanımı en az yetki ilkesini korumak için iki ayrı IAM rolü kullanır:
execution_role— imajı ECR'den çeker ve logları CloudWatch'a yazar.task_role— container'ın çalışma anında ihtiyaç duyduğu izinleri (örneğin secret okuma) taşır.
Worker'lar özel alt ağlarda (private_subnets) koştuğu için dışarıdan doğrudan erişime kapalıdır; yalnızca giden isteklerle CaptchaAI API'sine ulaşırlar.
# ecs.tf — Fargate-based CAPTCHA workers
resource "aws_ecs_cluster" "captcha" {
name = "captcha-workers-${var.environment}"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_task_definition" "captcha_worker" {
family = "captcha-worker-${var.environment}"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.worker_cpu
memory = var.worker_memory
execution_role_arn = aws_iam_role.ecs_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
container_definitions = jsonencode([
{
name = "captcha-worker"
image = "${aws_ecr_repository.captcha_worker.repository_url}:latest"
environment = [
{ name = "CAPTCHAAI_CONCURRENCY", value = tostring(var.captchaai_concurrency) },
{ name = "CAPTCHAAI_POLL_INTERVAL", value = "5" },
{ name = "ENVIRONMENT", value = var.environment },
]
secrets = [
{
name = "CAPTCHAAI_API_KEY"
valueFrom = aws_secretsmanager_secret.captchaai_api_key.arn
}
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = aws_cloudwatch_log_group.captcha.name
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "worker"
}
}
}
])
}
resource "aws_ecs_service" "captcha_worker" {
name = "captcha-workers"
cluster = aws_ecs_cluster.captcha.id
task_definition = aws_ecs_task_definition.captcha_worker.arn
desired_count = var.worker_count
launch_type = "FARGATE"
network_configuration {
subnets = var.private_subnets
security_groups = [aws_security_group.captcha_worker.id]
}
}
Yük altında otomatik ölçeklendirme
Kuyruk derinleştiğinde worker sayısı artar, boşta kaldığında azalır. Ölçek yukarı çıkarken kısa (120 sn), aşağı inerken daha uzun (300 sn) bir cooldown kullanmak, ani yük düşüşlerinde gereksiz küçülmeyi önler.
# autoscaling.tf
resource "aws_appautoscaling_target" "captcha" {
max_capacity = var.max_workers
min_capacity = var.worker_count
resource_id = "service/${aws_ecs_cluster.captcha.name}/${aws_ecs_service.captcha_worker.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
# Scale up when queue is deep
resource "aws_appautoscaling_policy" "scale_up" {
name = "captcha-scale-up"
policy_type = "StepScaling"
resource_id = aws_appautoscaling_target.captcha.resource_id
scalable_dimension = aws_appautoscaling_target.captcha.scalable_dimension
service_namespace = aws_appautoscaling_target.captcha.service_namespace
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 120
step_adjustment {
scaling_adjustment = 2
metric_interval_lower_bound = 0
}
}
}
# Scale down when idle
resource "aws_appautoscaling_policy" "scale_down" {
name = "captcha-scale-down"
policy_type = "StepScaling"
resource_id = aws_appautoscaling_target.captcha.resource_id
scalable_dimension = aws_appautoscaling_target.captcha.scalable_dimension
service_namespace = aws_appautoscaling_target.captcha.service_namespace
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 300
step_adjustment {
scaling_adjustment = -1
metric_interval_upper_bound = 0
}
}
}
Ortam bazlı değişkenler
Buradaki en kritik bağ, eşzamanlılık ile CaptchaAI plan thread sayısı arasındadır. Toplam eşzamanlı görev = worker_count × captchaai_concurrency. Production örneğinde bu 5 × 20 = 100 eşzamanlı görev demektir ve PREMIUM ($170/ay, 100 thread) planına denk gelir; dev ortamında 1 × 3 = 3 görev BASIC ($15/ay, 5 thread) ile rahatça karşılanır. Planınızın thread sayısını aşarsanız fazladan istekler hata almaz, sadece kuyrukta bekler. CaptchaAI thread başına faturalandığı ve her thread'de sınırsız çözüm sunduğu için aylık maliyetiniz USD cinsinden öngörülebilir kalır — TL kurundaki oynaklıktan bağımsız olarak bütçe yapabilirsiniz.
# environments/dev.tfvars
environment = "dev"
worker_count = 1
max_workers = 3
worker_cpu = 256
worker_memory = 512
captchaai_concurrency = 3
# environments/production.tfvars
environment = "production"
worker_count = 5
max_workers = 20
worker_cpu = 1024
worker_memory = 2048
captchaai_concurrency = 20
Worker uygulama kodu
Container bu kodu çalıştırır: API anahtarını ortam değişkeninden okur, görevi in.php uç noktasına gönderir ve token hazır olana kadar res.php'yi sorgular. SIGTERM yakalayan graceful shutdown, ölçek aşağı inerken devam eden çözümlerin yarıda kesilmemesini sağlar.
"""captcha_worker.py — The container runs this."""
import os
import time
import signal
import requests
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
CONCURRENCY = int(os.environ.get("CAPTCHAAI_CONCURRENCY", "10"))
POLL_INTERVAL = int(os.environ.get("CAPTCHAAI_POLL_INTERVAL", "5"))
running = True
def shutdown_handler(signum, frame):
global running
print("Graceful shutdown initiated")
running = False
signal.signal(signal.SIGTERM, shutdown_handler)
signal.signal(signal.SIGINT, shutdown_handler)
session = requests.Session()
def solve_captcha(sitekey, pageurl):
resp = session.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(POLL_INTERVAL)
result = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
# Main loop — pull tasks from SQS or Redis
print(f"Worker started: concurrency={CONCURRENCY}")
while running:
# Pull tasks from your queue here
time.sleep(1)
print("Worker shutdown complete")
Terraform dağıtım komutları
Akış dört adımdan oluşur ve altyapı kod olduğundan tekrar ayağa kaldırmak yine tek komuttur:
terraform init— sağlayıcıları ve state backend'ini hazırlayın.terraform plan— uygulanacak değişiklikleri gözden geçirin.terraform apply— altyapıyı ilgili ortamın.tfvarsdosyasıyla oluşturun.terraform destroy— dev ortamını iş bittiğinde temizleyin.
# Initialize
terraform init
# Plan for production
terraform plan -var-file=environments/production.tfvars
# Apply
terraform apply -var-file=environments/production.tfvars
# Destroy (dev cleanup)
terraform destroy -var-file=environments/dev.tfvars
Gözlemlenebilirlik
Worker'lar üretime çıktıktan sonra izlemeniz gereken üç sinyal vardır:
- CloudWatch logları — her worker'ın çözüm ve hata çıktısı;
awslogs-stream-prefixile ayrıştırılır. - Container Insights — CPU/bellek kullanımı ve görev sayısı; ölçeklendirme eşiklerini burada doğrularsınız.
- CaptchaAI paneli — aktif thread kullanımı ve bakiye; plan sınırınıza yaklaşıp yaklaşmadığınızı gösterir.
Sorun giderme
| Sorun | Olası neden | Çözüm |
|---|---|---|
| Dağıtımda gizli anahtar bulunamıyor | Secrets Manager değeri henüz girilmemiş | terraform apply öncesi gizli anahtar değerini oluşturun |
| Worker'lar ilk açılışta çöküyor | Eksik ortam değişkeni veya yanlış imaj | CloudWatch loglarını inceleyin; ECR imaj etiketini doğrulayın |
| Otomatik ölçeklendirme tetiklenmiyor | Eksik CloudWatch alarmı veya yanlış metrik | Ölçeklendirme politikasındaki alarm ARN'sini kontrol edin |
| State kilidi hatası | Önceki apply yarıda kesilmiş |
Kilidi kaldırın: terraform force-unlock <lock-id> |
Sık sorulan sorular
captchaai_concurrency değerini plan thread sayısıyla nasıl eşleştiririm?
Toplam eşzamanlı görev worker_count × captchaai_concurrency ile hesaplanır ve bu sayı planınızın thread sayısını aşmamalıdır. Örneğin 100 eşzamanlı görev PREMIUM ($170/ay, 100 thread) planına denk gelir. Yük arttıkça worker başına eşzamanlılığı zorlamak yerine planı yükselterek thread havuzunu büyütün.
API anahtarını Terraform state'ine sızdırmadan nasıl yönetirim?
Anahtarı hiçbir .tf dosyasına ya da değişken varsayılanına yazmayın. AWS Secrets Manager'da saklayın ve ECS görev tanımında yalnızca valueFrom ile referans verin; anahtar çalışma anında container'a enjekte olur, state dosyasına düz metin olarak düşmez.
Fargate mı yoksa EC2 mı kullanmalıyım?
Hızlı başlangıç ve otomatik ölçeklendirme için Fargate; sabit, yüksek hacimli yükte maliyet için rezerve EC2 örnekleri. Çoğu ekip Fargate ile başlar, kararlı yükü zamanla EC2'ye taşır.
Terraform state'ini ekip olarak nasıl güvenli tutarım?
State'i S3 backend'inde tutun ve bir DynamoDB kilit tablosu tanımlayın; kilit, iki kişinin aynı anda apply çalıştırıp state'i bozmasını engeller. encrypt = true ile state şifrelenir, geçmişi korumak için bucket versiyonlamayı açın.
Bu altyapı hangi CAPTCHA türlerini çözer?
Worker kodu userrecaptcha metodunu kullanır; aynı desen method değerini değiştirerek reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3 ve görüntü/OCR türlerinde de çalışır. CaptchaFox, Friendly Captcha ve Lemin (beta) türleri de desteklenir; hCaptcha ve FunCaptcha ise desteklenmez.
Sonraki adımlar
Altyapınızı koda dökün: CaptchaAI API anahtarınızı alın ve ilk worker kümenizi Terraform ile dağıtın.
İlgili kılavuzlar: