Sur une seule machine, un worker CaptchaAI s'installe à la main en quelques minutes. Sur une flotte de dix ou vingt serveurs, cette approche manuelle devient la première source de dérive : versions qui divergent, fichiers de service désynchronisés, mises à jour appliquées à moitié. Ansible répond exactement à ce problème : un rôle versionné décrit l'état voulu de chaque worker, et vous le rejouez à l'identique sur tout le parc.
Ce guide construit un rôle captcha-worker complet, un inventaire qui sépare production et préproduction, puis trois playbooks :
- Déploiement initial — bootstrap complet de la flotte.
- Mise à jour progressive — nouvelle version sans coupure.
- Contrôle de santé — état du service et de l'API.
L'ensemble reste idempotent : rejouer le rôle sur un hôte déjà conforme ne change rien.
Arborescence du projet Ansible
L'arborescence cible suit les conventions Ansible : un rôle réutilisable sous roles/, les inventaires par environnement, et les playbooks qui orchestrent le tout.
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
Inventaire : séparer production et préproduction
L'inventaire distingue vos environnements : la production tourne avec une forte concurrence et des logs réduits ; la préproduction reste bavarde pour le diagnostic. C'est aussi ici que vous épinglez la version de worker par groupe d'hôtes, ce qui rend un rollback aussi simple qu'un changement de variable.
# 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"
Aligner la concurrence sur vos threads CaptchaAI
La variable captchaai_concurrency fixe le nombre de résolutions traitées en parallèle par un hôte. Calez-la sur les threads de votre offre :
- BASIC ($15/mois, 5 threads) : une concurrence de 20 serait disproportionnée.
- ADVANCE ($90/mois, 50 threads) : absorbe sans peine une concurrence élevée.
Réduire les logs en production (warning) évite aussi que des logs verbeux capturent des fragments de requêtes : dans un cadre RGPD, journalisez le strict nécessaire.
Le rôle captcha-worker
Le rôle captcha-worker regroupe tout ce qu'un serveur doit contenir pour exécuter un worker : utilisateur système dédié, environnement Python isolé, service systemd et sa configuration. Le découper en defaults, tasks, templates et handlers garde chaque responsabilité à sa place.
Variables par défaut du rôle
Ces valeurs s'appliquent tant que l'inventaire ne les surcharge pas. Elles décrivent un worker prudent : concurrence modérée, journalisation en info, trois tentatives.
# 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
Tâches d'installation et de service
Les tâches s'exécutent dans l'ordre : utilisateur, répertoire, dépendances système et Python, déploiement du code et de la configuration, activation du service. Chaque tâche est idempotente, et grâce aux notify, le service n'est redémarré que si un fichier a réellement changé.
# 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
Ce rôle pose le socle de déploiements répétables : même utilisateur, même arborescence, même service, quel que soit le serveur.
Templates de configuration et service systemd
Deux templates Jinja2 produisent les fichiers finaux à partir des variables :
config.yaml.j2génère la configuration du worker.captcha-worker.service.j2décrit le service systemd, avec un durcissement de sécurité (NoNewPrivileges,ProtectSystem=strict) qui limite ce que le processus peut toucher sur l'hôte.
# 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 }}
# 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
La clé API n'est jamais écrite en clair : elle arrive par la variable captchaai_api_key, injectée à l'exécution ou lue depuis Ansible Vault (voir la FAQ).
Handlers de rechargement
Les handlers ne se déclenchent que sur notification : un changement de configuration ou de code recharge systemd puis redémarre le worker — jamais à chaque exécution, seulement quand quelque chose a réellement bougé.
# 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
Les playbooks
Trois playbooks couvrent le cycle de vie de la flotte : premier déploiement, mise à jour progressive et surveillance.
Déploiement initial de la flotte
Le playbook de déploiement demande la clé API de façon interactive (vars_prompt), vérifie la connectivité, applique le rôle, puis confirme que le service est actif. C'est celui à lancer pour un bootstrap ou un redéploiement complet.
# 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 }}"
Pour une exécution non interactive (CI/CD), remplacez vars_prompt par une variable chiffrée dans Vault.
Mise à jour progressive (rolling update)
C'est le playbook le plus important en production. serial: 1 force Ansible à traiter un hôte à la fois : il draine les tâches en cours, arrête le worker, déploie la nouvelle version, redémarre, puis attend que le contrôle de santé réponde 200 avant de passer au suivant.
# 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 }}"
Avec max_fail_percentage: 0, la moindre erreur stoppe le déploiement : une version défectueuse n'atteint jamais le reste de la flotte. C'est la différence entre une mise à jour prudente et une panne générale.
Contrôle de santé de la flotte
Le contrôle de santé combine deux vérifications : l'état du service systemd sur chaque hôte et une interrogation de l'API CaptchaAI depuis la machine de contrôle, pour confirmer que le solde est lisible. Lancez-le en routine ou après chaque déploiement.
# 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 }}
Commandes ansible-playbook courantes
Les opérations du quotidien restent simples : un playbook par intention.
# 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
Dépannage
| Problème | Cause probable | Correctif |
|---|---|---|
| Hôte injoignable (« unreachable ») | Clé SSH absente ou mauvais utilisateur | Ajoutez la clé avec ssh-copy-id user@host et vérifiez ansible_host |
| Le service ne démarre pas | Variable captchaai_api_key absente |
Fournissez-la via vars_prompt ou Ansible Vault |
| Rolling update bloqué sur un hôte | Le contrôle de santé ne renvoie jamais 200 |
Consultez journalctl -u captcha-worker et augmentez retries/delay |
| La nouvelle config n'est pas appliquée | Le handler n'a pas été notifié | Relancez avec --force-handlers ou vérifiez la détection de changement |
| Concurrence incohérente entre hôtes | Variable surchargée dans l'inventaire | Vérifiez group_vars/host_vars et réalignez sur vos threads CaptchaAI |
FAQ
Comment chiffrer la clé API avec Ansible Vault ?
Chiffrez-la avec ansible-vault encrypt_string 'votre-cle-api' --name 'captchaai_api_key', puis référencez la variable dans group_vars ou l'inventaire. Elle n'apparaît jamais en clair dans le dépôt et le playbook la déchiffre à l'exécution avec --ask-vault-pass.
Comment déployer sur un seul worker sans toucher au reste ?
Ajoutez --limit worker-1 à la commande ansible-playbook : Ansible n'exécute les tâches que sur l'hôte ciblé, idéal pour valider une version avant de la généraliser.
Que faire si un rolling update reste bloqué sur un hôte ?
Avec serial: 1 et max_fail_percentage: 0, un échec de contrôle de santé arrête volontairement le déploiement. Diagnostiquez l'hôte via journalctl -u captcha-worker, corrigez, puis relancez : grâce à l'idempotence, les hôtes déjà à jour ne sont pas retouchés.
Ansible peut-il déployer des workers sur OVHcloud ou Scaleway ?
Oui. Ansible ne dépend pas du fournisseur : dès qu'un serveur est joignable en SSH — chez OVHcloud, Scaleway ou dans une région AWS comme eu-west-3 (Paris) — le même rôle s'applique. En général, Terraform crée les serveurs et Ansible les configure.
À quelle fréquence relancer le playbook de configuration ?
Aussi souvent que vous le souhaitez : le rôle est idempotent. Le rejouer sur un parc conforme ne provoque aucun changement ni redémarrage. Beaucoup d'équipes le planifient pour corriger toute dérive de configuration.
Pour aller plus loin
Si vous exploitez déjà plusieurs workers, récupérez votre clé API CaptchaAI et formalisez vos déploiements dans des playbooks versionnés plutôt que dans des opérations SSH manuelles : vous y gagnez reproductibilité, auditabilité et rollbacks propres.
Guides associés :
- Provisionner l'infrastructure avec Terraform
- Déployer des workers en conteneurs Docker
- Gérer la configuration de production CaptchaAI