DevOps & Scaling

Ansible Playbook untuk Penerapan Worker CaptchaAI

Menambah satu worker baru ke armada pemecahan CAPTCHA Anda seharusnya tidak berarti login SSH manual ke setiap server, menyalin skrip Python satu per satu, lalu mengatur systemd service dengan tangan. Itulah yang dihapus oleh Ansible playbook di panduan ini: satu perintah ansible-playbook menerapkan worker yang sama persis — kode, konfigurasi, service systemd — ke tiga server atau tiga puluh server sekaligus, lalu memperbaruinya lewat rolling update tanpa mematikan seluruh armada.

Terraform menyediakan server dan jaringannya; Ansible masuk setelah itu untuk mengisi server tersebut. Role captcha-worker di bawah ini mencakup instalasi dependensi, deployment kode worker, template konfigurasi, dan service systemd dalam satu paket yang idempotent — jalankan ulang kapan saja tanpa efek samping. Susunan ini juga cocok untuk tim yang men-deploy worker di beberapa region sekaligus, misalnya AWS ap-southeast-1 (Singapura) untuk trafik regional dan ap-southeast-3 (Jakarta) untuk latensi lokal — cukup tambahkan host baru ke inventory, tidak perlu menulis ulang playbook-nya.

Struktur Proyek Ansible untuk Worker CaptchaAI

Playbook ini mengikuti struktur role standar Ansible — satu role captcha-worker yang dipakai ulang oleh tiga playbook berbeda (deploy, rolling update, health check):

ansible/
├── inventory/
│   ├── production.yml
│   └── staging.yml
├── roles/
│   └── captcha-worker/
│       ├── tasks/
│       │   └── main.yml
│       ├── templates/
│       │   ├── captcha-worker.service.j2
│       │   └── config.yaml.j2
│       ├── handlers/
│       │   └── main.yml
│       └── defaults/
│           └── main.yml
├── playbooks/
│   ├── deploy.yml
│   ├── rolling-update.yml
│   └── health-check.yml
└── ansible.cfg

Inventory: Staging vs Production

Inventory memisahkan host staging dari production, dan variabelnya sengaja dibuat berbeda. Worker staging memakai captchaai_log_level: debug dan versi release candidate supaya mudah dipantau saat diuji; worker production memakai warning dan concurrency yang lebih tinggi (20 dibanding 5) karena menangani trafik nyata:

# inventory/production.yml
all:
  children:
    captcha_workers:
      hosts:
        worker-1:
          ansible_host: 10.0.1.10
        worker-2:
          ansible_host: 10.0.1.11
        worker-3:
          ansible_host: 10.0.1.12
      vars:
        captchaai_concurrency: 20
        captchaai_poll_interval: 3
        captchaai_log_level: warning
        worker_version: "1.3.0"
# inventory/staging.yml
all:
  children:
    captcha_workers:
      hosts:
        staging-worker-1:
          ansible_host: 10.0.2.10
      vars:
        captchaai_concurrency: 5
        captchaai_poll_interval: 5
        captchaai_log_level: debug
        worker_version: "1.4.0-rc1"

Angka captchaai_concurrency di sini menentukan berapa banyak task yang dikirim tiap worker ke API CaptchaAI secara paralel — ini yang perlu Anda selaraskan dengan alokasi thread pada paket CaptchaAI Anda, bukan sekadar dinaikkan asal-asalan (lihat catatan skala di bagian playbook di bawah).

Role captcha-worker: Konfigurasi Inti

Role ini punya empat bagian — variabel default, task, template, dan handler — yang bersama-sama menginstal dependensi, men-deploy kode worker, dan mendaftarkannya sebagai systemd service.

Variabel Default

# roles/captcha-worker/defaults/main.yml
captchaai_concurrency: 10
captchaai_poll_interval: 5
captchaai_log_level: info
captchaai_timeout: 300
captchaai_retries: 3
worker_version: "latest"
worker_user: captcha
worker_dir: /opt/captcha-worker
worker_venv: /opt/captcha-worker/venv

