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

Ansible Playbooks Phần 2: Tasks, Variables và Handlers

Phần 2 của series Ansible Playbooks tập trung vào các thành phần quan trọng: Tasks, Variables và Handlers.

Phần 2: Tasks, Variables và Handlers:

  • Tasks và cách tổ chức tasks
  • Variables: khai báo, sử dụng, precedence
  • Variables từ external files
  • Register để lưu output
  • Handlers và notifications
  • Ví dụ deploy với variables và handlers

Tasks

Là từng bước Ansible sẽ thực thi. Mỗi task gọi một module và truyền parameters.

Cấu trúc task cơ bản

- name: Cài nginx
  apt:
    name: nginx
    state: present
  become: yes

Task với nhiều parameters

- name: Copy nginx config
  copy:
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf
    owner: root
    group: root
    mode: '0644'
    backup: yes
  become: yes
  notify: restart nginx

Multiple tasks trong một play

tasks:
  - name: Update apt cache
    apt:
      update_cache: yes
      cache_valid_time: 3600
    become: yes

  - name: Install packages
    apt:
      name: "{{ item }}"
      state: present
    loop:
      - nginx
      - git
      - vim
    become: yes

  - name: Start nginx service
    service:
      name: nginx
      state: started
      enabled: yes
    become: yes

Task organization best practices

Dictionary format vs Inline

# BAD - Inline format khó đọc
- name: Install nginx
  apt: name=nginx state=present update_cache=yes

# GOOD - Dictionary format dễ đọc
- name: Install nginx
  apt:
    name: nginx
    state: present
    update_cache: yes

Descriptive names

# BAD - Không rõ ràng
- apt:
    name: nginx

# GOOD - Mô tả chi tiết
- name: Install nginx web server for production environment
  apt:
    name: nginx
    state: present

Variables (Biến)

Biến giúp tái sử dụng giá trị và customize behavior.

Khai báo trong Playbook

- name: Deploy application
  hosts: web
  become: yes
  
  vars:
    package_name: nginx
    http_port: 80
    server_name: example.com
    app_user: www-data
    
  tasks:
    - name: Install {{ package_name }}
      apt:
        name: "{{ package_name }}"
        state: present

Sử dụng biến

tasks:
  - name: Install {{ package_name }}
    apt:
      name: "{{ package_name }}"
      state: present

  - name: Configure nginx
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    vars:
      port: "{{ http_port }}"
      domain: "{{ server_name }}"

Variables từ file external

- name: Deploy application
  hosts: web
  vars_files:
    - vars/common.yml
    - vars/{{ env }}.yml  # dev.yml, staging.yml, prod.yml
  tasks:
    # ... tasks using variables

vars/common.yml:

app_name: myapp
app_port: 8080
log_level: info
timezone: Asia/Ho_Chi_Minh

vars/prod.yml:

env: production
debug: false
workers: 8
max_connections: 1000

vars/dev.yml:

env: development
debug: true
workers: 2
max_connections: 100

Variable types

String variables

vars:
  app_name: "myapp"
  server_name: example.com

Numeric variables

vars:
  http_port: 80
  max_workers: 4

Boolean variables

vars:
  enable_ssl: true
  debug_mode: false

List variables

vars:
  packages:
    - nginx
    - git
    - vim
  
  allowed_ips:
    - "192.168.1.0/24"
    - "10.0.0.0/8"

Dictionary variables

vars:
  database:
    host: localhost
    port: 5432
    name: myapp_db
    user: dbuser
  
  nginx:
    port: 80
    workers: 4
    keepalive_timeout: 65

Variable precedence (thứ tự ưu tiên)

Ansible có 22 levels of variable precedence, một số quan trọng:

  1. Extra vars (-e trong command line) - Cao nhất
  2. Task vars (trong task)
  3. Block vars (trong block)
  4. Play vars (trong play)
  5. Play vars_files
  6. Host vars (host_vars/hostname.yml)
  7. Group vars (group_vars/groupname.yml)
  8. Inventory vars (trong inventory file)
  9. Role defaults - Thấp nhất
# Extra vars override mọi thứ khác
ansible-playbook site.yml -e "env=production http_port=8080"

# Multiple extra vars
ansible-playbook site.yml -e "env=production" -e "debug=false"

# Extra vars từ file
ansible-playbook site.yml -e "@vars/override.yml"

Using variables in templates

Template file: nginx.conf.j2

