BÀI VIẾT // [DEVOPS] Đôi khi Bash script tốt hơn Ansible
Đôi khi Bash script tốt hơn Ansible

Đôi khi Bash script tốt hơn Ansible

So sánh Bash và Ansible trong DevOps: khi nào nên dùng Bash script, khi nào nên dùng Ansible? Code mẫu deploy + restart service trên cả hai.

DEVOPS BASH

Bash vs Ansible — Khi nào nên chọn cái nào?

Trong series Bash, chúng ta đã thấy Bash cực kỳ mạnh mẽ cho automation. Nhưng trong DevOps, Ansible cũng là một lựa chọn phổ biến cho infrastructure automation. Vậy khi nào nên dùng Bash, khi nào nên dùng Ansible?

Đây không phải là câu hỏi “cái nào tốt hơn” mà là “cái nào phù hợp hơn” cho tình huống cụ thể. Bài viết này sẽ so sánh khách quan, kèm code mẫu thực tế, để bạn đưa ra lựa chọn đúng đắn.


So sánh tổng quan

Tiêu chíBashAnsible
Learning curveThấp — ai cũng biếtTrung bình — cần học YAML, modules
Đọc hiểuRất dễ — plain textDễ — YAML rõ ràng
IdempotentKhông — cần viết thủ côngCó — built-in
Tái sử dụngTrung bình — source/functionCao — roles, modules
InventoryManual — file hoặc arrayBuilt-in — dynamic inventory
TestingKhó — cần mockDễ — molecule
DebugDễ — bash -xTrung bình — verbose mode
DependencyKhông cóCần Python, SSH
Remote executionSSH thủ côngBuilt-in
Khi nào phù hợpQuick scripts, small tasksComplex infrastructure, multi-server

Khi nào nên dùng Bash?

Bash phù hợp khi:

  • Script đơn giản, chạy locally — backup, cleanup, health check
  • Debug nhanhbash -x giúp see từng dòng thực thi
  • Không cần dependency — Bash có sẵn trên mọi Linux server
  • Team nhỏ, cần sự linh hoạt — không muốn setup Ansible infrastructure
  • On-call situation — cần fix nhanh, không có thời gian học playbook

Code mẫu: Deploy với Bash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/bin/env bash
# ==============================================================================
# deploy.sh — Deploy application via Bash
# ==============================================================================

set -euo pipefail

readonly APP_NAME="myapp"
readonly DEPLOY_DIR="/opt/${APP_NAME}"
readonly SERVICE_NAME="${APP_NAME}.service"
readonly SERVERS=("web-01" "web-02" "web-03")
readonly SSH_KEY="${HOME}/.ssh/deploy_key"

log() { echo "[$(date '+%H:%M:%S')] $1"; }

deploy_server() {
    local server="$1"
    log "Deploying to ${server}..."

    # Pull code
    ssh -i "$SSH_KEY" "deploy@${server}" \
        "cd ${DEPLOY_DIR} && git pull origin main"

    # Restart service
    ssh -i "$SSH_KEY" "deploy@${server}" \
        "sudo systemctl restart ${SERVICE_NAME}"

    # Health check
    local status
    status=$(ssh -i "$SSH_KEY" "deploy@${server}" \
        "curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/health")

    if [[ "$status" == "200" ]]; then
        log "${server}: OK"
    else
        log "${server}: FAILED (status: ${status})"
        return 1
    fi
}

# Deploy parallel (max 3)
for server in "${SERVERS[@]}"; do
    deploy_server "$server" &
    # Limit concurrent deployments
    while (( $(jobs -r | wc -l) >= 3 )); do
        sleep 0.5
    done
done

wait
log "Deployment completed"

Khi nào nên dùng Ansible?

Ansible phù hợp khi:

  • Infrastructure phức tạp — nhiều servers, nhiều roles
  • Cần idempotent — chạy lại mà không sợ thay đổi unintended
  • Team lớn, cần convention — YAML rõ ràng, dễ review
  • Cần audit trail — Ansible log từng task
  • Multi-environment — dev, staging, production với inventory riêng

Code mẫu: Deploy với Ansible

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# deploy.yml
---
- name: Deploy application
  hosts: webservers
  become: yes
  vars:
    app_name: myapp
    deploy_dir: /opt/myapp
    service_name: myapp.service

  tasks:
    - name: Pull latest code
      git:
        repo: "https://github.com/org/myapp.git"
        dest: "{{ deploy_dir }}"
        version: main
      notify: Restart service

    - name: Ensure service is running
      systemd:
        name: "{{ service_name }}"
        state: started
        enabled: yes

    - name: Wait for health check
      uri:
        url: "http://localhost:8080/health"
        status_code: 200
      retries: 10
      delay: 5

  handlers:
    - name: Restart service
      systemd:
        name: "{{ service_name }}"
        state: restarted
1
2
3
4
5
6
7
8
# Chạy playbook
ansible-playbook -i inventory/hosts deploy.yml

# Dry run (check mode)
ansible-playbook -i inventory/hosts deploy.yml --check

# Limit to specific server
ansible-playbook -i inventory/hosts deploy.yml --limit web-01

So sánh cùng một task

Task: Restart service nếu config thay đổi

Bash:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env bash
# Kiểm tra file thay đổi và restart service

CONFIG_FILE="/etc/myapp/config.yml"
BACKUP_FILE="/tmp/config_backup"

current_hash=$(md5sum "$CONFIG_FILE" | awk '{print $1}')

if [[ -f "$BACKUP_FILE" ]]; then
    old_hash=$(cat "$BACKUP_FILE")
else
    old_hash=""
fi

if [[ "$current_hash" != "$old_hash" ]]; then
    echo "Config changed, restarting service..."
    sudo systemctl restart myapp.service
    echo "$current_hash" > "$BACKUP_FILE"
else
    echo "Config unchanged, skipping restart"
fi

Ansible:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
- name: Restart service if config changed
  hosts: webservers
  tasks:
    - name: Copy config file
      copy:
        src: files/config.yml
        dest: /etc/myapp/config.yml
      register: config_result

    - name: Restart service
      systemd:
        name: myapp.service
        state: restarted
      when: config_result.changed

Phân tích

BashAnsible
Dòng code~15 dòng~12 dòng
Đọc hiểuRất dễDễ
IdempotentKhông — cần hash trackingCó — register + when
RemoteCần SSH loopBuilt-in

Team maturity là yếu tố quyết định

Ansible cần discipline

Ansible mạnh nhưng đòi hỏi:

  • Convention rõ ràng — đặt tên task, variable thống nhất
  • Code review nghiêm túc — YAML dễ viết nhưng dễ loạn
  • Testing — dùng molecule hoặc Terratest
  • Documentation — mỗi role phải có README

Nếu team không có những thứ này, playbook sẽ biến thành “YAML spaghetti” — khó debug hơn cả Bash.

Bash phù hợp với team linh hoạt

Bash phù hợp khi:

  • Team nhỏ (< 5 người) — không cần quy trình phức tạp
  • Cần fix nhanh — on-call situation
  • Scripts ngắn — dưới 200 dòng
  • Không muốn dependency — chỉ cần Bash và SSH

Kết hợp cả hai

Trong thực tế, nhiều team dùng cả hai:

TaskDùng gì
Quick fix, on-callBash
Deploy đơn giảnBash
Infrastructure provisioningAnsible
Configuration managementAnsible
Cron job đơn giảnBash
Multi-server orchestrationAnsible

Ví dụ:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Bash script gọi Ansible playbook
#!/usr/bin/env bash
set -euo pipefail

echo "Running infrastructure setup..."
ansible-playbook -i inventory/prod setup.yml

echo "Deploying application..."
ansible-playbook -i inventory/prod deploy.yml

echo "Running post-deploy checks..."
ansible-playbook -i inventory/prod health-check.yml

echo "All done!"

Ghi chú triển khai

  • Đừng thần thánh hóa công cụ: Cả Bash và Ansible đều là tools. Chọn tool phù hợp với task, không phải “trend”.
  • Team review: Dù dùng Bash hay Ansible, code review đều quan trọng. Bash cần check cho security, Ansible cần check cho idempotency.
  • Documentation: Bash scripts nên có --help và comment. Ansible roles nên có README và variable docs.
  • Testing: Bash khó test hơn, nhưng vẫn nên test critical scripts. Ansible có molecule cho testing.
  • Progressive adoption: Bắt đầu với Bash khi team nhỏ. Khi team lớn hơn và cần structure, migrate dần sang Ansible.

Lời kết

Bash và Ansible không phải là đối thủ mà là complementary tools. Bash tuyệt vời cho quick scripts, debugging, và situations cần sự linh hoạt. Ansible tuyệt vời cho complex infrastructure, multi-server management, và teams cần convention.

Chọn công cụ phù hợp với task và maturity level của team. Đừng dùng Ansible cho task 5 dòng Bash có thể xử lý, và đừng dùng Bash cho infrastructure phức tạp cần idempotent.

Điều quan trọng nhất là hiểu strengths và weaknesses của mỗi tool để đưa ra quyết định đúng đắn trong DevOps workflow.

THẢO LUẬN & BÌNH LUẬN