DevOps & Scaling

Terraform + CaptchaAI: CAPTCHA Çalışanları için Kod Olarak Altyapı

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 valueFrom ile 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:

  1. terraform init — sağlayıcıları ve state backend'ini hazırlayın.
  2. terraform plan — uygulanacak değişiklikleri gözden geçirin.
  3. terraform apply — altyapıyı ilgili ortamın .tfvars dosyasıyla oluşturun.
  4. 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-prefix ile 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:

Bu makale için yorumlar devre dışı bırakılmıştır.