server {
    listen {{ http_port }};
    server_name {{ server_name }};
    root {{ document_root }};
    
    access_log {{ log_dir }}/access.log;
    error_log {{ log_dir }}/error.log;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

Playbook:

- name: Configure nginx
  template:
    src: templates/nginx.conf.j2
    dest: /etc/nginx/sites-available/default
  vars:
    http_port: 80
    server_name: example.com
    document_root: /var/www/html
    log_dir: /var/log/nginx

Register - Lưu output của task

- name: Check nginx version
  command: nginx -v
  register: nginx_version
  ignore_errors: yes

- name: Display nginx version
  debug:
    var: nginx_version.stderr

- name: Check if config file exists
  stat:
    path: /etc/nginx/nginx.conf
  register: config_file

- name: Backup config if exists
  copy:
    src: /etc/nginx/nginx.conf
    dest: /etc/nginx/nginx.conf.backup
    remote_src: yes
  when: config_file.stat.exists

- name: Run application
  shell: /opt/app/start.sh
  register: app_start

- name: Show app output
  debug:
    msg: |
      Return code: {{ app_start.rc }}
      Stdout: {{ app_start.stdout }}
      Stderr: {{ app_start.stderr }}

Register output fields

Field Mô tả
stdout Output standard
stderr Error output
rc Return code (0 = success)
changed Task có thay đổi không
failed Task có fail không
skipped Task có bị skip không

Handlers

Handlers là special tasks chỉ chạy khi được notify và chỉ chạy một lần dù được notify nhiều lần.

Khi nào dùng Handlers?

  • Restart service khi config thay đổi
  • Reload configuration
  • Clear cache
  • Rebuild indexes
  • Bất kỳ tác vụ nào cần chạy sau khi có thay đổi

Cú pháp cơ bản

tasks:
  - name: Copy nginx config
    copy:
      src: nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: restart nginx

  - name: Copy php config
    copy:
      src: php.ini
      dest: /etc/php/8.1/fpm/php.ini
    notify: restart nginx

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted

Lưu ý: Handler restart nginx chỉ chạy một lần dù được notify 2 lần.

Multiple handlers

tasks:
  - name: Update nginx config
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    notify:
      - reload nginx
      - clear cache
      - send notification

handlers:
  - name: reload nginx
    service:
      name: nginx
      state: reloaded

  - name: clear cache
    shell: rm -rf /var/cache/nginx/*
    args:
      warn: false

  - name: send notification
    debug:
      msg: "Nginx configuration has been updated and reloaded"

Handlers với listen

Nhiều handlers cùng listen một keyword:

tasks:
  - name: Update nginx config
    copy:
      src: nginx.conf
      dest: /etc/nginx/nginx.conf
    notify: restart web services

  - name: Update php-fpm config
    copy:
      src: php-fpm.conf
      dest: /etc/php/8.1/fpm/php-fpm.conf
    notify: restart web services

handlers:
  - name: restart nginx
    service:
      name: nginx
      state: restarted
    listen: restart web services

  - name: restart php-fpm
    service:
      name: php8.1-fpm
      state: restarted
    listen: restart web services

Handler execution order

Handlers chạy:

  1. Sau khi tất cả tasks hoàn thành
  2. Theo thứ tự định nghĩa trong handlers section
  3. Chỉ một lần dù được notify nhiều lần
tasks:
  - name: Task 1
    copy:
      src: file1
      dest: /tmp/file1
    notify: handler 1

  - name: Task 2
    copy:
      src: file2
      dest: /tmp/file2
    notify: handler 2

  - name: Task 3
    copy:
      src: file3
      dest: /tmp/file3
    notify: handler 1  # Handler 1 vẫn chỉ chạy 1 lần

handlers:
  - name: handler 1
    debug:
      msg: "Handler 1 executed"

  - name: handler 2
    debug:
      msg: "Handler 2 executed"

# Execution order:
# 1. Task 1, Task 2, Task 3 chạy
# 2. Handler 1 chạy (chỉ 1 lần)
# 3. Handler 2 chạy

Force handlers với meta

tasks:
  - name: Update config
    template:
      src: app.conf.j2
      dest: /etc/app/app.conf
    notify: restart app

  - name: Force handlers to run now
    meta: flush_handlers

  - name: Check app is running
    uri:
      url: http://localhost:8080/health
      status_code: 200

💡 Key Takeaways

  • Tasks là building blocks của Playbooks
  • Variables giúp tái sử dụng và customize behavior
  • Variable precedence: Extra vars > Play vars > Group vars > Inventory vars > Role defaults
  • Register lưu output của tasks để sử dụng cho tasks sau
  • Handlers chỉ chạy khi được notify và chỉ chạy một lần
  • Handlers chạy sau khi tất cả tasks hoàn thành

🎯 Thực hành

  • Viết playbook sử dụng variables từ external file
  • Sử dụng register để lưu output và hiển thị kết quả
  • Tạo handlers cho restart multiple services
  • Deploy một ứng dụng với variables và handlers