Task: Instalasi dan Deploy

Task-nya idempotent — menjalankan ulang playbook yang sama tidak membuat user, virtualenv, atau dependensi duplikat, karena Ansible mengecek state saat ini sebelum mengubah apa pun:

# roles/captcha-worker/tasks/main.yml
---

- name: Create worker user
  ansible.builtin.user:
    name: "{{ worker_user }}"
    system: true
    shell: /usr/sbin/nologin
    home: "{{ worker_dir }}"

- name: Create worker directory
  ansible.builtin.file:
    path: "{{ worker_dir }}"
    state: directory
    owner: "{{ worker_user }}"
    mode: "0755"

- name: Install system dependencies
  ansible.builtin.apt:
    name:

      - python3
      - python3-venv
      - python3-pip
    state: present
    update_cache: true

- name: Create Python virtual environment
  ansible.builtin.command:
    cmd: python3 -m venv {{ worker_venv }}
    creates: "{{ worker_venv }}/bin/activate"

- name: Install Python dependencies
  ansible.builtin.pip:
    name:

      - requests>=2.31.0
      - pyyaml>=6.0
    virtualenv: "{{ worker_venv }}"

- name: Deploy worker application
  ansible.builtin.copy:
    src: captcha_worker.py
    dest: "{{ worker_dir }}/captcha_worker.py"
    owner: "{{ worker_user }}"
    mode: "0644"
  notify: restart captcha-worker

- name: Deploy configuration
  ansible.builtin.template:
    src: config.yaml.j2
    dest: "{{ worker_dir }}/config.yaml"
    owner: "{{ worker_user }}"
    mode: "0600"
  notify: restart captcha-worker

- name: Deploy systemd service
  ansible.builtin.template:
    src: captcha-worker.service.j2
    dest: /etc/systemd/system/captcha-worker.service
    mode: "0644"
  notify:

    - reload systemd
    - restart captcha-worker

- name: Enable and start service
  ansible.builtin.systemd:
    name: captcha-worker
    enabled: true
    state: started

Template Konfigurasi dan Service

# roles/captcha-worker/templates/config.yaml.j2
# CaptchaAI Worker Configuration
# Managed by Ansible — do not edit manually
concurrency: {{ captchaai_concurrency }}
poll_interval: {{ captchaai_poll_interval }}
timeout: {{ captchaai_timeout }}
retries: {{ captchaai_retries }}
log_level: {{ captchaai_log_level }}

Template service systemd-nya menambahkan hardening dasar (NoNewPrivileges, ProtectSystem: strict) supaya worker berjalan dengan privilege minimum yang benar-benar dibutuhkan:

# roles/captcha-worker/templates/captcha-worker.service.j2
[Unit]
Description=CaptchaAI CAPTCHA Solving Worker
After=network.target
Wants=network-online.target

[Service]
Type=simple
User={{ worker_user }}
WorkingDirectory={{ worker_dir }}
ExecStart={{ worker_venv }}/bin/python {{ worker_dir }}/captcha_worker.py
Environment=CAPTCHAAI_API_KEY={{ captchaai_api_key }}
Restart=always
RestartSec=10
TimeoutStopSec=30

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths={{ worker_dir }}

[Install]
WantedBy=multi-user.target

Handler Restart

Task Deploy worker application, Deploy configuration, dan Deploy systemd service di atas semuanya memicu handler ini lewat notify — restart hanya terjadi kalau ada file yang benar-benar berubah, bukan di setiap run:

# roles/captcha-worker/handlers/main.yml
---

- name: reload systemd
  ansible.builtin.systemd:
    daemon_reload: true

- name: restart captcha-worker
  ansible.builtin.systemd:
    name: captcha-worker
    state: restarted

Playbook: Deploy, Rolling Update, dan Health Check

