CAPTCHA çözüm katmanını AWS panelinden elle kurduğunuzda asıl sorun ilk kurulum değil, üçüncü aydır: staging'de üç worker, production'da beş worker koşuyordur ama kimse eşzamanlılık ayarının plan thread sayısıyla hâlâ uyumlu olup olmadığını bilmez. Terraform bu belirsizliği ortadan kaldırır — worker sayısı, CPU/bellek, ölçeklendirme eşikleri ve eşzamanlılık tek bir depoda gözden geçirilebilir dosyalar hâlinde durur, her ortam aynı koddan doğar.
Aşağıda AWS ECS Fargate üzerinde çalışan bir CaptchaAI worker kümesini sıfırdan kuruyoruz: uzak state, Secrets Manager'da saklanan API anahtarı, görev tanımı, otomatik ölçeklendirme ve ortam bazlı .tfvars dosyaları. Kurulum kod olduğu için tekrarlanabilir, yıkım tek komutluk, maliyet hesabı da öngörülebilir kalır.
Başlamadan önce hazır olması gerekenler
- Terraform 1.5 veya üstü ve
aws configureile tanımlanmış kimlik bilgileri. - CaptchaAI API anahtarı ve iş yükünüze uyan bir plan — hangi planın hangi eşzamanlılığa denk geldiğini bir sonraki bölümde hesaplıyoruz.
- ECR'ye gönderilmiş bir worker container imajı.
- State için bir S3 bucket, kilitleme için bir DynamoDB tablosu.
API'yi hiç kullanmadıysanız önce tek bir çözümü lokalde çalıştırın; altyapıyı ancak akışın uçtan uca çalıştığını gördükten sonra koda dökmek çok daha az zaman kaybettirir.
Kapasiteyi plana göre hesaplayın
Bu kurulumdaki en kritik bağ, Terraform değişkenleriyle CaptchaAI planınız arasındadır:
Toplam eşzamanlı görev = worker_count × captchaai_concurrency
Bu sayı planınızın thread sayısını aşmamalıdır. Production örneğimizde 5 × 20 = 100 eşzamanlı görev çıkar; bu da 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. Thread sayısını aştığınızda fazla istekler hata almaz, yalnızca kuyrukta bekler — yani belirti düşen çözüm oranı değil, uzayan çözüm süresidir.
Türkiye'deki ekipler için burada pratik bir avantaj var: CaptchaAI thread başına faturalandırır, her thread'de sınırsız çözüm sunar ve fiyatlar USD'dir. Bir e-ticaret QA ekibi kampanya döneminde ölçek yukarı çıkarken çözüm başına maliyeti yeniden hesaplamak zorunda kalmaz; aylık gider seçtiğiniz plan neyse odur. .tfvars dosyasındaki eşzamanlılık değerini artırmadan önce planın thread havuzunu büyütmek, sürprizsiz bütçe için en basit kuraldır.
Depo düzeni
Kod üç katmana ayrılır; bu ayrım sayesinde tek bir depodan dev, staging ve production yönetilir:
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 dosyalar.- Uzak state (
backend "s3") — S3'te duran, 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
Adım 1: Provider ve uzak state
State'i S3'te tutar, DynamoDB tablosuyla kilitlersiniz. Kilit olmadan iki mühendis aynı anda apply çalıştırdığında state bozulur; encrypt = true ise dosyayı sunucu tarafında ş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
}
Adım 2: Ortamlar arasında değişecek girdiler
worker_count, worker_cpu ve captchaai_concurrency her ortamda farklı değer alır. Varsayılanlar burada dururken gerçek değerler .tfvars dosyalarından gelir — böylece production ayarını değiştirmek için modül koduna hiç dokunmazsınız.
# 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
}
Adım 3: API anahtarını state'in dışında tutun
Terraform state'i, içine giren her değeri düz metin olarak saklar. Bu yüzden API anahtarı üç kuralla yönetilir:
- Anahtarı hiçbir
.tfdosyasına veya değişken varsayılanına yazmayın. - Terraform yalnızca Secrets Manager kaydını oluşturur; değeri panelden ya da CLI ile ayrıca girersiniz.
- ECS görev tanımı anahtarı sadece
valueFromile referans alır; anahtar çalışma anında container'a enjekte edilir.
# 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
}
Adım 4: Fargate worker kümesi
Worker'lar containerInsights açık bir kümede çalışır. Her container anahtarı 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 ilkesi için iki ayrı IAM rolü kullanır:
execution_role— imajı ECR'den çeker, logları CloudWatch'a yazar.task_role— container'ın çalışma anında ihtiyaç duyduğu izinleri taşır (örneğin secret okuma).
Worker'lar özel alt ağlarda (private_subnets) koşar; dışarıdan doğrudan erişime kapalıdır ve CaptchaAI API'sine yalnızca giden isteklerle 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]
}
}
Adım 5: Kuyruk derinliğine göre otomatik ölçeklendirme
Kuyruk büyüdüğünde worker sayısı artar, boşta kaldığında azalır. Yukarı çıkarken kısa (120 sn), aşağı inerken uzun (300 sn) bir cooldown kullanmak, dalgalı yükte kümenin sürekli büyüyüp küçülmesini engeller.
# 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
}
}
}
Adım 6: Ortam dosyalarını yazın
Buradaki sayılar, yukarıda hesapladığınız plan kapasitesinin doğrudan yansımasıdır. Dev ortamı tek worker ve düşük eşzamanlılıkla çalışır:
# environments/dev.tfvars
environment = "dev"
worker_count = 1
max_workers = 3
worker_cpu = 256
worker_memory = 512
captchaai_concurrency = 3
Production ise beş worker ve worker başına 20 eşzamanlı görevle koşar:
# environments/production.tfvars
environment = "production"
worker_count = 5
max_workers = 20
worker_cpu = 1024
worker_memory = 2048
captchaai_concurrency = 20
Adım 7: Worker uygulama kodu
Container şu kodu çalıştırır: anahtarı 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 — bu ayrıntı atlandığında her ölçek küçülmesi birkaç görevi çöpe atar.
"""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")
Örnekteki method değeri userrecaptcha; aynı worker iskeletini yalnızca bu değeri değiştirerek reCAPTCHA v3, Cloudflare Turnstile veya GeeTest v3 akışlarında da kullanabilirsiniz. Görev gönderimi ve sorgulama mantığı tüm türlerde aynı kalır.
Adım 8: Dağıtım
# 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
Sıra sabittir: init sağlayıcıları ve state backend'ini hazırlar, plan uygulanacak değişiklikleri gösterir, apply altyapıyı ilgili .tfvars dosyasıyla kurar, destroy ise dev ortamını iş bittiğinde temizler. Ekip içinde plan çıktısını pull request'e eklemek, altyapı değişikliğini tıpkı kod gibi gözden geçirilebilir hâle getirir.
Üretimde izlenecek üç sinyal
- 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> |
| Ölçek büyüdükçe çözüm süresi uzuyor | Eşzamanlılık plan thread sayısını aşmış | captchaai_concurrency değerini düşürün ya da planı yükseltin |
Sık sorulan sorular
Terraform state dosyasını ekipçe nasıl güvende 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 dosya şifrelenir; bucket versiyonlamayı açarsanız hatalı bir apply sonrası geçmişe dönebilirsiniz.
Ölçek aşağı inerken devam eden çözümler kaybolur mu?
Worker kodu SIGTERM sinyalini yakalıyorsa hayır. ECS önce sinyali gönderir, worker yeni görev almayı bırakır ve elindeki çözümü tamamlar. Bu işleyicisi bulunmayan bir container'da her ölçek küçülmesi yarım kalmış görevler üretir.
worker_cpu ve worker_memory değerlerini nasıl seçmeliyim?
CAPTCHA worker'ı ağırlıklı olarak I/O bekler, CPU'yu zorlamaz; dev için 256 CPU / 512 MB fazlasıyla yeter. Production'da 1024 CPU / 2048 MB tercih etmemizin nedeni hesaplama yükü değil, yüksek eşzamanlılıkta açık bağlantı ve bellek tüketiminin artmasıdır.
Aynı yapıyı GCP veya Azure üzerinde kurabilir miyim?
Evet. AWS provider'ını ve kaynaklarını GCP (Cloud Run, GKE) ya da Azure (Container Instances, AKS) karşılıklarıyla değiştirmeniz yeterli; modül düzeni, değişken isimleri ve eşzamanlılık hesabı aynı kalır.
Bu altyapı hangi CAPTCHA türlerinde çalışır?
method değerini değiştirerek reCAPTCHA v2/v3, Cloudflare Turnstile, Cloudflare doğrulama akışı, GeeTest v3, BLS ve görüntü/OCR türlerini çözebilirsiniz. CaptchaFox (beta), Friendly Captcha (beta) ve Lemin (beta) de desteklenir. hCaptcha ve FunCaptcha desteklenmez; GeeTest v4 için ise çok yakında notu geçerlidir.
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: