Site logo
Tác giả
  • avatar Nguyễn Đức Xinh
    Name
    Nguyễn Đức Xinh
    Twitter
Ngày xuất bản
Ngày xuất bản

Error Handling và Debugging trong Ansible: Hướng dẫn xử lý lỗi và troubleshooting hiệu quả

Giới thiệu

Khi làm việc với Ansible, bạn sẽ không tránh khỏi việc gặp lỗi - từ lỗi cú pháp đơn giản đến lỗi logic phức tạp. Khả năng xử lý lỗi hiệu quả và debug nhanh chóng là kỹ năng quan trọng giúp bạn trở thành một Ansible engineer chuyên nghiệp.

Trong bài này, chúng ta sẽ học cách:

  • Xử lý lỗi một cách chủ động trong playbook
  • Sử dụng các công cụ debug có sẵn
  • Áp dụng các kỹ thuật troubleshooting hiệu quả

1. Hiểu về Error Handling trong Ansible

1.1 Hành vi mặc định khi có lỗi

Mặc định, khi một task fail, Ansible sẽ:

  • Dừng thực thi playbook trên host đó
  • Tiếp tục chạy trên các host khác (nếu có)
  • Báo lỗi và exit với status code khác 0
---
- name: Demo lỗi mặc định
  hosts: webservers
  tasks:
    - name: Task này sẽ fail
      command: /bin/false
    
    - name: Task này sẽ không chạy
      debug:
        msg: "Bạn sẽ không thấy message này"

1.2 Ignore Errors - Bỏ qua lỗi

Sử dụng ignore_errors: yes khi bạn biết task có thể fail nhưng muốn tiếp tục:

- name: Kiểm tra service  tồn tại không
  command: systemctl status httpd
  register: service_status
  ignore_errors: yes

- name: Cài đặt nếu chưa 
  yum:
    name: httpd
    state: present
  when: service_status.rc != 0

Lưu ý: Chỉ dùng ignore_errors khi bạn thực sự hiểu tại sao lỗi xảy ra và nó không ảnh hưởng đến logic playbook.

2. Kiểm soát Error với Failed_when

2.1 Định nghĩa điều kiện fail tùy chỉnh

failed_when cho phép bạn quyết định khi nào task được coi là fail:

- name: Kiểm tra disk space
  shell: df -h / | tail -1 | awk '{print $5}' | sed 's/%//'
  register: disk_usage
  failed_when: disk_usage.stdout|int > 80

- name: Chạy script  kiểm tra output
  script: /tmp/check_health.sh
  register: health_check
  failed_when: "'ERROR' in health_check.stdout"

2.2 Ví dụ thực tế: Kiểm tra web service

- name: Kiểm tra web service response
  uri:
    url: "http://{{ inventory_hostname }}/health"
    return_content: yes
  register: health_response
  failed_when: 
    - health_response.status != 200
    - "'healthy' not in health_response.content"

3. Changed_when - Kiểm soát trạng thái Changed

Đôi khi task chạy thành công nhưng không thực sự thay đổi gì. Sử dụng changed_when để báo cáo chính xác:

- name: Kiểm tra config file syntax
  command: nginx -t
  register: nginx_test
  changed_when: false  # Command này chỉ test, không thay đổi gì

- name: Lấy thông tin hệ thống
  shell: uname -a
  register: system_info
  changed_when: false

4. Block và Rescue - Xử lý lỗi có cấu trúc

4.1 Cấu trúc Block-Rescue-Always

Tương tự try-catch trong lập trình, Ansible có block-rescue-always:

- name: Demo Block Rescue
  hosts: webservers
  tasks:
    - block:
        - name: Cài đặt package
          yum:
            name: nginx
            state: present
        
        - name: Start service
          service:
            name: nginx
            state: started
      
      rescue:
        - name: Thông báo lỗi
          debug:
            msg: "Có lỗi xảy ra khi cài đặt nginx!"
        
        - name: Gửi email cảnh báo
          mail:
            subject: "Ansible Error on {{ inventory_hostname }}"
            body: "Failed to install nginx"
            to: admin@example.com
      
      always:
        - name: Ghi log
          lineinfile:
            path: /var/log/ansible_deploy.log
            line: "Deployment attempted at {{ ansible_date_time.iso8601 }}"
            create: yes

4.2 Ví dụ thực tế: Deploy an toàn

- name: Deploy ứng dụng với rollback
  hosts: appservers
  tasks:
    - block:
        - name: Backup version hiện tại
          command: cp -r /var/www/app /var/www/app.backup
        
        - name: Deploy version mới
          git:
            repo: 'https://github.com/example/app.git'
            dest: /var/www/app
            version: main
        
        - name: Restart application
          service:
            name: myapp
            state: restarted
      
      rescue:
        - name: Rollback về version 
          command: mv /var/www/app.backup /var/www/app
        
        - name: Restart với version 
          service:
            name: myapp
            state: restarted
        
        - name: Notify team
          debug:
            msg: "Deploy failed! Đã rollback về version trước."

5. Debug Module - Công cụ debug chính

5.1 Debug cơ bản

- name: Debug đơn giản
  debug:
    msg: "Giá trị của biến: {{ my_variable }}"

- name: Debug với verbosity level
  debug:
    msg: "Thông tin chi tiết này chỉ hiện khi chạy với -v"
    verbosity: 1

5.2 Debug variables và facts

- name: Hiển thị tất cả facts của host
  debug:
    var: ansible_facts

- name: Debug một variable cụ thể
  debug:
    var: hostvars[inventory_hostname]

- name: Debug với format đẹp hơn
  debug:
    msg: |
      Hostname: {{ ansible_hostname }}
      IP Address: {{ ansible_default_ipv4.address }}
      OS: {{ ansible_distribution }} {{ ansible_distribution_version }}

6. Kỹ thuật Debugging nâng cao

6.1 Assert - Kiểm tra điều kiện

- name: Kiểm tra điều kiện trước khi tiếp tục
  assert:
    that:
      - ansible_distribution == "CentOS"
      - ansible_distribution_major_version|int >= 7
      - ansible_memtotal_mb >= 2048
    fail_msg: "Server không đáp ứng yêu cầu tối thiểu"
    success_msg: "Server đạt yêu cầu, tiếp tục deploy"

6.2 Register và Debug kết hợp

- name: Chạy command  debug output
  shell: ps aux | grep nginx | wc -l
  register: nginx_processes

- name: Hiển thị kết quả đầy đủ
  debug:
    var: nginx_processes

- name: Chỉ hiển thị stdout
  debug:
    msg: "Số process nginx: {{ nginx_processes.stdout }}"

6.3 Sử dụng --step và --start-at-task

# Chạy từng task một, xác nhận trước khi tiếp tục
ansible-playbook playbook.yml --step

# Bắt đầu từ một task cụ thể
ansible-playbook playbook.yml --start-at-task="Install nginx"

# Chạy với check mode (dry-run)
ansible-playbook playbook.yml --check

# Tăng verbosity level
ansible-playbook playbook.yml -vvv

7. Best Practices

7.1 Checklist debug hiệu quả

  1. Bắt đầu với syntax check:
ansible-playbook playbook.yml --syntax-check
  1. Sử dụng check mode trước:
ansible-playbook playbook.yml --check --diff
  1. Tăng verbosity khi cần:
-v    # Thông tin cơ bản
-vv   # Chi tiết hơn
-vvv  # Rất chi tiết
-vvvv # Connection debugging

7.2 Cấu trúc error handling tốt

- name: Production deployment với error handling đầy đủ
  hosts: production
  tasks:
    - name: Pre-deployment checks
      block:
        - name: Kiểm tra disk space
          assert:
            that: ansible_facts.devices.sda.partitions.sda1.size_available|int > 1000000000
            fail_msg: "Không đủ disk space"
        
        - name: Kiểm tra memory
          assert:
            that: ansible_memfree_mb > 500
            fail_msg: "Không đủ RAM"
      
      rescue:
        - name: Cleanup  thử lại
          command: "{{ cleanup_script }}"
          when: cleanup_script is defined

    - name: Main deployment
      block:
        - name: Deploy application
          include_tasks: deploy.yml
      
      rescue:
        - name: Rollback
          include_tasks: rollback.yml
        
        - name: Send alert
          include_tasks: alert.yml
      
      always:
        - name: Log deployment
          include_tasks: logging.yml

Tổng kết

Trong bài này, chúng ta đã học:

  • Error Handling: ignore_errors, failed_when, changed_when
  • Block-Rescue-Always: Cấu trúc xử lý lỗi có tổ chức
  • Debug Module: Công cụ debug chính trong Ansible
  • Assert: Kiểm tra điều kiện trước khi thực thi
  • CLI Options: --check, --step, -vvv cho debugging

Bài tập thực hành

Hãy tạo một playbook để:

  1. Cài đặt nginx
  2. Kiểm tra service đã chạy chưa
  3. Nếu fail, thử cài đặt apache thay thế
  4. Log tất cả các bước vào file
  5. Gửi thông báo khi hoàn thành hoặc fail

Tip: Sử dụng block-rescue và register để theo dõi từng bước!