Tiga playbook di atas role yang sama ini menangani tiga skenario operasional yang berbeda.

Deploy

Playbook ini meminta API key lewat vars_prompt saat dijalankan (jangan hardcode di file), mengecek konektivitas dulu sebelum apply, lalu memverifikasi status service setelahnya:

# playbooks/deploy.yml
---

- name: Deploy CaptchaAI Workers
  hosts: captcha_workers
  become: true
  vars_prompt:

    - name: captchaai_api_key
      prompt: "Enter CaptchaAI API key"
      private: true

  pre_tasks:

    - name: Verify connectivity
      ansible.builtin.ping:

  roles:

    - captcha-worker

  post_tasks:

    - name: Wait for worker to start
      ansible.builtin.wait_for:
        port: 8080
        timeout: 30
      ignore_errors: true

    - name: Check worker status
      ansible.builtin.systemd:
        name: captcha-worker
      register: worker_status

    - name: Report status
      ansible.builtin.debug:
        msg: "Worker {{ inventory_hostname }}: {{ worker_status.status.ActiveState }}"

Rolling Update

serial: 1 memastikan hanya satu host yang diperbarui pada satu waktu, dan max_fail_percentage: 0 menghentikan seluruh rollout begitu satu host gagal — armada tetap melayani task dari host lain selama proses berjalan:

# playbooks/rolling-update.yml
---

- name: Rolling Update CaptchaAI Workers
  hosts: captcha_workers
  become: true
  serial: 1   # Update one host at a time
  max_fail_percentage: 0

  tasks:

    - name: Drain current tasks
      ansible.builtin.command:
        cmd: "{{ worker_venv }}/bin/python {{ worker_dir }}/drain.py"
      timeout: 120
      ignore_errors: true

    - name: Stop worker
      ansible.builtin.systemd:
        name: captcha-worker
        state: stopped

    - name: Deploy new version
      ansible.builtin.copy:
        src: "captcha_worker.py"
        dest: "{{ worker_dir }}/captcha_worker.py"
        owner: "{{ worker_user }}"
        mode: "0644"

    - name: Update dependencies
      ansible.builtin.pip:
        requirements: "{{ worker_dir }}/requirements.txt"
        virtualenv: "{{ worker_venv }}"

    - name: Start worker
      ansible.builtin.systemd:
        name: captcha-worker
        state: started

    - name: Verify worker health
      ansible.builtin.uri:
        url: "http://localhost:8080/health"
        return_content: true
      register: health
      until: health.status == 200
      retries: 6
      delay: 10

    - name: Report update result
      ansible.builtin.debug:
        msg: "{{ inventory_hostname }} updated — {{ health.content }}"

Health Check

Playbook ini dijalankan tanpa become untuk cek API (task Check API connectivity berjalan lewat delegate_to: localhost, bukan di server worker), lalu menampilkan saldo akun lewat res.php:

# playbooks/health-check.yml
---

- name: Check CaptchaAI Worker Health
  hosts: captcha_workers
  become: false
  gather_facts: false

  tasks:

    - name: Check systemd service
      ansible.builtin.systemd:
        name: captcha-worker
      register: service_status
      become: true

    - name: Check API connectivity
      ansible.builtin.uri:
        url: "https://ocr.captchaai.com/res.php?key={{ captchaai_api_key }}&action=getbalance&json=1"
        return_content: true
      register: api_check
      delegate_to: localhost
      run_once: true

    - name: Summary
      ansible.builtin.debug:
        msg: |
          Host: {{ inventory_hostname }}
          Service: {{ service_status.status.ActiveState }}
          API Balance: {{ (api_check.content | from_json).request }}

