Strategy & Serial #
Secara default Ansible menjalankan setiap task di semua host sebelum pindah ke task berikutnya. Ini disebut strategi linear — aman dan mudah diprediksi, tapi tidak selalu optimal. Untuk deployment yang ingin setiap server berjalan secepat mungkin secara independen, atau untuk rolling deployment yang hanya mengupdate beberapa server sekaligus, kamu perlu memahami cara mengendalikan alur eksekusi paralel ini.
Tiga Strategy Utama #
linear (default):
Task 1 → semua host selesai → Task 2 → semua host selesai → ...
Kelebihan: Mudah diprediksi, semua host selalu di tahap yang sama
Kekurangan: Host yang cepat menunggu host yang lambat
free:
Setiap host berjalan secepat mungkin, tidak menunggu host lain
Kelebihan: Lebih cepat secara total jika ada variasi kecepatan host
Kekurangan: Host bisa di tahap yang berbeda — lebih sulit di-debug
host_pinned:
Seperti free, tapi setiap 'slot' paralel diselesaikan sebelum lanjut
Berguna saat kamu ingin membatasi berapa host yang aktif sekaligus
# Menggunakan strategy di level play
- name: Deploy dengan free strategy
hosts: webservers
strategy: free # Setiap host berjalan independen
tasks:
- name: Pull kode
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
- name: Install dependencies
pip:
requirements: /opt/app/requirements.txt
virtualenv: /opt/app/venv
# Setiap host langsung lanjut ke task ini setelah pull selesai
# tanpa menunggu host lain selesai pull
serial: Rolling Deployment #
serial mengontrol berapa banyak host yang diproses sekaligus dalam satu “batch”:
- name: Rolling deployment — 1 server sekaligus
hosts: webservers
serial: 1 # Update satu server, tunggu selesai, baru lanjut ke berikutnya
tasks:
- name: Deploy kode baru
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
- name: Restart aplikasi
systemd:
name: myapp
state: restarted
- name: Verifikasi health
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
retries: 6
delay: 5
serial bisa berupa angka, persentase, atau list untuk ramp-up bertahap:
# Serial sebagai persentase
- hosts: webservers
serial: "25%" # Update 25% server sekaligus (misal: 2 dari 8 server)
# Serial sebagai list: canary deployment
- hosts: webservers
serial:
- 1 # Batch 1: satu server saja (canary)
- "10%" # Batch 2: 10% dari sisa
- "50%" # Batch 3: 50% dari sisa
- "100%" # Batch 4: semua yang tersisa
Pola list ini sangat berguna untuk canary deployment — deploy ke satu server dulu, verifikasi, baru lanjut ke lebih banyak server.
Pola Canary Deployment #
# playbooks/canary-deploy.yml
---
- name: Canary deployment — tahap 1 (1 server)
hosts: webservers
serial: 1
max_fail_percentage: 0 # Hentikan jika canary gagal
tasks:
- name: Deploy ke canary server
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
- name: Restart aplikasi
systemd:
name: myapp
state: restarted
- name: Tunggu dan verifikasi canary
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
retries: 12
delay: 10
- name: Verifikasi error rate canary tidak meningkat
uri:
url: "http://prometheus.internal/api/v1/query"
method: GET
body_format: form-urlencoded
body: >-
query=rate(http_requests_total{status=~"5..",instance="{{ inventory_hostname }}"}[5m])
register: error_rate
failed_when:
- error_rate.json.data.result | length > 0
- error_rate.json.data.result[0].value[1] | float > 0.01
- name: Deploy ke sisa server setelah canary OK
hosts: webservers[1:] # Semua kecuali server pertama (canary)
serial: "25%"
tasks:
- name: Deploy ke sisa server
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
- name: Restart aplikasi
systemd:
name: myapp
state: restarted
throttle: Batasi Konkurensi di Level Task #
serial mengontrol batch di level play. throttle membatasi konkurensi di level task individual — berguna untuk task yang membebani resource eksternal:
- name: Deploy ke semua server
hosts: webservers
strategy: free # Setiap host berjalan secepat mungkin
tasks:
- name: Pull kode (bisa paralel sepenuhnya)
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
- name: Download artifact dari S3 (batasi 5 download sekaligus)
aws_s3:
bucket: my-artifacts
object: "releases/{{ version }}/app.tar.gz"
dest: /tmp/app.tar.gz
mode: get
throttle: 5 # Maksimal 5 host menjalankan task ini bersamaan
# Mencegah throttling dari S3 atau membanjiri bandwidth
- name: Restart aplikasi (bisa paralel sepenuhnya)
systemd:
name: myapp
state: restarted
run_once dengan Serial #
Saat menggunakan serial, task dengan run_once hanya berjalan sekali di batch pertama, bukan di setiap batch:
- name: Rolling deploy dengan migrasi database
hosts: appservers
serial: 2
pre_tasks:
- name: Jalankan migrasi database (hanya sekali, di awal)
command: python manage.py migrate
run_once: true # Hanya di batch pertama, server pertama
delegate_to: "{{ groups['appservers'][0] }}"
tasks:
- name: Deploy kode ke semua server (per batch)
git:
repo: https://github.com/company/app.git
dest: /opt/app
version: "{{ version }}"
Ringkasan #
linear(default): semua host menyelesaikan satu task sebelum lanjut — mudah diprediksi tapi bisa lambat jika ada variasi kecepatan host.free: setiap host berjalan secepat mungkin tanpa menunggu host lain — lebih cepat, tapi lebih sulit di-debug karena host bisa di tahap berbeda.serial: 1untuk zero-downtime rolling deployment — update satu server, verifikasi, baru lanjut ke berikutnya.serialsebagai list ([1, "10%", "50%", "100%"]) untuk canary deployment — ramp-up bertahap dengan verifikasi di setiap tahap.throttleuntuk membatasi konkurensi di level task individual — berguna saat task membebani resource eksternal (S3, database, API rate limit).max_fail_percentage: 0bersamaserialuntuk menghentikan deployment segera jika ada kegagalan — tidak ada batch berikutnya jika batch sebelumnya gagal.