Sebelum menambah worker baru lewat inventory, cek dulu alokasi thread paket CaptchaAI Anda — captchaai_concurrency di atas hanya berguna kalau paket API-nya menampung angka itu. Tiga worker dengan concurrency 20 berarti sampai 60 task berjalan paralel; paket ADVANCE ($90/bulan, 50 thread) sudah mepet di titik itu, sementara CORPORATE ($240/bulan, 150 thread) memberi ruang untuk worker keempat dan kelima tanpa task tertahan di antrean. Ini pertimbangan nyata untuk tim scraping dan automation Indonesia yang biasanya menambah worker bertahap sesuai volume klien, bukan sekaligus di awal.

Menjalankan Playbook Ansible

# Deploy to staging
ansible-playbook -i inventory/staging.yml playbooks/deploy.yml

# Rolling update in production
ansible-playbook -i inventory/production.yml playbooks/rolling-update.yml

# Health check
ansible-playbook -i inventory/production.yml playbooks/health-check.yml

# Limit to specific hosts
ansible-playbook -i inventory/production.yml playbooks/deploy.yml --limit worker-1

Jalankan --limit worker-1 dulu setiap kali Anda mengubah role — memvalidasi perubahan di satu host sebelum menyebar ke seluruh armada jauh lebih murah daripada memperbaiki tiga puluh host sekaligus.

Mengatasi Masalah Umum

Sebagian besar kegagalan playbook ada di empat pola berikut:

Masalah Penyebab Solusi
Host tidak dapat dijangkau Kunci SSH tidak dikonfigurasi Tambahkan kunci SSH: ssh-copy-id user@host
Service tidak mau start Env var API key tidak ada Periksa vars_prompt atau gunakan Ansible Vault
Rolling update terhenti Health check gagal Periksa journalctl -u captcha-worker; tambah retries
Konfigurasi tidak diterapkan Handler tidak terpicu Jalankan dengan --force-handlers atau tambahkan changed_when: true

Pertanyaan Umum

Bagaimana cara menyimpan API key CaptchaAI dengan aman di Ansible?

Jangan taruh API key polos di file inventory. Enkripsi dengan Ansible Vault: ansible-vault encrypt_string 'YOUR_API_KEY' --name 'captchaai_api_key', lalu referensikan variabel terenkripsi itu di group_vars atau saat menjalankan playbook.

Berapa banyak worker yang bisa ditangani satu playbook sekaligus?

Tidak ada batas dari sisi Ansible — struktur inventory ini sudah teruji untuk puluhan host dalam satu file. Batas praktisnya ada di alokasi thread paket CaptchaAI Anda dan kapasitas jaringan server, bukan di Ansible itu sendiri.

Apakah rolling update ini menyebabkan downtime pada task yang sedang berjalan?

Task Drain current tasks dijalankan lebih dulu supaya worker menyelesaikan task yang sedang jalan sebelum service dihentikan, dan serial: 1 memastikan hanya satu host yang update di satu waktu — armada tetap menerima task dari host lain selama proses berlangsung.

Bisakah inventory ini menampung worker di beberapa region sekaligus, misalnya Singapura dan Jakarta?

Bisa. Tambahkan grup host baru di inventory/production.yml dengan ansible_host masing-masing region — misalnya AWS ap-southeast-1 untuk Singapura atau ap-southeast-3 untuk Jakarta — lalu jalankan playbook yang sama dengan --limit kalau Anda hanya ingin menargetkan satu region dulu.

Apa bedanya Ansible dengan Terraform untuk deployment worker CaptchaAI?

Terraform menyediakan infrastrukturnya — membuat server dan jaringan. Ansible mengonfigurasi isi server yang sudah ada — instal dependensi, deploy kode, atur service. Keduanya dipakai berurutan: Terraform membuat armada, Ansible yang mengisinya.

Langkah Selanjutnya

Anda sudah punya playbook untuk deploy dan mengelola armada worker CaptchaAI — yang belum adalah API key-nya. Ambil API key CaptchaAI Anda dan jalankan deploy.yml ke server pertama hari ini.

Panduan terkait:

Komentar dinonaktifkan untuk artikel ini.